xref: /openbmc/qemu/target/hppa/translate.c (revision 9dfcd2434989bb09b1ca11258180d9095c1d7ba8)
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 
45bc921866SRichard Henderson typedef struct DisasIAQE {
46bc921866SRichard Henderson     /* IASQ; may be null for no change from TB. */
47bc921866SRichard Henderson     TCGv_i64 space;
480d89cb7cSRichard Henderson     /* IAOQ base; may be null for relative address. */
49bc921866SRichard Henderson     TCGv_i64 base;
500d89cb7cSRichard Henderson     /* IAOQ addend; if base is null, relative to ctx->iaoq_first. */
51bc921866SRichard Henderson     int64_t disp;
52bc921866SRichard Henderson } DisasIAQE;
53bc921866SRichard Henderson 
5480603007SRichard Henderson typedef struct DisasDelayException {
5580603007SRichard Henderson     struct DisasDelayException *next;
5680603007SRichard Henderson     TCGLabel *lab;
5780603007SRichard Henderson     uint32_t insn;
5880603007SRichard Henderson     bool set_iir;
5980603007SRichard Henderson     int8_t set_n;
6080603007SRichard Henderson     uint8_t excp;
6180603007SRichard Henderson     /* Saved state at parent insn. */
6280603007SRichard Henderson     DisasIAQE iaq_f, iaq_b;
6380603007SRichard Henderson } DisasDelayException;
6480603007SRichard Henderson 
6561766fe9SRichard Henderson typedef struct DisasContext {
66d01a3625SRichard Henderson     DisasContextBase base;
6761766fe9SRichard Henderson     CPUState *cs;
6861766fe9SRichard Henderson 
69bc921866SRichard Henderson     /* IAQ_Front, IAQ_Back. */
70bc921866SRichard Henderson     DisasIAQE iaq_f, iaq_b;
71bc921866SRichard Henderson     /* IAQ_Next, for jumps, otherwise null for simple advance. */
72bc921866SRichard Henderson     DisasIAQE iaq_j, *iaq_n;
7361766fe9SRichard Henderson 
740d89cb7cSRichard Henderson     /* IAOQ_Front at entry to TB. */
750d89cb7cSRichard Henderson     uint64_t iaoq_first;
760d89cb7cSRichard Henderson 
7761766fe9SRichard Henderson     DisasCond null_cond;
7861766fe9SRichard Henderson     TCGLabel *null_lab;
7961766fe9SRichard Henderson 
8080603007SRichard Henderson     DisasDelayException *delay_excp_list;
81a4db4a78SRichard Henderson     TCGv_i64 zero;
82a4db4a78SRichard Henderson 
831a19da0dSRichard Henderson     uint32_t insn;
84494737b7SRichard Henderson     uint32_t tb_flags;
853d68ee7bSRichard Henderson     int mmu_idx;
863d68ee7bSRichard Henderson     int privilege;
8761766fe9SRichard Henderson     bool psw_n_nonzero;
88bd6243a3SRichard Henderson     bool is_pa20;
8924638bd1SRichard Henderson     bool insn_start_updated;
90217d1a5eSRichard Henderson 
91217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
92217d1a5eSRichard Henderson     MemOp unalign;
93217d1a5eSRichard Henderson #endif
9461766fe9SRichard Henderson } DisasContext;
9561766fe9SRichard Henderson 
96217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY
97217d1a5eSRichard Henderson #define UNALIGN(C)       (C)->unalign
9817fe594cSRichard Henderson #define MMU_DISABLED(C)  false
99217d1a5eSRichard Henderson #else
1002d4afb03SRichard Henderson #define UNALIGN(C)       MO_ALIGN
10117fe594cSRichard Henderson #define MMU_DISABLED(C)  MMU_IDX_MMU_DISABLED((C)->mmu_idx)
102217d1a5eSRichard Henderson #endif
103217d1a5eSRichard Henderson 
104e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently.  */
105451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val)
106e36f27efSRichard Henderson {
107881d1073SHelge Deller     /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */
108881d1073SHelge Deller     if (ctx->is_pa20) {
109e36f27efSRichard Henderson         if (val & PSW_SM_W) {
110881d1073SHelge Deller             val |= PSW_W;
111881d1073SHelge Deller         }
112881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_G);
113881d1073SHelge Deller     } else {
114881d1073SHelge Deller         val &= ~(PSW_SM_W | PSW_SM_E | PSW_O);
115e36f27efSRichard Henderson     }
116e36f27efSRichard Henderson     return val;
117e36f27efSRichard Henderson }
118e36f27efSRichard Henderson 
119deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base.  */
120451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val)
121deee69a1SRichard Henderson {
122deee69a1SRichard Henderson     return ~val;
123deee69a1SRichard Henderson }
124deee69a1SRichard Henderson 
1251cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value
1261cd012a5SRichard Henderson    we use for the final M.  */
127451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val)
1281cd012a5SRichard Henderson {
1291cd012a5SRichard Henderson     return val & 2 ? (val & 1 ? -1 : 1) : 0;
1301cd012a5SRichard Henderson }
1311cd012a5SRichard Henderson 
132740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify.  */
133451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val)
134740038d7SRichard Henderson {
135740038d7SRichard Henderson     return val ? 1 : -1;
136740038d7SRichard Henderson }
137740038d7SRichard Henderson 
138451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val)
139740038d7SRichard Henderson {
140740038d7SRichard Henderson     return val ? -1 : 1;
141740038d7SRichard Henderson }
142740038d7SRichard Henderson 
143740038d7SRichard Henderson /* Used for branch targets and fp memory ops.  */
144451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val)
14501afb7beSRichard Henderson {
14601afb7beSRichard Henderson     return val << 2;
14701afb7beSRichard Henderson }
14801afb7beSRichard Henderson 
1490588e061SRichard Henderson /* Used for assemble_21.  */
150451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val)
1510588e061SRichard Henderson {
1520588e061SRichard Henderson     return val << 11;
1530588e061SRichard Henderson }
1540588e061SRichard Henderson 
15572ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val)
15672ae4f2bSRichard Henderson {
15772ae4f2bSRichard Henderson     /*
15872ae4f2bSRichard Henderson      * Officially, 32 * x + 32 - y.
15972ae4f2bSRichard Henderson      * Here, x is already in bit 5, and y is [4:0].
16072ae4f2bSRichard Henderson      * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1,
16172ae4f2bSRichard Henderson      * with the overflow from bit 4 summing with x.
16272ae4f2bSRichard Henderson      */
16372ae4f2bSRichard Henderson     return (val ^ 31) + 1;
16472ae4f2bSRichard Henderson }
16572ae4f2bSRichard Henderson 
1664768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */
1674768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val)
1684768c28eSRichard Henderson {
1694768c28eSRichard Henderson     /*
1704768c28eSRichard Henderson      * @val is bit 0 and bits [4:15].
1714768c28eSRichard Henderson      * Swizzle thing around depending on PSW.W.
1724768c28eSRichard Henderson      */
1734768c28eSRichard Henderson     int im10a = extract32(val, 1, 10);
1744768c28eSRichard Henderson     int s = extract32(val, 11, 2);
1754768c28eSRichard Henderson     int i = (-(val & 1) << 13) | (im10a << 3);
1764768c28eSRichard Henderson 
1774768c28eSRichard Henderson     if (ctx->tb_flags & PSW_W) {
1784768c28eSRichard Henderson         i ^= s << 13;
1794768c28eSRichard Henderson     }
1804768c28eSRichard Henderson     return i;
1814768c28eSRichard Henderson }
1824768c28eSRichard Henderson 
18346174e14SRichard Henderson /* Expander for assemble_16a(s,im11a,i). */
18446174e14SRichard Henderson static int expand_12a(DisasContext *ctx, int val)
18546174e14SRichard Henderson {
18646174e14SRichard Henderson     /*
18746174e14SRichard Henderson      * @val is bit 0 and bits [3:15].
18846174e14SRichard Henderson      * Swizzle thing around depending on PSW.W.
18946174e14SRichard Henderson      */
19046174e14SRichard Henderson     int im11a = extract32(val, 1, 11);
19146174e14SRichard Henderson     int s = extract32(val, 12, 2);
19246174e14SRichard Henderson     int i = (-(val & 1) << 13) | (im11a << 2);
19346174e14SRichard Henderson 
19446174e14SRichard Henderson     if (ctx->tb_flags & PSW_W) {
19546174e14SRichard Henderson         i ^= s << 13;
19646174e14SRichard Henderson     }
19746174e14SRichard Henderson     return i;
19846174e14SRichard Henderson }
19946174e14SRichard Henderson 
20072bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */
20172bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val)
20272bace2dSRichard Henderson {
20372bace2dSRichard Henderson     /*
20472bace2dSRichard Henderson      * @val is bits [0:15], containing both im14 and s.
20572bace2dSRichard Henderson      * Swizzle thing around depending on PSW.W.
20672bace2dSRichard Henderson      */
20772bace2dSRichard Henderson     int s = extract32(val, 14, 2);
20872bace2dSRichard Henderson     int i = (-(val & 1) << 13) | extract32(val, 1, 13);
20972bace2dSRichard Henderson 
21072bace2dSRichard Henderson     if (ctx->tb_flags & PSW_W) {
21172bace2dSRichard Henderson         i ^= s << 13;
21272bace2dSRichard Henderson     }
21372bace2dSRichard Henderson     return i;
21472bace2dSRichard Henderson }
21572bace2dSRichard Henderson 
21672bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */
21772bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp)
21872bace2dSRichard Henderson {
21972bace2dSRichard Henderson     return ctx->tb_flags & PSW_W ? 0 : sp;
22072bace2dSRichard Henderson }
22172bace2dSRichard Henderson 
222c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */
223c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val)
224c65c3ee1SRichard Henderson {
225c65c3ee1SRichard Henderson     return val ? val : 4; /* 0 == "*<<" */
226c65c3ee1SRichard Henderson }
227c65c3ee1SRichard Henderson 
22882d0c831SRichard Henderson /*
22982d0c831SRichard Henderson  * In many places pa1.x did not decode the bit that later became
23082d0c831SRichard Henderson  * the pa2.0 D bit.  Suppress D unless the cpu is pa2.0.
23182d0c831SRichard Henderson  */
23282d0c831SRichard Henderson static int pa20_d(DisasContext *ctx, int val)
23382d0c831SRichard Henderson {
23482d0c831SRichard Henderson     return ctx->is_pa20 & val;
23582d0c831SRichard Henderson }
23601afb7beSRichard Henderson 
23740f9f908SRichard Henderson /* Include the auto-generated decoder.  */
238abff1abfSPaolo Bonzini #include "decode-insns.c.inc"
23940f9f908SRichard Henderson 
24061766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
24161766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
242869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
24361766fe9SRichard Henderson 
24461766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
24561766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
246869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
24761766fe9SRichard Henderson 
248e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately
249e1b5a5edSRichard Henderson    to recognize unmasked interrupts.  */
250e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT      DISAS_TARGET_2
251c5d0aec2SRichard Henderson #define DISAS_EXIT                  DISAS_TARGET_3
252e1b5a5edSRichard Henderson 
25361766fe9SRichard Henderson /* global register indexes */
2546fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32];
25533423472SRichard Henderson static TCGv_i64 cpu_sr[4];
256494737b7SRichard Henderson static TCGv_i64 cpu_srH;
2576fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f;
2586fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b;
259c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f;
260c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b;
2616fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar;
2626fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n;
2636fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v;
2646fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb;
2656fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb;
26661766fe9SRichard Henderson 
26761766fe9SRichard Henderson void hppa_translate_init(void)
26861766fe9SRichard Henderson {
26961766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
27061766fe9SRichard Henderson 
2716fd0c7bcSRichard Henderson     typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar;
27261766fe9SRichard Henderson     static const GlobalVar vars[] = {
27335136a77SRichard Henderson         { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) },
27461766fe9SRichard Henderson         DEF_VAR(psw_n),
27561766fe9SRichard Henderson         DEF_VAR(psw_v),
27661766fe9SRichard Henderson         DEF_VAR(psw_cb),
27761766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
27861766fe9SRichard Henderson         DEF_VAR(iaoq_f),
27961766fe9SRichard Henderson         DEF_VAR(iaoq_b),
28061766fe9SRichard Henderson     };
28161766fe9SRichard Henderson 
28261766fe9SRichard Henderson #undef DEF_VAR
28361766fe9SRichard Henderson 
28461766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
28561766fe9SRichard Henderson     static const char gr_names[32][4] = {
28661766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
28761766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
28861766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
28961766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
29061766fe9SRichard Henderson     };
29133423472SRichard Henderson     /* SR[4-7] are not global registers so that we can index them.  */
292494737b7SRichard Henderson     static const char sr_names[5][4] = {
293494737b7SRichard Henderson         "sr0", "sr1", "sr2", "sr3", "srH"
29433423472SRichard Henderson     };
29561766fe9SRichard Henderson 
29661766fe9SRichard Henderson     int i;
29761766fe9SRichard Henderson 
298f764718dSRichard Henderson     cpu_gr[0] = NULL;
29961766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
300ad75a51eSRichard Henderson         cpu_gr[i] = tcg_global_mem_new(tcg_env,
30161766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
30261766fe9SRichard Henderson                                        gr_names[i]);
30361766fe9SRichard Henderson     }
30433423472SRichard Henderson     for (i = 0; i < 4; i++) {
305ad75a51eSRichard Henderson         cpu_sr[i] = tcg_global_mem_new_i64(tcg_env,
30633423472SRichard Henderson                                            offsetof(CPUHPPAState, sr[i]),
30733423472SRichard Henderson                                            sr_names[i]);
30833423472SRichard Henderson     }
309ad75a51eSRichard Henderson     cpu_srH = tcg_global_mem_new_i64(tcg_env,
310494737b7SRichard Henderson                                      offsetof(CPUHPPAState, sr[4]),
311494737b7SRichard Henderson                                      sr_names[4]);
31261766fe9SRichard Henderson 
31361766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
31461766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
315ad75a51eSRichard Henderson         *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name);
31661766fe9SRichard Henderson     }
317c301f34eSRichard Henderson 
318ad75a51eSRichard Henderson     cpu_iasq_f = tcg_global_mem_new_i64(tcg_env,
319c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_f),
320c301f34eSRichard Henderson                                         "iasq_f");
321ad75a51eSRichard Henderson     cpu_iasq_b = tcg_global_mem_new_i64(tcg_env,
322c301f34eSRichard Henderson                                         offsetof(CPUHPPAState, iasq_b),
323c301f34eSRichard Henderson                                         "iasq_b");
32461766fe9SRichard Henderson }
32561766fe9SRichard Henderson 
326f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg)
327f5b5c857SRichard Henderson {
32824638bd1SRichard Henderson     assert(!ctx->insn_start_updated);
32924638bd1SRichard Henderson     ctx->insn_start_updated = true;
33024638bd1SRichard Henderson     tcg_set_insn_start_param(ctx->base.insn_start, 2, breg);
331f5b5c857SRichard Henderson }
332f5b5c857SRichard Henderson 
333129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
334129e9cc3SRichard Henderson {
335f764718dSRichard Henderson     return (DisasCond){
336f764718dSRichard Henderson         .c = TCG_COND_NEVER,
337f764718dSRichard Henderson         .a0 = NULL,
338f764718dSRichard Henderson         .a1 = NULL,
339f764718dSRichard Henderson     };
340129e9cc3SRichard Henderson }
341129e9cc3SRichard Henderson 
342df0232feSRichard Henderson static DisasCond cond_make_t(void)
343df0232feSRichard Henderson {
344df0232feSRichard Henderson     return (DisasCond){
345df0232feSRichard Henderson         .c = TCG_COND_ALWAYS,
346df0232feSRichard Henderson         .a0 = NULL,
347df0232feSRichard Henderson         .a1 = NULL,
348df0232feSRichard Henderson     };
349df0232feSRichard Henderson }
350df0232feSRichard Henderson 
351129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
352129e9cc3SRichard Henderson {
353f764718dSRichard Henderson     return (DisasCond){
354f764718dSRichard Henderson         .c = TCG_COND_NE,
355f764718dSRichard Henderson         .a0 = cpu_psw_n,
3566fd0c7bcSRichard Henderson         .a1 = tcg_constant_i64(0)
357f764718dSRichard Henderson     };
358129e9cc3SRichard Henderson }
359129e9cc3SRichard Henderson 
3604c42fd0dSRichard Henderson static DisasCond cond_make_tt(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
361b47a4a02SSven Schnelle {
362b47a4a02SSven Schnelle     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
3634fe9533aSRichard Henderson     return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 };
3644fe9533aSRichard Henderson }
3654fe9533aSRichard Henderson 
3664c42fd0dSRichard Henderson static DisasCond cond_make_ti(TCGCond c, TCGv_i64 a0, uint64_t imm)
3674fe9533aSRichard Henderson {
3684c42fd0dSRichard Henderson     return cond_make_tt(c, a0, tcg_constant_i64(imm));
369b47a4a02SSven Schnelle }
370b47a4a02SSven Schnelle 
3714c42fd0dSRichard Henderson static DisasCond cond_make_vi(TCGCond c, TCGv_i64 a0, uint64_t imm)
372129e9cc3SRichard Henderson {
373aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3746fd0c7bcSRichard Henderson     tcg_gen_mov_i64(tmp, a0);
3754c42fd0dSRichard Henderson     return cond_make_ti(c, tmp, imm);
376129e9cc3SRichard Henderson }
377129e9cc3SRichard Henderson 
3784c42fd0dSRichard Henderson static DisasCond cond_make_vv(TCGCond c, TCGv_i64 a0, TCGv_i64 a1)
379129e9cc3SRichard Henderson {
380aac0f603SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
381aac0f603SRichard Henderson     TCGv_i64 t1 = tcg_temp_new_i64();
382129e9cc3SRichard Henderson 
3836fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t0, a0);
3846fd0c7bcSRichard Henderson     tcg_gen_mov_i64(t1, a1);
3854c42fd0dSRichard Henderson     return cond_make_tt(c, t0, t1);
386129e9cc3SRichard Henderson }
387129e9cc3SRichard Henderson 
3886fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg)
38961766fe9SRichard Henderson {
39061766fe9SRichard Henderson     if (reg == 0) {
391bc3da3cfSRichard Henderson         return ctx->zero;
39261766fe9SRichard Henderson     } else {
39361766fe9SRichard Henderson         return cpu_gr[reg];
39461766fe9SRichard Henderson     }
39561766fe9SRichard Henderson }
39661766fe9SRichard Henderson 
3976fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg)
39861766fe9SRichard Henderson {
399129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
400aac0f603SRichard Henderson         return tcg_temp_new_i64();
40161766fe9SRichard Henderson     } else {
40261766fe9SRichard Henderson         return cpu_gr[reg];
40361766fe9SRichard Henderson     }
40461766fe9SRichard Henderson }
40561766fe9SRichard Henderson 
4066fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t)
407129e9cc3SRichard Henderson {
408129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
4096fd0c7bcSRichard Henderson         tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0,
410129e9cc3SRichard Henderson                             ctx->null_cond.a1, dest, t);
411129e9cc3SRichard Henderson     } else {
4126fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, t);
413129e9cc3SRichard Henderson     }
414129e9cc3SRichard Henderson }
415129e9cc3SRichard Henderson 
4166fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t)
417129e9cc3SRichard Henderson {
418129e9cc3SRichard Henderson     if (reg != 0) {
419129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
420129e9cc3SRichard Henderson     }
421129e9cc3SRichard Henderson }
422129e9cc3SRichard Henderson 
423e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
42496d6407fSRichard Henderson # define HI_OFS  0
42596d6407fSRichard Henderson # define LO_OFS  4
42696d6407fSRichard Henderson #else
42796d6407fSRichard Henderson # define HI_OFS  4
42896d6407fSRichard Henderson # define LO_OFS  0
42996d6407fSRichard Henderson #endif
43096d6407fSRichard Henderson 
43196d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
43296d6407fSRichard Henderson {
43396d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
434ad75a51eSRichard Henderson     tcg_gen_ld_i32(ret, tcg_env,
43596d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
43696d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
43796d6407fSRichard Henderson     return ret;
43896d6407fSRichard Henderson }
43996d6407fSRichard Henderson 
440ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
441ebe9383cSRichard Henderson {
442ebe9383cSRichard Henderson     if (rt == 0) {
4430992a930SRichard Henderson         TCGv_i32 ret = tcg_temp_new_i32();
4440992a930SRichard Henderson         tcg_gen_movi_i32(ret, 0);
4450992a930SRichard Henderson         return ret;
446ebe9383cSRichard Henderson     } else {
447ebe9383cSRichard Henderson         return load_frw_i32(rt);
448ebe9383cSRichard Henderson     }
449ebe9383cSRichard Henderson }
450ebe9383cSRichard Henderson 
451ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
452ebe9383cSRichard Henderson {
453ebe9383cSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
4540992a930SRichard Henderson     if (rt == 0) {
4550992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4560992a930SRichard Henderson     } else {
457ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(ret, tcg_env,
458ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
459ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
460ebe9383cSRichard Henderson     }
4610992a930SRichard Henderson     return ret;
462ebe9383cSRichard Henderson }
463ebe9383cSRichard Henderson 
46496d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
46596d6407fSRichard Henderson {
466ad75a51eSRichard Henderson     tcg_gen_st_i32(val, tcg_env,
46796d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
46896d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
46996d6407fSRichard Henderson }
47096d6407fSRichard Henderson 
47196d6407fSRichard Henderson #undef HI_OFS
47296d6407fSRichard Henderson #undef LO_OFS
47396d6407fSRichard Henderson 
47496d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
47596d6407fSRichard Henderson {
47696d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
477ad75a51eSRichard Henderson     tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt]));
47896d6407fSRichard Henderson     return ret;
47996d6407fSRichard Henderson }
48096d6407fSRichard Henderson 
481ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
482ebe9383cSRichard Henderson {
483ebe9383cSRichard Henderson     if (rt == 0) {
4840992a930SRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
4850992a930SRichard Henderson         tcg_gen_movi_i64(ret, 0);
4860992a930SRichard Henderson         return ret;
487ebe9383cSRichard Henderson     } else {
488ebe9383cSRichard Henderson         return load_frd(rt);
489ebe9383cSRichard Henderson     }
490ebe9383cSRichard Henderson }
491ebe9383cSRichard Henderson 
49296d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
49396d6407fSRichard Henderson {
494ad75a51eSRichard Henderson     tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt]));
49596d6407fSRichard Henderson }
49696d6407fSRichard Henderson 
49733423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg)
49833423472SRichard Henderson {
49933423472SRichard Henderson #ifdef CONFIG_USER_ONLY
50033423472SRichard Henderson     tcg_gen_movi_i64(dest, 0);
50133423472SRichard Henderson #else
50233423472SRichard Henderson     if (reg < 4) {
50333423472SRichard Henderson         tcg_gen_mov_i64(dest, cpu_sr[reg]);
504494737b7SRichard Henderson     } else if (ctx->tb_flags & TB_FLAG_SR_SAME) {
505494737b7SRichard Henderson         tcg_gen_mov_i64(dest, cpu_srH);
50633423472SRichard Henderson     } else {
507ad75a51eSRichard Henderson         tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg]));
50833423472SRichard Henderson     }
50933423472SRichard Henderson #endif
51033423472SRichard Henderson }
51133423472SRichard Henderson 
512129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
513129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
514129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
515129e9cc3SRichard Henderson {
516129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
517129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
518129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
519129e9cc3SRichard Henderson 
520129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
521129e9cc3SRichard Henderson 
522129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
5236e94937aSRichard Henderson         if (ctx->null_cond.a0 == cpu_psw_n) {
524aac0f603SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new_i64();
5256fd0c7bcSRichard Henderson             tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n);
526129e9cc3SRichard Henderson         }
527129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
528129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
529129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
530129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
531129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
5326fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
533129e9cc3SRichard Henderson         }
534129e9cc3SRichard Henderson 
5356fd0c7bcSRichard Henderson         tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0,
536129e9cc3SRichard Henderson                            ctx->null_cond.a1, ctx->null_lab);
537e0137378SRichard Henderson         ctx->null_cond = cond_make_f();
538129e9cc3SRichard Henderson     }
539129e9cc3SRichard Henderson }
540129e9cc3SRichard Henderson 
541129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
542129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
543129e9cc3SRichard Henderson {
544129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
545129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
5466fd0c7bcSRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, 0);
547129e9cc3SRichard Henderson         }
548129e9cc3SRichard Henderson         return;
549129e9cc3SRichard Henderson     }
5506e94937aSRichard Henderson     if (ctx->null_cond.a0 != cpu_psw_n) {
5516fd0c7bcSRichard Henderson         tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n,
552129e9cc3SRichard Henderson                             ctx->null_cond.a0, ctx->null_cond.a1);
553129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
554129e9cc3SRichard Henderson     }
555e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
556129e9cc3SRichard Henderson }
557129e9cc3SRichard Henderson 
558129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
559129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
560129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
561129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
562129e9cc3SRichard Henderson {
563129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
5646fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, x);
565129e9cc3SRichard Henderson     }
566129e9cc3SRichard Henderson }
567129e9cc3SRichard Henderson 
568129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
56940f9f908SRichard Henderson    This is the pair to nullify_over.  Always returns true so that
57040f9f908SRichard Henderson    it may be tail-called from a translate function.  */
57131234768SRichard Henderson static bool nullify_end(DisasContext *ctx)
572129e9cc3SRichard Henderson {
573129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
57431234768SRichard Henderson     DisasJumpType status = ctx->base.is_jmp;
575129e9cc3SRichard Henderson 
576f49b3537SRichard Henderson     /* For NEXT, NORETURN, STALE, we can easily continue (or exit).
577f49b3537SRichard Henderson        For UPDATED, we cannot update on the nullified path.  */
578f49b3537SRichard Henderson     assert(status != DISAS_IAQ_N_UPDATED);
579f49b3537SRichard Henderson 
580129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
581129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
582129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
583129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
58431234768SRichard Henderson         return true;
585129e9cc3SRichard Henderson     }
586129e9cc3SRichard Henderson     ctx->null_lab = NULL;
587129e9cc3SRichard Henderson 
588129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
589129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
590129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
591129e9cc3SRichard Henderson         gen_set_label(null_lab);
592129e9cc3SRichard Henderson     } else {
593129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
594129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
595129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
596129e9cc3SRichard Henderson            label we have the proper value in place.  */
597129e9cc3SRichard Henderson         nullify_save(ctx);
598129e9cc3SRichard Henderson         gen_set_label(null_lab);
599129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
600129e9cc3SRichard Henderson     }
601869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
60231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NEXT;
603129e9cc3SRichard Henderson     }
60431234768SRichard Henderson     return true;
605129e9cc3SRichard Henderson }
606129e9cc3SRichard Henderson 
607bc921866SRichard Henderson static bool iaqe_variable(const DisasIAQE *e)
608bc921866SRichard Henderson {
609bc921866SRichard Henderson     return e->base || e->space;
610bc921866SRichard Henderson }
611bc921866SRichard Henderson 
612bc921866SRichard Henderson static DisasIAQE iaqe_incr(const DisasIAQE *e, int64_t disp)
613bc921866SRichard Henderson {
614bc921866SRichard Henderson     return (DisasIAQE){
615bc921866SRichard Henderson         .space = e->space,
616bc921866SRichard Henderson         .base = e->base,
617bc921866SRichard Henderson         .disp = e->disp + disp,
618bc921866SRichard Henderson     };
619bc921866SRichard Henderson }
620bc921866SRichard Henderson 
621bc921866SRichard Henderson static DisasIAQE iaqe_branchi(DisasContext *ctx, int64_t disp)
622bc921866SRichard Henderson {
623bc921866SRichard Henderson     return (DisasIAQE){
624bc921866SRichard Henderson         .space = ctx->iaq_b.space,
625bc921866SRichard Henderson         .disp = ctx->iaq_f.disp + 8 + disp,
626bc921866SRichard Henderson     };
627bc921866SRichard Henderson }
628bc921866SRichard Henderson 
629bc921866SRichard Henderson static DisasIAQE iaqe_next_absv(DisasContext *ctx, TCGv_i64 var)
630bc921866SRichard Henderson {
631bc921866SRichard Henderson     return (DisasIAQE){
632bc921866SRichard Henderson         .space = ctx->iaq_b.space,
633bc921866SRichard Henderson         .base = var,
634bc921866SRichard Henderson     };
635bc921866SRichard Henderson }
636bc921866SRichard Henderson 
6376fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest,
638bc921866SRichard Henderson                             const DisasIAQE *src)
63961766fe9SRichard Henderson {
6407d50b696SSven Schnelle     uint64_t mask = gva_offset_mask(ctx->tb_flags);
641f13bf343SRichard Henderson 
642bc921866SRichard Henderson     if (src->base == NULL) {
6430d89cb7cSRichard Henderson         tcg_gen_movi_i64(dest, (ctx->iaoq_first + src->disp) & mask);
644bc921866SRichard Henderson     } else if (src->disp == 0) {
645bc921866SRichard Henderson         tcg_gen_andi_i64(dest, src->base, mask);
64661766fe9SRichard Henderson     } else {
647bc921866SRichard Henderson         tcg_gen_addi_i64(dest, src->base, src->disp);
648bc921866SRichard Henderson         tcg_gen_andi_i64(dest, dest, mask);
64961766fe9SRichard Henderson     }
65061766fe9SRichard Henderson }
65161766fe9SRichard Henderson 
652bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f,
653bc921866SRichard Henderson                                 const DisasIAQE *b)
65485e6cda0SRichard Henderson {
655bc921866SRichard Henderson     DisasIAQE b_next;
65685e6cda0SRichard Henderson 
657bc921866SRichard Henderson     if (b == NULL) {
658bc921866SRichard Henderson         b_next = iaqe_incr(f, 4);
659bc921866SRichard Henderson         b = &b_next;
66085e6cda0SRichard Henderson     }
661bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, f);
662bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, b);
663bc921866SRichard Henderson     if (f->space) {
664bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, f->space);
665588deedaSRichard Henderson     }
666bc921866SRichard Henderson     if (b->space || f->space) {
667bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space);
668588deedaSRichard Henderson     }
66985e6cda0SRichard Henderson }
67085e6cda0SRichard Henderson 
67143541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0)
67243541db0SRichard Henderson {
67343541db0SRichard Henderson     tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER);
67443541db0SRichard Henderson     if (!link) {
67543541db0SRichard Henderson         return;
67643541db0SRichard Henderson     }
6770d89cb7cSRichard Henderson     DisasIAQE next = iaqe_incr(&ctx->iaq_b, 4);
6780d89cb7cSRichard Henderson     copy_iaoq_entry(ctx, cpu_gr[link], &next);
67943541db0SRichard Henderson #ifndef CONFIG_USER_ONLY
68043541db0SRichard Henderson     if (with_sr0) {
68143541db0SRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b);
68243541db0SRichard Henderson     }
68343541db0SRichard Henderson #endif
68443541db0SRichard Henderson }
68543541db0SRichard Henderson 
68661766fe9SRichard Henderson static void gen_excp_1(int exception)
68761766fe9SRichard Henderson {
688ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
68961766fe9SRichard Henderson }
69061766fe9SRichard Henderson 
69131234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
69261766fe9SRichard Henderson {
693bc921866SRichard Henderson     install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b);
694129e9cc3SRichard Henderson     nullify_save(ctx);
69561766fe9SRichard Henderson     gen_excp_1(exception);
69631234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
69761766fe9SRichard Henderson }
69861766fe9SRichard Henderson 
69980603007SRichard Henderson static DisasDelayException *delay_excp(DisasContext *ctx, uint8_t excp)
70080603007SRichard Henderson {
70180603007SRichard Henderson     DisasDelayException *e = tcg_malloc(sizeof(DisasDelayException));
70280603007SRichard Henderson 
70380603007SRichard Henderson     memset(e, 0, sizeof(*e));
70480603007SRichard Henderson     e->next = ctx->delay_excp_list;
70580603007SRichard Henderson     ctx->delay_excp_list = e;
70680603007SRichard Henderson 
70780603007SRichard Henderson     e->lab = gen_new_label();
70880603007SRichard Henderson     e->insn = ctx->insn;
70980603007SRichard Henderson     e->set_iir = true;
71080603007SRichard Henderson     e->set_n = ctx->psw_n_nonzero ? 0 : -1;
71180603007SRichard Henderson     e->excp = excp;
71280603007SRichard Henderson     e->iaq_f = ctx->iaq_f;
71380603007SRichard Henderson     e->iaq_b = ctx->iaq_b;
71480603007SRichard Henderson 
71580603007SRichard Henderson     return e;
71680603007SRichard Henderson }
71780603007SRichard Henderson 
71831234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
7191a19da0dSRichard Henderson {
72080603007SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
7216fd0c7bcSRichard Henderson         tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
722ad75a51eSRichard Henderson                        tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
72331234768SRichard Henderson         gen_excp(ctx, exc);
72480603007SRichard Henderson     } else {
72580603007SRichard Henderson         DisasDelayException *e = delay_excp(ctx, exc);
72680603007SRichard Henderson         tcg_gen_brcond_i64(tcg_invert_cond(ctx->null_cond.c),
72780603007SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1, e->lab);
72880603007SRichard Henderson         ctx->null_cond = cond_make_f();
72980603007SRichard Henderson     }
73080603007SRichard Henderson     return true;
7311a19da0dSRichard Henderson }
7321a19da0dSRichard Henderson 
73331234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
73461766fe9SRichard Henderson {
73531234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
73661766fe9SRichard Henderson }
73761766fe9SRichard Henderson 
73840f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
73940f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
74040f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
74140f9f908SRichard Henderson #else
742e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
743e1b5a5edSRichard Henderson     do {                                     \
744e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
74531234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
746e1b5a5edSRichard Henderson         }                                    \
747e1b5a5edSRichard Henderson     } while (0)
74840f9f908SRichard Henderson #endif
749e1b5a5edSRichard Henderson 
750bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f,
751bc921866SRichard Henderson                         const DisasIAQE *b)
75261766fe9SRichard Henderson {
753bc921866SRichard Henderson     return (!iaqe_variable(f) &&
754bc921866SRichard Henderson             (b == NULL || !iaqe_variable(b)) &&
7550d89cb7cSRichard Henderson             translator_use_goto_tb(&ctx->base, ctx->iaoq_first + f->disp));
75661766fe9SRichard Henderson }
75761766fe9SRichard Henderson 
758129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
759129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
760129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
761129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
762129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
763129e9cc3SRichard Henderson {
764f9b11bc2SRichard Henderson     return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE)
765bc921866SRichard Henderson             && !iaqe_variable(&ctx->iaq_b)
7660d89cb7cSRichard Henderson             && (((ctx->iaoq_first + ctx->iaq_b.disp) ^ ctx->iaoq_first)
7670d89cb7cSRichard Henderson                 & TARGET_PAGE_MASK) == 0);
768129e9cc3SRichard Henderson }
769129e9cc3SRichard Henderson 
77061766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
771bc921866SRichard Henderson                         const DisasIAQE *f, const DisasIAQE *b)
77261766fe9SRichard Henderson {
773*9dfcd243SRichard Henderson     install_iaq_entries(ctx, f, b);
774bc921866SRichard Henderson     if (use_goto_tb(ctx, f, b)) {
77561766fe9SRichard Henderson         tcg_gen_goto_tb(which);
77607ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
77761766fe9SRichard Henderson     } else {
7787f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
77961766fe9SRichard Henderson     }
78061766fe9SRichard Henderson }
78161766fe9SRichard Henderson 
782b47a4a02SSven Schnelle static bool cond_need_sv(int c)
783b47a4a02SSven Schnelle {
784b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
785b47a4a02SSven Schnelle }
786b47a4a02SSven Schnelle 
787b47a4a02SSven Schnelle static bool cond_need_cb(int c)
788b47a4a02SSven Schnelle {
789b47a4a02SSven Schnelle     return c == 4 || c == 5;
790b47a4a02SSven Schnelle }
791b47a4a02SSven Schnelle 
792b47a4a02SSven Schnelle /*
793b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
794b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
795b47a4a02SSven Schnelle  */
796b2167459SRichard Henderson 
797a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
798fe2d066aSRichard Henderson                          TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv)
799b2167459SRichard Henderson {
800d6d46be1SRichard Henderson     TCGCond sign_cond, zero_cond;
801d6d46be1SRichard Henderson     uint64_t sign_imm, zero_imm;
802b2167459SRichard Henderson     DisasCond cond;
8036fd0c7bcSRichard Henderson     TCGv_i64 tmp;
804b2167459SRichard Henderson 
805d6d46be1SRichard Henderson     if (d) {
806d6d46be1SRichard Henderson         /* 64-bit condition. */
807d6d46be1SRichard Henderson         sign_imm = 0;
808d6d46be1SRichard Henderson         sign_cond = TCG_COND_LT;
809d6d46be1SRichard Henderson         zero_imm = 0;
810d6d46be1SRichard Henderson         zero_cond = TCG_COND_EQ;
811d6d46be1SRichard Henderson     } else {
812d6d46be1SRichard Henderson         /* 32-bit condition. */
813d6d46be1SRichard Henderson         sign_imm = 1ull << 31;
814d6d46be1SRichard Henderson         sign_cond = TCG_COND_TSTNE;
815d6d46be1SRichard Henderson         zero_imm = UINT32_MAX;
816d6d46be1SRichard Henderson         zero_cond = TCG_COND_TSTEQ;
817d6d46be1SRichard Henderson     }
818d6d46be1SRichard Henderson 
819b2167459SRichard Henderson     switch (cf >> 1) {
820b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
821b2167459SRichard Henderson         cond = cond_make_f();
822b2167459SRichard Henderson         break;
823b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
824d6d46be1SRichard Henderson         cond = cond_make_vi(zero_cond, res, zero_imm);
825b2167459SRichard Henderson         break;
826b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
827aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8286fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
829d6d46be1SRichard Henderson         cond = cond_make_ti(sign_cond, tmp, sign_imm);
830b2167459SRichard Henderson         break;
831b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
832b47a4a02SSven Schnelle         /*
833b47a4a02SSven Schnelle          * Simplify:
834b47a4a02SSven Schnelle          *   (N ^ V) | Z
835b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
836b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
837d6d46be1SRichard Henderson          *   ((res ^ sv) < 0 ? 1 : !res)
838d6d46be1SRichard Henderson          *   !((res ^ sv) < 0 ? 0 : res)
839b47a4a02SSven Schnelle          */
840aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
841d6d46be1SRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
842d6d46be1SRichard Henderson         tcg_gen_movcond_i64(sign_cond, tmp,
843d6d46be1SRichard Henderson                             tmp, tcg_constant_i64(sign_imm),
844d6d46be1SRichard Henderson                             ctx->zero, res);
845d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
846b2167459SRichard Henderson         break;
847fe2d066aSRichard Henderson     case 4: /* NUV / UV      (!UV / UV) */
8484c42fd0dSRichard Henderson         cond = cond_make_vi(TCG_COND_EQ, uv, 0);
849b2167459SRichard Henderson         break;
850fe2d066aSRichard Henderson     case 5: /* ZNV / VNZ     (!UV | Z / UV & !Z) */
851aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
852fe2d066aSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res);
853d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
854b2167459SRichard Henderson         break;
855b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
856d6d46be1SRichard Henderson         cond = cond_make_vi(sign_cond, sv, sign_imm);
857b2167459SRichard Henderson         break;
858b2167459SRichard Henderson     case 7: /* OD / EV */
859d6d46be1SRichard Henderson         cond = cond_make_vi(TCG_COND_TSTNE, res, 1);
860b2167459SRichard Henderson         break;
861b2167459SRichard Henderson     default:
862b2167459SRichard Henderson         g_assert_not_reached();
863b2167459SRichard Henderson     }
864b2167459SRichard Henderson     if (cf & 1) {
865b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
866b2167459SRichard Henderson     }
867b2167459SRichard Henderson 
868b2167459SRichard Henderson     return cond;
869b2167459SRichard Henderson }
870b2167459SRichard Henderson 
871b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
872b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
873b2167459SRichard Henderson    deleted as unused.  */
874b2167459SRichard Henderson 
8754fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
8766fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
8776fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
878b2167459SRichard Henderson {
8794fe9533aSRichard Henderson     TCGCond tc;
8804fe9533aSRichard Henderson     bool ext_uns;
881b2167459SRichard Henderson 
882b2167459SRichard Henderson     switch (cf >> 1) {
883b2167459SRichard Henderson     case 1: /* = / <> */
8844fe9533aSRichard Henderson         tc = TCG_COND_EQ;
8854fe9533aSRichard Henderson         ext_uns = true;
886b2167459SRichard Henderson         break;
887b2167459SRichard Henderson     case 2: /* < / >= */
8884fe9533aSRichard Henderson         tc = TCG_COND_LT;
8894fe9533aSRichard Henderson         ext_uns = false;
890b2167459SRichard Henderson         break;
891b2167459SRichard Henderson     case 3: /* <= / > */
8924fe9533aSRichard Henderson         tc = TCG_COND_LE;
8934fe9533aSRichard Henderson         ext_uns = false;
894b2167459SRichard Henderson         break;
895b2167459SRichard Henderson     case 4: /* << / >>= */
8964fe9533aSRichard Henderson         tc = TCG_COND_LTU;
8974fe9533aSRichard Henderson         ext_uns = true;
898b2167459SRichard Henderson         break;
899b2167459SRichard Henderson     case 5: /* <<= / >> */
9004fe9533aSRichard Henderson         tc = TCG_COND_LEU;
9014fe9533aSRichard Henderson         ext_uns = true;
902b2167459SRichard Henderson         break;
903b2167459SRichard Henderson     default:
904a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
905b2167459SRichard Henderson     }
906b2167459SRichard Henderson 
9074fe9533aSRichard Henderson     if (cf & 1) {
9084fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
9094fe9533aSRichard Henderson     }
91082d0c831SRichard Henderson     if (!d) {
911aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
912aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
9134fe9533aSRichard Henderson 
9144fe9533aSRichard Henderson         if (ext_uns) {
9156fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
9166fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
9174fe9533aSRichard Henderson         } else {
9186fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
9196fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
9204fe9533aSRichard Henderson         }
9214c42fd0dSRichard Henderson         return cond_make_tt(tc, t1, t2);
9224fe9533aSRichard Henderson     }
9234c42fd0dSRichard Henderson     return cond_make_vv(tc, in1, in2);
924b2167459SRichard Henderson }
925b2167459SRichard Henderson 
926df0232feSRichard Henderson /*
927df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
928df0232feSRichard Henderson  * computed, and use of them is undefined.
929df0232feSRichard Henderson  *
930df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
931df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
932df0232feSRichard Henderson  * how cases c={2,3} are treated.
933df0232feSRichard Henderson  */
934b2167459SRichard Henderson 
935b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
9366fd0c7bcSRichard Henderson                              TCGv_i64 res)
937b2167459SRichard Henderson {
938b5af8423SRichard Henderson     TCGCond tc;
939fbe65c64SRichard Henderson     uint64_t imm;
940a751eb31SRichard Henderson 
941fbe65c64SRichard Henderson     switch (cf >> 1) {
942fbe65c64SRichard Henderson     case 0:  /* never / always */
943fbe65c64SRichard Henderson     case 4:  /* undef, C */
944fbe65c64SRichard Henderson     case 5:  /* undef, C & !Z */
945fbe65c64SRichard Henderson     case 6:  /* undef, V */
946fbe65c64SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
947fbe65c64SRichard Henderson     case 1:  /* == / <> */
948fbe65c64SRichard Henderson         tc = d ? TCG_COND_EQ : TCG_COND_TSTEQ;
949fbe65c64SRichard Henderson         imm = d ? 0 : UINT32_MAX;
950b5af8423SRichard Henderson         break;
951fbe65c64SRichard Henderson     case 2:  /* < / >= */
952fbe65c64SRichard Henderson         tc = d ? TCG_COND_LT : TCG_COND_TSTNE;
953fbe65c64SRichard Henderson         imm = d ? 0 : 1ull << 31;
954b5af8423SRichard Henderson         break;
955fbe65c64SRichard Henderson     case 3:  /* <= / > */
956fbe65c64SRichard Henderson         tc = cf & 1 ? TCG_COND_GT : TCG_COND_LE;
95782d0c831SRichard Henderson         if (!d) {
958aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
9596fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
9604c42fd0dSRichard Henderson             return cond_make_ti(tc, tmp, 0);
961b5af8423SRichard Henderson         }
9624c42fd0dSRichard Henderson         return cond_make_vi(tc, res, 0);
963fbe65c64SRichard Henderson     case 7: /* OD / EV */
964fbe65c64SRichard Henderson         tc = TCG_COND_TSTNE;
965fbe65c64SRichard Henderson         imm = 1;
966fbe65c64SRichard Henderson         break;
967fbe65c64SRichard Henderson     default:
968fbe65c64SRichard Henderson         g_assert_not_reached();
969fbe65c64SRichard Henderson     }
970fbe65c64SRichard Henderson     if (cf & 1) {
971fbe65c64SRichard Henderson         tc = tcg_invert_cond(tc);
972fbe65c64SRichard Henderson     }
973fbe65c64SRichard Henderson     return cond_make_vi(tc, res, imm);
974b2167459SRichard Henderson }
975b2167459SRichard Henderson 
97698cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
97798cd9ca7SRichard Henderson 
9784fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9796fd0c7bcSRichard Henderson                              TCGv_i64 res)
98098cd9ca7SRichard Henderson {
98198cd9ca7SRichard Henderson     unsigned c, f;
98298cd9ca7SRichard Henderson 
98398cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
98498cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
98598cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
98698cd9ca7SRichard Henderson     c = orig & 3;
98798cd9ca7SRichard Henderson     if (c == 3) {
98898cd9ca7SRichard Henderson         c = 7;
98998cd9ca7SRichard Henderson     }
99098cd9ca7SRichard Henderson     f = (orig & 4) / 4;
99198cd9ca7SRichard Henderson 
992b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
99398cd9ca7SRichard Henderson }
99498cd9ca7SRichard Henderson 
99546bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
99646bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
997b2167459SRichard Henderson {
99846bb3d46SRichard Henderson     TCGv_i64 tmp;
999c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
100046bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
1001b2167459SRichard Henderson 
1002b2167459SRichard Henderson     switch (cf >> 1) {
1003578b8132SSven Schnelle     case 1: /* SBW / NBW */
1004578b8132SSven Schnelle         if (d) {
100546bb3d46SRichard Henderson             ones = d_repl;
100646bb3d46SRichard Henderson             sgns = d_repl << 31;
1007578b8132SSven Schnelle         }
1008578b8132SSven Schnelle         break;
1009b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
101046bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
101146bb3d46SRichard Henderson         sgns = ones << 7;
101246bb3d46SRichard Henderson         break;
101346bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
101446bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
101546bb3d46SRichard Henderson         sgns = ones << 15;
101646bb3d46SRichard Henderson         break;
101746bb3d46SRichard Henderson     }
101846bb3d46SRichard Henderson     if (ones == 0) {
101946bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
102046bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
102146bb3d46SRichard Henderson     }
102246bb3d46SRichard Henderson 
102346bb3d46SRichard Henderson     /*
102446bb3d46SRichard Henderson      * See hasless(v,1) from
1025b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1026b2167459SRichard Henderson      */
1027aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
102846bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
10296fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
1030b2167459SRichard Henderson 
103125f97be7SRichard Henderson     return cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, tmp, sgns);
1032b2167459SRichard Henderson }
1033b2167459SRichard Henderson 
10346fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
10356fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
103672ca8753SRichard Henderson {
103782d0c831SRichard Henderson     if (!d) {
1038aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
10396fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
104072ca8753SRichard Henderson         return t;
104172ca8753SRichard Henderson     }
104272ca8753SRichard Henderson     return cb_msb;
104372ca8753SRichard Henderson }
104472ca8753SRichard Henderson 
10456fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
104672ca8753SRichard Henderson {
104772ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
104872ca8753SRichard Henderson }
104972ca8753SRichard Henderson 
1050b2167459SRichard Henderson /* Compute signed overflow for addition.  */
10516fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1052f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1053f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1054b2167459SRichard Henderson {
1055aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1056aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1057b2167459SRichard Henderson 
10586fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10596fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10606fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1061b2167459SRichard Henderson 
1062f8f5986eSRichard Henderson     switch (shift) {
1063f8f5986eSRichard Henderson     case 0:
1064f8f5986eSRichard Henderson         break;
1065f8f5986eSRichard Henderson     case 1:
1066f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1067f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1068f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1069f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1070f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1071f8f5986eSRichard Henderson         break;
1072f8f5986eSRichard Henderson     default:
1073f8f5986eSRichard Henderson         {
1074f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1075f8f5986eSRichard Henderson 
1076f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1077f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1078f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1079f8f5986eSRichard Henderson             /*
1080f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1081f8f5986eSRichard Henderson              * differs, then we have overflow.
1082f8f5986eSRichard Henderson              */
1083f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1084f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1085f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1086f8f5986eSRichard Henderson         }
1087f8f5986eSRichard Henderson     }
1088b2167459SRichard Henderson     return sv;
1089b2167459SRichard Henderson }
1090b2167459SRichard Henderson 
1091f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1092f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1093f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1094f8f5986eSRichard Henderson {
1095f8f5986eSRichard Henderson     if (shift == 0) {
1096f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1097f8f5986eSRichard Henderson     } else {
1098f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1099f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1100f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1101f8f5986eSRichard Henderson         return tmp;
1102f8f5986eSRichard Henderson     }
1103f8f5986eSRichard Henderson }
1104f8f5986eSRichard Henderson 
1105b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
11066fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
11076fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1108b2167459SRichard Henderson {
1109aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1110aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1111b2167459SRichard Henderson 
11126fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
11136fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
11146fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1115b2167459SRichard Henderson 
1116b2167459SRichard Henderson     return sv;
1117b2167459SRichard Henderson }
1118b2167459SRichard Henderson 
1119269ca0a9SRichard Henderson static void gen_tc(DisasContext *ctx, DisasCond *cond)
1120269ca0a9SRichard Henderson {
1121269ca0a9SRichard Henderson     DisasDelayException *e;
1122269ca0a9SRichard Henderson 
1123269ca0a9SRichard Henderson     switch (cond->c) {
1124269ca0a9SRichard Henderson     case TCG_COND_NEVER:
1125269ca0a9SRichard Henderson         break;
1126269ca0a9SRichard Henderson     case TCG_COND_ALWAYS:
1127269ca0a9SRichard Henderson         gen_excp_iir(ctx, EXCP_COND);
1128269ca0a9SRichard Henderson         break;
1129269ca0a9SRichard Henderson     default:
1130269ca0a9SRichard Henderson         e = delay_excp(ctx, EXCP_COND);
1131269ca0a9SRichard Henderson         tcg_gen_brcond_i64(cond->c, cond->a0, cond->a1, e->lab);
1132269ca0a9SRichard Henderson         /* In the non-trap path, the condition is known false. */
1133269ca0a9SRichard Henderson         *cond = cond_make_f();
1134269ca0a9SRichard Henderson         break;
1135269ca0a9SRichard Henderson     }
1136269ca0a9SRichard Henderson }
1137269ca0a9SRichard Henderson 
1138a0ea4becSRichard Henderson static void gen_tsv(DisasContext *ctx, TCGv_i64 *sv, bool d)
1139a0ea4becSRichard Henderson {
1140a0ea4becSRichard Henderson     DisasCond cond = do_cond(ctx, /* SV */ 12, d, NULL, NULL, *sv);
1141a0ea4becSRichard Henderson     DisasDelayException *e = delay_excp(ctx, EXCP_OVERFLOW);
1142a0ea4becSRichard Henderson 
1143a0ea4becSRichard Henderson     tcg_gen_brcond_i64(cond.c, cond.a0, cond.a1, e->lab);
1144a0ea4becSRichard Henderson 
1145a0ea4becSRichard Henderson     /* In the non-trap path, V is known zero. */
1146a0ea4becSRichard Henderson     *sv = tcg_constant_i64(0);
1147a0ea4becSRichard Henderson }
1148a0ea4becSRichard Henderson 
1149f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
11506fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1151faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1152b2167459SRichard Henderson {
1153f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1154b2167459SRichard Henderson     unsigned c = cf >> 1;
1155b2167459SRichard Henderson     DisasCond cond;
1156b2167459SRichard Henderson 
1157aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1158f764718dSRichard Henderson     cb = NULL;
1159f764718dSRichard Henderson     cb_msb = NULL;
1160b2167459SRichard Henderson 
1161f8f5986eSRichard Henderson     in1 = orig_in1;
1162b2167459SRichard Henderson     if (shift) {
1163aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11646fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1165b2167459SRichard Henderson         in1 = tmp;
1166b2167459SRichard Henderson     }
1167b2167459SRichard Henderson 
1168b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1169aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1170aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1171bdcccc17SRichard Henderson 
1172a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1173b2167459SRichard Henderson         if (is_c) {
11746fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1175a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1176b2167459SRichard Henderson         }
11776fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
11786fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1179b2167459SRichard Henderson     } else {
11806fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1181b2167459SRichard Henderson         if (is_c) {
11826fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1183b2167459SRichard Henderson         }
1184b2167459SRichard Henderson     }
1185b2167459SRichard Henderson 
1186b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1187f764718dSRichard Henderson     sv = NULL;
1188b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1189f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1190b2167459SRichard Henderson         if (is_tsv) {
1191a0ea4becSRichard Henderson             gen_tsv(ctx, &sv, d);
1192b2167459SRichard Henderson         }
1193b2167459SRichard Henderson     }
1194b2167459SRichard Henderson 
1195f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1196f8f5986eSRichard Henderson     uv = NULL;
1197f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1198f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1199f8f5986eSRichard Henderson     }
1200f8f5986eSRichard Henderson 
1201b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1202f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1203b2167459SRichard Henderson     if (is_tc) {
1204269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1205b2167459SRichard Henderson     }
1206b2167459SRichard Henderson 
1207b2167459SRichard Henderson     /* Write back the result.  */
1208b2167459SRichard Henderson     if (!is_l) {
1209b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1210b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1211b2167459SRichard Henderson     }
1212b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1213b2167459SRichard Henderson 
1214b2167459SRichard Henderson     /* Install the new nullification.  */
1215b2167459SRichard Henderson     ctx->null_cond = cond;
1216b2167459SRichard Henderson }
1217b2167459SRichard Henderson 
1218faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
12190c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
12200c982a28SRichard Henderson {
12216fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12220c982a28SRichard Henderson 
1223269ca0a9SRichard Henderson     if (unlikely(is_tc && a->cf == 1)) {
1224269ca0a9SRichard Henderson         /* Unconditional trap on condition. */
1225269ca0a9SRichard Henderson         return gen_excp_iir(ctx, EXCP_COND);
1226269ca0a9SRichard Henderson     }
12270c982a28SRichard Henderson     if (a->cf) {
12280c982a28SRichard Henderson         nullify_over(ctx);
12290c982a28SRichard Henderson     }
12300c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12310c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1232faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1233faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
12340c982a28SRichard Henderson     return nullify_end(ctx);
12350c982a28SRichard Henderson }
12360c982a28SRichard Henderson 
12370588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
12380588e061SRichard Henderson                        bool is_tsv, bool is_tc)
12390588e061SRichard Henderson {
12406fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12410588e061SRichard Henderson 
1242269ca0a9SRichard Henderson     if (unlikely(is_tc && a->cf == 1)) {
1243269ca0a9SRichard Henderson         /* Unconditional trap on condition. */
1244269ca0a9SRichard Henderson         return gen_excp_iir(ctx, EXCP_COND);
1245269ca0a9SRichard Henderson     }
12460588e061SRichard Henderson     if (a->cf) {
12470588e061SRichard Henderson         nullify_over(ctx);
12480588e061SRichard Henderson     }
12496fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12500588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1251faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1252faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
12530588e061SRichard Henderson     return nullify_end(ctx);
12540588e061SRichard Henderson }
12550588e061SRichard Henderson 
12566fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12576fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
125863c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1259b2167459SRichard Henderson {
1260269ca0a9SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb;
1261b2167459SRichard Henderson     unsigned c = cf >> 1;
1262b2167459SRichard Henderson     DisasCond cond;
1263b2167459SRichard Henderson 
1264aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1265aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1266aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1267b2167459SRichard Henderson 
1268b2167459SRichard Henderson     if (is_b) {
1269b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
12706fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1271a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1272a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1273a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
12746fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
12756fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1276b2167459SRichard Henderson     } else {
1277bdcccc17SRichard Henderson         /*
1278bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1279bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1280bdcccc17SRichard Henderson          */
12816fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1282a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
12836fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12846fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1285b2167459SRichard Henderson     }
1286b2167459SRichard Henderson 
1287b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1288f764718dSRichard Henderson     sv = NULL;
1289b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1290b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1291b2167459SRichard Henderson         if (is_tsv) {
1292a0ea4becSRichard Henderson             gen_tsv(ctx, &sv, d);
1293b2167459SRichard Henderson         }
1294b2167459SRichard Henderson     }
1295b2167459SRichard Henderson 
1296b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1297b2167459SRichard Henderson     if (!is_b) {
12984fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1299b2167459SRichard Henderson     } else {
1300a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1301b2167459SRichard Henderson     }
1302b2167459SRichard Henderson 
1303b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1304b2167459SRichard Henderson     if (is_tc) {
1305269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1306b2167459SRichard Henderson     }
1307b2167459SRichard Henderson 
1308b2167459SRichard Henderson     /* Write back the result.  */
1309b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1310b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1311b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1312b2167459SRichard Henderson 
1313b2167459SRichard Henderson     /* Install the new nullification.  */
1314b2167459SRichard Henderson     ctx->null_cond = cond;
1315b2167459SRichard Henderson }
1316b2167459SRichard Henderson 
131763c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13180c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
13190c982a28SRichard Henderson {
13206fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13210c982a28SRichard Henderson 
13220c982a28SRichard Henderson     if (a->cf) {
13230c982a28SRichard Henderson         nullify_over(ctx);
13240c982a28SRichard Henderson     }
13250c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13260c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
132763c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
13280c982a28SRichard Henderson     return nullify_end(ctx);
13290c982a28SRichard Henderson }
13300c982a28SRichard Henderson 
13310588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
13320588e061SRichard Henderson {
13336fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
13340588e061SRichard Henderson 
13350588e061SRichard Henderson     if (a->cf) {
13360588e061SRichard Henderson         nullify_over(ctx);
13370588e061SRichard Henderson     }
13386fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
13390588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
134063c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
134163c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
13420588e061SRichard Henderson     return nullify_end(ctx);
13430588e061SRichard Henderson }
13440588e061SRichard Henderson 
13456fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13466fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1347b2167459SRichard Henderson {
13486fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1349b2167459SRichard Henderson     DisasCond cond;
1350b2167459SRichard Henderson 
1351aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
13526fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1353b2167459SRichard Henderson 
1354b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1355f764718dSRichard Henderson     sv = NULL;
1356b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1357b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1358b2167459SRichard Henderson     }
1359b2167459SRichard Henderson 
1360b2167459SRichard Henderson     /* Form the condition for the compare.  */
13614fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1362b2167459SRichard Henderson 
1363b2167459SRichard Henderson     /* Clear.  */
13646fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1365b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1366b2167459SRichard Henderson 
1367b2167459SRichard Henderson     /* Install the new nullification.  */
1368b2167459SRichard Henderson     ctx->null_cond = cond;
1369b2167459SRichard Henderson }
1370b2167459SRichard Henderson 
13716fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13726fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
13736fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1374b2167459SRichard Henderson {
13756fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1376b2167459SRichard Henderson 
1377b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1378b2167459SRichard Henderson     fn(dest, in1, in2);
1379b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1380b2167459SRichard Henderson 
1381b2167459SRichard Henderson     /* Install the new nullification.  */
1382b5af8423SRichard Henderson     ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1383b2167459SRichard Henderson }
1384b2167459SRichard Henderson 
1385fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13866fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13870c982a28SRichard Henderson {
13886fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13890c982a28SRichard Henderson 
13900c982a28SRichard Henderson     if (a->cf) {
13910c982a28SRichard Henderson         nullify_over(ctx);
13920c982a28SRichard Henderson     }
13930c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13940c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1395fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13960c982a28SRichard Henderson     return nullify_end(ctx);
13970c982a28SRichard Henderson }
13980c982a28SRichard Henderson 
139946bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
140046bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
140146bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1402b2167459SRichard Henderson {
140346bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
140446bb3d46SRichard Henderson     uint64_t test_cb = 0;
1405b2167459SRichard Henderson     DisasCond cond;
1406b2167459SRichard Henderson 
140746bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
140846bb3d46SRichard Henderson     switch (cf >> 1) {
140946bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
141046bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
141146bb3d46SRichard Henderson         break;
141246bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
141346bb3d46SRichard Henderson         if (d) {
141446bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1415b2167459SRichard Henderson         } else {
141646bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
141746bb3d46SRichard Henderson         }
141846bb3d46SRichard Henderson         break;
141946bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
142046bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
142146bb3d46SRichard Henderson         break;
142246bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
142346bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
142446bb3d46SRichard Henderson         break;
142546bb3d46SRichard Henderson     }
142646bb3d46SRichard Henderson     if (!d) {
142746bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
142846bb3d46SRichard Henderson     }
1429b2167459SRichard Henderson 
143046bb3d46SRichard Henderson     if (!test_cb) {
143146bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
143246bb3d46SRichard Henderson         if (is_add) {
143346bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
143446bb3d46SRichard Henderson         } else {
143546bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
143646bb3d46SRichard Henderson         }
143746bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
143846bb3d46SRichard Henderson     } else {
143946bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
144046bb3d46SRichard Henderson 
144146bb3d46SRichard Henderson         if (d) {
144246bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
144346bb3d46SRichard Henderson             if (is_add) {
144446bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
144546bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
144646bb3d46SRichard Henderson             } else {
144746bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
144846bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
144946bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
145046bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
145146bb3d46SRichard Henderson             }
145246bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
145346bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
145446bb3d46SRichard Henderson         } else {
145546bb3d46SRichard Henderson             if (is_add) {
145646bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
145746bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
145846bb3d46SRichard Henderson             } else {
145946bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
146046bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
146146bb3d46SRichard Henderson             }
146246bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
146346bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
146446bb3d46SRichard Henderson         }
146546bb3d46SRichard Henderson 
14663289ea0eSRichard Henderson         cond = cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
14673289ea0eSRichard Henderson                             cb, test_cb);
146846bb3d46SRichard Henderson     }
1469b2167459SRichard Henderson 
1470b2167459SRichard Henderson     if (is_tc) {
1471269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1472b2167459SRichard Henderson     }
1473b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1474b2167459SRichard Henderson 
1475b2167459SRichard Henderson     ctx->null_cond = cond;
1476b2167459SRichard Henderson }
1477b2167459SRichard Henderson 
147886f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14798d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14808d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14818d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14828d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14836fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
148486f8d05fSRichard Henderson {
148586f8d05fSRichard Henderson     TCGv_ptr ptr;
14866fd0c7bcSRichard Henderson     TCGv_i64 tmp;
148786f8d05fSRichard Henderson     TCGv_i64 spc;
148886f8d05fSRichard Henderson 
148986f8d05fSRichard Henderson     if (sp != 0) {
14908d6ae7fbSRichard Henderson         if (sp < 0) {
14918d6ae7fbSRichard Henderson             sp = ~sp;
14928d6ae7fbSRichard Henderson         }
14936fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14948d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14958d6ae7fbSRichard Henderson         return spc;
149686f8d05fSRichard Henderson     }
1497494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1498494737b7SRichard Henderson         return cpu_srH;
1499494737b7SRichard Henderson     }
150086f8d05fSRichard Henderson 
150186f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1502aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
15036fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
150486f8d05fSRichard Henderson 
1505698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
15066fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
15076fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
15086fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
150986f8d05fSRichard Henderson 
1510ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
151186f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
151286f8d05fSRichard Henderson 
151386f8d05fSRichard Henderson     return spc;
151486f8d05fSRichard Henderson }
151586f8d05fSRichard Henderson #endif
151686f8d05fSRichard Henderson 
15176fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1518c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
151986f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
152086f8d05fSRichard Henderson {
15216fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
15226fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15236fd0c7bcSRichard Henderson     TCGv_i64 addr;
152486f8d05fSRichard Henderson 
1525f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1526f5b5c857SRichard Henderson 
152786f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
152886f8d05fSRichard Henderson     if (rx) {
1529aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15306fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
15316fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
153286f8d05fSRichard Henderson     } else if (disp || modify) {
1533aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15346fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
153586f8d05fSRichard Henderson     } else {
153686f8d05fSRichard Henderson         ofs = base;
153786f8d05fSRichard Henderson     }
153886f8d05fSRichard Henderson 
153986f8d05fSRichard Henderson     *pofs = ofs;
15406fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
15417d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
15427d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1543698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
154486f8d05fSRichard Henderson     if (!is_phys) {
1545d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
154686f8d05fSRichard Henderson     }
154786f8d05fSRichard Henderson #endif
154886f8d05fSRichard Henderson }
154986f8d05fSRichard Henderson 
155096d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
155196d6407fSRichard Henderson  * < 0 for pre-modify,
155296d6407fSRichard Henderson  * > 0 for post-modify,
155396d6407fSRichard Henderson  * = 0 for no base register update.
155496d6407fSRichard Henderson  */
155596d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1556c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
155714776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
155896d6407fSRichard Henderson {
15596fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15606fd0c7bcSRichard Henderson     TCGv_i64 addr;
156196d6407fSRichard Henderson 
156296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
156396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
156496d6407fSRichard Henderson 
156586f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
156617fe594cSRichard Henderson              MMU_DISABLED(ctx));
1567c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
156886f8d05fSRichard Henderson     if (modify) {
156986f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
157096d6407fSRichard Henderson     }
157196d6407fSRichard Henderson }
157296d6407fSRichard Henderson 
157396d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1574c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
157514776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
157696d6407fSRichard Henderson {
15776fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15786fd0c7bcSRichard Henderson     TCGv_i64 addr;
157996d6407fSRichard Henderson 
158096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
158196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
158296d6407fSRichard Henderson 
158386f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
158417fe594cSRichard Henderson              MMU_DISABLED(ctx));
1585217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
158686f8d05fSRichard Henderson     if (modify) {
158786f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
158896d6407fSRichard Henderson     }
158996d6407fSRichard Henderson }
159096d6407fSRichard Henderson 
159196d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1592c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
159314776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
159496d6407fSRichard Henderson {
15956fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15966fd0c7bcSRichard Henderson     TCGv_i64 addr;
159796d6407fSRichard Henderson 
159896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
159996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
160096d6407fSRichard Henderson 
160186f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
160217fe594cSRichard Henderson              MMU_DISABLED(ctx));
1603217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
160486f8d05fSRichard Henderson     if (modify) {
160586f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
160696d6407fSRichard Henderson     }
160796d6407fSRichard Henderson }
160896d6407fSRichard Henderson 
160996d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1610c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
161114776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
161296d6407fSRichard Henderson {
16136fd0c7bcSRichard Henderson     TCGv_i64 ofs;
16146fd0c7bcSRichard Henderson     TCGv_i64 addr;
161596d6407fSRichard Henderson 
161696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
161796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
161896d6407fSRichard Henderson 
161986f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
162017fe594cSRichard Henderson              MMU_DISABLED(ctx));
1621217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
162286f8d05fSRichard Henderson     if (modify) {
162386f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
162496d6407fSRichard Henderson     }
162596d6407fSRichard Henderson }
162696d6407fSRichard Henderson 
16271cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1628c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
162914776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
163096d6407fSRichard Henderson {
16316fd0c7bcSRichard Henderson     TCGv_i64 dest;
163296d6407fSRichard Henderson 
163396d6407fSRichard Henderson     nullify_over(ctx);
163496d6407fSRichard Henderson 
163596d6407fSRichard Henderson     if (modify == 0) {
163696d6407fSRichard Henderson         /* No base register update.  */
163796d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
163896d6407fSRichard Henderson     } else {
163996d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1640aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
164196d6407fSRichard Henderson     }
16426fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
164396d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
164496d6407fSRichard Henderson 
16451cd012a5SRichard Henderson     return nullify_end(ctx);
164696d6407fSRichard Henderson }
164796d6407fSRichard Henderson 
1648740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1649c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
165086f8d05fSRichard Henderson                       unsigned sp, int modify)
165196d6407fSRichard Henderson {
165296d6407fSRichard Henderson     TCGv_i32 tmp;
165396d6407fSRichard Henderson 
165496d6407fSRichard Henderson     nullify_over(ctx);
165596d6407fSRichard Henderson 
165696d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
165786f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
165896d6407fSRichard Henderson     save_frw_i32(rt, tmp);
165996d6407fSRichard Henderson 
166096d6407fSRichard Henderson     if (rt == 0) {
1661ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
166296d6407fSRichard Henderson     }
166396d6407fSRichard Henderson 
1664740038d7SRichard Henderson     return nullify_end(ctx);
166596d6407fSRichard Henderson }
166696d6407fSRichard Henderson 
1667740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1668740038d7SRichard Henderson {
1669740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1670740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1671740038d7SRichard Henderson }
1672740038d7SRichard Henderson 
1673740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1674c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
167586f8d05fSRichard Henderson                       unsigned sp, int modify)
167696d6407fSRichard Henderson {
167796d6407fSRichard Henderson     TCGv_i64 tmp;
167896d6407fSRichard Henderson 
167996d6407fSRichard Henderson     nullify_over(ctx);
168096d6407fSRichard Henderson 
168196d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1682fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
168396d6407fSRichard Henderson     save_frd(rt, tmp);
168496d6407fSRichard Henderson 
168596d6407fSRichard Henderson     if (rt == 0) {
1686ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
168796d6407fSRichard Henderson     }
168896d6407fSRichard Henderson 
1689740038d7SRichard Henderson     return nullify_end(ctx);
1690740038d7SRichard Henderson }
1691740038d7SRichard Henderson 
1692740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1693740038d7SRichard Henderson {
1694740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1695740038d7SRichard Henderson                      a->disp, a->sp, a->m);
169696d6407fSRichard Henderson }
169796d6407fSRichard Henderson 
16981cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1699c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
170014776ab5STony Nguyen                      int modify, MemOp mop)
170196d6407fSRichard Henderson {
170296d6407fSRichard Henderson     nullify_over(ctx);
17036fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
17041cd012a5SRichard Henderson     return nullify_end(ctx);
170596d6407fSRichard Henderson }
170696d6407fSRichard Henderson 
1707740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1708c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
170986f8d05fSRichard Henderson                        unsigned sp, int modify)
171096d6407fSRichard Henderson {
171196d6407fSRichard Henderson     TCGv_i32 tmp;
171296d6407fSRichard Henderson 
171396d6407fSRichard Henderson     nullify_over(ctx);
171496d6407fSRichard Henderson 
171596d6407fSRichard Henderson     tmp = load_frw_i32(rt);
171686f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
171796d6407fSRichard Henderson 
1718740038d7SRichard Henderson     return nullify_end(ctx);
171996d6407fSRichard Henderson }
172096d6407fSRichard Henderson 
1721740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1722740038d7SRichard Henderson {
1723740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1724740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1725740038d7SRichard Henderson }
1726740038d7SRichard Henderson 
1727740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1728c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
172986f8d05fSRichard Henderson                        unsigned sp, int modify)
173096d6407fSRichard Henderson {
173196d6407fSRichard Henderson     TCGv_i64 tmp;
173296d6407fSRichard Henderson 
173396d6407fSRichard Henderson     nullify_over(ctx);
173496d6407fSRichard Henderson 
173596d6407fSRichard Henderson     tmp = load_frd(rt);
1736fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
173796d6407fSRichard Henderson 
1738740038d7SRichard Henderson     return nullify_end(ctx);
1739740038d7SRichard Henderson }
1740740038d7SRichard Henderson 
1741740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1742740038d7SRichard Henderson {
1743740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1744740038d7SRichard Henderson                       a->disp, a->sp, a->m);
174596d6407fSRichard Henderson }
174696d6407fSRichard Henderson 
17471ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1748ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1749ebe9383cSRichard Henderson {
1750ebe9383cSRichard Henderson     TCGv_i32 tmp;
1751ebe9383cSRichard Henderson 
1752ebe9383cSRichard Henderson     nullify_over(ctx);
1753ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1754ebe9383cSRichard Henderson 
1755ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1756ebe9383cSRichard Henderson 
1757ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
17581ca74648SRichard Henderson     return nullify_end(ctx);
1759ebe9383cSRichard Henderson }
1760ebe9383cSRichard Henderson 
17611ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1762ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1763ebe9383cSRichard Henderson {
1764ebe9383cSRichard Henderson     TCGv_i32 dst;
1765ebe9383cSRichard Henderson     TCGv_i64 src;
1766ebe9383cSRichard Henderson 
1767ebe9383cSRichard Henderson     nullify_over(ctx);
1768ebe9383cSRichard Henderson     src = load_frd(ra);
1769ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1770ebe9383cSRichard Henderson 
1771ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1772ebe9383cSRichard Henderson 
1773ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17741ca74648SRichard Henderson     return nullify_end(ctx);
1775ebe9383cSRichard Henderson }
1776ebe9383cSRichard Henderson 
17771ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1778ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1779ebe9383cSRichard Henderson {
1780ebe9383cSRichard Henderson     TCGv_i64 tmp;
1781ebe9383cSRichard Henderson 
1782ebe9383cSRichard Henderson     nullify_over(ctx);
1783ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1784ebe9383cSRichard Henderson 
1785ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1786ebe9383cSRichard Henderson 
1787ebe9383cSRichard Henderson     save_frd(rt, tmp);
17881ca74648SRichard Henderson     return nullify_end(ctx);
1789ebe9383cSRichard Henderson }
1790ebe9383cSRichard Henderson 
17911ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1792ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1793ebe9383cSRichard Henderson {
1794ebe9383cSRichard Henderson     TCGv_i32 src;
1795ebe9383cSRichard Henderson     TCGv_i64 dst;
1796ebe9383cSRichard Henderson 
1797ebe9383cSRichard Henderson     nullify_over(ctx);
1798ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1799ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1800ebe9383cSRichard Henderson 
1801ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1802ebe9383cSRichard Henderson 
1803ebe9383cSRichard Henderson     save_frd(rt, dst);
18041ca74648SRichard Henderson     return nullify_end(ctx);
1805ebe9383cSRichard Henderson }
1806ebe9383cSRichard Henderson 
18071ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1808ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
180931234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1810ebe9383cSRichard Henderson {
1811ebe9383cSRichard Henderson     TCGv_i32 a, b;
1812ebe9383cSRichard Henderson 
1813ebe9383cSRichard Henderson     nullify_over(ctx);
1814ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1815ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1816ebe9383cSRichard Henderson 
1817ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1818ebe9383cSRichard Henderson 
1819ebe9383cSRichard Henderson     save_frw_i32(rt, a);
18201ca74648SRichard Henderson     return nullify_end(ctx);
1821ebe9383cSRichard Henderson }
1822ebe9383cSRichard Henderson 
18231ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1824ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
182531234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1826ebe9383cSRichard Henderson {
1827ebe9383cSRichard Henderson     TCGv_i64 a, b;
1828ebe9383cSRichard Henderson 
1829ebe9383cSRichard Henderson     nullify_over(ctx);
1830ebe9383cSRichard Henderson     a = load_frd0(ra);
1831ebe9383cSRichard Henderson     b = load_frd0(rb);
1832ebe9383cSRichard Henderson 
1833ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1834ebe9383cSRichard Henderson 
1835ebe9383cSRichard Henderson     save_frd(rt, a);
18361ca74648SRichard Henderson     return nullify_end(ctx);
1837ebe9383cSRichard Henderson }
1838ebe9383cSRichard Henderson 
183998cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
184098cd9ca7SRichard Henderson    have already had nullification handled.  */
18412644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
184298cd9ca7SRichard Henderson                        unsigned link, bool is_n)
184398cd9ca7SRichard Henderson {
1844bc921866SRichard Henderson     ctx->iaq_j = iaqe_branchi(ctx, disp);
18452644f80bSRichard Henderson 
184698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
184743541db0SRichard Henderson         install_link(ctx, link, false);
184898cd9ca7SRichard Henderson         if (is_n) {
1849d08ad0e0SRichard Henderson             if (use_nullify_skip(ctx)) {
1850d08ad0e0SRichard Henderson                 nullify_set(ctx, 0);
1851bc921866SRichard Henderson                 gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
1852d08ad0e0SRichard Henderson                 ctx->base.is_jmp = DISAS_NORETURN;
1853d08ad0e0SRichard Henderson                 return true;
1854d08ad0e0SRichard Henderson             }
185598cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
185698cd9ca7SRichard Henderson         }
1857bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
185898cd9ca7SRichard Henderson     } else {
185998cd9ca7SRichard Henderson         nullify_over(ctx);
186098cd9ca7SRichard Henderson 
186143541db0SRichard Henderson         install_link(ctx, link, false);
186298cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
186398cd9ca7SRichard Henderson             nullify_set(ctx, 0);
1864bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
186598cd9ca7SRichard Henderson         } else {
186698cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
1867bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j);
186898cd9ca7SRichard Henderson         }
186931234768SRichard Henderson         nullify_end(ctx);
187098cd9ca7SRichard Henderson 
187198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1872bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL);
187331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
187498cd9ca7SRichard Henderson     }
187501afb7beSRichard Henderson     return true;
187698cd9ca7SRichard Henderson }
187798cd9ca7SRichard Henderson 
187898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
187998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1880c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
188198cd9ca7SRichard Henderson                        DisasCond *cond)
188298cd9ca7SRichard Henderson {
1883bc921866SRichard Henderson     DisasIAQE next;
188498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
188598cd9ca7SRichard Henderson     TCGCond c = cond->c;
188698cd9ca7SRichard Henderson     bool n;
188798cd9ca7SRichard Henderson 
188898cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
188998cd9ca7SRichard Henderson 
189098cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
189198cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18922644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
189398cd9ca7SRichard Henderson     }
189498cd9ca7SRichard Henderson 
189598cd9ca7SRichard Henderson     taken = gen_new_label();
18966fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
189798cd9ca7SRichard Henderson 
189898cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
189998cd9ca7SRichard Henderson     n = is_n && disp < 0;
190098cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
190198cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1902bc921866SRichard Henderson         next = iaqe_incr(&ctx->iaq_b, 4);
1903bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &next, NULL);
190498cd9ca7SRichard Henderson     } else {
190598cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
190698cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
190798cd9ca7SRichard Henderson             ctx->null_lab = NULL;
190898cd9ca7SRichard Henderson         }
190998cd9ca7SRichard Henderson         nullify_set(ctx, n);
1910bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL);
191198cd9ca7SRichard Henderson     }
191298cd9ca7SRichard Henderson 
191398cd9ca7SRichard Henderson     gen_set_label(taken);
191498cd9ca7SRichard Henderson 
191598cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
191698cd9ca7SRichard Henderson     n = is_n && disp >= 0;
1917bc921866SRichard Henderson 
1918bc921866SRichard Henderson     next = iaqe_branchi(ctx, disp);
191998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
192098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1921bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &next, NULL);
192298cd9ca7SRichard Henderson     } else {
192398cd9ca7SRichard Henderson         nullify_set(ctx, n);
1924bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, &next);
192598cd9ca7SRichard Henderson     }
192698cd9ca7SRichard Henderson 
192798cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
192898cd9ca7SRichard Henderson     if (ctx->null_lab) {
192998cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
193098cd9ca7SRichard Henderson         ctx->null_lab = NULL;
193131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
193298cd9ca7SRichard Henderson     } else {
193331234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
193498cd9ca7SRichard Henderson     }
193501afb7beSRichard Henderson     return true;
193698cd9ca7SRichard Henderson }
193798cd9ca7SRichard Henderson 
1938bc921866SRichard Henderson /*
1939bc921866SRichard Henderson  * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1940bc921866SRichard Henderson  * This handles nullification of the branch itself.
1941bc921866SRichard Henderson  */
1942bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link,
1943bc921866SRichard Henderson                        bool with_sr0, bool is_n)
194498cd9ca7SRichard Henderson {
1945d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1946019f4159SRichard Henderson         install_link(ctx, link, with_sr0);
194798cd9ca7SRichard Henderson         if (is_n) {
1948c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1949bc921866SRichard Henderson                 install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1950c301f34eSRichard Henderson                 nullify_set(ctx, 0);
195131234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
195201afb7beSRichard Henderson                 return true;
1953c301f34eSRichard Henderson             }
195498cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
195598cd9ca7SRichard Henderson         }
1956bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
1957d582c1faSRichard Henderson         return true;
1958d582c1faSRichard Henderson     }
195998cd9ca7SRichard Henderson 
1960d582c1faSRichard Henderson     nullify_over(ctx);
1961d582c1faSRichard Henderson 
1962019f4159SRichard Henderson     install_link(ctx, link, with_sr0);
1963d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1964bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1965d582c1faSRichard Henderson         nullify_set(ctx, 0);
1966d582c1faSRichard Henderson     } else {
1967bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j);
1968d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1969d582c1faSRichard Henderson     }
1970d582c1faSRichard Henderson 
19717f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1972d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
197301afb7beSRichard Henderson     return nullify_end(ctx);
197498cd9ca7SRichard Henderson }
197598cd9ca7SRichard Henderson 
1976660eefe1SRichard Henderson /* Implement
1977660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1978660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1979660eefe1SRichard Henderson  *    else
1980660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1981660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1982660eefe1SRichard Henderson  */
19836fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1984660eefe1SRichard Henderson {
19851874e6c2SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
1986660eefe1SRichard Henderson     switch (ctx->privilege) {
1987660eefe1SRichard Henderson     case 0:
1988660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
19891874e6c2SRichard Henderson         tcg_gen_mov_i64(dest, offset);
19901874e6c2SRichard Henderson         break;
1991660eefe1SRichard Henderson     case 3:
1992993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
19936fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1994660eefe1SRichard Henderson         break;
1995660eefe1SRichard Henderson     default:
19966fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19976fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19980bb02029SRichard Henderson         tcg_gen_umax_i64(dest, dest, offset);
1999660eefe1SRichard Henderson         break;
2000660eefe1SRichard Henderson     }
2001660eefe1SRichard Henderson     return dest;
2002660eefe1SRichard Henderson }
2003660eefe1SRichard Henderson 
2004ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
20057ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
20067ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
20077ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
20087ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
20097ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
20107ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
20117ad439dfSRichard Henderson    aforementioned BE.  */
201231234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
20137ad439dfSRichard Henderson {
20140d89cb7cSRichard Henderson     assert(ctx->iaq_f.disp == 0);
20150d89cb7cSRichard Henderson 
20167ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
20177ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
20188b81968cSMichael Tokarev        next insn within the privileged page.  */
20197ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
20207ad439dfSRichard Henderson     case TCG_COND_NEVER:
20217ad439dfSRichard Henderson         break;
20227ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
20236fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
20247ad439dfSRichard Henderson         goto do_sigill;
20257ad439dfSRichard Henderson     default:
20267ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
20277ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
20287ad439dfSRichard Henderson         g_assert_not_reached();
20297ad439dfSRichard Henderson     }
20307ad439dfSRichard Henderson 
20317ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
20327ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
20337ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
20347ad439dfSRichard Henderson        under such conditions.  */
20350d89cb7cSRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) {
20367ad439dfSRichard Henderson         goto do_sigill;
20377ad439dfSRichard Henderson     }
20387ad439dfSRichard Henderson 
20390d89cb7cSRichard Henderson     switch (ctx->base.pc_first) {
20407ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20412986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
204231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
204331234768SRichard Henderson         break;
20447ad439dfSRichard Henderson 
20457ad439dfSRichard Henderson     case 0xb0: /* LWS */
20467ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
204731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
204831234768SRichard Henderson         break;
20497ad439dfSRichard Henderson 
20507ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
2051bc921866SRichard Henderson         {
2052bc921866SRichard Henderson             DisasIAQE next = { .base = tcg_temp_new_i64() };
2053bc921866SRichard Henderson 
2054bc921866SRichard Henderson             tcg_gen_st_i64(cpu_gr[26], tcg_env,
2055bc921866SRichard Henderson                            offsetof(CPUHPPAState, cr[27]));
20563c13b0ffSRichard Henderson             tcg_gen_ori_i64(next.base, cpu_gr[31], PRIV_USER);
2057bc921866SRichard Henderson             install_iaq_entries(ctx, &next, NULL);
205831234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
2059bc921866SRichard Henderson         }
206031234768SRichard Henderson         break;
20617ad439dfSRichard Henderson 
20627ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20637ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
206431234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
206531234768SRichard Henderson         break;
20667ad439dfSRichard Henderson 
20677ad439dfSRichard Henderson     default:
20687ad439dfSRichard Henderson     do_sigill:
20692986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
207031234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
207131234768SRichard Henderson         break;
20727ad439dfSRichard Henderson     }
20737ad439dfSRichard Henderson }
2074ba1d0b44SRichard Henderson #endif
20757ad439dfSRichard Henderson 
2076deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2077b2167459SRichard Henderson {
2078e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
207931234768SRichard Henderson     return true;
2080b2167459SRichard Henderson }
2081b2167459SRichard Henderson 
208240f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
208398a9cb79SRichard Henderson {
208431234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
208598a9cb79SRichard Henderson }
208698a9cb79SRichard Henderson 
2087e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
208898a9cb79SRichard Henderson {
208998a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
209098a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
209198a9cb79SRichard Henderson 
2092e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
209331234768SRichard Henderson     return true;
209498a9cb79SRichard Henderson }
209598a9cb79SRichard Henderson 
2096c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
209798a9cb79SRichard Henderson {
2098bc921866SRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
209998a9cb79SRichard Henderson 
2100bc921866SRichard Henderson     copy_iaoq_entry(ctx, dest, &ctx->iaq_f);
2101bc921866SRichard Henderson     tcg_gen_andi_i64(dest, dest, -4);
2102bc921866SRichard Henderson 
2103bc921866SRichard Henderson     save_gpr(ctx, a->t, dest);
2104e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
210531234768SRichard Henderson     return true;
210698a9cb79SRichard Henderson }
210798a9cb79SRichard Henderson 
2108c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
210998a9cb79SRichard Henderson {
2110c603e14aSRichard Henderson     unsigned rt = a->t;
2111c603e14aSRichard Henderson     unsigned rs = a->sp;
211233423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
211398a9cb79SRichard Henderson 
211433423472SRichard Henderson     load_spr(ctx, t0, rs);
211533423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
211633423472SRichard Henderson 
2117967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
211898a9cb79SRichard Henderson 
2119e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
212031234768SRichard Henderson     return true;
212198a9cb79SRichard Henderson }
212298a9cb79SRichard Henderson 
2123c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
212498a9cb79SRichard Henderson {
2125c603e14aSRichard Henderson     unsigned rt = a->t;
2126c603e14aSRichard Henderson     unsigned ctl = a->r;
21276fd0c7bcSRichard Henderson     TCGv_i64 tmp;
212898a9cb79SRichard Henderson 
212998a9cb79SRichard Henderson     switch (ctl) {
213035136a77SRichard Henderson     case CR_SAR:
2131c603e14aSRichard Henderson         if (a->e == 0) {
213298a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
213398a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
21346fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
213598a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
213635136a77SRichard Henderson             goto done;
213798a9cb79SRichard Henderson         }
213898a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
213935136a77SRichard Henderson         goto done;
214035136a77SRichard Henderson     case CR_IT: /* Interval Timer */
214135136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
214235136a77SRichard Henderson         nullify_over(ctx);
214398a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2144dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
214531234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
214649c29d6cSRichard Henderson         }
21470c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
214898a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
214931234768SRichard Henderson         return nullify_end(ctx);
215098a9cb79SRichard Henderson     case 26:
215198a9cb79SRichard Henderson     case 27:
215298a9cb79SRichard Henderson         break;
215398a9cb79SRichard Henderson     default:
215498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
215535136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
215635136a77SRichard Henderson         break;
215798a9cb79SRichard Henderson     }
215898a9cb79SRichard Henderson 
2159aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21606fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
216135136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
216235136a77SRichard Henderson 
216335136a77SRichard Henderson  done:
2164e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
216531234768SRichard Henderson     return true;
216698a9cb79SRichard Henderson }
216798a9cb79SRichard Henderson 
2168c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
216933423472SRichard Henderson {
2170c603e14aSRichard Henderson     unsigned rr = a->r;
2171c603e14aSRichard Henderson     unsigned rs = a->sp;
2172967662cdSRichard Henderson     TCGv_i64 tmp;
217333423472SRichard Henderson 
217433423472SRichard Henderson     if (rs >= 5) {
217533423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
217633423472SRichard Henderson     }
217733423472SRichard Henderson     nullify_over(ctx);
217833423472SRichard Henderson 
2179967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2180967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
218133423472SRichard Henderson 
218233423472SRichard Henderson     if (rs >= 4) {
2183967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2184494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
218533423472SRichard Henderson     } else {
2186967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
218733423472SRichard Henderson     }
218833423472SRichard Henderson 
218931234768SRichard Henderson     return nullify_end(ctx);
219033423472SRichard Henderson }
219133423472SRichard Henderson 
2192c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
219398a9cb79SRichard Henderson {
2194c603e14aSRichard Henderson     unsigned ctl = a->t;
21956fd0c7bcSRichard Henderson     TCGv_i64 reg;
21966fd0c7bcSRichard Henderson     TCGv_i64 tmp;
219798a9cb79SRichard Henderson 
219835136a77SRichard Henderson     if (ctl == CR_SAR) {
21994845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2200aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22016fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
220298a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
220398a9cb79SRichard Henderson 
2204e0137378SRichard Henderson         ctx->null_cond = cond_make_f();
220531234768SRichard Henderson         return true;
220698a9cb79SRichard Henderson     }
220798a9cb79SRichard Henderson 
220835136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
220935136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
221035136a77SRichard Henderson 
2211c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
221235136a77SRichard Henderson     nullify_over(ctx);
22134c34bab0SHelge Deller 
22144c34bab0SHelge Deller     if (ctx->is_pa20) {
22154845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
22164c34bab0SHelge Deller     } else {
22174c34bab0SHelge Deller         reg = tcg_temp_new_i64();
22184c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
22194c34bab0SHelge Deller     }
22204845f015SSven Schnelle 
222135136a77SRichard Henderson     switch (ctl) {
222235136a77SRichard Henderson     case CR_IT:
2223104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2224104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2225104281c1SRichard Henderson         }
2226ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
222735136a77SRichard Henderson         break;
22284f5f2548SRichard Henderson     case CR_EIRR:
22296ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
22306ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2231ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
22326ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
223331234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22344f5f2548SRichard Henderson         break;
22354f5f2548SRichard Henderson 
223635136a77SRichard Henderson     case CR_IIASQ:
223735136a77SRichard Henderson     case CR_IIAOQ:
223835136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
223935136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2240aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22416fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
224235136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
22436fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
22446fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
224535136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
224635136a77SRichard Henderson         break;
224735136a77SRichard Henderson 
2248d5de20bdSSven Schnelle     case CR_PID1:
2249d5de20bdSSven Schnelle     case CR_PID2:
2250d5de20bdSSven Schnelle     case CR_PID3:
2251d5de20bdSSven Schnelle     case CR_PID4:
22526fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2253d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2254ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2255d5de20bdSSven Schnelle #endif
2256d5de20bdSSven Schnelle         break;
2257d5de20bdSSven Schnelle 
22586ebebea7SRichard Henderson     case CR_EIEM:
22596ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22606ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22616ebebea7SRichard Henderson         /* FALLTHRU */
226235136a77SRichard Henderson     default:
22636fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
226435136a77SRichard Henderson         break;
226535136a77SRichard Henderson     }
226631234768SRichard Henderson     return nullify_end(ctx);
22674f5f2548SRichard Henderson #endif
226835136a77SRichard Henderson }
226935136a77SRichard Henderson 
2270c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
227198a9cb79SRichard Henderson {
2272aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
227398a9cb79SRichard Henderson 
22746fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22756fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
227698a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
227798a9cb79SRichard Henderson 
2278e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
227931234768SRichard Henderson     return true;
228098a9cb79SRichard Henderson }
228198a9cb79SRichard Henderson 
2282e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
228398a9cb79SRichard Henderson {
22846fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
228598a9cb79SRichard Henderson 
22862330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22872330504cSHelge Deller     /* We don't implement space registers in user mode. */
22886fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22892330504cSHelge Deller #else
2290967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2291967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22922330504cSHelge Deller #endif
2293e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
229498a9cb79SRichard Henderson 
2295e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
229631234768SRichard Henderson     return true;
229798a9cb79SRichard Henderson }
229898a9cb79SRichard Henderson 
2299e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2300e36f27efSRichard Henderson {
23017b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2302e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23037b2d70a1SHelge Deller #else
23046fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2305e1b5a5edSRichard Henderson 
23067b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
23077b2d70a1SHelge Deller     if (a->i) {
23087b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23097b2d70a1SHelge Deller     }
23107b2d70a1SHelge Deller 
2311e1b5a5edSRichard Henderson     nullify_over(ctx);
2312e1b5a5edSRichard Henderson 
2313aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23146fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23156fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2316ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2317e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2318e1b5a5edSRichard Henderson 
2319e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
232031234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
232131234768SRichard Henderson     return nullify_end(ctx);
2322e36f27efSRichard Henderson #endif
2323e1b5a5edSRichard Henderson }
2324e1b5a5edSRichard Henderson 
2325e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2326e1b5a5edSRichard Henderson {
2327e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2328e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
23296fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2330e1b5a5edSRichard Henderson 
2331e1b5a5edSRichard Henderson     nullify_over(ctx);
2332e1b5a5edSRichard Henderson 
2333aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23346fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23356fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2336ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2337e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2338e1b5a5edSRichard Henderson 
2339e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
234031234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
234131234768SRichard Henderson     return nullify_end(ctx);
2342e36f27efSRichard Henderson #endif
2343e1b5a5edSRichard Henderson }
2344e1b5a5edSRichard Henderson 
2345c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2346e1b5a5edSRichard Henderson {
2347e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2348c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
23496fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2350e1b5a5edSRichard Henderson     nullify_over(ctx);
2351e1b5a5edSRichard Henderson 
2352c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2353aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2354ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2355e1b5a5edSRichard Henderson 
2356e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
235731234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
235831234768SRichard Henderson     return nullify_end(ctx);
2359c603e14aSRichard Henderson #endif
2360e1b5a5edSRichard Henderson }
2361f49b3537SRichard Henderson 
2362e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2363f49b3537SRichard Henderson {
2364f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2365e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2366f49b3537SRichard Henderson     nullify_over(ctx);
2367f49b3537SRichard Henderson 
2368e36f27efSRichard Henderson     if (rfi_r) {
2369ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2370f49b3537SRichard Henderson     } else {
2371ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2372f49b3537SRichard Henderson     }
237331234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
237407ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
237531234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2376f49b3537SRichard Henderson 
237731234768SRichard Henderson     return nullify_end(ctx);
2378e36f27efSRichard Henderson #endif
2379f49b3537SRichard Henderson }
23806210db05SHelge Deller 
2381e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2382e36f27efSRichard Henderson {
2383e36f27efSRichard Henderson     return do_rfi(ctx, false);
2384e36f27efSRichard Henderson }
2385e36f27efSRichard Henderson 
2386e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2387e36f27efSRichard Henderson {
2388e36f27efSRichard Henderson     return do_rfi(ctx, true);
2389e36f27efSRichard Henderson }
2390e36f27efSRichard Henderson 
239196927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23926210db05SHelge Deller {
23936210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
239496927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23956210db05SHelge Deller     nullify_over(ctx);
2396ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
239731234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
239831234768SRichard Henderson     return nullify_end(ctx);
239996927adbSRichard Henderson #endif
24006210db05SHelge Deller }
240196927adbSRichard Henderson 
240296927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
240396927adbSRichard Henderson {
240496927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
240596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
240696927adbSRichard Henderson     nullify_over(ctx);
2407ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
240896927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
240996927adbSRichard Henderson     return nullify_end(ctx);
241096927adbSRichard Henderson #endif
241196927adbSRichard Henderson }
2412e1b5a5edSRichard Henderson 
2413558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
24144a4554c6SHelge Deller {
24154a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24164a4554c6SHelge Deller     nullify_over(ctx);
2417558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2418558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2419558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2420558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2421558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2422558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2423558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24244a4554c6SHelge Deller     return nullify_end(ctx);
2425558c09beSRichard Henderson }
2426558c09beSRichard Henderson 
24273bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
24283bdf2081SHelge Deller {
24293bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24303bdf2081SHelge Deller     nullify_over(ctx);
24313bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
24323bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
24333bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
24343bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
24353bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
24363bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
24373bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24383bdf2081SHelge Deller     return nullify_end(ctx);
24393bdf2081SHelge Deller }
24403bdf2081SHelge Deller 
2441558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2442558c09beSRichard Henderson {
2443558c09beSRichard Henderson     return do_getshadowregs(ctx);
24444a4554c6SHelge Deller }
24454a4554c6SHelge Deller 
2446deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
244798a9cb79SRichard Henderson {
2448deee69a1SRichard Henderson     if (a->m) {
24496fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
24506fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
24516fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
245298a9cb79SRichard Henderson 
245398a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
24546fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2455deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2456deee69a1SRichard Henderson     }
2457e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
245831234768SRichard Henderson     return true;
245998a9cb79SRichard Henderson }
246098a9cb79SRichard Henderson 
2461ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2462ad1fdacdSSven Schnelle {
2463ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2464ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2465ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2466ad1fdacdSSven Schnelle }
2467ad1fdacdSSven Schnelle 
2468deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
246998a9cb79SRichard Henderson {
24706fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2471eed14219SRichard Henderson     TCGv_i32 level, want;
24726fd0c7bcSRichard Henderson     TCGv_i64 addr;
247398a9cb79SRichard Henderson 
247498a9cb79SRichard Henderson     nullify_over(ctx);
247598a9cb79SRichard Henderson 
2476deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2477deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2478eed14219SRichard Henderson 
2479deee69a1SRichard Henderson     if (a->imm) {
2480e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
248198a9cb79SRichard Henderson     } else {
2482eed14219SRichard Henderson         level = tcg_temp_new_i32();
24836fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2484eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
248598a9cb79SRichard Henderson     }
248629dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2487eed14219SRichard Henderson 
2488ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2489eed14219SRichard Henderson 
2490deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
249131234768SRichard Henderson     return nullify_end(ctx);
249298a9cb79SRichard Henderson }
249398a9cb79SRichard Henderson 
2494deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24958d6ae7fbSRichard Henderson {
24968577f354SRichard Henderson     if (ctx->is_pa20) {
24978577f354SRichard Henderson         return false;
24988577f354SRichard Henderson     }
2499deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2500deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
25016fd0c7bcSRichard Henderson     TCGv_i64 addr;
25026fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
25038d6ae7fbSRichard Henderson 
25048d6ae7fbSRichard Henderson     nullify_over(ctx);
25058d6ae7fbSRichard Henderson 
2506deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2507deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2508deee69a1SRichard Henderson     if (a->addr) {
25098577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
25108d6ae7fbSRichard Henderson     } else {
25118577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
25128d6ae7fbSRichard Henderson     }
25138d6ae7fbSRichard Henderson 
251432dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
251532dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
251631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
251731234768SRichard Henderson     }
251831234768SRichard Henderson     return nullify_end(ctx);
2519deee69a1SRichard Henderson #endif
25208d6ae7fbSRichard Henderson }
252163300a00SRichard Henderson 
2522eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
252363300a00SRichard Henderson {
2524deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2525deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
25266fd0c7bcSRichard Henderson     TCGv_i64 addr;
25276fd0c7bcSRichard Henderson     TCGv_i64 ofs;
252863300a00SRichard Henderson 
252963300a00SRichard Henderson     nullify_over(ctx);
253063300a00SRichard Henderson 
2531deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2532eb25d10fSHelge Deller 
2533eb25d10fSHelge Deller     /*
2534eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2535eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2536eb25d10fSHelge Deller      */
2537eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2538eb25d10fSHelge Deller     if (ctx->is_pa20) {
2539eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
254063300a00SRichard Henderson     }
2541eb25d10fSHelge Deller 
2542eb25d10fSHelge Deller     if (local) {
2543eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
254463300a00SRichard Henderson     } else {
2545ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
254663300a00SRichard Henderson     }
254763300a00SRichard Henderson 
2548eb25d10fSHelge Deller     if (a->m) {
2549eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2550eb25d10fSHelge Deller     }
2551eb25d10fSHelge Deller 
2552eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2553eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2554eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2555eb25d10fSHelge Deller     }
2556eb25d10fSHelge Deller     return nullify_end(ctx);
2557eb25d10fSHelge Deller #endif
2558eb25d10fSHelge Deller }
2559eb25d10fSHelge Deller 
2560eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2561eb25d10fSHelge Deller {
2562eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2563eb25d10fSHelge Deller }
2564eb25d10fSHelge Deller 
2565eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2566eb25d10fSHelge Deller {
2567eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2568eb25d10fSHelge Deller }
2569eb25d10fSHelge Deller 
2570eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2571eb25d10fSHelge Deller {
2572eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2573eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2574eb25d10fSHelge Deller     nullify_over(ctx);
2575eb25d10fSHelge Deller 
2576eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2577eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2578eb25d10fSHelge Deller 
257963300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
258032dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
258131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
258231234768SRichard Henderson     }
258331234768SRichard Henderson     return nullify_end(ctx);
2584deee69a1SRichard Henderson #endif
258563300a00SRichard Henderson }
25862dfcca9fSRichard Henderson 
25876797c315SNick Hudson /*
25886797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25896797c315SNick Hudson  * See
25906797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25916797c315SNick Hudson  *     page 13-9 (195/206)
25926797c315SNick Hudson  */
25936797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25946797c315SNick Hudson {
25958577f354SRichard Henderson     if (ctx->is_pa20) {
25968577f354SRichard Henderson         return false;
25978577f354SRichard Henderson     }
25986797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25996797c315SNick Hudson #ifndef CONFIG_USER_ONLY
26006fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
26016fd0c7bcSRichard Henderson     TCGv_i64 reg;
26026797c315SNick Hudson 
26036797c315SNick Hudson     nullify_over(ctx);
26046797c315SNick Hudson 
26056797c315SNick Hudson     /*
26066797c315SNick Hudson      * FIXME:
26076797c315SNick Hudson      *  if (not (pcxl or pcxl2))
26086797c315SNick Hudson      *    return gen_illegal(ctx);
26096797c315SNick Hudson      */
26106797c315SNick Hudson 
26116fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
26126fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
26136fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
26146797c315SNick Hudson 
2615ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
26166797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
26176797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2618ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
26196797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
26206797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
26216797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2622d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
26236797c315SNick Hudson 
26246797c315SNick Hudson     reg = load_gpr(ctx, a->r);
26256797c315SNick Hudson     if (a->addr) {
26268577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
26276797c315SNick Hudson     } else {
26288577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
26296797c315SNick Hudson     }
26306797c315SNick Hudson 
26316797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
26326797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
26336797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26346797c315SNick Hudson     }
26356797c315SNick Hudson     return nullify_end(ctx);
26366797c315SNick Hudson #endif
26376797c315SNick Hudson }
26386797c315SNick Hudson 
26398577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
26408577f354SRichard Henderson {
26418577f354SRichard Henderson     if (!ctx->is_pa20) {
26428577f354SRichard Henderson         return false;
26438577f354SRichard Henderson     }
26448577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
26458577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
26468577f354SRichard Henderson     nullify_over(ctx);
26478577f354SRichard Henderson     {
26488577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
26498577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
26508577f354SRichard Henderson 
26518577f354SRichard Henderson         if (a->data) {
26528577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
26538577f354SRichard Henderson         } else {
26548577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
26558577f354SRichard Henderson         }
26568577f354SRichard Henderson     }
26578577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26588577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26598577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26608577f354SRichard Henderson     }
26618577f354SRichard Henderson     return nullify_end(ctx);
26628577f354SRichard Henderson #endif
26638577f354SRichard Henderson }
26648577f354SRichard Henderson 
2665deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26662dfcca9fSRichard Henderson {
2667deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2668deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26696fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26706fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26712dfcca9fSRichard Henderson 
26722dfcca9fSRichard Henderson     nullify_over(ctx);
26732dfcca9fSRichard Henderson 
2674deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26752dfcca9fSRichard Henderson 
2676aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2677ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26782dfcca9fSRichard Henderson 
26792dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2680deee69a1SRichard Henderson     if (a->m) {
2681deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26822dfcca9fSRichard Henderson     }
2683deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26842dfcca9fSRichard Henderson 
268531234768SRichard Henderson     return nullify_end(ctx);
2686deee69a1SRichard Henderson #endif
26872dfcca9fSRichard Henderson }
268843a97b81SRichard Henderson 
2689deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
269043a97b81SRichard Henderson {
269143a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
269243a97b81SRichard Henderson 
269343a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
269443a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
269543a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
269643a97b81SRichard Henderson        since the entire address space is coherent.  */
2697a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
269843a97b81SRichard Henderson 
2699e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
270031234768SRichard Henderson     return true;
270143a97b81SRichard Henderson }
270298a9cb79SRichard Henderson 
2703faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2704b2167459SRichard Henderson {
27050c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2706b2167459SRichard Henderson }
2707b2167459SRichard Henderson 
2708faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2709b2167459SRichard Henderson {
27100c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2711b2167459SRichard Henderson }
2712b2167459SRichard Henderson 
2713faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2714b2167459SRichard Henderson {
27150c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2716b2167459SRichard Henderson }
2717b2167459SRichard Henderson 
2718faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2719b2167459SRichard Henderson {
27200c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
27210c982a28SRichard Henderson }
2722b2167459SRichard Henderson 
2723faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
27240c982a28SRichard Henderson {
27250c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
27260c982a28SRichard Henderson }
27270c982a28SRichard Henderson 
272863c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
27290c982a28SRichard Henderson {
27300c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
27310c982a28SRichard Henderson }
27320c982a28SRichard Henderson 
273363c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27340c982a28SRichard Henderson {
27350c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
27360c982a28SRichard Henderson }
27370c982a28SRichard Henderson 
273863c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27390c982a28SRichard Henderson {
27400c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
27410c982a28SRichard Henderson }
27420c982a28SRichard Henderson 
274363c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27440c982a28SRichard Henderson {
27450c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
27460c982a28SRichard Henderson }
27470c982a28SRichard Henderson 
274863c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
27490c982a28SRichard Henderson {
27500c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
27510c982a28SRichard Henderson }
27520c982a28SRichard Henderson 
275363c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27540c982a28SRichard Henderson {
27550c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27560c982a28SRichard Henderson }
27570c982a28SRichard Henderson 
2758fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27590c982a28SRichard Henderson {
27606fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27610c982a28SRichard Henderson }
27620c982a28SRichard Henderson 
2763fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27640c982a28SRichard Henderson {
27656fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27660c982a28SRichard Henderson }
27670c982a28SRichard Henderson 
2768fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27690c982a28SRichard Henderson {
27700c982a28SRichard Henderson     if (a->cf == 0) {
27710c982a28SRichard Henderson         unsigned r2 = a->r2;
27720c982a28SRichard Henderson         unsigned r1 = a->r1;
27730c982a28SRichard Henderson         unsigned rt = a->t;
27740c982a28SRichard Henderson 
27757aee8189SRichard Henderson         if (rt == 0) { /* NOP */
2776e0137378SRichard Henderson             ctx->null_cond = cond_make_f();
27777aee8189SRichard Henderson             return true;
27787aee8189SRichard Henderson         }
27797aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2780b2167459SRichard Henderson             if (r1 == 0) {
27816fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27826fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2783b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2784b2167459SRichard Henderson             } else {
2785b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2786b2167459SRichard Henderson             }
2787e0137378SRichard Henderson             ctx->null_cond = cond_make_f();
278831234768SRichard Henderson             return true;
2789b2167459SRichard Henderson         }
27907aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27917aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27927aee8189SRichard Henderson          *
27937aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27947aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27957aee8189SRichard Henderson          *                      currently implemented as idle.
27967aee8189SRichard Henderson          */
27977aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27987aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27997aee8189SRichard Henderson                until the next timer interrupt.  */
28007aee8189SRichard Henderson             nullify_over(ctx);
28017aee8189SRichard Henderson 
28027aee8189SRichard Henderson             /* Advance the instruction queue.  */
2803bc921866SRichard Henderson             install_iaq_entries(ctx, &ctx->iaq_b, NULL);
28047aee8189SRichard Henderson             nullify_set(ctx, 0);
28057aee8189SRichard Henderson 
28067aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2807ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
280829dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
28097aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
28107aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
28117aee8189SRichard Henderson 
28127aee8189SRichard Henderson             return nullify_end(ctx);
28137aee8189SRichard Henderson         }
28147aee8189SRichard Henderson #endif
28157aee8189SRichard Henderson     }
28166fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
28177aee8189SRichard Henderson }
2818b2167459SRichard Henderson 
2819fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2820b2167459SRichard Henderson {
28216fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
28220c982a28SRichard Henderson }
28230c982a28SRichard Henderson 
2824345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
28250c982a28SRichard Henderson {
28266fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2827b2167459SRichard Henderson 
28280c982a28SRichard Henderson     if (a->cf) {
2829b2167459SRichard Henderson         nullify_over(ctx);
2830b2167459SRichard Henderson     }
28310c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28320c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2833345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
283431234768SRichard Henderson     return nullify_end(ctx);
2835b2167459SRichard Henderson }
2836b2167459SRichard Henderson 
2837af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2838b2167459SRichard Henderson {
283946bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2840b2167459SRichard Henderson 
28410c982a28SRichard Henderson     if (a->cf) {
2842b2167459SRichard Henderson         nullify_over(ctx);
2843b2167459SRichard Henderson     }
284446bb3d46SRichard Henderson 
28450c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28460c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
284746bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
284846bb3d46SRichard Henderson 
284946bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
285046bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
285146bb3d46SRichard Henderson 
285246bb3d46SRichard Henderson     ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
285331234768SRichard Henderson     return nullify_end(ctx);
2854b2167459SRichard Henderson }
2855b2167459SRichard Henderson 
2856af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2857b2167459SRichard Henderson {
28586fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2859b2167459SRichard Henderson 
2860ababac16SRichard Henderson     if (a->cf == 0) {
2861ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2862ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2863ababac16SRichard Henderson 
2864ababac16SRichard Henderson         if (a->r1 == 0) {
2865ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2866ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2867ababac16SRichard Henderson         } else {
2868ababac16SRichard Henderson             /*
2869ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2870ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2871ababac16SRichard Henderson              * which does not require an extra temporary.
2872ababac16SRichard Henderson              */
2873ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2874ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2875ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2876b2167459SRichard Henderson         }
2877ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2878e0137378SRichard Henderson         ctx->null_cond = cond_make_f();
2879ababac16SRichard Henderson         return true;
2880ababac16SRichard Henderson     }
2881ababac16SRichard Henderson 
2882ababac16SRichard Henderson     nullify_over(ctx);
28830c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28840c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2885aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28866fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
288746bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
288831234768SRichard Henderson     return nullify_end(ctx);
2889b2167459SRichard Henderson }
2890b2167459SRichard Henderson 
2891af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2892b2167459SRichard Henderson {
28930c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28940c982a28SRichard Henderson }
28950c982a28SRichard Henderson 
2896af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28970c982a28SRichard Henderson {
28980c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28990c982a28SRichard Henderson }
29000c982a28SRichard Henderson 
2901af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
29020c982a28SRichard Henderson {
29036fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2904b2167459SRichard Henderson 
2905b2167459SRichard Henderson     nullify_over(ctx);
2906b2167459SRichard Henderson 
2907aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2908d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2909b2167459SRichard Henderson     if (!is_i) {
29106fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2911b2167459SRichard Henderson     }
29126fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
29136fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
291446bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
291546bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
291631234768SRichard Henderson     return nullify_end(ctx);
2917b2167459SRichard Henderson }
2918b2167459SRichard Henderson 
2919af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2920b2167459SRichard Henderson {
29210c982a28SRichard Henderson     return do_dcor(ctx, a, false);
29220c982a28SRichard Henderson }
29230c982a28SRichard Henderson 
2924af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
29250c982a28SRichard Henderson {
29260c982a28SRichard Henderson     return do_dcor(ctx, a, true);
29270c982a28SRichard Henderson }
29280c982a28SRichard Henderson 
29290c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
29300c982a28SRichard Henderson {
2931a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2932b2167459SRichard Henderson 
2933b2167459SRichard Henderson     nullify_over(ctx);
2934b2167459SRichard Henderson 
29350c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
29360c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2937b2167459SRichard Henderson 
2938aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2939aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2940aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2941aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2942b2167459SRichard Henderson 
2943b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
29446fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
29456fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2946b2167459SRichard Henderson 
294772ca8753SRichard Henderson     /*
294872ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
294972ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
295072ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
295172ca8753SRichard Henderson      * proper inputs to the addition without movcond.
295272ca8753SRichard Henderson      */
29536fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29546fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29556fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
295672ca8753SRichard Henderson 
2957a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2958a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2959a4db4a78SRichard Henderson                      addc, ctx->zero);
2960b2167459SRichard Henderson 
2961b2167459SRichard Henderson     /* Write back the result register.  */
29620c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2963b2167459SRichard Henderson 
2964b2167459SRichard Henderson     /* Write back PSW[CB].  */
29656fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29666fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2967b2167459SRichard Henderson 
2968f8f5986eSRichard Henderson     /*
2969f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2970f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2971f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2972f8f5986eSRichard Henderson      */
2973f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29746fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2975b2167459SRichard Henderson 
2976b2167459SRichard Henderson     /* Install the new nullification.  */
29770c982a28SRichard Henderson     if (a->cf) {
2978f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2979b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2980f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2981f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2982f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2983b2167459SRichard Henderson         }
2984f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2985b2167459SRichard Henderson     }
2986b2167459SRichard Henderson 
298731234768SRichard Henderson     return nullify_end(ctx);
2988b2167459SRichard Henderson }
2989b2167459SRichard Henderson 
29900588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2991b2167459SRichard Henderson {
29920588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29930588e061SRichard Henderson }
29940588e061SRichard Henderson 
29950588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29960588e061SRichard Henderson {
29970588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29980588e061SRichard Henderson }
29990588e061SRichard Henderson 
30000588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
30010588e061SRichard Henderson {
30020588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
30030588e061SRichard Henderson }
30040588e061SRichard Henderson 
30050588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
30060588e061SRichard Henderson {
30070588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
30080588e061SRichard Henderson }
30090588e061SRichard Henderson 
30100588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
30110588e061SRichard Henderson {
30120588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
30130588e061SRichard Henderson }
30140588e061SRichard Henderson 
30150588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
30160588e061SRichard Henderson {
30170588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
30180588e061SRichard Henderson }
30190588e061SRichard Henderson 
3020345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
30210588e061SRichard Henderson {
30226fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
3023b2167459SRichard Henderson 
30240588e061SRichard Henderson     if (a->cf) {
3025b2167459SRichard Henderson         nullify_over(ctx);
3026b2167459SRichard Henderson     }
3027b2167459SRichard Henderson 
30286fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
30290588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
3030345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
3031b2167459SRichard Henderson 
303231234768SRichard Henderson     return nullify_end(ctx);
3033b2167459SRichard Henderson }
3034b2167459SRichard Henderson 
30350843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
30360843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
30370843563fSRichard Henderson {
30380843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
30390843563fSRichard Henderson 
30400843563fSRichard Henderson     if (!ctx->is_pa20) {
30410843563fSRichard Henderson         return false;
30420843563fSRichard Henderson     }
30430843563fSRichard Henderson 
30440843563fSRichard Henderson     nullify_over(ctx);
30450843563fSRichard Henderson 
30460843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
30470843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
30480843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
30490843563fSRichard Henderson 
30500843563fSRichard Henderson     fn(dest, r1, r2);
30510843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30520843563fSRichard Henderson 
30530843563fSRichard Henderson     return nullify_end(ctx);
30540843563fSRichard Henderson }
30550843563fSRichard Henderson 
3056151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3057151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3058151f309bSRichard Henderson {
3059151f309bSRichard Henderson     TCGv_i64 r, dest;
3060151f309bSRichard Henderson 
3061151f309bSRichard Henderson     if (!ctx->is_pa20) {
3062151f309bSRichard Henderson         return false;
3063151f309bSRichard Henderson     }
3064151f309bSRichard Henderson 
3065151f309bSRichard Henderson     nullify_over(ctx);
3066151f309bSRichard Henderson 
3067151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3068151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3069151f309bSRichard Henderson 
3070151f309bSRichard Henderson     fn(dest, r, a->i);
3071151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3072151f309bSRichard Henderson 
3073151f309bSRichard Henderson     return nullify_end(ctx);
3074151f309bSRichard Henderson }
3075151f309bSRichard Henderson 
30763bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30773bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30783bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30793bbb8e48SRichard Henderson {
30803bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30813bbb8e48SRichard Henderson 
30823bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30833bbb8e48SRichard Henderson         return false;
30843bbb8e48SRichard Henderson     }
30853bbb8e48SRichard Henderson 
30863bbb8e48SRichard Henderson     nullify_over(ctx);
30873bbb8e48SRichard Henderson 
30883bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30893bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30903bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30913bbb8e48SRichard Henderson 
30923bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30933bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30943bbb8e48SRichard Henderson 
30953bbb8e48SRichard Henderson     return nullify_end(ctx);
30963bbb8e48SRichard Henderson }
30973bbb8e48SRichard Henderson 
30980843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30990843563fSRichard Henderson {
31000843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
31010843563fSRichard Henderson }
31020843563fSRichard Henderson 
31030843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
31040843563fSRichard Henderson {
31050843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
31060843563fSRichard Henderson }
31070843563fSRichard Henderson 
31080843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
31090843563fSRichard Henderson {
31100843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
31110843563fSRichard Henderson }
31120843563fSRichard Henderson 
31131b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
31141b3cb7c8SRichard Henderson {
31151b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
31161b3cb7c8SRichard Henderson }
31171b3cb7c8SRichard Henderson 
3118151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3119151f309bSRichard Henderson {
3120151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3121151f309bSRichard Henderson }
3122151f309bSRichard Henderson 
3123151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3124151f309bSRichard Henderson {
3125151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3126151f309bSRichard Henderson }
3127151f309bSRichard Henderson 
3128151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3129151f309bSRichard Henderson {
3130151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3131151f309bSRichard Henderson }
3132151f309bSRichard Henderson 
31333bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
31343bbb8e48SRichard Henderson {
31353bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
31363bbb8e48SRichard Henderson }
31373bbb8e48SRichard Henderson 
31383bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
31393bbb8e48SRichard Henderson {
31403bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
31413bbb8e48SRichard Henderson }
31423bbb8e48SRichard Henderson 
314310c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
314410c9e58dSRichard Henderson {
314510c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
314610c9e58dSRichard Henderson }
314710c9e58dSRichard Henderson 
314810c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
314910c9e58dSRichard Henderson {
315010c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
315110c9e58dSRichard Henderson }
315210c9e58dSRichard Henderson 
315310c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
315410c9e58dSRichard Henderson {
315510c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
315610c9e58dSRichard Henderson }
315710c9e58dSRichard Henderson 
3158c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3159c2a7ee3fSRichard Henderson {
3160c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3161c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3162c2a7ee3fSRichard Henderson 
3163c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3164c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3165c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3166c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3167c2a7ee3fSRichard Henderson }
3168c2a7ee3fSRichard Henderson 
3169c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3170c2a7ee3fSRichard Henderson {
3171c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3172c2a7ee3fSRichard Henderson }
3173c2a7ee3fSRichard Henderson 
3174c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3175c2a7ee3fSRichard Henderson {
3176c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3177c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3178c2a7ee3fSRichard Henderson 
3179c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3180c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3181c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3182c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3183c2a7ee3fSRichard Henderson }
3184c2a7ee3fSRichard Henderson 
3185c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3186c2a7ee3fSRichard Henderson {
3187c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3188c2a7ee3fSRichard Henderson }
3189c2a7ee3fSRichard Henderson 
3190c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3191c2a7ee3fSRichard Henderson {
3192c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3193c2a7ee3fSRichard Henderson 
3194c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3195c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3196c2a7ee3fSRichard Henderson }
3197c2a7ee3fSRichard Henderson 
3198c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3199c2a7ee3fSRichard Henderson {
3200c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3201c2a7ee3fSRichard Henderson }
3202c2a7ee3fSRichard Henderson 
3203c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3204c2a7ee3fSRichard Henderson {
3205c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3206c2a7ee3fSRichard Henderson }
3207c2a7ee3fSRichard Henderson 
3208c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3209c2a7ee3fSRichard Henderson {
3210c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3211c2a7ee3fSRichard Henderson }
3212c2a7ee3fSRichard Henderson 
32134e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
32144e7abdb1SRichard Henderson {
32154e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
32164e7abdb1SRichard Henderson 
32174e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
32184e7abdb1SRichard Henderson         return false;
32194e7abdb1SRichard Henderson     }
32204e7abdb1SRichard Henderson 
32214e7abdb1SRichard Henderson     nullify_over(ctx);
32224e7abdb1SRichard Henderson 
32234e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
32244e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
32254e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
32264e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
32274e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
32284e7abdb1SRichard Henderson 
32294e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
32304e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
32314e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
32324e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
32334e7abdb1SRichard Henderson 
32344e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
32354e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
32364e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
32374e7abdb1SRichard Henderson 
32384e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
32394e7abdb1SRichard Henderson     return nullify_end(ctx);
32404e7abdb1SRichard Henderson }
32414e7abdb1SRichard Henderson 
32421cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
324396d6407fSRichard Henderson {
3244b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3245b5caa17cSRichard Henderson        /*
3246b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3247b5caa17cSRichard Henderson         * Any base modification still occurs.
3248b5caa17cSRichard Henderson         */
3249b5caa17cSRichard Henderson         if (a->t == 0) {
3250b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3251b5caa17cSRichard Henderson         }
3252b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32530786a3b6SHelge Deller         return gen_illegal(ctx);
3254c53e401eSRichard Henderson     }
32551cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32561cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
325796d6407fSRichard Henderson }
325896d6407fSRichard Henderson 
32591cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
326096d6407fSRichard Henderson {
32611cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3262c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32630786a3b6SHelge Deller         return gen_illegal(ctx);
326496d6407fSRichard Henderson     }
3265c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32660786a3b6SHelge Deller }
326796d6407fSRichard Henderson 
32681cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
326996d6407fSRichard Henderson {
3270b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3271a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32726fd0c7bcSRichard Henderson     TCGv_i64 addr;
327396d6407fSRichard Henderson 
3274c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
327551416c4eSRichard Henderson         return gen_illegal(ctx);
327651416c4eSRichard Henderson     }
327751416c4eSRichard Henderson 
327896d6407fSRichard Henderson     nullify_over(ctx);
327996d6407fSRichard Henderson 
32801cd012a5SRichard Henderson     if (a->m) {
328186f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
328286f8d05fSRichard Henderson            we see the result of the load.  */
3283aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
328496d6407fSRichard Henderson     } else {
32851cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
328696d6407fSRichard Henderson     }
328796d6407fSRichard Henderson 
3288c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
328917fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3290b1af755cSRichard Henderson 
3291b1af755cSRichard Henderson     /*
3292b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3293b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3294b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3295b1af755cSRichard Henderson      *
3296b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3297b1af755cSRichard Henderson      * with the ,co completer.
3298b1af755cSRichard Henderson      */
3299b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3300b1af755cSRichard Henderson 
3301a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3302b1af755cSRichard Henderson 
33031cd012a5SRichard Henderson     if (a->m) {
33041cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
330596d6407fSRichard Henderson     }
33061cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
330796d6407fSRichard Henderson 
330831234768SRichard Henderson     return nullify_end(ctx);
330996d6407fSRichard Henderson }
331096d6407fSRichard Henderson 
33111cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
331296d6407fSRichard Henderson {
33136fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33146fd0c7bcSRichard Henderson     TCGv_i64 addr;
331596d6407fSRichard Henderson 
331696d6407fSRichard Henderson     nullify_over(ctx);
331796d6407fSRichard Henderson 
33181cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
331917fe594cSRichard Henderson              MMU_DISABLED(ctx));
33201cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
33211cd012a5SRichard Henderson     if (a->a) {
3322f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3323ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3324f9f46db4SEmilio G. Cota         } else {
3325ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3326f9f46db4SEmilio G. Cota         }
3327f9f46db4SEmilio G. Cota     } else {
3328f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3329ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
333096d6407fSRichard Henderson         } else {
3331ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
333296d6407fSRichard Henderson         }
3333f9f46db4SEmilio G. Cota     }
33341cd012a5SRichard Henderson     if (a->m) {
33356fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
33361cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
333796d6407fSRichard Henderson     }
333896d6407fSRichard Henderson 
333931234768SRichard Henderson     return nullify_end(ctx);
334096d6407fSRichard Henderson }
334196d6407fSRichard Henderson 
334225460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
334325460fc5SRichard Henderson {
33446fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33456fd0c7bcSRichard Henderson     TCGv_i64 addr;
334625460fc5SRichard Henderson 
334725460fc5SRichard Henderson     if (!ctx->is_pa20) {
334825460fc5SRichard Henderson         return false;
334925460fc5SRichard Henderson     }
335025460fc5SRichard Henderson     nullify_over(ctx);
335125460fc5SRichard Henderson 
335225460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
335317fe594cSRichard Henderson              MMU_DISABLED(ctx));
335425460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
335525460fc5SRichard Henderson     if (a->a) {
335625460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
335725460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
335825460fc5SRichard Henderson         } else {
335925460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
336025460fc5SRichard Henderson         }
336125460fc5SRichard Henderson     } else {
336225460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
336325460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
336425460fc5SRichard Henderson         } else {
336525460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
336625460fc5SRichard Henderson         }
336725460fc5SRichard Henderson     }
336825460fc5SRichard Henderson     if (a->m) {
33696fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
337025460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
337125460fc5SRichard Henderson     }
337225460fc5SRichard Henderson 
337325460fc5SRichard Henderson     return nullify_end(ctx);
337425460fc5SRichard Henderson }
337525460fc5SRichard Henderson 
33761cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3377d0a851ccSRichard Henderson {
3378d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3379d0a851ccSRichard Henderson 
3380d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3381451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33821cd012a5SRichard Henderson     trans_ld(ctx, a);
3383d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
338431234768SRichard Henderson     return true;
3385d0a851ccSRichard Henderson }
3386d0a851ccSRichard Henderson 
33871cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3388d0a851ccSRichard Henderson {
3389d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3390d0a851ccSRichard Henderson 
3391d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3392451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33931cd012a5SRichard Henderson     trans_st(ctx, a);
3394d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
339531234768SRichard Henderson     return true;
3396d0a851ccSRichard Henderson }
339795412a61SRichard Henderson 
33980588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3399b2167459SRichard Henderson {
34006fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3401b2167459SRichard Henderson 
34026fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
34030588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3404e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
340531234768SRichard Henderson     return true;
3406b2167459SRichard Henderson }
3407b2167459SRichard Henderson 
34080588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3409b2167459SRichard Henderson {
34106fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
34116fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3412b2167459SRichard Henderson 
34136fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3414b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3415e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
341631234768SRichard Henderson     return true;
3417b2167459SRichard Henderson }
3418b2167459SRichard Henderson 
34190588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3420b2167459SRichard Henderson {
34216fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3422b2167459SRichard Henderson 
3423b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3424d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
34250588e061SRichard Henderson     if (a->b == 0) {
34266fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3427b2167459SRichard Henderson     } else {
34286fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3429b2167459SRichard Henderson     }
34300588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3431e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
343231234768SRichard Henderson     return true;
3433b2167459SRichard Henderson }
3434b2167459SRichard Henderson 
34356fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3436e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
343798cd9ca7SRichard Henderson {
34386fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
343998cd9ca7SRichard Henderson     DisasCond cond;
344098cd9ca7SRichard Henderson 
344198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3442aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
344398cd9ca7SRichard Henderson 
34446fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
344598cd9ca7SRichard Henderson 
3446f764718dSRichard Henderson     sv = NULL;
3447b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
344898cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
344998cd9ca7SRichard Henderson     }
345098cd9ca7SRichard Henderson 
34514fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
345201afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
345398cd9ca7SRichard Henderson }
345498cd9ca7SRichard Henderson 
345501afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
345698cd9ca7SRichard Henderson {
3457e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3458e9efd4bcSRichard Henderson         return false;
3459e9efd4bcSRichard Henderson     }
346001afb7beSRichard Henderson     nullify_over(ctx);
3461e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3462e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
346301afb7beSRichard Henderson }
346401afb7beSRichard Henderson 
346501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
346601afb7beSRichard Henderson {
3467c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3468c65c3ee1SRichard Henderson         return false;
3469c65c3ee1SRichard Henderson     }
347001afb7beSRichard Henderson     nullify_over(ctx);
34716fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3472c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
347301afb7beSRichard Henderson }
347401afb7beSRichard Henderson 
34756fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
347601afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
347701afb7beSRichard Henderson {
34786fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
347998cd9ca7SRichard Henderson     DisasCond cond;
3480bdcccc17SRichard Henderson     bool d = false;
348198cd9ca7SRichard Henderson 
3482f25d3160SRichard Henderson     /*
3483f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3484f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3485f25d3160SRichard Henderson      */
3486f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3487f25d3160SRichard Henderson         d = c >= 5;
3488f25d3160SRichard Henderson         if (d) {
3489f25d3160SRichard Henderson             c &= 3;
3490f25d3160SRichard Henderson         }
3491f25d3160SRichard Henderson     }
3492f25d3160SRichard Henderson 
349398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3494aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3495f764718dSRichard Henderson     sv = NULL;
3496bdcccc17SRichard Henderson     cb_cond = NULL;
349798cd9ca7SRichard Henderson 
3498b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3499aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3500aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3501bdcccc17SRichard Henderson 
35026fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
35036fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
35046fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
35056fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3506bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3507b47a4a02SSven Schnelle     } else {
35086fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3509b47a4a02SSven Schnelle     }
3510b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3511f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
351298cd9ca7SRichard Henderson     }
351398cd9ca7SRichard Henderson 
3514a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
351543675d20SSven Schnelle     save_gpr(ctx, r, dest);
351601afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
351798cd9ca7SRichard Henderson }
351898cd9ca7SRichard Henderson 
351901afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
352098cd9ca7SRichard Henderson {
352101afb7beSRichard Henderson     nullify_over(ctx);
352201afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
352301afb7beSRichard Henderson }
352401afb7beSRichard Henderson 
352501afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
352601afb7beSRichard Henderson {
352701afb7beSRichard Henderson     nullify_over(ctx);
35286fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
352901afb7beSRichard Henderson }
353001afb7beSRichard Henderson 
353101afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
353201afb7beSRichard Henderson {
35336fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
353498cd9ca7SRichard Henderson     DisasCond cond;
353598cd9ca7SRichard Henderson 
353698cd9ca7SRichard Henderson     nullify_over(ctx);
353798cd9ca7SRichard Henderson 
3538aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
353901afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
354082d0c831SRichard Henderson     if (a->d) {
354182d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
354282d0c831SRichard Henderson     } else {
35431e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
35446fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
35456fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
35461e9ab9fbSRichard Henderson     }
354798cd9ca7SRichard Henderson 
35484c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
354901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
355098cd9ca7SRichard Henderson }
355198cd9ca7SRichard Henderson 
355201afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
355398cd9ca7SRichard Henderson {
355401afb7beSRichard Henderson     DisasCond cond;
3555b041ec9dSRichard Henderson     int p = a->p | (a->d ? 0 : 32);
355601afb7beSRichard Henderson 
355701afb7beSRichard Henderson     nullify_over(ctx);
3558b041ec9dSRichard Henderson     cond = cond_make_vi(a->c ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
3559b041ec9dSRichard Henderson                         load_gpr(ctx, a->r), 1ull << (63 - p));
356001afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
356101afb7beSRichard Henderson }
356201afb7beSRichard Henderson 
356301afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
356401afb7beSRichard Henderson {
35656fd0c7bcSRichard Henderson     TCGv_i64 dest;
356698cd9ca7SRichard Henderson     DisasCond cond;
356798cd9ca7SRichard Henderson 
356898cd9ca7SRichard Henderson     nullify_over(ctx);
356998cd9ca7SRichard Henderson 
357001afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
357101afb7beSRichard Henderson     if (a->r1 == 0) {
35726fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
357398cd9ca7SRichard Henderson     } else {
35746fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
357598cd9ca7SRichard Henderson     }
357698cd9ca7SRichard Henderson 
35774fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35784fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
357901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
358001afb7beSRichard Henderson }
358101afb7beSRichard Henderson 
358201afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
358301afb7beSRichard Henderson {
35846fd0c7bcSRichard Henderson     TCGv_i64 dest;
358501afb7beSRichard Henderson     DisasCond cond;
358601afb7beSRichard Henderson 
358701afb7beSRichard Henderson     nullify_over(ctx);
358801afb7beSRichard Henderson 
358901afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35906fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
359101afb7beSRichard Henderson 
35924fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35934fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
359401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
359598cd9ca7SRichard Henderson }
359698cd9ca7SRichard Henderson 
3597f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
35980b1347d2SRichard Henderson {
35996fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
36000b1347d2SRichard Henderson 
3601f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3602f7b775a9SRichard Henderson         return false;
3603f7b775a9SRichard Henderson     }
360430878590SRichard Henderson     if (a->c) {
36050b1347d2SRichard Henderson         nullify_over(ctx);
36060b1347d2SRichard Henderson     }
36070b1347d2SRichard Henderson 
360830878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3609f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
361030878590SRichard Henderson     if (a->r1 == 0) {
3611f7b775a9SRichard Henderson         if (a->d) {
36126fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3613f7b775a9SRichard Henderson         } else {
3614aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3615f7b775a9SRichard Henderson 
36166fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
36176fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
36186fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3619f7b775a9SRichard Henderson         }
362030878590SRichard Henderson     } else if (a->r1 == a->r2) {
3621f7b775a9SRichard Henderson         if (a->d) {
36226fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3623f7b775a9SRichard Henderson         } else {
36240b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3625e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3626e1d635e8SRichard Henderson 
36276fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
36286fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3629f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3630e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
36316fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3632f7b775a9SRichard Henderson         }
3633f7b775a9SRichard Henderson     } else {
36346fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3635f7b775a9SRichard Henderson 
3636f7b775a9SRichard Henderson         if (a->d) {
3637aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3638aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3639f7b775a9SRichard Henderson 
36406fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3641a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
36426fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3643a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
36446fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36450b1347d2SRichard Henderson         } else {
36460b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36470b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36480b1347d2SRichard Henderson 
36496fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3650967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3651967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36520b1347d2SRichard Henderson         }
3653f7b775a9SRichard Henderson     }
365430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36550b1347d2SRichard Henderson 
36560b1347d2SRichard Henderson     /* Install the new nullification.  */
3657d37fad0aSSven Schnelle     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
365831234768SRichard Henderson     return nullify_end(ctx);
36590b1347d2SRichard Henderson }
36600b1347d2SRichard Henderson 
3661f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36620b1347d2SRichard Henderson {
3663f7b775a9SRichard Henderson     unsigned width, sa;
36646fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36650b1347d2SRichard Henderson 
3666f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3667f7b775a9SRichard Henderson         return false;
3668f7b775a9SRichard Henderson     }
366930878590SRichard Henderson     if (a->c) {
36700b1347d2SRichard Henderson         nullify_over(ctx);
36710b1347d2SRichard Henderson     }
36720b1347d2SRichard Henderson 
3673f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3674f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3675f7b775a9SRichard Henderson 
367630878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
367730878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
367805bfd4dbSRichard Henderson     if (a->r1 == 0) {
36796fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3680c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36816fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3682f7b775a9SRichard Henderson     } else {
3683f7b775a9SRichard Henderson         assert(!a->d);
3684f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36850b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36866fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36870b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36886fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36890b1347d2SRichard Henderson         } else {
3690967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3691967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36920b1347d2SRichard Henderson         }
3693f7b775a9SRichard Henderson     }
369430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36950b1347d2SRichard Henderson 
36960b1347d2SRichard Henderson     /* Install the new nullification.  */
3697d37fad0aSSven Schnelle     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
369831234768SRichard Henderson     return nullify_end(ctx);
36990b1347d2SRichard Henderson }
37000b1347d2SRichard Henderson 
3701bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
37020b1347d2SRichard Henderson {
3703bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
37046fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
37050b1347d2SRichard Henderson 
3706bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3707bd792da3SRichard Henderson         return false;
3708bd792da3SRichard Henderson     }
370930878590SRichard Henderson     if (a->c) {
37100b1347d2SRichard Henderson         nullify_over(ctx);
37110b1347d2SRichard Henderson     }
37120b1347d2SRichard Henderson 
371330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
371430878590SRichard Henderson     src = load_gpr(ctx, a->r);
3715aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37160b1347d2SRichard Henderson 
37170b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
37186fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
37196fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3720d781cb77SRichard Henderson 
372130878590SRichard Henderson     if (a->se) {
3722bd792da3SRichard Henderson         if (!a->d) {
37236fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3724bd792da3SRichard Henderson             src = dest;
3725bd792da3SRichard Henderson         }
37266fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
37276fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
37280b1347d2SRichard Henderson     } else {
3729bd792da3SRichard Henderson         if (!a->d) {
37306fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3731bd792da3SRichard Henderson             src = dest;
3732bd792da3SRichard Henderson         }
37336fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
37346fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
37350b1347d2SRichard Henderson     }
373630878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37370b1347d2SRichard Henderson 
37380b1347d2SRichard Henderson     /* Install the new nullification.  */
3739bd792da3SRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
374031234768SRichard Henderson     return nullify_end(ctx);
37410b1347d2SRichard Henderson }
37420b1347d2SRichard Henderson 
3743bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37440b1347d2SRichard Henderson {
3745bd792da3SRichard Henderson     unsigned len, cpos, width;
37466fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37470b1347d2SRichard Henderson 
3748bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3749bd792da3SRichard Henderson         return false;
3750bd792da3SRichard Henderson     }
375130878590SRichard Henderson     if (a->c) {
37520b1347d2SRichard Henderson         nullify_over(ctx);
37530b1347d2SRichard Henderson     }
37540b1347d2SRichard Henderson 
3755bd792da3SRichard Henderson     len = a->len;
3756bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3757bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3758bd792da3SRichard Henderson     if (cpos + len > width) {
3759bd792da3SRichard Henderson         len = width - cpos;
3760bd792da3SRichard Henderson     }
3761bd792da3SRichard Henderson 
376230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
376330878590SRichard Henderson     src = load_gpr(ctx, a->r);
376430878590SRichard Henderson     if (a->se) {
37656fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37660b1347d2SRichard Henderson     } else {
37676fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37680b1347d2SRichard Henderson     }
376930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37700b1347d2SRichard Henderson 
37710b1347d2SRichard Henderson     /* Install the new nullification.  */
3772bd792da3SRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
377331234768SRichard Henderson     return nullify_end(ctx);
37740b1347d2SRichard Henderson }
37750b1347d2SRichard Henderson 
377672ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37770b1347d2SRichard Henderson {
377872ae4f2bSRichard Henderson     unsigned len, width;
3779c53e401eSRichard Henderson     uint64_t mask0, mask1;
37806fd0c7bcSRichard Henderson     TCGv_i64 dest;
37810b1347d2SRichard Henderson 
378272ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
378372ae4f2bSRichard Henderson         return false;
378472ae4f2bSRichard Henderson     }
378530878590SRichard Henderson     if (a->c) {
37860b1347d2SRichard Henderson         nullify_over(ctx);
37870b1347d2SRichard Henderson     }
378872ae4f2bSRichard Henderson 
378972ae4f2bSRichard Henderson     len = a->len;
379072ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
379172ae4f2bSRichard Henderson     if (a->cpos + len > width) {
379272ae4f2bSRichard Henderson         len = width - a->cpos;
37930b1347d2SRichard Henderson     }
37940b1347d2SRichard Henderson 
379530878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
379630878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
379730878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
37980b1347d2SRichard Henderson 
379930878590SRichard Henderson     if (a->nz) {
38006fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
38016fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
38026fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
38030b1347d2SRichard Henderson     } else {
38046fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
38050b1347d2SRichard Henderson     }
380630878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38070b1347d2SRichard Henderson 
38080b1347d2SRichard Henderson     /* Install the new nullification.  */
380972ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
381031234768SRichard Henderson     return nullify_end(ctx);
38110b1347d2SRichard Henderson }
38120b1347d2SRichard Henderson 
381372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
38140b1347d2SRichard Henderson {
381530878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
381672ae4f2bSRichard Henderson     unsigned len, width;
38176fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
38180b1347d2SRichard Henderson 
381972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
382072ae4f2bSRichard Henderson         return false;
382172ae4f2bSRichard Henderson     }
382230878590SRichard Henderson     if (a->c) {
38230b1347d2SRichard Henderson         nullify_over(ctx);
38240b1347d2SRichard Henderson     }
382572ae4f2bSRichard Henderson 
382672ae4f2bSRichard Henderson     len = a->len;
382772ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
382872ae4f2bSRichard Henderson     if (a->cpos + len > width) {
382972ae4f2bSRichard Henderson         len = width - a->cpos;
38300b1347d2SRichard Henderson     }
38310b1347d2SRichard Henderson 
383230878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
383330878590SRichard Henderson     val = load_gpr(ctx, a->r);
38340b1347d2SRichard Henderson     if (rs == 0) {
38356fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38360b1347d2SRichard Henderson     } else {
38376fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38380b1347d2SRichard Henderson     }
383930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38400b1347d2SRichard Henderson 
38410b1347d2SRichard Henderson     /* Install the new nullification.  */
384272ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
384331234768SRichard Henderson     return nullify_end(ctx);
38440b1347d2SRichard Henderson }
38450b1347d2SRichard Henderson 
384672ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38476fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38480b1347d2SRichard Henderson {
38490b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
385072ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38516fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3852c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38530b1347d2SRichard Henderson 
38540b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3855aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3856aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38570b1347d2SRichard Henderson 
38580b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38596fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38606fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38610b1347d2SRichard Henderson 
3862aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38636fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38646fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38650b1347d2SRichard Henderson     if (rs) {
38666fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38676fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38686fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38696fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38700b1347d2SRichard Henderson     } else {
38716fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38720b1347d2SRichard Henderson     }
38730b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38740b1347d2SRichard Henderson 
38750b1347d2SRichard Henderson     /* Install the new nullification.  */
387672ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, c, d, dest);
387731234768SRichard Henderson     return nullify_end(ctx);
38780b1347d2SRichard Henderson }
38790b1347d2SRichard Henderson 
388072ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
388130878590SRichard Henderson {
388272ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
388372ae4f2bSRichard Henderson         return false;
388472ae4f2bSRichard Henderson     }
3885a6deecceSSven Schnelle     if (a->c) {
3886a6deecceSSven Schnelle         nullify_over(ctx);
3887a6deecceSSven Schnelle     }
388872ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
388972ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
389030878590SRichard Henderson }
389130878590SRichard Henderson 
389272ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
389330878590SRichard Henderson {
389472ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
389572ae4f2bSRichard Henderson         return false;
389672ae4f2bSRichard Henderson     }
3897a6deecceSSven Schnelle     if (a->c) {
3898a6deecceSSven Schnelle         nullify_over(ctx);
3899a6deecceSSven Schnelle     }
390072ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
39016fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
390230878590SRichard Henderson }
39030b1347d2SRichard Henderson 
39048340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
390598cd9ca7SRichard Henderson {
3906019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
3907bc921866SRichard Henderson     ctx->iaq_j.space = tcg_temp_new_i64();
3908bc921866SRichard Henderson     load_spr(ctx, ctx->iaq_j.space, a->sp);
3909c301f34eSRichard Henderson #endif
3910019f4159SRichard Henderson 
3911bc921866SRichard Henderson     ctx->iaq_j.base = tcg_temp_new_i64();
3912bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
3913bc921866SRichard Henderson 
3914bc921866SRichard Henderson     tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp);
3915bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base);
3916bc921866SRichard Henderson 
3917bc921866SRichard Henderson     return do_ibranch(ctx, a->l, true, a->n);
391898cd9ca7SRichard Henderson }
391998cd9ca7SRichard Henderson 
39208340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
392198cd9ca7SRichard Henderson {
39222644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
392398cd9ca7SRichard Henderson }
392498cd9ca7SRichard Henderson 
39258340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
392643e05652SRichard Henderson {
3927bc921866SRichard Henderson     int64_t disp = a->disp;
392843e05652SRichard Henderson 
39296e5f5300SSven Schnelle     nullify_over(ctx);
39306e5f5300SSven Schnelle 
393143e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
393243e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
393343e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
393443e05652SRichard Henderson      *    b  gateway
393543e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
393643e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
393743e05652SRichard Henderson      * diagnose the security hole
393843e05652SRichard Henderson      *    b  gateway
393943e05652SRichard Henderson      *    b  evil
394043e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
394143e05652SRichard Henderson      */
3942bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
394343e05652SRichard Henderson         return gen_illegal(ctx);
394443e05652SRichard Henderson     }
394543e05652SRichard Henderson 
394643e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
394743e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
394894956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
394943e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
395043e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
395143e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
395243e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
395343e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
395443e05652SRichard Henderson         if (type < 0) {
395531234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
395631234768SRichard Henderson             return true;
395743e05652SRichard Henderson         }
395843e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
395943e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
3960bc921866SRichard Henderson             disp -= ctx->privilege;
3961bc921866SRichard Henderson             disp += type - 4;
396243e05652SRichard Henderson         }
396343e05652SRichard Henderson     } else {
3964bc921866SRichard Henderson         disp -= ctx->privilege;  /* priv = 0 */
396543e05652SRichard Henderson     }
396643e05652SRichard Henderson #endif
396743e05652SRichard Henderson 
39686e5f5300SSven Schnelle     if (a->l) {
39696fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39706e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39716fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39726e5f5300SSven Schnelle         }
39736fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39746e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
39756e5f5300SSven Schnelle     }
39766e5f5300SSven Schnelle 
3977bc921866SRichard Henderson     return do_dbranch(ctx, disp, 0, a->n);
397843e05652SRichard Henderson }
397943e05652SRichard Henderson 
39808340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
398198cd9ca7SRichard Henderson {
3982b35aec85SRichard Henderson     if (a->x) {
3983bc921866SRichard Henderson         DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8);
3984bc921866SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
3985bc921866SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
3986bc921866SRichard Henderson 
3987660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
3988bc921866SRichard Henderson         copy_iaoq_entry(ctx, t0, &next);
3989bc921866SRichard Henderson         tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3);
3990bc921866SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
3991bc921866SRichard Henderson 
3992bc921866SRichard Henderson         ctx->iaq_j = iaqe_next_absv(ctx, t0);
3993bc921866SRichard Henderson         return do_ibranch(ctx, a->l, false, a->n);
3994b35aec85SRichard Henderson     } else {
3995b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
39962644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
3997b35aec85SRichard Henderson     }
399898cd9ca7SRichard Henderson }
399998cd9ca7SRichard Henderson 
40008340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
400198cd9ca7SRichard Henderson {
40026fd0c7bcSRichard Henderson     TCGv_i64 dest;
400398cd9ca7SRichard Henderson 
40048340f534SRichard Henderson     if (a->x == 0) {
40058340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
400698cd9ca7SRichard Henderson     } else {
4007aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
40086fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
40096fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
401098cd9ca7SRichard Henderson     }
4011660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
4012bc921866SRichard Henderson     ctx->iaq_j = iaqe_next_absv(ctx, dest);
4013bc921866SRichard Henderson 
4014bc921866SRichard Henderson     return do_ibranch(ctx, 0, false, a->n);
401598cd9ca7SRichard Henderson }
401698cd9ca7SRichard Henderson 
40178340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
401898cd9ca7SRichard Henderson {
4019019f4159SRichard Henderson     TCGv_i64 b = load_gpr(ctx, a->b);
402098cd9ca7SRichard Henderson 
4021019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
4022bc921866SRichard Henderson     ctx->iaq_j.space = space_select(ctx, 0, b);
4023c301f34eSRichard Henderson #endif
4024bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, b);
4025bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
4026019f4159SRichard Henderson 
4027bc921866SRichard Henderson     return do_ibranch(ctx, a->l, false, a->n);
402898cd9ca7SRichard Henderson }
402998cd9ca7SRichard Henderson 
4030a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4031a8966ba7SRichard Henderson {
4032a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4033a8966ba7SRichard Henderson     return ctx->is_pa20;
4034a8966ba7SRichard Henderson }
4035a8966ba7SRichard Henderson 
40361ca74648SRichard Henderson /*
40371ca74648SRichard Henderson  * Float class 0
40381ca74648SRichard Henderson  */
4039ebe9383cSRichard Henderson 
40401ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4041ebe9383cSRichard Henderson {
4042ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4043ebe9383cSRichard Henderson }
4044ebe9383cSRichard Henderson 
404559f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
404659f8c04bSHelge Deller {
4047a300dad3SRichard Henderson     uint64_t ret;
4048a300dad3SRichard Henderson 
4049c53e401eSRichard Henderson     if (ctx->is_pa20) {
4050a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4051a300dad3SRichard Henderson     } else {
4052a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4053a300dad3SRichard Henderson     }
4054a300dad3SRichard Henderson 
405559f8c04bSHelge Deller     nullify_over(ctx);
4056a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
405759f8c04bSHelge Deller     return nullify_end(ctx);
405859f8c04bSHelge Deller }
405959f8c04bSHelge Deller 
40601ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40611ca74648SRichard Henderson {
40621ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40631ca74648SRichard Henderson }
40641ca74648SRichard Henderson 
4065ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4066ebe9383cSRichard Henderson {
4067ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4068ebe9383cSRichard Henderson }
4069ebe9383cSRichard Henderson 
40701ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40711ca74648SRichard Henderson {
40721ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40731ca74648SRichard Henderson }
40741ca74648SRichard Henderson 
40751ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4076ebe9383cSRichard Henderson {
4077ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4078ebe9383cSRichard Henderson }
4079ebe9383cSRichard Henderson 
40801ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
40811ca74648SRichard Henderson {
40821ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
40831ca74648SRichard Henderson }
40841ca74648SRichard Henderson 
4085ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4086ebe9383cSRichard Henderson {
4087ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4088ebe9383cSRichard Henderson }
4089ebe9383cSRichard Henderson 
40901ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
40911ca74648SRichard Henderson {
40921ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
40931ca74648SRichard Henderson }
40941ca74648SRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
41011ca74648SRichard Henderson {
41021ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
41031ca74648SRichard Henderson }
41041ca74648SRichard Henderson 
41051ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
41101ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
41111ca74648SRichard Henderson {
41121ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
41131ca74648SRichard Henderson }
41141ca74648SRichard Henderson 
41151ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4116ebe9383cSRichard Henderson {
4117ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4118ebe9383cSRichard Henderson }
4119ebe9383cSRichard Henderson 
41201ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41211ca74648SRichard Henderson {
41221ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41231ca74648SRichard Henderson }
41241ca74648SRichard Henderson 
4125ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4126ebe9383cSRichard Henderson {
4127ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4128ebe9383cSRichard Henderson }
4129ebe9383cSRichard Henderson 
41301ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41311ca74648SRichard Henderson {
41321ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41331ca74648SRichard Henderson }
41341ca74648SRichard Henderson 
41351ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4136ebe9383cSRichard Henderson {
4137ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4138ebe9383cSRichard Henderson }
4139ebe9383cSRichard Henderson 
41401ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41411ca74648SRichard Henderson {
41421ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41431ca74648SRichard Henderson }
41441ca74648SRichard Henderson 
4145ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4146ebe9383cSRichard Henderson {
4147ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4148ebe9383cSRichard Henderson }
4149ebe9383cSRichard Henderson 
41501ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41511ca74648SRichard Henderson {
41521ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41531ca74648SRichard Henderson }
41541ca74648SRichard Henderson 
41551ca74648SRichard Henderson /*
41561ca74648SRichard Henderson  * Float class 1
41571ca74648SRichard Henderson  */
41581ca74648SRichard Henderson 
41591ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41601ca74648SRichard Henderson {
41611ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41621ca74648SRichard Henderson }
41631ca74648SRichard Henderson 
41641ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41651ca74648SRichard Henderson {
41661ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41671ca74648SRichard Henderson }
41681ca74648SRichard Henderson 
41691ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41701ca74648SRichard Henderson {
41711ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41721ca74648SRichard Henderson }
41731ca74648SRichard Henderson 
41741ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
41751ca74648SRichard Henderson {
41761ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
41771ca74648SRichard Henderson }
41781ca74648SRichard Henderson 
41791ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
41801ca74648SRichard Henderson {
41811ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
41821ca74648SRichard Henderson }
41831ca74648SRichard Henderson 
41841ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
41851ca74648SRichard Henderson {
41861ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
41871ca74648SRichard Henderson }
41881ca74648SRichard Henderson 
41891ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
41901ca74648SRichard Henderson {
41911ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
41921ca74648SRichard Henderson }
41931ca74648SRichard Henderson 
41941ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
41951ca74648SRichard Henderson {
41961ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
41971ca74648SRichard Henderson }
41981ca74648SRichard Henderson 
41991ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
42001ca74648SRichard Henderson {
42011ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
42021ca74648SRichard Henderson }
42031ca74648SRichard Henderson 
42041ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
42051ca74648SRichard Henderson {
42061ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
42071ca74648SRichard Henderson }
42081ca74648SRichard Henderson 
42091ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
42101ca74648SRichard Henderson {
42111ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
42121ca74648SRichard Henderson }
42131ca74648SRichard Henderson 
42141ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42151ca74648SRichard Henderson {
42161ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42171ca74648SRichard Henderson }
42181ca74648SRichard Henderson 
42191ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42201ca74648SRichard Henderson {
42211ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42221ca74648SRichard Henderson }
42231ca74648SRichard Henderson 
42241ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42251ca74648SRichard Henderson {
42261ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42271ca74648SRichard Henderson }
42281ca74648SRichard Henderson 
42291ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42301ca74648SRichard Henderson {
42311ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42321ca74648SRichard Henderson }
42331ca74648SRichard Henderson 
42341ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42351ca74648SRichard Henderson {
42361ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42371ca74648SRichard Henderson }
42381ca74648SRichard Henderson 
42391ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42401ca74648SRichard Henderson {
42411ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42421ca74648SRichard Henderson }
42431ca74648SRichard Henderson 
42441ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42451ca74648SRichard Henderson {
42461ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42471ca74648SRichard Henderson }
42481ca74648SRichard Henderson 
42491ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42501ca74648SRichard Henderson {
42511ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42521ca74648SRichard Henderson }
42531ca74648SRichard Henderson 
42541ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42551ca74648SRichard Henderson {
42561ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42571ca74648SRichard Henderson }
42581ca74648SRichard Henderson 
42591ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42601ca74648SRichard Henderson {
42611ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42621ca74648SRichard Henderson }
42631ca74648SRichard Henderson 
42641ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42651ca74648SRichard Henderson {
42661ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42671ca74648SRichard Henderson }
42681ca74648SRichard Henderson 
42691ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42701ca74648SRichard Henderson {
42711ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42721ca74648SRichard Henderson }
42731ca74648SRichard Henderson 
42741ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
42751ca74648SRichard Henderson {
42761ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
42771ca74648SRichard Henderson }
42781ca74648SRichard Henderson 
42791ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
42801ca74648SRichard Henderson {
42811ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
42821ca74648SRichard Henderson }
42831ca74648SRichard Henderson 
42841ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
42851ca74648SRichard Henderson {
42861ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
42871ca74648SRichard Henderson }
42881ca74648SRichard Henderson 
42891ca74648SRichard Henderson /*
42901ca74648SRichard Henderson  * Float class 2
42911ca74648SRichard Henderson  */
42921ca74648SRichard Henderson 
42931ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4294ebe9383cSRichard Henderson {
4295ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4296ebe9383cSRichard Henderson 
4297ebe9383cSRichard Henderson     nullify_over(ctx);
4298ebe9383cSRichard Henderson 
42991ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
43001ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
430129dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
430229dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4303ebe9383cSRichard Henderson 
4304ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4305ebe9383cSRichard Henderson 
43061ca74648SRichard Henderson     return nullify_end(ctx);
4307ebe9383cSRichard Henderson }
4308ebe9383cSRichard Henderson 
43091ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4310ebe9383cSRichard Henderson {
4311ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4312ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4313ebe9383cSRichard Henderson 
4314ebe9383cSRichard Henderson     nullify_over(ctx);
4315ebe9383cSRichard Henderson 
43161ca74648SRichard Henderson     ta = load_frd0(a->r1);
43171ca74648SRichard Henderson     tb = load_frd0(a->r2);
431829dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
431929dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4320ebe9383cSRichard Henderson 
4321ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4322ebe9383cSRichard Henderson 
432331234768SRichard Henderson     return nullify_end(ctx);
4324ebe9383cSRichard Henderson }
4325ebe9383cSRichard Henderson 
43261ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4327ebe9383cSRichard Henderson {
43283692ad21SRichard Henderson     TCGCond tc = TCG_COND_TSTNE;
43293692ad21SRichard Henderson     uint32_t mask;
43306fd0c7bcSRichard Henderson     TCGv_i64 t;
4331ebe9383cSRichard Henderson 
4332ebe9383cSRichard Henderson     nullify_over(ctx);
4333ebe9383cSRichard Henderson 
4334aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43356fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4336ebe9383cSRichard Henderson 
43371ca74648SRichard Henderson     if (a->y == 1) {
43381ca74648SRichard Henderson         switch (a->c) {
4339ebe9383cSRichard Henderson         case 0: /* simple */
4340f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK;
4341f33a22c1SRichard Henderson             break;
4342ebe9383cSRichard Henderson         case 2: /* rej */
43433692ad21SRichard Henderson             tc = TCG_COND_TSTEQ;
4344ebe9383cSRichard Henderson             /* fallthru */
4345ebe9383cSRichard Henderson         case 1: /* acc */
4346f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ_MASK;
4347ebe9383cSRichard Henderson             break;
4348ebe9383cSRichard Henderson         case 6: /* rej8 */
43493692ad21SRichard Henderson             tc = TCG_COND_TSTEQ;
4350ebe9383cSRichard Henderson             /* fallthru */
4351ebe9383cSRichard Henderson         case 5: /* acc8 */
4352f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_6_MASK;
4353ebe9383cSRichard Henderson             break;
4354ebe9383cSRichard Henderson         case 9: /* acc6 */
4355f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_4_MASK;
4356ebe9383cSRichard Henderson             break;
4357ebe9383cSRichard Henderson         case 13: /* acc4 */
4358f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_2_MASK;
4359ebe9383cSRichard Henderson             break;
4360ebe9383cSRichard Henderson         case 17: /* acc2 */
4361f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_MASK;
4362ebe9383cSRichard Henderson             break;
4363ebe9383cSRichard Henderson         default:
43641ca74648SRichard Henderson             gen_illegal(ctx);
43651ca74648SRichard Henderson             return true;
4366ebe9383cSRichard Henderson         }
43671ca74648SRichard Henderson     } else {
43681ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
43693692ad21SRichard Henderson         mask = R_FPSR_CA0_MASK >> cbit;
43701ca74648SRichard Henderson     }
43711ca74648SRichard Henderson 
43723692ad21SRichard Henderson     ctx->null_cond = cond_make_ti(tc, t, mask);
437331234768SRichard Henderson     return nullify_end(ctx);
4374ebe9383cSRichard Henderson }
4375ebe9383cSRichard Henderson 
43761ca74648SRichard Henderson /*
43771ca74648SRichard Henderson  * Float class 2
43781ca74648SRichard Henderson  */
43791ca74648SRichard Henderson 
43801ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4381ebe9383cSRichard Henderson {
43821ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
43831ca74648SRichard Henderson }
43841ca74648SRichard Henderson 
43851ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
43861ca74648SRichard Henderson {
43871ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
43881ca74648SRichard Henderson }
43891ca74648SRichard Henderson 
43901ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
43911ca74648SRichard Henderson {
43921ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
43931ca74648SRichard Henderson }
43941ca74648SRichard Henderson 
43951ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
43961ca74648SRichard Henderson {
43971ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
43981ca74648SRichard Henderson }
43991ca74648SRichard Henderson 
44001ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
44011ca74648SRichard Henderson {
44021ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
44031ca74648SRichard Henderson }
44041ca74648SRichard Henderson 
44051ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44061ca74648SRichard Henderson {
44071ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44081ca74648SRichard Henderson }
44091ca74648SRichard Henderson 
44101ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44111ca74648SRichard Henderson {
44121ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44131ca74648SRichard Henderson }
44141ca74648SRichard Henderson 
44151ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44161ca74648SRichard Henderson {
44171ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44181ca74648SRichard Henderson }
44191ca74648SRichard Henderson 
44201ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44211ca74648SRichard Henderson {
44221ca74648SRichard Henderson     TCGv_i64 x, y;
4423ebe9383cSRichard Henderson 
4424ebe9383cSRichard Henderson     nullify_over(ctx);
4425ebe9383cSRichard Henderson 
44261ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44271ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44281ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44291ca74648SRichard Henderson     save_frd(a->t, x);
4430ebe9383cSRichard Henderson 
443131234768SRichard Henderson     return nullify_end(ctx);
4432ebe9383cSRichard Henderson }
4433ebe9383cSRichard Henderson 
4434ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4435ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4436ebe9383cSRichard Henderson {
4437ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4438ebe9383cSRichard Henderson }
4439ebe9383cSRichard Henderson 
4440b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4441ebe9383cSRichard Henderson {
4442b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4443b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4444b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4445b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4446b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4447ebe9383cSRichard Henderson 
4448ebe9383cSRichard Henderson     nullify_over(ctx);
4449ebe9383cSRichard Henderson 
4450ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4451ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4452ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4453ebe9383cSRichard Henderson 
445431234768SRichard Henderson     return nullify_end(ctx);
4455ebe9383cSRichard Henderson }
4456ebe9383cSRichard Henderson 
4457b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4458b1e2af57SRichard Henderson {
4459b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4460b1e2af57SRichard Henderson }
4461b1e2af57SRichard Henderson 
4462b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4463b1e2af57SRichard Henderson {
4464b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4465b1e2af57SRichard Henderson }
4466b1e2af57SRichard Henderson 
4467b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4468b1e2af57SRichard Henderson {
4469b1e2af57SRichard Henderson     nullify_over(ctx);
4470b1e2af57SRichard Henderson 
4471b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4472b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4473b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4474b1e2af57SRichard Henderson 
4475b1e2af57SRichard Henderson     return nullify_end(ctx);
4476b1e2af57SRichard Henderson }
4477b1e2af57SRichard Henderson 
4478b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4479b1e2af57SRichard Henderson {
4480b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4481b1e2af57SRichard Henderson }
4482b1e2af57SRichard Henderson 
4483b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4484b1e2af57SRichard Henderson {
4485b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4486b1e2af57SRichard Henderson }
4487b1e2af57SRichard Henderson 
4488c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4489ebe9383cSRichard Henderson {
4490c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4491ebe9383cSRichard Henderson 
4492ebe9383cSRichard Henderson     nullify_over(ctx);
4493c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4494c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4495c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4496ebe9383cSRichard Henderson 
4497c3bad4f8SRichard Henderson     if (a->neg) {
4498ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4499ebe9383cSRichard Henderson     } else {
4500ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4501ebe9383cSRichard Henderson     }
4502ebe9383cSRichard Henderson 
4503c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
450431234768SRichard Henderson     return nullify_end(ctx);
4505ebe9383cSRichard Henderson }
4506ebe9383cSRichard Henderson 
4507c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4508ebe9383cSRichard Henderson {
4509c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4510ebe9383cSRichard Henderson 
4511ebe9383cSRichard Henderson     nullify_over(ctx);
4512c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4513c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4514c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4515ebe9383cSRichard Henderson 
4516c3bad4f8SRichard Henderson     if (a->neg) {
4517ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4518ebe9383cSRichard Henderson     } else {
4519ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4520ebe9383cSRichard Henderson     }
4521ebe9383cSRichard Henderson 
4522c3bad4f8SRichard Henderson     save_frd(a->t, x);
452331234768SRichard Henderson     return nullify_end(ctx);
4524ebe9383cSRichard Henderson }
4525ebe9383cSRichard Henderson 
452638193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
452738193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
452815da177bSSven Schnelle {
4529cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4530cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4531ad75a51eSRichard Henderson     nullify_over(ctx);
4532ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4533cf6b28d4SHelge Deller     return nullify_end(ctx);
453438193127SRichard Henderson #endif
453515da177bSSven Schnelle }
453638193127SRichard Henderson 
453738193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
453838193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
453938193127SRichard Henderson {
454038193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
454138193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4542dbca0835SHelge Deller     nullify_over(ctx);
4543dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4544dbca0835SHelge Deller     return nullify_end(ctx);
4545ad75a51eSRichard Henderson #endif
454638193127SRichard Henderson }
454738193127SRichard Henderson 
45483bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45493bdf2081SHelge Deller {
45503bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45513bdf2081SHelge Deller }
45523bdf2081SHelge Deller 
45533bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45543bdf2081SHelge Deller {
45553bdf2081SHelge Deller     return ctx->is_pa20 && do_getshadowregs(ctx);
45563bdf2081SHelge Deller }
45573bdf2081SHelge Deller 
45583bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45593bdf2081SHelge Deller {
45603bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45613bdf2081SHelge Deller }
45623bdf2081SHelge Deller 
45633bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45643bdf2081SHelge Deller {
45653bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
45663bdf2081SHelge Deller }
45673bdf2081SHelge Deller 
456838193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
456938193127SRichard Henderson {
457038193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4571ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4572ad75a51eSRichard Henderson     return true;
4573ad75a51eSRichard Henderson }
457415da177bSSven Schnelle 
4575b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
457661766fe9SRichard Henderson {
457751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4578*9dfcd243SRichard Henderson     uint64_t cs_base, iaoq_f, iaoq_b;
4579f764718dSRichard Henderson     int bound;
458061766fe9SRichard Henderson 
458151b061fbSRichard Henderson     ctx->cs = cs;
4582494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4583bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
45843d68ee7bSRichard Henderson 
45853d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
45863c13b0ffSRichard Henderson     ctx->privilege = PRIV_USER;
45873d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4588217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4589c301f34eSRichard Henderson #else
4590494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4591bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4592bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4593451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
4594*9dfcd243SRichard Henderson #endif
45953d68ee7bSRichard Henderson 
4596c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
4597*9dfcd243SRichard Henderson     cs_base = ctx->base.tb->cs_base;
4598*9dfcd243SRichard Henderson     iaoq_f = cs_base & MAKE_64BIT_MASK(32, 32);
4599*9dfcd243SRichard Henderson     iaoq_f |= ctx->base.pc_first & MAKE_64BIT_MASK(2, 30);
4600*9dfcd243SRichard Henderson     iaoq_f |= ctx->privilege;
4601*9dfcd243SRichard Henderson     ctx->iaoq_first = iaoq_f;
4602c301f34eSRichard Henderson 
4603*9dfcd243SRichard Henderson     if (unlikely(cs_base & CS_BASE_DIFFSPACE)) {
4604bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4605*9dfcd243SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4606*9dfcd243SRichard Henderson     } else if (unlikely(cs_base & CS_BASE_DIFFPAGE)) {
4607*9dfcd243SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4608*9dfcd243SRichard Henderson     } else {
4609*9dfcd243SRichard Henderson         iaoq_b = (iaoq_f & TARGET_PAGE_MASK) | (cs_base & ~TARGET_PAGE_MASK);
4610*9dfcd243SRichard Henderson         ctx->iaq_b.disp = iaoq_b - iaoq_f;
4611bc921866SRichard Henderson     }
461261766fe9SRichard Henderson 
4613a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4614a4db4a78SRichard Henderson 
46153d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46163d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4617b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
461861766fe9SRichard Henderson }
461961766fe9SRichard Henderson 
462051b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
462151b061fbSRichard Henderson {
462251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
462361766fe9SRichard Henderson 
46243d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
462551b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
462651b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4627494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
462851b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
462951b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4630129e9cc3SRichard Henderson     }
463151b061fbSRichard Henderson     ctx->null_lab = NULL;
463261766fe9SRichard Henderson }
463361766fe9SRichard Henderson 
463451b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
463551b061fbSRichard Henderson {
463651b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
463751b061fbSRichard Henderson 
4638bc921866SRichard Henderson     tcg_debug_assert(!iaqe_variable(&ctx->iaq_f));
46390d89cb7cSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp,
46400d89cb7cSRichard Henderson                        (iaqe_variable(&ctx->iaq_b) ? -1 :
46410d89cb7cSRichard Henderson                         ctx->iaoq_first + ctx->iaq_b.disp), 0);
464224638bd1SRichard Henderson     ctx->insn_start_updated = false;
464351b061fbSRichard Henderson }
464451b061fbSRichard Henderson 
464551b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
464651b061fbSRichard Henderson {
464751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4648b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
464951b061fbSRichard Henderson     DisasJumpType ret;
465051b061fbSRichard Henderson 
465151b061fbSRichard Henderson     /* Execute one insn.  */
4652ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4653c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
465431234768SRichard Henderson         do_page_zero(ctx);
465531234768SRichard Henderson         ret = ctx->base.is_jmp;
4656869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4657ba1d0b44SRichard Henderson     } else
4658ba1d0b44SRichard Henderson #endif
4659ba1d0b44SRichard Henderson     {
466061766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
466161766fe9SRichard Henderson            the page permissions for execute.  */
46624e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
466361766fe9SRichard Henderson 
4664bc921866SRichard Henderson         /*
4665bc921866SRichard Henderson          * Set up the IA queue for the next insn.
4666bc921866SRichard Henderson          * This will be overwritten by a branch.
4667bc921866SRichard Henderson          */
4668bc921866SRichard Henderson         ctx->iaq_n = NULL;
4669bc921866SRichard Henderson         memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j));
467061766fe9SRichard Henderson 
467151b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
467251b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4673869051eaSRichard Henderson             ret = DISAS_NEXT;
4674129e9cc3SRichard Henderson         } else {
46751a19da0dSRichard Henderson             ctx->insn = insn;
467631274b46SRichard Henderson             if (!decode(ctx, insn)) {
467731274b46SRichard Henderson                 gen_illegal(ctx);
467831274b46SRichard Henderson             }
467931234768SRichard Henderson             ret = ctx->base.is_jmp;
468051b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4681129e9cc3SRichard Henderson         }
468261766fe9SRichard Henderson     }
468361766fe9SRichard Henderson 
4684dbdccbdfSRichard Henderson     /* If the TranslationBlock must end, do so. */
4685dbdccbdfSRichard Henderson     ctx->base.pc_next += 4;
4686dbdccbdfSRichard Henderson     if (ret != DISAS_NEXT) {
4687dbdccbdfSRichard Henderson         return;
468861766fe9SRichard Henderson     }
4689dbdccbdfSRichard Henderson     /* Note this also detects a priority change. */
4690bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b)
4691bc921866SRichard Henderson         || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
4692dbdccbdfSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
4693dbdccbdfSRichard Henderson         return;
4694129e9cc3SRichard Henderson     }
4695dbdccbdfSRichard Henderson 
4696dbdccbdfSRichard Henderson     /*
4697dbdccbdfSRichard Henderson      * Advance the insn queue.
4698dbdccbdfSRichard Henderson      * The only exit now is DISAS_TOO_MANY from the translator loop.
4699dbdccbdfSRichard Henderson      */
4700bc921866SRichard Henderson     ctx->iaq_f.disp = ctx->iaq_b.disp;
4701bc921866SRichard Henderson     if (!ctx->iaq_n) {
4702bc921866SRichard Henderson         ctx->iaq_b.disp += 4;
4703bc921866SRichard Henderson         return;
4704bc921866SRichard Henderson     }
4705bc921866SRichard Henderson     /*
4706bc921866SRichard Henderson      * If IAQ_Next is variable in any way, we need to copy into the
4707bc921866SRichard Henderson      * IAQ_Back globals, in case the next insn raises an exception.
4708bc921866SRichard Henderson      */
4709bc921866SRichard Henderson     if (ctx->iaq_n->base) {
4710bc921866SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n);
4711bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4712bc921866SRichard Henderson         ctx->iaq_b.disp = 0;
47130dcd6640SRichard Henderson     } else {
4714bc921866SRichard Henderson         ctx->iaq_b.disp = ctx->iaq_n->disp;
47150dcd6640SRichard Henderson     }
4716bc921866SRichard Henderson     if (ctx->iaq_n->space) {
4717bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space);
4718bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4719142faf5fSRichard Henderson     }
472061766fe9SRichard Henderson }
472161766fe9SRichard Henderson 
472251b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
472351b061fbSRichard Henderson {
472451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4725e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
4726dbdccbdfSRichard Henderson     /* Assume the insn queue has not been advanced. */
4727bc921866SRichard Henderson     DisasIAQE *f = &ctx->iaq_b;
4728bc921866SRichard Henderson     DisasIAQE *b = ctx->iaq_n;
472951b061fbSRichard Henderson 
4730e1b5a5edSRichard Henderson     switch (is_jmp) {
4731869051eaSRichard Henderson     case DISAS_NORETURN:
473261766fe9SRichard Henderson         break;
473351b061fbSRichard Henderson     case DISAS_TOO_MANY:
4734dbdccbdfSRichard Henderson         /* The insn queue has not been advanced. */
4735bc921866SRichard Henderson         f = &ctx->iaq_f;
4736bc921866SRichard Henderson         b = &ctx->iaq_b;
473761766fe9SRichard Henderson         /* FALLTHRU */
4738dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE:
4739bc921866SRichard Henderson         if (use_goto_tb(ctx, f, b)
4740dbdccbdfSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4741dbdccbdfSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
4742dbdccbdfSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4743bc921866SRichard Henderson             gen_goto_tb(ctx, 0, f, b);
47448532a14eSRichard Henderson             break;
474561766fe9SRichard Henderson         }
4746c5d0aec2SRichard Henderson         /* FALLTHRU */
4747dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4748bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
4749dbdccbdfSRichard Henderson         nullify_save(ctx);
4750dbdccbdfSRichard Henderson         if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4751dbdccbdfSRichard Henderson             tcg_gen_exit_tb(NULL, 0);
4752dbdccbdfSRichard Henderson             break;
4753dbdccbdfSRichard Henderson         }
4754dbdccbdfSRichard Henderson         /* FALLTHRU */
4755dbdccbdfSRichard Henderson     case DISAS_IAQ_N_UPDATED:
4756dbdccbdfSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
4757dbdccbdfSRichard Henderson         break;
4758c5d0aec2SRichard Henderson     case DISAS_EXIT:
4759c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
476061766fe9SRichard Henderson         break;
476161766fe9SRichard Henderson     default:
476251b061fbSRichard Henderson         g_assert_not_reached();
476361766fe9SRichard Henderson     }
476480603007SRichard Henderson 
476580603007SRichard Henderson     for (DisasDelayException *e = ctx->delay_excp_list; e ; e = e->next) {
476680603007SRichard Henderson         gen_set_label(e->lab);
476780603007SRichard Henderson         if (e->set_n >= 0) {
476880603007SRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, e->set_n);
476980603007SRichard Henderson         }
477080603007SRichard Henderson         if (e->set_iir) {
477180603007SRichard Henderson             tcg_gen_st_i64(tcg_constant_i64(e->insn), tcg_env,
477280603007SRichard Henderson                            offsetof(CPUHPPAState, cr[CR_IIR]));
477380603007SRichard Henderson         }
477480603007SRichard Henderson         install_iaq_entries(ctx, &e->iaq_f, &e->iaq_b);
477580603007SRichard Henderson         gen_excp_1(e->excp);
477680603007SRichard Henderson     }
477751b061fbSRichard Henderson }
477861766fe9SRichard Henderson 
47798eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
47808eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
478151b061fbSRichard Henderson {
4782c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
478361766fe9SRichard Henderson 
4784ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4785ba1d0b44SRichard Henderson     switch (pc) {
47867ad439dfSRichard Henderson     case 0x00:
47878eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4788ba1d0b44SRichard Henderson         return;
47897ad439dfSRichard Henderson     case 0xb0:
47908eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4791ba1d0b44SRichard Henderson         return;
47927ad439dfSRichard Henderson     case 0xe0:
47938eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4794ba1d0b44SRichard Henderson         return;
47957ad439dfSRichard Henderson     case 0x100:
47968eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4797ba1d0b44SRichard Henderson         return;
47987ad439dfSRichard Henderson     }
4799ba1d0b44SRichard Henderson #endif
4800ba1d0b44SRichard Henderson 
48018eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
48028eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
480361766fe9SRichard Henderson }
480451b061fbSRichard Henderson 
480551b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
480651b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
480751b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
480851b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
480951b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
481051b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
481151b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
481251b061fbSRichard Henderson };
481351b061fbSRichard Henderson 
4814597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
481532f0c394SAnton Johansson                            vaddr pc, void *host_pc)
481651b061fbSRichard Henderson {
4817bc921866SRichard Henderson     DisasContext ctx = { };
4818306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
481961766fe9SRichard Henderson }
4820