xref: /openbmc/qemu/target/hppa/translate.c (revision 081a0ed188d8d9d9038f00337d331d185a7ae331)
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 {
640bc921866SRichard Henderson     if (src->base == NULL) {
641*081a0ed1SRichard Henderson         tcg_gen_movi_i64(dest, ctx->iaoq_first + src->disp);
64261766fe9SRichard Henderson     } else {
643bc921866SRichard Henderson         tcg_gen_addi_i64(dest, src->base, src->disp);
64461766fe9SRichard Henderson     }
64561766fe9SRichard Henderson }
64661766fe9SRichard Henderson 
647bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f,
648bc921866SRichard Henderson                                 const DisasIAQE *b)
64985e6cda0SRichard Henderson {
650bc921866SRichard Henderson     DisasIAQE b_next;
65185e6cda0SRichard Henderson 
652bc921866SRichard Henderson     if (b == NULL) {
653bc921866SRichard Henderson         b_next = iaqe_incr(f, 4);
654bc921866SRichard Henderson         b = &b_next;
65585e6cda0SRichard Henderson     }
656bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_f, f);
657bc921866SRichard Henderson     copy_iaoq_entry(ctx, cpu_iaoq_b, b);
658bc921866SRichard Henderson     if (f->space) {
659bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_f, f->space);
660588deedaSRichard Henderson     }
661bc921866SRichard Henderson     if (b->space || f->space) {
662bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space);
663588deedaSRichard Henderson     }
66485e6cda0SRichard Henderson }
66585e6cda0SRichard Henderson 
66643541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0)
66743541db0SRichard Henderson {
66843541db0SRichard Henderson     tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER);
66943541db0SRichard Henderson     if (!link) {
67043541db0SRichard Henderson         return;
67143541db0SRichard Henderson     }
6720d89cb7cSRichard Henderson     DisasIAQE next = iaqe_incr(&ctx->iaq_b, 4);
6730d89cb7cSRichard Henderson     copy_iaoq_entry(ctx, cpu_gr[link], &next);
67443541db0SRichard Henderson #ifndef CONFIG_USER_ONLY
67543541db0SRichard Henderson     if (with_sr0) {
67643541db0SRichard Henderson         tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b);
67743541db0SRichard Henderson     }
67843541db0SRichard Henderson #endif
67943541db0SRichard Henderson }
68043541db0SRichard Henderson 
68161766fe9SRichard Henderson static void gen_excp_1(int exception)
68261766fe9SRichard Henderson {
683ad75a51eSRichard Henderson     gen_helper_excp(tcg_env, tcg_constant_i32(exception));
68461766fe9SRichard Henderson }
68561766fe9SRichard Henderson 
68631234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception)
68761766fe9SRichard Henderson {
688bc921866SRichard Henderson     install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b);
689129e9cc3SRichard Henderson     nullify_save(ctx);
69061766fe9SRichard Henderson     gen_excp_1(exception);
69131234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
69261766fe9SRichard Henderson }
69361766fe9SRichard Henderson 
69480603007SRichard Henderson static DisasDelayException *delay_excp(DisasContext *ctx, uint8_t excp)
69580603007SRichard Henderson {
69680603007SRichard Henderson     DisasDelayException *e = tcg_malloc(sizeof(DisasDelayException));
69780603007SRichard Henderson 
69880603007SRichard Henderson     memset(e, 0, sizeof(*e));
69980603007SRichard Henderson     e->next = ctx->delay_excp_list;
70080603007SRichard Henderson     ctx->delay_excp_list = e;
70180603007SRichard Henderson 
70280603007SRichard Henderson     e->lab = gen_new_label();
70380603007SRichard Henderson     e->insn = ctx->insn;
70480603007SRichard Henderson     e->set_iir = true;
70580603007SRichard Henderson     e->set_n = ctx->psw_n_nonzero ? 0 : -1;
70680603007SRichard Henderson     e->excp = excp;
70780603007SRichard Henderson     e->iaq_f = ctx->iaq_f;
70880603007SRichard Henderson     e->iaq_b = ctx->iaq_b;
70980603007SRichard Henderson 
71080603007SRichard Henderson     return e;
71180603007SRichard Henderson }
71280603007SRichard Henderson 
71331234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc)
7141a19da0dSRichard Henderson {
71580603007SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
7166fd0c7bcSRichard Henderson         tcg_gen_st_i64(tcg_constant_i64(ctx->insn),
717ad75a51eSRichard Henderson                        tcg_env, offsetof(CPUHPPAState, cr[CR_IIR]));
71831234768SRichard Henderson         gen_excp(ctx, exc);
71980603007SRichard Henderson     } else {
72080603007SRichard Henderson         DisasDelayException *e = delay_excp(ctx, exc);
72180603007SRichard Henderson         tcg_gen_brcond_i64(tcg_invert_cond(ctx->null_cond.c),
72280603007SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1, e->lab);
72380603007SRichard Henderson         ctx->null_cond = cond_make_f();
72480603007SRichard Henderson     }
72580603007SRichard Henderson     return true;
7261a19da0dSRichard Henderson }
7271a19da0dSRichard Henderson 
72831234768SRichard Henderson static bool gen_illegal(DisasContext *ctx)
72961766fe9SRichard Henderson {
73031234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_ILL);
73161766fe9SRichard Henderson }
73261766fe9SRichard Henderson 
73340f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY
73440f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
73540f9f908SRichard Henderson     return gen_excp_iir(ctx, EXCP)
73640f9f908SRichard Henderson #else
737e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \
738e1b5a5edSRichard Henderson     do {                                     \
739e1b5a5edSRichard Henderson         if (ctx->privilege != 0) {           \
74031234768SRichard Henderson             return gen_excp_iir(ctx, EXCP);  \
741e1b5a5edSRichard Henderson         }                                    \
742e1b5a5edSRichard Henderson     } while (0)
74340f9f908SRichard Henderson #endif
744e1b5a5edSRichard Henderson 
745bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f,
746bc921866SRichard Henderson                         const DisasIAQE *b)
74761766fe9SRichard Henderson {
748bc921866SRichard Henderson     return (!iaqe_variable(f) &&
749bc921866SRichard Henderson             (b == NULL || !iaqe_variable(b)) &&
7500d89cb7cSRichard Henderson             translator_use_goto_tb(&ctx->base, ctx->iaoq_first + f->disp));
75161766fe9SRichard Henderson }
75261766fe9SRichard Henderson 
753129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
754129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
755129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
756129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
757129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
758129e9cc3SRichard Henderson {
759f9b11bc2SRichard Henderson     return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE)
760bc921866SRichard Henderson             && !iaqe_variable(&ctx->iaq_b)
7610d89cb7cSRichard Henderson             && (((ctx->iaoq_first + ctx->iaq_b.disp) ^ ctx->iaoq_first)
7620d89cb7cSRichard Henderson                 & TARGET_PAGE_MASK) == 0);
763129e9cc3SRichard Henderson }
764129e9cc3SRichard Henderson 
76561766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
766bc921866SRichard Henderson                         const DisasIAQE *f, const DisasIAQE *b)
76761766fe9SRichard Henderson {
7689dfcd243SRichard Henderson     install_iaq_entries(ctx, f, b);
769bc921866SRichard Henderson     if (use_goto_tb(ctx, f, b)) {
77061766fe9SRichard Henderson         tcg_gen_goto_tb(which);
77107ea28b4SRichard Henderson         tcg_gen_exit_tb(ctx->base.tb, which);
77261766fe9SRichard Henderson     } else {
7737f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
77461766fe9SRichard Henderson     }
77561766fe9SRichard Henderson }
77661766fe9SRichard Henderson 
777b47a4a02SSven Schnelle static bool cond_need_sv(int c)
778b47a4a02SSven Schnelle {
779b47a4a02SSven Schnelle     return c == 2 || c == 3 || c == 6;
780b47a4a02SSven Schnelle }
781b47a4a02SSven Schnelle 
782b47a4a02SSven Schnelle static bool cond_need_cb(int c)
783b47a4a02SSven Schnelle {
784b47a4a02SSven Schnelle     return c == 4 || c == 5;
785b47a4a02SSven Schnelle }
786b47a4a02SSven Schnelle 
787b47a4a02SSven Schnelle /*
788b47a4a02SSven Schnelle  * Compute conditional for arithmetic.  See Page 5-3, Table 5-1, of
789b47a4a02SSven Schnelle  * the Parisc 1.1 Architecture Reference Manual for details.
790b47a4a02SSven Schnelle  */
791b2167459SRichard Henderson 
792a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d,
793fe2d066aSRichard Henderson                          TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv)
794b2167459SRichard Henderson {
795d6d46be1SRichard Henderson     TCGCond sign_cond, zero_cond;
796d6d46be1SRichard Henderson     uint64_t sign_imm, zero_imm;
797b2167459SRichard Henderson     DisasCond cond;
7986fd0c7bcSRichard Henderson     TCGv_i64 tmp;
799b2167459SRichard Henderson 
800d6d46be1SRichard Henderson     if (d) {
801d6d46be1SRichard Henderson         /* 64-bit condition. */
802d6d46be1SRichard Henderson         sign_imm = 0;
803d6d46be1SRichard Henderson         sign_cond = TCG_COND_LT;
804d6d46be1SRichard Henderson         zero_imm = 0;
805d6d46be1SRichard Henderson         zero_cond = TCG_COND_EQ;
806d6d46be1SRichard Henderson     } else {
807d6d46be1SRichard Henderson         /* 32-bit condition. */
808d6d46be1SRichard Henderson         sign_imm = 1ull << 31;
809d6d46be1SRichard Henderson         sign_cond = TCG_COND_TSTNE;
810d6d46be1SRichard Henderson         zero_imm = UINT32_MAX;
811d6d46be1SRichard Henderson         zero_cond = TCG_COND_TSTEQ;
812d6d46be1SRichard Henderson     }
813d6d46be1SRichard Henderson 
814b2167459SRichard Henderson     switch (cf >> 1) {
815b47a4a02SSven Schnelle     case 0: /* Never / TR    (0 / 1) */
816b2167459SRichard Henderson         cond = cond_make_f();
817b2167459SRichard Henderson         break;
818b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
819d6d46be1SRichard Henderson         cond = cond_make_vi(zero_cond, res, zero_imm);
820b2167459SRichard Henderson         break;
821b47a4a02SSven Schnelle     case 2: /* < / >=        (N ^ V / !(N ^ V) */
822aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
8236fd0c7bcSRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
824d6d46be1SRichard Henderson         cond = cond_make_ti(sign_cond, tmp, sign_imm);
825b2167459SRichard Henderson         break;
826b47a4a02SSven Schnelle     case 3: /* <= / >        (N ^ V) | Z / !((N ^ V) | Z) */
827b47a4a02SSven Schnelle         /*
828b47a4a02SSven Schnelle          * Simplify:
829b47a4a02SSven Schnelle          *   (N ^ V) | Z
830b47a4a02SSven Schnelle          *   ((res < 0) ^ (sv < 0)) | !res
831b47a4a02SSven Schnelle          *   ((res ^ sv) < 0) | !res
832d6d46be1SRichard Henderson          *   ((res ^ sv) < 0 ? 1 : !res)
833d6d46be1SRichard Henderson          *   !((res ^ sv) < 0 ? 0 : res)
834b47a4a02SSven Schnelle          */
835aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
836d6d46be1SRichard Henderson         tcg_gen_xor_i64(tmp, res, sv);
837d6d46be1SRichard Henderson         tcg_gen_movcond_i64(sign_cond, tmp,
838d6d46be1SRichard Henderson                             tmp, tcg_constant_i64(sign_imm),
839d6d46be1SRichard Henderson                             ctx->zero, res);
840d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
841b2167459SRichard Henderson         break;
842fe2d066aSRichard Henderson     case 4: /* NUV / UV      (!UV / UV) */
8434c42fd0dSRichard Henderson         cond = cond_make_vi(TCG_COND_EQ, uv, 0);
844b2167459SRichard Henderson         break;
845fe2d066aSRichard Henderson     case 5: /* ZNV / VNZ     (!UV | Z / UV & !Z) */
846aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
847fe2d066aSRichard Henderson         tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res);
848d6d46be1SRichard Henderson         cond = cond_make_ti(zero_cond, tmp, zero_imm);
849b2167459SRichard Henderson         break;
850b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
851d6d46be1SRichard Henderson         cond = cond_make_vi(sign_cond, sv, sign_imm);
852b2167459SRichard Henderson         break;
853b2167459SRichard Henderson     case 7: /* OD / EV */
854d6d46be1SRichard Henderson         cond = cond_make_vi(TCG_COND_TSTNE, res, 1);
855b2167459SRichard Henderson         break;
856b2167459SRichard Henderson     default:
857b2167459SRichard Henderson         g_assert_not_reached();
858b2167459SRichard Henderson     }
859b2167459SRichard Henderson     if (cf & 1) {
860b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
861b2167459SRichard Henderson     }
862b2167459SRichard Henderson 
863b2167459SRichard Henderson     return cond;
864b2167459SRichard Henderson }
865b2167459SRichard Henderson 
866b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
867b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
868b2167459SRichard Henderson    deleted as unused.  */
869b2167459SRichard Henderson 
8704fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d,
8716fd0c7bcSRichard Henderson                              TCGv_i64 res, TCGv_i64 in1,
8726fd0c7bcSRichard Henderson                              TCGv_i64 in2, TCGv_i64 sv)
873b2167459SRichard Henderson {
8744fe9533aSRichard Henderson     TCGCond tc;
8754fe9533aSRichard Henderson     bool ext_uns;
876b2167459SRichard Henderson 
877b2167459SRichard Henderson     switch (cf >> 1) {
878b2167459SRichard Henderson     case 1: /* = / <> */
8794fe9533aSRichard Henderson         tc = TCG_COND_EQ;
8804fe9533aSRichard Henderson         ext_uns = true;
881b2167459SRichard Henderson         break;
882b2167459SRichard Henderson     case 2: /* < / >= */
8834fe9533aSRichard Henderson         tc = TCG_COND_LT;
8844fe9533aSRichard Henderson         ext_uns = false;
885b2167459SRichard Henderson         break;
886b2167459SRichard Henderson     case 3: /* <= / > */
8874fe9533aSRichard Henderson         tc = TCG_COND_LE;
8884fe9533aSRichard Henderson         ext_uns = false;
889b2167459SRichard Henderson         break;
890b2167459SRichard Henderson     case 4: /* << / >>= */
8914fe9533aSRichard Henderson         tc = TCG_COND_LTU;
8924fe9533aSRichard Henderson         ext_uns = true;
893b2167459SRichard Henderson         break;
894b2167459SRichard Henderson     case 5: /* <<= / >> */
8954fe9533aSRichard Henderson         tc = TCG_COND_LEU;
8964fe9533aSRichard Henderson         ext_uns = true;
897b2167459SRichard Henderson         break;
898b2167459SRichard Henderson     default:
899a751eb31SRichard Henderson         return do_cond(ctx, cf, d, res, NULL, sv);
900b2167459SRichard Henderson     }
901b2167459SRichard Henderson 
9024fe9533aSRichard Henderson     if (cf & 1) {
9034fe9533aSRichard Henderson         tc = tcg_invert_cond(tc);
9044fe9533aSRichard Henderson     }
90582d0c831SRichard Henderson     if (!d) {
906aac0f603SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
907aac0f603SRichard Henderson         TCGv_i64 t2 = tcg_temp_new_i64();
9084fe9533aSRichard Henderson 
9094fe9533aSRichard Henderson         if (ext_uns) {
9106fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t1, in1);
9116fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(t2, in2);
9124fe9533aSRichard Henderson         } else {
9136fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t1, in1);
9146fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(t2, in2);
9154fe9533aSRichard Henderson         }
9164c42fd0dSRichard Henderson         return cond_make_tt(tc, t1, t2);
9174fe9533aSRichard Henderson     }
9184c42fd0dSRichard Henderson     return cond_make_vv(tc, in1, in2);
919b2167459SRichard Henderson }
920b2167459SRichard Henderson 
921df0232feSRichard Henderson /*
922df0232feSRichard Henderson  * Similar, but for logicals, where the carry and overflow bits are not
923df0232feSRichard Henderson  * computed, and use of them is undefined.
924df0232feSRichard Henderson  *
925df0232feSRichard Henderson  * Undefined or not, hardware does not trap.  It seems reasonable to
926df0232feSRichard Henderson  * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's
927df0232feSRichard Henderson  * how cases c={2,3} are treated.
928df0232feSRichard Henderson  */
929b2167459SRichard Henderson 
930b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d,
9316fd0c7bcSRichard Henderson                              TCGv_i64 res)
932b2167459SRichard Henderson {
933b5af8423SRichard Henderson     TCGCond tc;
934fbe65c64SRichard Henderson     uint64_t imm;
935a751eb31SRichard Henderson 
936fbe65c64SRichard Henderson     switch (cf >> 1) {
937fbe65c64SRichard Henderson     case 0:  /* never / always */
938fbe65c64SRichard Henderson     case 4:  /* undef, C */
939fbe65c64SRichard Henderson     case 5:  /* undef, C & !Z */
940fbe65c64SRichard Henderson     case 6:  /* undef, V */
941fbe65c64SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
942fbe65c64SRichard Henderson     case 1:  /* == / <> */
943fbe65c64SRichard Henderson         tc = d ? TCG_COND_EQ : TCG_COND_TSTEQ;
944fbe65c64SRichard Henderson         imm = d ? 0 : UINT32_MAX;
945b5af8423SRichard Henderson         break;
946fbe65c64SRichard Henderson     case 2:  /* < / >= */
947fbe65c64SRichard Henderson         tc = d ? TCG_COND_LT : TCG_COND_TSTNE;
948fbe65c64SRichard Henderson         imm = d ? 0 : 1ull << 31;
949b5af8423SRichard Henderson         break;
950fbe65c64SRichard Henderson     case 3:  /* <= / > */
951fbe65c64SRichard Henderson         tc = cf & 1 ? TCG_COND_GT : TCG_COND_LE;
95282d0c831SRichard Henderson         if (!d) {
953aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
9546fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(tmp, res);
9554c42fd0dSRichard Henderson             return cond_make_ti(tc, tmp, 0);
956b5af8423SRichard Henderson         }
9574c42fd0dSRichard Henderson         return cond_make_vi(tc, res, 0);
958fbe65c64SRichard Henderson     case 7: /* OD / EV */
959fbe65c64SRichard Henderson         tc = TCG_COND_TSTNE;
960fbe65c64SRichard Henderson         imm = 1;
961fbe65c64SRichard Henderson         break;
962fbe65c64SRichard Henderson     default:
963fbe65c64SRichard Henderson         g_assert_not_reached();
964fbe65c64SRichard Henderson     }
965fbe65c64SRichard Henderson     if (cf & 1) {
966fbe65c64SRichard Henderson         tc = tcg_invert_cond(tc);
967fbe65c64SRichard Henderson     }
968fbe65c64SRichard Henderson     return cond_make_vi(tc, res, imm);
969b2167459SRichard Henderson }
970b2167459SRichard Henderson 
97198cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
97298cd9ca7SRichard Henderson 
9734fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d,
9746fd0c7bcSRichard Henderson                              TCGv_i64 res)
97598cd9ca7SRichard Henderson {
97698cd9ca7SRichard Henderson     unsigned c, f;
97798cd9ca7SRichard Henderson 
97898cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
97998cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
98098cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
98198cd9ca7SRichard Henderson     c = orig & 3;
98298cd9ca7SRichard Henderson     if (c == 3) {
98398cd9ca7SRichard Henderson         c = 7;
98498cd9ca7SRichard Henderson     }
98598cd9ca7SRichard Henderson     f = (orig & 4) / 4;
98698cd9ca7SRichard Henderson 
987b5af8423SRichard Henderson     return do_log_cond(ctx, c * 2 + f, d, res);
98898cd9ca7SRichard Henderson }
98998cd9ca7SRichard Henderson 
99046bb3d46SRichard Henderson /* Similar, but for unit zero conditions.  */
99146bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res)
992b2167459SRichard Henderson {
99346bb3d46SRichard Henderson     TCGv_i64 tmp;
994c53e401eSRichard Henderson     uint64_t d_repl = d ? 0x0000000100000001ull : 1;
99546bb3d46SRichard Henderson     uint64_t ones = 0, sgns = 0;
996b2167459SRichard Henderson 
997b2167459SRichard Henderson     switch (cf >> 1) {
998578b8132SSven Schnelle     case 1: /* SBW / NBW */
999578b8132SSven Schnelle         if (d) {
100046bb3d46SRichard Henderson             ones = d_repl;
100146bb3d46SRichard Henderson             sgns = d_repl << 31;
1002578b8132SSven Schnelle         }
1003578b8132SSven Schnelle         break;
1004b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
100546bb3d46SRichard Henderson         ones = d_repl * 0x01010101u;
100646bb3d46SRichard Henderson         sgns = ones << 7;
100746bb3d46SRichard Henderson         break;
100846bb3d46SRichard Henderson     case 3: /* SHZ / NHZ */
100946bb3d46SRichard Henderson         ones = d_repl * 0x00010001u;
101046bb3d46SRichard Henderson         sgns = ones << 15;
101146bb3d46SRichard Henderson         break;
101246bb3d46SRichard Henderson     }
101346bb3d46SRichard Henderson     if (ones == 0) {
101446bb3d46SRichard Henderson         /* Undefined, or 0/1 (never/always). */
101546bb3d46SRichard Henderson         return cf & 1 ? cond_make_t() : cond_make_f();
101646bb3d46SRichard Henderson     }
101746bb3d46SRichard Henderson 
101846bb3d46SRichard Henderson     /*
101946bb3d46SRichard Henderson      * See hasless(v,1) from
1020b2167459SRichard Henderson      * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
1021b2167459SRichard Henderson      */
1022aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
102346bb3d46SRichard Henderson     tcg_gen_subi_i64(tmp, res, ones);
10246fd0c7bcSRichard Henderson     tcg_gen_andc_i64(tmp, tmp, res);
1025b2167459SRichard Henderson 
102625f97be7SRichard Henderson     return cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, tmp, sgns);
1027b2167459SRichard Henderson }
1028b2167459SRichard Henderson 
10296fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d,
10306fd0c7bcSRichard Henderson                           TCGv_i64 cb, TCGv_i64 cb_msb)
103172ca8753SRichard Henderson {
103282d0c831SRichard Henderson     if (!d) {
1033aac0f603SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
10346fd0c7bcSRichard Henderson         tcg_gen_extract_i64(t, cb, 32, 1);
103572ca8753SRichard Henderson         return t;
103672ca8753SRichard Henderson     }
103772ca8753SRichard Henderson     return cb_msb;
103872ca8753SRichard Henderson }
103972ca8753SRichard Henderson 
10406fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d)
104172ca8753SRichard Henderson {
104272ca8753SRichard Henderson     return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb);
104372ca8753SRichard Henderson }
104472ca8753SRichard Henderson 
1045b2167459SRichard Henderson /* Compute signed overflow for addition.  */
10466fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res,
1047f8f5986eSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2,
1048f8f5986eSRichard Henderson                           TCGv_i64 orig_in1, int shift, bool d)
1049b2167459SRichard Henderson {
1050aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1051aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1052b2167459SRichard Henderson 
10536fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
10546fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
10556fd0c7bcSRichard Henderson     tcg_gen_andc_i64(sv, sv, tmp);
1056b2167459SRichard Henderson 
1057f8f5986eSRichard Henderson     switch (shift) {
1058f8f5986eSRichard Henderson     case 0:
1059f8f5986eSRichard Henderson         break;
1060f8f5986eSRichard Henderson     case 1:
1061f8f5986eSRichard Henderson         /* Shift left by one and compare the sign. */
1062f8f5986eSRichard Henderson         tcg_gen_add_i64(tmp, orig_in1, orig_in1);
1063f8f5986eSRichard Henderson         tcg_gen_xor_i64(tmp, tmp, orig_in1);
1064f8f5986eSRichard Henderson         /* Incorporate into the overflow. */
1065f8f5986eSRichard Henderson         tcg_gen_or_i64(sv, sv, tmp);
1066f8f5986eSRichard Henderson         break;
1067f8f5986eSRichard Henderson     default:
1068f8f5986eSRichard Henderson         {
1069f8f5986eSRichard Henderson             int sign_bit = d ? 63 : 31;
1070f8f5986eSRichard Henderson 
1071f8f5986eSRichard Henderson             /* Compare the sign against all lower bits. */
1072f8f5986eSRichard Henderson             tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1);
1073f8f5986eSRichard Henderson             tcg_gen_xor_i64(tmp, tmp, orig_in1);
1074f8f5986eSRichard Henderson             /*
1075f8f5986eSRichard Henderson              * If one of the bits shifting into or through the sign
1076f8f5986eSRichard Henderson              * differs, then we have overflow.
1077f8f5986eSRichard Henderson              */
1078f8f5986eSRichard Henderson             tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift);
1079f8f5986eSRichard Henderson             tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero,
1080f8f5986eSRichard Henderson                                 tcg_constant_i64(-1), sv);
1081f8f5986eSRichard Henderson         }
1082f8f5986eSRichard Henderson     }
1083b2167459SRichard Henderson     return sv;
1084b2167459SRichard Henderson }
1085b2167459SRichard Henderson 
1086f8f5986eSRichard Henderson /* Compute unsigned overflow for addition.  */
1087f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb,
1088f8f5986eSRichard Henderson                           TCGv_i64 in1, int shift, bool d)
1089f8f5986eSRichard Henderson {
1090f8f5986eSRichard Henderson     if (shift == 0) {
1091f8f5986eSRichard Henderson         return get_carry(ctx, d, cb, cb_msb);
1092f8f5986eSRichard Henderson     } else {
1093f8f5986eSRichard Henderson         TCGv_i64 tmp = tcg_temp_new_i64();
1094f8f5986eSRichard Henderson         tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift);
1095f8f5986eSRichard Henderson         tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb));
1096f8f5986eSRichard Henderson         return tmp;
1097f8f5986eSRichard Henderson     }
1098f8f5986eSRichard Henderson }
1099f8f5986eSRichard Henderson 
1100b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
11016fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res,
11026fd0c7bcSRichard Henderson                           TCGv_i64 in1, TCGv_i64 in2)
1103b2167459SRichard Henderson {
1104aac0f603SRichard Henderson     TCGv_i64 sv = tcg_temp_new_i64();
1105aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
1106b2167459SRichard Henderson 
11076fd0c7bcSRichard Henderson     tcg_gen_xor_i64(sv, res, in1);
11086fd0c7bcSRichard Henderson     tcg_gen_xor_i64(tmp, in1, in2);
11096fd0c7bcSRichard Henderson     tcg_gen_and_i64(sv, sv, tmp);
1110b2167459SRichard Henderson 
1111b2167459SRichard Henderson     return sv;
1112b2167459SRichard Henderson }
1113b2167459SRichard Henderson 
1114269ca0a9SRichard Henderson static void gen_tc(DisasContext *ctx, DisasCond *cond)
1115269ca0a9SRichard Henderson {
1116269ca0a9SRichard Henderson     DisasDelayException *e;
1117269ca0a9SRichard Henderson 
1118269ca0a9SRichard Henderson     switch (cond->c) {
1119269ca0a9SRichard Henderson     case TCG_COND_NEVER:
1120269ca0a9SRichard Henderson         break;
1121269ca0a9SRichard Henderson     case TCG_COND_ALWAYS:
1122269ca0a9SRichard Henderson         gen_excp_iir(ctx, EXCP_COND);
1123269ca0a9SRichard Henderson         break;
1124269ca0a9SRichard Henderson     default:
1125269ca0a9SRichard Henderson         e = delay_excp(ctx, EXCP_COND);
1126269ca0a9SRichard Henderson         tcg_gen_brcond_i64(cond->c, cond->a0, cond->a1, e->lab);
1127269ca0a9SRichard Henderson         /* In the non-trap path, the condition is known false. */
1128269ca0a9SRichard Henderson         *cond = cond_make_f();
1129269ca0a9SRichard Henderson         break;
1130269ca0a9SRichard Henderson     }
1131269ca0a9SRichard Henderson }
1132269ca0a9SRichard Henderson 
1133a0ea4becSRichard Henderson static void gen_tsv(DisasContext *ctx, TCGv_i64 *sv, bool d)
1134a0ea4becSRichard Henderson {
1135a0ea4becSRichard Henderson     DisasCond cond = do_cond(ctx, /* SV */ 12, d, NULL, NULL, *sv);
1136a0ea4becSRichard Henderson     DisasDelayException *e = delay_excp(ctx, EXCP_OVERFLOW);
1137a0ea4becSRichard Henderson 
1138a0ea4becSRichard Henderson     tcg_gen_brcond_i64(cond.c, cond.a0, cond.a1, e->lab);
1139a0ea4becSRichard Henderson 
1140a0ea4becSRichard Henderson     /* In the non-trap path, V is known zero. */
1141a0ea4becSRichard Henderson     *sv = tcg_constant_i64(0);
1142a0ea4becSRichard Henderson }
1143a0ea4becSRichard Henderson 
1144f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1,
11456fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned shift, bool is_l,
1146faf97ba1SRichard Henderson                    bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d)
1147b2167459SRichard Henderson {
1148f8f5986eSRichard Henderson     TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp;
1149b2167459SRichard Henderson     unsigned c = cf >> 1;
1150b2167459SRichard Henderson     DisasCond cond;
1151b2167459SRichard Henderson 
1152aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1153f764718dSRichard Henderson     cb = NULL;
1154f764718dSRichard Henderson     cb_msb = NULL;
1155b2167459SRichard Henderson 
1156f8f5986eSRichard Henderson     in1 = orig_in1;
1157b2167459SRichard Henderson     if (shift) {
1158aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
11596fd0c7bcSRichard Henderson         tcg_gen_shli_i64(tmp, in1, shift);
1160b2167459SRichard Henderson         in1 = tmp;
1161b2167459SRichard Henderson     }
1162b2167459SRichard Henderson 
1163b47a4a02SSven Schnelle     if (!is_l || cond_need_cb(c)) {
1164aac0f603SRichard Henderson         cb_msb = tcg_temp_new_i64();
1165aac0f603SRichard Henderson         cb = tcg_temp_new_i64();
1166bdcccc17SRichard Henderson 
1167a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
1168b2167459SRichard Henderson         if (is_c) {
11696fd0c7bcSRichard Henderson             tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb,
1170a4db4a78SRichard Henderson                              get_psw_carry(ctx, d), ctx->zero);
1171b2167459SRichard Henderson         }
11726fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
11736fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1174b2167459SRichard Henderson     } else {
11756fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
1176b2167459SRichard Henderson         if (is_c) {
11776fd0c7bcSRichard Henderson             tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d));
1178b2167459SRichard Henderson         }
1179b2167459SRichard Henderson     }
1180b2167459SRichard Henderson 
1181b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1182f764718dSRichard Henderson     sv = NULL;
1183b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1184f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d);
1185b2167459SRichard Henderson         if (is_tsv) {
1186a0ea4becSRichard Henderson             gen_tsv(ctx, &sv, d);
1187b2167459SRichard Henderson         }
1188b2167459SRichard Henderson     }
1189b2167459SRichard Henderson 
1190f8f5986eSRichard Henderson     /* Compute unsigned overflow if required.  */
1191f8f5986eSRichard Henderson     uv = NULL;
1192f8f5986eSRichard Henderson     if (cond_need_cb(c)) {
1193f8f5986eSRichard Henderson         uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d);
1194f8f5986eSRichard Henderson     }
1195f8f5986eSRichard Henderson 
1196b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1197f8f5986eSRichard Henderson     cond = do_cond(ctx, cf, d, dest, uv, sv);
1198b2167459SRichard Henderson     if (is_tc) {
1199269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1200b2167459SRichard Henderson     }
1201b2167459SRichard Henderson 
1202b2167459SRichard Henderson     /* Write back the result.  */
1203b2167459SRichard Henderson     if (!is_l) {
1204b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
1205b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1206b2167459SRichard Henderson     }
1207b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1208b2167459SRichard Henderson 
1209b2167459SRichard Henderson     /* Install the new nullification.  */
1210b2167459SRichard Henderson     ctx->null_cond = cond;
1211b2167459SRichard Henderson }
1212b2167459SRichard Henderson 
1213faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a,
12140c982a28SRichard Henderson                        bool is_l, bool is_tsv, bool is_tc, bool is_c)
12150c982a28SRichard Henderson {
12166fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
12170c982a28SRichard Henderson 
1218269ca0a9SRichard Henderson     if (unlikely(is_tc && a->cf == 1)) {
1219269ca0a9SRichard Henderson         /* Unconditional trap on condition. */
1220269ca0a9SRichard Henderson         return gen_excp_iir(ctx, EXCP_COND);
1221269ca0a9SRichard Henderson     }
12220c982a28SRichard Henderson     if (a->cf) {
12230c982a28SRichard Henderson         nullify_over(ctx);
12240c982a28SRichard Henderson     }
12250c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
12260c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1227faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l,
1228faf97ba1SRichard Henderson            is_tsv, is_tc, is_c, a->cf, a->d);
12290c982a28SRichard Henderson     return nullify_end(ctx);
12300c982a28SRichard Henderson }
12310c982a28SRichard Henderson 
12320588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a,
12330588e061SRichard Henderson                        bool is_tsv, bool is_tc)
12340588e061SRichard Henderson {
12356fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
12360588e061SRichard Henderson 
1237269ca0a9SRichard Henderson     if (unlikely(is_tc && a->cf == 1)) {
1238269ca0a9SRichard Henderson         /* Unconditional trap on condition. */
1239269ca0a9SRichard Henderson         return gen_excp_iir(ctx, EXCP_COND);
1240269ca0a9SRichard Henderson     }
12410588e061SRichard Henderson     if (a->cf) {
12420588e061SRichard Henderson         nullify_over(ctx);
12430588e061SRichard Henderson     }
12446fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
12450588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
1246faf97ba1SRichard Henderson     /* All ADDI conditions are 32-bit. */
1247faf97ba1SRichard Henderson     do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false);
12480588e061SRichard Henderson     return nullify_end(ctx);
12490588e061SRichard Henderson }
12500588e061SRichard Henderson 
12516fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
12526fd0c7bcSRichard Henderson                    TCGv_i64 in2, bool is_tsv, bool is_b,
125363c427c6SRichard Henderson                    bool is_tc, unsigned cf, bool d)
1254b2167459SRichard Henderson {
1255269ca0a9SRichard Henderson     TCGv_i64 dest, sv, cb, cb_msb;
1256b2167459SRichard Henderson     unsigned c = cf >> 1;
1257b2167459SRichard Henderson     DisasCond cond;
1258b2167459SRichard Henderson 
1259aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
1260aac0f603SRichard Henderson     cb = tcg_temp_new_i64();
1261aac0f603SRichard Henderson     cb_msb = tcg_temp_new_i64();
1262b2167459SRichard Henderson 
1263b2167459SRichard Henderson     if (is_b) {
1264b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
12656fd0c7bcSRichard Henderson         tcg_gen_not_i64(cb, in2);
1266a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero,
1267a4db4a78SRichard Henderson                          get_psw_carry(ctx, d), ctx->zero);
1268a4db4a78SRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero);
12696fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, in1);
12706fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1271b2167459SRichard Henderson     } else {
1272bdcccc17SRichard Henderson         /*
1273bdcccc17SRichard Henderson          * DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
1274bdcccc17SRichard Henderson          * operations by seeding the high word with 1 and subtracting.
1275bdcccc17SRichard Henderson          */
12766fd0c7bcSRichard Henderson         TCGv_i64 one = tcg_constant_i64(1);
1277a4db4a78SRichard Henderson         tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
12786fd0c7bcSRichard Henderson         tcg_gen_eqv_i64(cb, in1, in2);
12796fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
1280b2167459SRichard Henderson     }
1281b2167459SRichard Henderson 
1282b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1283f764718dSRichard Henderson     sv = NULL;
1284b47a4a02SSven Schnelle     if (is_tsv || cond_need_sv(c)) {
1285b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1286b2167459SRichard Henderson         if (is_tsv) {
1287a0ea4becSRichard Henderson             gen_tsv(ctx, &sv, d);
1288b2167459SRichard Henderson         }
1289b2167459SRichard Henderson     }
1290b2167459SRichard Henderson 
1291b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
1292b2167459SRichard Henderson     if (!is_b) {
12934fe9533aSRichard Henderson         cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1294b2167459SRichard Henderson     } else {
1295a751eb31SRichard Henderson         cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv);
1296b2167459SRichard Henderson     }
1297b2167459SRichard Henderson 
1298b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
1299b2167459SRichard Henderson     if (is_tc) {
1300269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1301b2167459SRichard Henderson     }
1302b2167459SRichard Henderson 
1303b2167459SRichard Henderson     /* Write back the result.  */
1304b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
1305b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
1306b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1307b2167459SRichard Henderson 
1308b2167459SRichard Henderson     /* Install the new nullification.  */
1309b2167459SRichard Henderson     ctx->null_cond = cond;
1310b2167459SRichard Henderson }
1311b2167459SRichard Henderson 
131263c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13130c982a28SRichard Henderson                        bool is_tsv, bool is_b, bool is_tc)
13140c982a28SRichard Henderson {
13156fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13160c982a28SRichard Henderson 
13170c982a28SRichard Henderson     if (a->cf) {
13180c982a28SRichard Henderson         nullify_over(ctx);
13190c982a28SRichard Henderson     }
13200c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13210c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
132263c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d);
13230c982a28SRichard Henderson     return nullify_end(ctx);
13240c982a28SRichard Henderson }
13250c982a28SRichard Henderson 
13260588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv)
13270588e061SRichard Henderson {
13286fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
13290588e061SRichard Henderson 
13300588e061SRichard Henderson     if (a->cf) {
13310588e061SRichard Henderson         nullify_over(ctx);
13320588e061SRichard Henderson     }
13336fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
13340588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
133563c427c6SRichard Henderson     /* All SUBI conditions are 32-bit. */
133663c427c6SRichard Henderson     do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false);
13370588e061SRichard Henderson     return nullify_end(ctx);
13380588e061SRichard Henderson }
13390588e061SRichard Henderson 
13406fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13416fd0c7bcSRichard Henderson                       TCGv_i64 in2, unsigned cf, bool d)
1342b2167459SRichard Henderson {
13436fd0c7bcSRichard Henderson     TCGv_i64 dest, sv;
1344b2167459SRichard Henderson     DisasCond cond;
1345b2167459SRichard Henderson 
1346aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
13476fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
1348b2167459SRichard Henderson 
1349b2167459SRichard Henderson     /* Compute signed overflow if required.  */
1350f764718dSRichard Henderson     sv = NULL;
1351b47a4a02SSven Schnelle     if (cond_need_sv(cf >> 1)) {
1352b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
1353b2167459SRichard Henderson     }
1354b2167459SRichard Henderson 
1355b2167459SRichard Henderson     /* Form the condition for the compare.  */
13564fe9533aSRichard Henderson     cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv);
1357b2167459SRichard Henderson 
1358b2167459SRichard Henderson     /* Clear.  */
13596fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
1360b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1361b2167459SRichard Henderson 
1362b2167459SRichard Henderson     /* Install the new nullification.  */
1363b2167459SRichard Henderson     ctx->null_cond = cond;
1364b2167459SRichard Henderson }
1365b2167459SRichard Henderson 
13666fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
13676fd0c7bcSRichard Henderson                    TCGv_i64 in2, unsigned cf, bool d,
13686fd0c7bcSRichard Henderson                    void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
1369b2167459SRichard Henderson {
13706fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, rt);
1371b2167459SRichard Henderson 
1372b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1373b2167459SRichard Henderson     fn(dest, in1, in2);
1374b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1375b2167459SRichard Henderson 
1376b2167459SRichard Henderson     /* Install the new nullification.  */
1377b5af8423SRichard Henderson     ctx->null_cond = do_log_cond(ctx, cf, d, dest);
1378b2167459SRichard Henderson }
1379b2167459SRichard Henderson 
1380fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a,
13816fd0c7bcSRichard Henderson                        void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
13820c982a28SRichard Henderson {
13836fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
13840c982a28SRichard Henderson 
13850c982a28SRichard Henderson     if (a->cf) {
13860c982a28SRichard Henderson         nullify_over(ctx);
13870c982a28SRichard Henderson     }
13880c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
13890c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
1390fa8e3bedSRichard Henderson     do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn);
13910c982a28SRichard Henderson     return nullify_end(ctx);
13920c982a28SRichard Henderson }
13930c982a28SRichard Henderson 
139446bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1,
139546bb3d46SRichard Henderson                            TCGv_i64 in2, unsigned cf, bool d,
139646bb3d46SRichard Henderson                            bool is_tc, bool is_add)
1397b2167459SRichard Henderson {
139846bb3d46SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
139946bb3d46SRichard Henderson     uint64_t test_cb = 0;
1400b2167459SRichard Henderson     DisasCond cond;
1401b2167459SRichard Henderson 
140246bb3d46SRichard Henderson     /* Select which carry-out bits to test. */
140346bb3d46SRichard Henderson     switch (cf >> 1) {
140446bb3d46SRichard Henderson     case 4: /* NDC / SDC -- 4-bit carries */
140546bb3d46SRichard Henderson         test_cb = dup_const(MO_8, 0x88);
140646bb3d46SRichard Henderson         break;
140746bb3d46SRichard Henderson     case 5: /* NWC / SWC -- 32-bit carries */
140846bb3d46SRichard Henderson         if (d) {
140946bb3d46SRichard Henderson             test_cb = dup_const(MO_32, INT32_MIN);
1410b2167459SRichard Henderson         } else {
141146bb3d46SRichard Henderson             cf &= 1; /* undefined -- map to never/always */
141246bb3d46SRichard Henderson         }
141346bb3d46SRichard Henderson         break;
141446bb3d46SRichard Henderson     case 6: /* NBC / SBC -- 8-bit carries */
141546bb3d46SRichard Henderson         test_cb = dup_const(MO_8, INT8_MIN);
141646bb3d46SRichard Henderson         break;
141746bb3d46SRichard Henderson     case 7: /* NHC / SHC -- 16-bit carries */
141846bb3d46SRichard Henderson         test_cb = dup_const(MO_16, INT16_MIN);
141946bb3d46SRichard Henderson         break;
142046bb3d46SRichard Henderson     }
142146bb3d46SRichard Henderson     if (!d) {
142246bb3d46SRichard Henderson         test_cb = (uint32_t)test_cb;
142346bb3d46SRichard Henderson     }
1424b2167459SRichard Henderson 
142546bb3d46SRichard Henderson     if (!test_cb) {
142646bb3d46SRichard Henderson         /* No need to compute carries if we don't need to test them. */
142746bb3d46SRichard Henderson         if (is_add) {
142846bb3d46SRichard Henderson             tcg_gen_add_i64(dest, in1, in2);
142946bb3d46SRichard Henderson         } else {
143046bb3d46SRichard Henderson             tcg_gen_sub_i64(dest, in1, in2);
143146bb3d46SRichard Henderson         }
143246bb3d46SRichard Henderson         cond = do_unit_zero_cond(cf, d, dest);
143346bb3d46SRichard Henderson     } else {
143446bb3d46SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
143546bb3d46SRichard Henderson 
143646bb3d46SRichard Henderson         if (d) {
143746bb3d46SRichard Henderson             TCGv_i64 cb_msb = tcg_temp_new_i64();
143846bb3d46SRichard Henderson             if (is_add) {
143946bb3d46SRichard Henderson                 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero);
144046bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
144146bb3d46SRichard Henderson             } else {
144246bb3d46SRichard Henderson                 /* See do_sub, !is_b. */
144346bb3d46SRichard Henderson                 TCGv_i64 one = tcg_constant_i64(1);
144446bb3d46SRichard Henderson                 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero);
144546bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
144646bb3d46SRichard Henderson             }
144746bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
144846bb3d46SRichard Henderson             tcg_gen_extract2_i64(cb, cb, cb_msb, 1);
144946bb3d46SRichard Henderson         } else {
145046bb3d46SRichard Henderson             if (is_add) {
145146bb3d46SRichard Henderson                 tcg_gen_add_i64(dest, in1, in2);
145246bb3d46SRichard Henderson                 tcg_gen_xor_i64(cb, in1, in2);
145346bb3d46SRichard Henderson             } else {
145446bb3d46SRichard Henderson                 tcg_gen_sub_i64(dest, in1, in2);
145546bb3d46SRichard Henderson                 tcg_gen_eqv_i64(cb, in1, in2);
145646bb3d46SRichard Henderson             }
145746bb3d46SRichard Henderson             tcg_gen_xor_i64(cb, cb, dest);
145846bb3d46SRichard Henderson             tcg_gen_shri_i64(cb, cb, 1);
145946bb3d46SRichard Henderson         }
146046bb3d46SRichard Henderson 
14613289ea0eSRichard Henderson         cond = cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
14623289ea0eSRichard Henderson                             cb, test_cb);
146346bb3d46SRichard Henderson     }
1464b2167459SRichard Henderson 
1465b2167459SRichard Henderson     if (is_tc) {
1466269ca0a9SRichard Henderson         gen_tc(ctx, &cond);
1467b2167459SRichard Henderson     }
1468b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1469b2167459SRichard Henderson 
1470b2167459SRichard Henderson     ctx->null_cond = cond;
1471b2167459SRichard Henderson }
1472b2167459SRichard Henderson 
147386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY
14748d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space
14758d6ae7fbSRichard Henderson    from the top 2 bits of the base register.  There are a few system
14768d6ae7fbSRichard Henderson    instructions that have a 3-bit space specifier, for which SR0 is
14778d6ae7fbSRichard Henderson    not special.  To handle this, pass ~SP.  */
14786fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base)
147986f8d05fSRichard Henderson {
148086f8d05fSRichard Henderson     TCGv_ptr ptr;
14816fd0c7bcSRichard Henderson     TCGv_i64 tmp;
148286f8d05fSRichard Henderson     TCGv_i64 spc;
148386f8d05fSRichard Henderson 
148486f8d05fSRichard Henderson     if (sp != 0) {
14858d6ae7fbSRichard Henderson         if (sp < 0) {
14868d6ae7fbSRichard Henderson             sp = ~sp;
14878d6ae7fbSRichard Henderson         }
14886fd0c7bcSRichard Henderson         spc = tcg_temp_new_i64();
14898d6ae7fbSRichard Henderson         load_spr(ctx, spc, sp);
14908d6ae7fbSRichard Henderson         return spc;
149186f8d05fSRichard Henderson     }
1492494737b7SRichard Henderson     if (ctx->tb_flags & TB_FLAG_SR_SAME) {
1493494737b7SRichard Henderson         return cpu_srH;
1494494737b7SRichard Henderson     }
149586f8d05fSRichard Henderson 
149686f8d05fSRichard Henderson     ptr = tcg_temp_new_ptr();
1497aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
14986fd0c7bcSRichard Henderson     spc = tcg_temp_new_i64();
149986f8d05fSRichard Henderson 
1500698240d1SRichard Henderson     /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */
15016fd0c7bcSRichard Henderson     tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5);
15026fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, 030);
15036fd0c7bcSRichard Henderson     tcg_gen_trunc_i64_ptr(ptr, tmp);
150486f8d05fSRichard Henderson 
1505ad75a51eSRichard Henderson     tcg_gen_add_ptr(ptr, ptr, tcg_env);
150686f8d05fSRichard Henderson     tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4]));
150786f8d05fSRichard Henderson 
150886f8d05fSRichard Henderson     return spc;
150986f8d05fSRichard Henderson }
151086f8d05fSRichard Henderson #endif
151186f8d05fSRichard Henderson 
15126fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs,
1513c53e401eSRichard Henderson                      unsigned rb, unsigned rx, int scale, int64_t disp,
151486f8d05fSRichard Henderson                      unsigned sp, int modify, bool is_phys)
151586f8d05fSRichard Henderson {
15166fd0c7bcSRichard Henderson     TCGv_i64 base = load_gpr(ctx, rb);
15176fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15186fd0c7bcSRichard Henderson     TCGv_i64 addr;
151986f8d05fSRichard Henderson 
1520f5b5c857SRichard Henderson     set_insn_breg(ctx, rb);
1521f5b5c857SRichard Henderson 
152286f8d05fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
152386f8d05fSRichard Henderson     if (rx) {
1524aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15256fd0c7bcSRichard Henderson         tcg_gen_shli_i64(ofs, cpu_gr[rx], scale);
15266fd0c7bcSRichard Henderson         tcg_gen_add_i64(ofs, ofs, base);
152786f8d05fSRichard Henderson     } else if (disp || modify) {
1528aac0f603SRichard Henderson         ofs = tcg_temp_new_i64();
15296fd0c7bcSRichard Henderson         tcg_gen_addi_i64(ofs, base, disp);
153086f8d05fSRichard Henderson     } else {
153186f8d05fSRichard Henderson         ofs = base;
153286f8d05fSRichard Henderson     }
153386f8d05fSRichard Henderson 
153486f8d05fSRichard Henderson     *pofs = ofs;
15356fd0c7bcSRichard Henderson     *pgva = addr = tcg_temp_new_i64();
15367d50b696SSven Schnelle     tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base,
15377d50b696SSven Schnelle                      gva_offset_mask(ctx->tb_flags));
1538698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY
153986f8d05fSRichard Henderson     if (!is_phys) {
1540d265360fSRichard Henderson         tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base));
154186f8d05fSRichard Henderson     }
154286f8d05fSRichard Henderson #endif
154386f8d05fSRichard Henderson }
154486f8d05fSRichard Henderson 
154596d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
154696d6407fSRichard Henderson  * < 0 for pre-modify,
154796d6407fSRichard Henderson  * > 0 for post-modify,
154896d6407fSRichard Henderson  * = 0 for no base register update.
154996d6407fSRichard Henderson  */
155096d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1551c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
155214776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
155396d6407fSRichard Henderson {
15546fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15556fd0c7bcSRichard Henderson     TCGv_i64 addr;
155696d6407fSRichard Henderson 
155796d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
155896d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
155996d6407fSRichard Henderson 
156086f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
156117fe594cSRichard Henderson              MMU_DISABLED(ctx));
1562c1f55d97SRichard Henderson     tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
156386f8d05fSRichard Henderson     if (modify) {
156486f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
156596d6407fSRichard Henderson     }
156696d6407fSRichard Henderson }
156796d6407fSRichard Henderson 
156896d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1569c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
157014776ab5STony Nguyen                        unsigned sp, int modify, MemOp mop)
157196d6407fSRichard Henderson {
15726fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15736fd0c7bcSRichard Henderson     TCGv_i64 addr;
157496d6407fSRichard Henderson 
157596d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
157696d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
157796d6407fSRichard Henderson 
157886f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
157917fe594cSRichard Henderson              MMU_DISABLED(ctx));
1580217d1a5eSRichard Henderson     tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
158186f8d05fSRichard Henderson     if (modify) {
158286f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
158396d6407fSRichard Henderson     }
158496d6407fSRichard Henderson }
158596d6407fSRichard Henderson 
158696d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1587c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
158814776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
158996d6407fSRichard Henderson {
15906fd0c7bcSRichard Henderson     TCGv_i64 ofs;
15916fd0c7bcSRichard Henderson     TCGv_i64 addr;
159296d6407fSRichard Henderson 
159396d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
159496d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
159596d6407fSRichard Henderson 
159686f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
159717fe594cSRichard Henderson              MMU_DISABLED(ctx));
1598217d1a5eSRichard Henderson     tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
159986f8d05fSRichard Henderson     if (modify) {
160086f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
160196d6407fSRichard Henderson     }
160296d6407fSRichard Henderson }
160396d6407fSRichard Henderson 
160496d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1605c53e401eSRichard Henderson                         unsigned rx, int scale, int64_t disp,
160614776ab5STony Nguyen                         unsigned sp, int modify, MemOp mop)
160796d6407fSRichard Henderson {
16086fd0c7bcSRichard Henderson     TCGv_i64 ofs;
16096fd0c7bcSRichard Henderson     TCGv_i64 addr;
161096d6407fSRichard Henderson 
161196d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
161296d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
161396d6407fSRichard Henderson 
161486f8d05fSRichard Henderson     form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify,
161517fe594cSRichard Henderson              MMU_DISABLED(ctx));
1616217d1a5eSRichard Henderson     tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx));
161786f8d05fSRichard Henderson     if (modify) {
161886f8d05fSRichard Henderson         save_gpr(ctx, rb, ofs);
161996d6407fSRichard Henderson     }
162096d6407fSRichard Henderson }
162196d6407fSRichard Henderson 
16221cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1623c53e401eSRichard Henderson                     unsigned rx, int scale, int64_t disp,
162414776ab5STony Nguyen                     unsigned sp, int modify, MemOp mop)
162596d6407fSRichard Henderson {
16266fd0c7bcSRichard Henderson     TCGv_i64 dest;
162796d6407fSRichard Henderson 
162896d6407fSRichard Henderson     nullify_over(ctx);
162996d6407fSRichard Henderson 
163096d6407fSRichard Henderson     if (modify == 0) {
163196d6407fSRichard Henderson         /* No base register update.  */
163296d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
163396d6407fSRichard Henderson     } else {
163496d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
1635aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
163696d6407fSRichard Henderson     }
16376fd0c7bcSRichard Henderson     do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop);
163896d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
163996d6407fSRichard Henderson 
16401cd012a5SRichard Henderson     return nullify_end(ctx);
164196d6407fSRichard Henderson }
164296d6407fSRichard Henderson 
1643740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1644c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
164586f8d05fSRichard Henderson                       unsigned sp, int modify)
164696d6407fSRichard Henderson {
164796d6407fSRichard Henderson     TCGv_i32 tmp;
164896d6407fSRichard Henderson 
164996d6407fSRichard Henderson     nullify_over(ctx);
165096d6407fSRichard Henderson 
165196d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
165286f8d05fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
165396d6407fSRichard Henderson     save_frw_i32(rt, tmp);
165496d6407fSRichard Henderson 
165596d6407fSRichard Henderson     if (rt == 0) {
1656ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
165796d6407fSRichard Henderson     }
165896d6407fSRichard Henderson 
1659740038d7SRichard Henderson     return nullify_end(ctx);
166096d6407fSRichard Henderson }
166196d6407fSRichard Henderson 
1662740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a)
1663740038d7SRichard Henderson {
1664740038d7SRichard Henderson     return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1665740038d7SRichard Henderson                      a->disp, a->sp, a->m);
1666740038d7SRichard Henderson }
1667740038d7SRichard Henderson 
1668740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1669c53e401eSRichard Henderson                       unsigned rx, int scale, int64_t disp,
167086f8d05fSRichard Henderson                       unsigned sp, int modify)
167196d6407fSRichard Henderson {
167296d6407fSRichard Henderson     TCGv_i64 tmp;
167396d6407fSRichard Henderson 
167496d6407fSRichard Henderson     nullify_over(ctx);
167596d6407fSRichard Henderson 
167696d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
1677fc313c64SFrédéric Pétrot     do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
167896d6407fSRichard Henderson     save_frd(rt, tmp);
167996d6407fSRichard Henderson 
168096d6407fSRichard Henderson     if (rt == 0) {
1681ad75a51eSRichard Henderson         gen_helper_loaded_fr0(tcg_env);
168296d6407fSRichard Henderson     }
168396d6407fSRichard Henderson 
1684740038d7SRichard Henderson     return nullify_end(ctx);
1685740038d7SRichard Henderson }
1686740038d7SRichard Henderson 
1687740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a)
1688740038d7SRichard Henderson {
1689740038d7SRichard Henderson     return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1690740038d7SRichard Henderson                      a->disp, a->sp, a->m);
169196d6407fSRichard Henderson }
169296d6407fSRichard Henderson 
16931cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1694c53e401eSRichard Henderson                      int64_t disp, unsigned sp,
169514776ab5STony Nguyen                      int modify, MemOp mop)
169696d6407fSRichard Henderson {
169796d6407fSRichard Henderson     nullify_over(ctx);
16986fd0c7bcSRichard Henderson     do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop);
16991cd012a5SRichard Henderson     return nullify_end(ctx);
170096d6407fSRichard Henderson }
170196d6407fSRichard Henderson 
1702740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1703c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
170486f8d05fSRichard Henderson                        unsigned sp, int modify)
170596d6407fSRichard Henderson {
170696d6407fSRichard Henderson     TCGv_i32 tmp;
170796d6407fSRichard Henderson 
170896d6407fSRichard Henderson     nullify_over(ctx);
170996d6407fSRichard Henderson 
171096d6407fSRichard Henderson     tmp = load_frw_i32(rt);
171186f8d05fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL);
171296d6407fSRichard Henderson 
1713740038d7SRichard Henderson     return nullify_end(ctx);
171496d6407fSRichard Henderson }
171596d6407fSRichard Henderson 
1716740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a)
1717740038d7SRichard Henderson {
1718740038d7SRichard Henderson     return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0,
1719740038d7SRichard Henderson                       a->disp, a->sp, a->m);
1720740038d7SRichard Henderson }
1721740038d7SRichard Henderson 
1722740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1723c53e401eSRichard Henderson                        unsigned rx, int scale, int64_t disp,
172486f8d05fSRichard Henderson                        unsigned sp, int modify)
172596d6407fSRichard Henderson {
172696d6407fSRichard Henderson     TCGv_i64 tmp;
172796d6407fSRichard Henderson 
172896d6407fSRichard Henderson     nullify_over(ctx);
172996d6407fSRichard Henderson 
173096d6407fSRichard Henderson     tmp = load_frd(rt);
1731fc313c64SFrédéric Pétrot     do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ);
173296d6407fSRichard Henderson 
1733740038d7SRichard Henderson     return nullify_end(ctx);
1734740038d7SRichard Henderson }
1735740038d7SRichard Henderson 
1736740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a)
1737740038d7SRichard Henderson {
1738740038d7SRichard Henderson     return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0,
1739740038d7SRichard Henderson                       a->disp, a->sp, a->m);
174096d6407fSRichard Henderson }
174196d6407fSRichard Henderson 
17421ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1743ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1744ebe9383cSRichard Henderson {
1745ebe9383cSRichard Henderson     TCGv_i32 tmp;
1746ebe9383cSRichard Henderson 
1747ebe9383cSRichard Henderson     nullify_over(ctx);
1748ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1749ebe9383cSRichard Henderson 
1750ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1751ebe9383cSRichard Henderson 
1752ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
17531ca74648SRichard Henderson     return nullify_end(ctx);
1754ebe9383cSRichard Henderson }
1755ebe9383cSRichard Henderson 
17561ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1757ebe9383cSRichard Henderson                        void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1758ebe9383cSRichard Henderson {
1759ebe9383cSRichard Henderson     TCGv_i32 dst;
1760ebe9383cSRichard Henderson     TCGv_i64 src;
1761ebe9383cSRichard Henderson 
1762ebe9383cSRichard Henderson     nullify_over(ctx);
1763ebe9383cSRichard Henderson     src = load_frd(ra);
1764ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1765ebe9383cSRichard Henderson 
1766ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1767ebe9383cSRichard Henderson 
1768ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
17691ca74648SRichard Henderson     return nullify_end(ctx);
1770ebe9383cSRichard Henderson }
1771ebe9383cSRichard Henderson 
17721ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1773ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1774ebe9383cSRichard Henderson {
1775ebe9383cSRichard Henderson     TCGv_i64 tmp;
1776ebe9383cSRichard Henderson 
1777ebe9383cSRichard Henderson     nullify_over(ctx);
1778ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1779ebe9383cSRichard Henderson 
1780ad75a51eSRichard Henderson     func(tmp, tcg_env, tmp);
1781ebe9383cSRichard Henderson 
1782ebe9383cSRichard Henderson     save_frd(rt, tmp);
17831ca74648SRichard Henderson     return nullify_end(ctx);
1784ebe9383cSRichard Henderson }
1785ebe9383cSRichard Henderson 
17861ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1787ebe9383cSRichard Henderson                        void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1788ebe9383cSRichard Henderson {
1789ebe9383cSRichard Henderson     TCGv_i32 src;
1790ebe9383cSRichard Henderson     TCGv_i64 dst;
1791ebe9383cSRichard Henderson 
1792ebe9383cSRichard Henderson     nullify_over(ctx);
1793ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1794ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1795ebe9383cSRichard Henderson 
1796ad75a51eSRichard Henderson     func(dst, tcg_env, src);
1797ebe9383cSRichard Henderson 
1798ebe9383cSRichard Henderson     save_frd(rt, dst);
17991ca74648SRichard Henderson     return nullify_end(ctx);
1800ebe9383cSRichard Henderson }
1801ebe9383cSRichard Henderson 
18021ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt,
1803ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
180431234768SRichard Henderson                         void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
1805ebe9383cSRichard Henderson {
1806ebe9383cSRichard Henderson     TCGv_i32 a, b;
1807ebe9383cSRichard Henderson 
1808ebe9383cSRichard Henderson     nullify_over(ctx);
1809ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1810ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1811ebe9383cSRichard Henderson 
1812ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1813ebe9383cSRichard Henderson 
1814ebe9383cSRichard Henderson     save_frw_i32(rt, a);
18151ca74648SRichard Henderson     return nullify_end(ctx);
1816ebe9383cSRichard Henderson }
1817ebe9383cSRichard Henderson 
18181ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt,
1819ebe9383cSRichard Henderson                         unsigned ra, unsigned rb,
182031234768SRichard Henderson                         void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64))
1821ebe9383cSRichard Henderson {
1822ebe9383cSRichard Henderson     TCGv_i64 a, b;
1823ebe9383cSRichard Henderson 
1824ebe9383cSRichard Henderson     nullify_over(ctx);
1825ebe9383cSRichard Henderson     a = load_frd0(ra);
1826ebe9383cSRichard Henderson     b = load_frd0(rb);
1827ebe9383cSRichard Henderson 
1828ad75a51eSRichard Henderson     func(a, tcg_env, a, b);
1829ebe9383cSRichard Henderson 
1830ebe9383cSRichard Henderson     save_frd(rt, a);
18311ca74648SRichard Henderson     return nullify_end(ctx);
1832ebe9383cSRichard Henderson }
1833ebe9383cSRichard Henderson 
183498cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
183598cd9ca7SRichard Henderson    have already had nullification handled.  */
18362644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp,
183798cd9ca7SRichard Henderson                        unsigned link, bool is_n)
183898cd9ca7SRichard Henderson {
1839bc921866SRichard Henderson     ctx->iaq_j = iaqe_branchi(ctx, disp);
18402644f80bSRichard Henderson 
184198cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
184243541db0SRichard Henderson         install_link(ctx, link, false);
184398cd9ca7SRichard Henderson         if (is_n) {
1844d08ad0e0SRichard Henderson             if (use_nullify_skip(ctx)) {
1845d08ad0e0SRichard Henderson                 nullify_set(ctx, 0);
1846bc921866SRichard Henderson                 gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
1847d08ad0e0SRichard Henderson                 ctx->base.is_jmp = DISAS_NORETURN;
1848d08ad0e0SRichard Henderson                 return true;
1849d08ad0e0SRichard Henderson             }
185098cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
185198cd9ca7SRichard Henderson         }
1852bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
185398cd9ca7SRichard Henderson     } else {
185498cd9ca7SRichard Henderson         nullify_over(ctx);
185598cd9ca7SRichard Henderson 
185643541db0SRichard Henderson         install_link(ctx, link, false);
185798cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
185898cd9ca7SRichard Henderson             nullify_set(ctx, 0);
1859bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL);
186098cd9ca7SRichard Henderson         } else {
186198cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
1862bc921866SRichard Henderson             gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j);
186398cd9ca7SRichard Henderson         }
186431234768SRichard Henderson         nullify_end(ctx);
186598cd9ca7SRichard Henderson 
186698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1867bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL);
186831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
186998cd9ca7SRichard Henderson     }
187001afb7beSRichard Henderson     return true;
187198cd9ca7SRichard Henderson }
187298cd9ca7SRichard Henderson 
187398cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
187498cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1875c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n,
187698cd9ca7SRichard Henderson                        DisasCond *cond)
187798cd9ca7SRichard Henderson {
1878bc921866SRichard Henderson     DisasIAQE next;
187998cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
188098cd9ca7SRichard Henderson     TCGCond c = cond->c;
188198cd9ca7SRichard Henderson     bool n;
188298cd9ca7SRichard Henderson 
188398cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
188498cd9ca7SRichard Henderson 
188598cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
188698cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
18872644f80bSRichard Henderson         return do_dbranch(ctx, disp, 0, is_n && disp >= 0);
188898cd9ca7SRichard Henderson     }
188998cd9ca7SRichard Henderson 
189098cd9ca7SRichard Henderson     taken = gen_new_label();
18916fd0c7bcSRichard Henderson     tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken);
189298cd9ca7SRichard Henderson 
189398cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
189498cd9ca7SRichard Henderson     n = is_n && disp < 0;
189598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
189698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1897bc921866SRichard Henderson         next = iaqe_incr(&ctx->iaq_b, 4);
1898bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &next, NULL);
189998cd9ca7SRichard Henderson     } else {
190098cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
190198cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
190298cd9ca7SRichard Henderson             ctx->null_lab = NULL;
190398cd9ca7SRichard Henderson         }
190498cd9ca7SRichard Henderson         nullify_set(ctx, n);
1905bc921866SRichard Henderson         gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL);
190698cd9ca7SRichard Henderson     }
190798cd9ca7SRichard Henderson 
190898cd9ca7SRichard Henderson     gen_set_label(taken);
190998cd9ca7SRichard Henderson 
191098cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
191198cd9ca7SRichard Henderson     n = is_n && disp >= 0;
1912bc921866SRichard Henderson 
1913bc921866SRichard Henderson     next = iaqe_branchi(ctx, disp);
191498cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
191598cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1916bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &next, NULL);
191798cd9ca7SRichard Henderson     } else {
191898cd9ca7SRichard Henderson         nullify_set(ctx, n);
1919bc921866SRichard Henderson         gen_goto_tb(ctx, 1, &ctx->iaq_b, &next);
192098cd9ca7SRichard Henderson     }
192198cd9ca7SRichard Henderson 
192298cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
192398cd9ca7SRichard Henderson     if (ctx->null_lab) {
192498cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
192598cd9ca7SRichard Henderson         ctx->null_lab = NULL;
192631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
192798cd9ca7SRichard Henderson     } else {
192831234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
192998cd9ca7SRichard Henderson     }
193001afb7beSRichard Henderson     return true;
193198cd9ca7SRichard Henderson }
193298cd9ca7SRichard Henderson 
1933bc921866SRichard Henderson /*
1934bc921866SRichard Henderson  * Emit an unconditional branch to an indirect target, in ctx->iaq_j.
1935bc921866SRichard Henderson  * This handles nullification of the branch itself.
1936bc921866SRichard Henderson  */
1937bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link,
1938bc921866SRichard Henderson                        bool with_sr0, bool is_n)
193998cd9ca7SRichard Henderson {
1940d582c1faSRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1941019f4159SRichard Henderson         install_link(ctx, link, with_sr0);
194298cd9ca7SRichard Henderson         if (is_n) {
1943c301f34eSRichard Henderson             if (use_nullify_skip(ctx)) {
1944bc921866SRichard Henderson                 install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1945c301f34eSRichard Henderson                 nullify_set(ctx, 0);
194631234768SRichard Henderson                 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
194701afb7beSRichard Henderson                 return true;
1948c301f34eSRichard Henderson             }
194998cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
195098cd9ca7SRichard Henderson         }
1951bc921866SRichard Henderson         ctx->iaq_n = &ctx->iaq_j;
1952d582c1faSRichard Henderson         return true;
1953d582c1faSRichard Henderson     }
195498cd9ca7SRichard Henderson 
1955d582c1faSRichard Henderson     nullify_over(ctx);
1956d582c1faSRichard Henderson 
1957019f4159SRichard Henderson     install_link(ctx, link, with_sr0);
1958d582c1faSRichard Henderson     if (is_n && use_nullify_skip(ctx)) {
1959bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_j, NULL);
1960d582c1faSRichard Henderson         nullify_set(ctx, 0);
1961d582c1faSRichard Henderson     } else {
1962bc921866SRichard Henderson         install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j);
1963d582c1faSRichard Henderson         nullify_set(ctx, is_n);
1964d582c1faSRichard Henderson     }
1965d582c1faSRichard Henderson 
19667f11636dSEmilio G. Cota     tcg_gen_lookup_and_goto_ptr();
1967d582c1faSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
196801afb7beSRichard Henderson     return nullify_end(ctx);
196998cd9ca7SRichard Henderson }
197098cd9ca7SRichard Henderson 
1971660eefe1SRichard Henderson /* Implement
1972660eefe1SRichard Henderson  *    if (IAOQ_Front{30..31} < GR[b]{30..31})
1973660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← GR[b]{30..31};
1974660eefe1SRichard Henderson  *    else
1975660eefe1SRichard Henderson  *      IAOQ_Next{30..31} ← IAOQ_Front{30..31};
1976660eefe1SRichard Henderson  * which keeps the privilege level from being increased.
1977660eefe1SRichard Henderson  */
19786fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset)
1979660eefe1SRichard Henderson {
19801874e6c2SRichard Henderson     TCGv_i64 dest = tcg_temp_new_i64();
1981660eefe1SRichard Henderson     switch (ctx->privilege) {
1982660eefe1SRichard Henderson     case 0:
1983660eefe1SRichard Henderson         /* Privilege 0 is maximum and is allowed to decrease.  */
19841874e6c2SRichard Henderson         tcg_gen_mov_i64(dest, offset);
19851874e6c2SRichard Henderson         break;
1986660eefe1SRichard Henderson     case 3:
1987993119feSRichard Henderson         /* Privilege 3 is minimum and is never allowed to increase.  */
19886fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, offset, 3);
1989660eefe1SRichard Henderson         break;
1990660eefe1SRichard Henderson     default:
19916fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, offset, -4);
19926fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, ctx->privilege);
19930bb02029SRichard Henderson         tcg_gen_umax_i64(dest, dest, offset);
1994660eefe1SRichard Henderson         break;
1995660eefe1SRichard Henderson     }
1996660eefe1SRichard Henderson     return dest;
1997660eefe1SRichard Henderson }
1998660eefe1SRichard Henderson 
1999ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
20007ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
20017ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
20027ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
20037ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
20047ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
20057ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
20067ad439dfSRichard Henderson    aforementioned BE.  */
200731234768SRichard Henderson static void do_page_zero(DisasContext *ctx)
20087ad439dfSRichard Henderson {
20090d89cb7cSRichard Henderson     assert(ctx->iaq_f.disp == 0);
20100d89cb7cSRichard Henderson 
20117ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
20127ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
20138b81968cSMichael Tokarev        next insn within the privileged page.  */
20147ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
20157ad439dfSRichard Henderson     case TCG_COND_NEVER:
20167ad439dfSRichard Henderson         break;
20177ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
20186fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cpu_psw_n, 0);
20197ad439dfSRichard Henderson         goto do_sigill;
20207ad439dfSRichard Henderson     default:
20217ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
20227ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
20237ad439dfSRichard Henderson         g_assert_not_reached();
20247ad439dfSRichard Henderson     }
20257ad439dfSRichard Henderson 
20267ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
20277ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
20287ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
20297ad439dfSRichard Henderson        under such conditions.  */
20300d89cb7cSRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) {
20317ad439dfSRichard Henderson         goto do_sigill;
20327ad439dfSRichard Henderson     }
20337ad439dfSRichard Henderson 
20340d89cb7cSRichard Henderson     switch (ctx->base.pc_first) {
20357ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
20362986721dSRichard Henderson         gen_excp_1(EXCP_IMP);
203731234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
203831234768SRichard Henderson         break;
20397ad439dfSRichard Henderson 
20407ad439dfSRichard Henderson     case 0xb0: /* LWS */
20417ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
204231234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
204331234768SRichard Henderson         break;
20447ad439dfSRichard Henderson 
20457ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
2046bc921866SRichard Henderson         {
2047bc921866SRichard Henderson             DisasIAQE next = { .base = tcg_temp_new_i64() };
2048bc921866SRichard Henderson 
2049bc921866SRichard Henderson             tcg_gen_st_i64(cpu_gr[26], tcg_env,
2050bc921866SRichard Henderson                            offsetof(CPUHPPAState, cr[27]));
20513c13b0ffSRichard Henderson             tcg_gen_ori_i64(next.base, cpu_gr[31], PRIV_USER);
2052bc921866SRichard Henderson             install_iaq_entries(ctx, &next, NULL);
205331234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
2054bc921866SRichard Henderson         }
205531234768SRichard Henderson         break;
20567ad439dfSRichard Henderson 
20577ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
20587ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
205931234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
206031234768SRichard Henderson         break;
20617ad439dfSRichard Henderson 
20627ad439dfSRichard Henderson     default:
20637ad439dfSRichard Henderson     do_sigill:
20642986721dSRichard Henderson         gen_excp_1(EXCP_ILL);
206531234768SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
206631234768SRichard Henderson         break;
20677ad439dfSRichard Henderson     }
20687ad439dfSRichard Henderson }
2069ba1d0b44SRichard Henderson #endif
20707ad439dfSRichard Henderson 
2071deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a)
2072b2167459SRichard Henderson {
2073e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
207431234768SRichard Henderson     return true;
2075b2167459SRichard Henderson }
2076b2167459SRichard Henderson 
207740f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a)
207898a9cb79SRichard Henderson {
207931234768SRichard Henderson     return gen_excp_iir(ctx, EXCP_BREAK);
208098a9cb79SRichard Henderson }
208198a9cb79SRichard Henderson 
2082e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a)
208398a9cb79SRichard Henderson {
208498a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
208598a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
208698a9cb79SRichard Henderson 
2087e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
208831234768SRichard Henderson     return true;
208998a9cb79SRichard Henderson }
209098a9cb79SRichard Henderson 
2091c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a)
209298a9cb79SRichard Henderson {
2093bc921866SRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
209498a9cb79SRichard Henderson 
2095bc921866SRichard Henderson     copy_iaoq_entry(ctx, dest, &ctx->iaq_f);
2096bc921866SRichard Henderson     tcg_gen_andi_i64(dest, dest, -4);
2097bc921866SRichard Henderson 
2098bc921866SRichard Henderson     save_gpr(ctx, a->t, dest);
2099e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
210031234768SRichard Henderson     return true;
210198a9cb79SRichard Henderson }
210298a9cb79SRichard Henderson 
2103c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a)
210498a9cb79SRichard Henderson {
2105c603e14aSRichard Henderson     unsigned rt = a->t;
2106c603e14aSRichard Henderson     unsigned rs = a->sp;
210733423472SRichard Henderson     TCGv_i64 t0 = tcg_temp_new_i64();
210898a9cb79SRichard Henderson 
210933423472SRichard Henderson     load_spr(ctx, t0, rs);
211033423472SRichard Henderson     tcg_gen_shri_i64(t0, t0, 32);
211133423472SRichard Henderson 
2112967662cdSRichard Henderson     save_gpr(ctx, rt, t0);
211398a9cb79SRichard Henderson 
2114e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
211531234768SRichard Henderson     return true;
211698a9cb79SRichard Henderson }
211798a9cb79SRichard Henderson 
2118c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a)
211998a9cb79SRichard Henderson {
2120c603e14aSRichard Henderson     unsigned rt = a->t;
2121c603e14aSRichard Henderson     unsigned ctl = a->r;
21226fd0c7bcSRichard Henderson     TCGv_i64 tmp;
212398a9cb79SRichard Henderson 
212498a9cb79SRichard Henderson     switch (ctl) {
212535136a77SRichard Henderson     case CR_SAR:
2126c603e14aSRichard Henderson         if (a->e == 0) {
212798a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
212898a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
21296fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
213098a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
213135136a77SRichard Henderson             goto done;
213298a9cb79SRichard Henderson         }
213398a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
213435136a77SRichard Henderson         goto done;
213535136a77SRichard Henderson     case CR_IT: /* Interval Timer */
213635136a77SRichard Henderson         /* FIXME: Respect PSW_S bit.  */
213735136a77SRichard Henderson         nullify_over(ctx);
213898a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
2139dfd1b812SRichard Henderson         if (translator_io_start(&ctx->base)) {
214031234768SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
214149c29d6cSRichard Henderson         }
21420c58c1bcSRichard Henderson         gen_helper_read_interval_timer(tmp);
214398a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
214431234768SRichard Henderson         return nullify_end(ctx);
214598a9cb79SRichard Henderson     case 26:
214698a9cb79SRichard Henderson     case 27:
214798a9cb79SRichard Henderson         break;
214898a9cb79SRichard Henderson     default:
214998a9cb79SRichard Henderson         /* All other control registers are privileged.  */
215035136a77SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
215135136a77SRichard Henderson         break;
215298a9cb79SRichard Henderson     }
215398a9cb79SRichard Henderson 
2154aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
21556fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
215635136a77SRichard Henderson     save_gpr(ctx, rt, tmp);
215735136a77SRichard Henderson 
215835136a77SRichard Henderson  done:
2159e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
216031234768SRichard Henderson     return true;
216198a9cb79SRichard Henderson }
216298a9cb79SRichard Henderson 
2163c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
216433423472SRichard Henderson {
2165c603e14aSRichard Henderson     unsigned rr = a->r;
2166c603e14aSRichard Henderson     unsigned rs = a->sp;
2167967662cdSRichard Henderson     TCGv_i64 tmp;
216833423472SRichard Henderson 
216933423472SRichard Henderson     if (rs >= 5) {
217033423472SRichard Henderson         CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
217133423472SRichard Henderson     }
217233423472SRichard Henderson     nullify_over(ctx);
217333423472SRichard Henderson 
2174967662cdSRichard Henderson     tmp = tcg_temp_new_i64();
2175967662cdSRichard Henderson     tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32);
217633423472SRichard Henderson 
217733423472SRichard Henderson     if (rs >= 4) {
2178967662cdSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs]));
2179494737b7SRichard Henderson         ctx->tb_flags &= ~TB_FLAG_SR_SAME;
218033423472SRichard Henderson     } else {
2181967662cdSRichard Henderson         tcg_gen_mov_i64(cpu_sr[rs], tmp);
218233423472SRichard Henderson     }
218333423472SRichard Henderson 
218431234768SRichard Henderson     return nullify_end(ctx);
218533423472SRichard Henderson }
218633423472SRichard Henderson 
2187c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
218898a9cb79SRichard Henderson {
2189c603e14aSRichard Henderson     unsigned ctl = a->t;
21906fd0c7bcSRichard Henderson     TCGv_i64 reg;
21916fd0c7bcSRichard Henderson     TCGv_i64 tmp;
219298a9cb79SRichard Henderson 
219335136a77SRichard Henderson     if (ctl == CR_SAR) {
21944845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
2195aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
21966fd0c7bcSRichard Henderson         tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31);
219798a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
219898a9cb79SRichard Henderson 
2199e0137378SRichard Henderson         ctx->null_cond = cond_make_f();
220031234768SRichard Henderson         return true;
220198a9cb79SRichard Henderson     }
220298a9cb79SRichard Henderson 
220335136a77SRichard Henderson     /* All other control registers are privileged or read-only.  */
220435136a77SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG);
220535136a77SRichard Henderson 
2206c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
220735136a77SRichard Henderson     nullify_over(ctx);
22084c34bab0SHelge Deller 
22094c34bab0SHelge Deller     if (ctx->is_pa20) {
22104845f015SSven Schnelle         reg = load_gpr(ctx, a->r);
22114c34bab0SHelge Deller     } else {
22124c34bab0SHelge Deller         reg = tcg_temp_new_i64();
22134c34bab0SHelge Deller         tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r));
22144c34bab0SHelge Deller     }
22154845f015SSven Schnelle 
221635136a77SRichard Henderson     switch (ctl) {
221735136a77SRichard Henderson     case CR_IT:
2218104281c1SRichard Henderson         if (translator_io_start(&ctx->base)) {
2219104281c1SRichard Henderson             ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2220104281c1SRichard Henderson         }
2221ad75a51eSRichard Henderson         gen_helper_write_interval_timer(tcg_env, reg);
222235136a77SRichard Henderson         break;
22234f5f2548SRichard Henderson     case CR_EIRR:
22246ebebea7SRichard Henderson         /* Helper modifies interrupt lines and is therefore IO. */
22256ebebea7SRichard Henderson         translator_io_start(&ctx->base);
2226ad75a51eSRichard Henderson         gen_helper_write_eirr(tcg_env, reg);
22276ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
222831234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22294f5f2548SRichard Henderson         break;
22304f5f2548SRichard Henderson 
223135136a77SRichard Henderson     case CR_IIASQ:
223235136a77SRichard Henderson     case CR_IIAOQ:
223335136a77SRichard Henderson         /* FIXME: Respect PSW_Q bit */
223435136a77SRichard Henderson         /* The write advances the queue and stores to the back element.  */
2235aac0f603SRichard Henderson         tmp = tcg_temp_new_i64();
22366fd0c7bcSRichard Henderson         tcg_gen_ld_i64(tmp, tcg_env,
223735136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
22386fd0c7bcSRichard Henderson         tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
22396fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env,
224035136a77SRichard Henderson                        offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ]));
224135136a77SRichard Henderson         break;
224235136a77SRichard Henderson 
2243d5de20bdSSven Schnelle     case CR_PID1:
2244d5de20bdSSven Schnelle     case CR_PID2:
2245d5de20bdSSven Schnelle     case CR_PID3:
2246d5de20bdSSven Schnelle     case CR_PID4:
22476fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
2248d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY
2249ad75a51eSRichard Henderson         gen_helper_change_prot_id(tcg_env);
2250d5de20bdSSven Schnelle #endif
2251d5de20bdSSven Schnelle         break;
2252d5de20bdSSven Schnelle 
22536ebebea7SRichard Henderson     case CR_EIEM:
22546ebebea7SRichard Henderson         /* Exit to re-evaluate interrupts in the main loop. */
22556ebebea7SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
22566ebebea7SRichard Henderson         /* FALLTHRU */
225735136a77SRichard Henderson     default:
22586fd0c7bcSRichard Henderson         tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl]));
225935136a77SRichard Henderson         break;
226035136a77SRichard Henderson     }
226131234768SRichard Henderson     return nullify_end(ctx);
22624f5f2548SRichard Henderson #endif
226335136a77SRichard Henderson }
226435136a77SRichard Henderson 
2265c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a)
226698a9cb79SRichard Henderson {
2267aac0f603SRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
226898a9cb79SRichard Henderson 
22696fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, load_gpr(ctx, a->r));
22706fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31);
227198a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
227298a9cb79SRichard Henderson 
2273e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
227431234768SRichard Henderson     return true;
227598a9cb79SRichard Henderson }
227698a9cb79SRichard Henderson 
2277e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a)
227898a9cb79SRichard Henderson {
22796fd0c7bcSRichard Henderson     TCGv_i64 dest = dest_gpr(ctx, a->t);
228098a9cb79SRichard Henderson 
22812330504cSHelge Deller #ifdef CONFIG_USER_ONLY
22822330504cSHelge Deller     /* We don't implement space registers in user mode. */
22836fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, 0);
22842330504cSHelge Deller #else
2285967662cdSRichard Henderson     tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b)));
2286967662cdSRichard Henderson     tcg_gen_shri_i64(dest, dest, 32);
22872330504cSHelge Deller #endif
2288e36f27efSRichard Henderson     save_gpr(ctx, a->t, dest);
228998a9cb79SRichard Henderson 
2290e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
229131234768SRichard Henderson     return true;
229298a9cb79SRichard Henderson }
229398a9cb79SRichard Henderson 
2294e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a)
2295e36f27efSRichard Henderson {
22967b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY
2297e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
22987b2d70a1SHelge Deller #else
22996fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2300e1b5a5edSRichard Henderson 
23017b2d70a1SHelge Deller     /* HP-UX 11i and HP ODE use rsm for read-access to PSW */
23027b2d70a1SHelge Deller     if (a->i) {
23037b2d70a1SHelge Deller         CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
23047b2d70a1SHelge Deller     }
23057b2d70a1SHelge Deller 
2306e1b5a5edSRichard Henderson     nullify_over(ctx);
2307e1b5a5edSRichard Henderson 
2308aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23096fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23106fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, ~a->i);
2311ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2312e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2313e1b5a5edSRichard Henderson 
2314e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_M.  */
231531234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
231631234768SRichard Henderson     return nullify_end(ctx);
2317e36f27efSRichard Henderson #endif
2318e1b5a5edSRichard Henderson }
2319e1b5a5edSRichard Henderson 
2320e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a)
2321e1b5a5edSRichard Henderson {
2322e36f27efSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2323e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
23246fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2325e1b5a5edSRichard Henderson 
2326e1b5a5edSRichard Henderson     nullify_over(ctx);
2327e1b5a5edSRichard Henderson 
2328aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
23296fd0c7bcSRichard Henderson     tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw));
23306fd0c7bcSRichard Henderson     tcg_gen_ori_i64(tmp, tmp, a->i);
2331ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, tmp);
2332e36f27efSRichard Henderson     save_gpr(ctx, a->t, tmp);
2333e1b5a5edSRichard Henderson 
2334e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts, e.g. PSW_I.  */
233531234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
233631234768SRichard Henderson     return nullify_end(ctx);
2337e36f27efSRichard Henderson #endif
2338e1b5a5edSRichard Henderson }
2339e1b5a5edSRichard Henderson 
2340c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a)
2341e1b5a5edSRichard Henderson {
2342e1b5a5edSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2343c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY
23446fd0c7bcSRichard Henderson     TCGv_i64 tmp, reg;
2345e1b5a5edSRichard Henderson     nullify_over(ctx);
2346e1b5a5edSRichard Henderson 
2347c603e14aSRichard Henderson     reg = load_gpr(ctx, a->r);
2348aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2349ad75a51eSRichard Henderson     gen_helper_swap_system_mask(tmp, tcg_env, reg);
2350e1b5a5edSRichard Henderson 
2351e1b5a5edSRichard Henderson     /* Exit the TB to recognize new interrupts.  */
235231234768SRichard Henderson     ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT;
235331234768SRichard Henderson     return nullify_end(ctx);
2354c603e14aSRichard Henderson #endif
2355e1b5a5edSRichard Henderson }
2356f49b3537SRichard Henderson 
2357e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r)
2358f49b3537SRichard Henderson {
2359f49b3537SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2360e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY
2361f49b3537SRichard Henderson     nullify_over(ctx);
2362f49b3537SRichard Henderson 
2363e36f27efSRichard Henderson     if (rfi_r) {
2364ad75a51eSRichard Henderson         gen_helper_rfi_r(tcg_env);
2365f49b3537SRichard Henderson     } else {
2366ad75a51eSRichard Henderson         gen_helper_rfi(tcg_env);
2367f49b3537SRichard Henderson     }
236831234768SRichard Henderson     /* Exit the TB to recognize new interrupts.  */
236907ea28b4SRichard Henderson     tcg_gen_exit_tb(NULL, 0);
237031234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
2371f49b3537SRichard Henderson 
237231234768SRichard Henderson     return nullify_end(ctx);
2373e36f27efSRichard Henderson #endif
2374f49b3537SRichard Henderson }
23756210db05SHelge Deller 
2376e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a)
2377e36f27efSRichard Henderson {
2378e36f27efSRichard Henderson     return do_rfi(ctx, false);
2379e36f27efSRichard Henderson }
2380e36f27efSRichard Henderson 
2381e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a)
2382e36f27efSRichard Henderson {
2383e36f27efSRichard Henderson     return do_rfi(ctx, true);
2384e36f27efSRichard Henderson }
2385e36f27efSRichard Henderson 
238696927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a)
23876210db05SHelge Deller {
23886210db05SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
238996927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
23906210db05SHelge Deller     nullify_over(ctx);
2391ad75a51eSRichard Henderson     gen_helper_halt(tcg_env);
239231234768SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
239331234768SRichard Henderson     return nullify_end(ctx);
239496927adbSRichard Henderson #endif
23956210db05SHelge Deller }
239696927adbSRichard Henderson 
239796927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a)
239896927adbSRichard Henderson {
239996927adbSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
240096927adbSRichard Henderson #ifndef CONFIG_USER_ONLY
240196927adbSRichard Henderson     nullify_over(ctx);
2402ad75a51eSRichard Henderson     gen_helper_reset(tcg_env);
240396927adbSRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
240496927adbSRichard Henderson     return nullify_end(ctx);
240596927adbSRichard Henderson #endif
240696927adbSRichard Henderson }
2407e1b5a5edSRichard Henderson 
2408558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx)
24094a4554c6SHelge Deller {
24104a4554c6SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24114a4554c6SHelge Deller     nullify_over(ctx);
2412558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
2413558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
2414558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
2415558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
2416558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
2417558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
2418558c09beSRichard Henderson     tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24194a4554c6SHelge Deller     return nullify_end(ctx);
2420558c09beSRichard Henderson }
2421558c09beSRichard Henderson 
24223bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx)
24233bdf2081SHelge Deller {
24243bdf2081SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
24253bdf2081SHelge Deller     nullify_over(ctx);
24263bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0]));
24273bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1]));
24283bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2]));
24293bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3]));
24303bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4]));
24313bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5]));
24323bdf2081SHelge Deller     tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6]));
24333bdf2081SHelge Deller     return nullify_end(ctx);
24343bdf2081SHelge Deller }
24353bdf2081SHelge Deller 
2436558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
2437558c09beSRichard Henderson {
2438558c09beSRichard Henderson     return do_getshadowregs(ctx);
24394a4554c6SHelge Deller }
24404a4554c6SHelge Deller 
2441deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
244298a9cb79SRichard Henderson {
2443deee69a1SRichard Henderson     if (a->m) {
24446fd0c7bcSRichard Henderson         TCGv_i64 dest = dest_gpr(ctx, a->b);
24456fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->b);
24466fd0c7bcSRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->x);
244798a9cb79SRichard Henderson 
244898a9cb79SRichard Henderson         /* The only thing we need to do is the base register modification.  */
24496fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, src1, src2);
2450deee69a1SRichard Henderson         save_gpr(ctx, a->b, dest);
2451deee69a1SRichard Henderson     }
2452e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
245331234768SRichard Henderson     return true;
245498a9cb79SRichard Henderson }
245598a9cb79SRichard Henderson 
2456ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a)
2457ad1fdacdSSven Schnelle {
2458ad1fdacdSSven Schnelle     /* End TB for flush instruction cache, so we pick up new insns. */
2459ad1fdacdSSven Schnelle     ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2460ad1fdacdSSven Schnelle     return trans_nop_addrx(ctx, a);
2461ad1fdacdSSven Schnelle }
2462ad1fdacdSSven Schnelle 
2463deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a)
246498a9cb79SRichard Henderson {
24656fd0c7bcSRichard Henderson     TCGv_i64 dest, ofs;
2466eed14219SRichard Henderson     TCGv_i32 level, want;
24676fd0c7bcSRichard Henderson     TCGv_i64 addr;
246898a9cb79SRichard Henderson 
246998a9cb79SRichard Henderson     nullify_over(ctx);
247098a9cb79SRichard Henderson 
2471deee69a1SRichard Henderson     dest = dest_gpr(ctx, a->t);
2472deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2473eed14219SRichard Henderson 
2474deee69a1SRichard Henderson     if (a->imm) {
2475e5d487c9SRichard Henderson         level = tcg_constant_i32(a->ri & 3);
247698a9cb79SRichard Henderson     } else {
2477eed14219SRichard Henderson         level = tcg_temp_new_i32();
24786fd0c7bcSRichard Henderson         tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri));
2479eed14219SRichard Henderson         tcg_gen_andi_i32(level, level, 3);
248098a9cb79SRichard Henderson     }
248129dd6f64SRichard Henderson     want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ);
2482eed14219SRichard Henderson 
2483ad75a51eSRichard Henderson     gen_helper_probe(dest, tcg_env, addr, level, want);
2484eed14219SRichard Henderson 
2485deee69a1SRichard Henderson     save_gpr(ctx, a->t, dest);
248631234768SRichard Henderson     return nullify_end(ctx);
248798a9cb79SRichard Henderson }
248898a9cb79SRichard Henderson 
2489deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
24908d6ae7fbSRichard Henderson {
24918577f354SRichard Henderson     if (ctx->is_pa20) {
24928577f354SRichard Henderson         return false;
24938577f354SRichard Henderson     }
2494deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2495deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
24966fd0c7bcSRichard Henderson     TCGv_i64 addr;
24976fd0c7bcSRichard Henderson     TCGv_i64 ofs, reg;
24988d6ae7fbSRichard Henderson 
24998d6ae7fbSRichard Henderson     nullify_over(ctx);
25008d6ae7fbSRichard Henderson 
2501deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
2502deee69a1SRichard Henderson     reg = load_gpr(ctx, a->r);
2503deee69a1SRichard Henderson     if (a->addr) {
25048577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
25058d6ae7fbSRichard Henderson     } else {
25068577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
25078d6ae7fbSRichard Henderson     }
25088d6ae7fbSRichard Henderson 
250932dc7569SSven Schnelle     /* Exit TB for TLB change if mmu is enabled.  */
251032dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
251131234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
251231234768SRichard Henderson     }
251331234768SRichard Henderson     return nullify_end(ctx);
2514deee69a1SRichard Henderson #endif
25158d6ae7fbSRichard Henderson }
251663300a00SRichard Henderson 
2517eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local)
251863300a00SRichard Henderson {
2519deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2520deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
25216fd0c7bcSRichard Henderson     TCGv_i64 addr;
25226fd0c7bcSRichard Henderson     TCGv_i64 ofs;
252363300a00SRichard Henderson 
252463300a00SRichard Henderson     nullify_over(ctx);
252563300a00SRichard Henderson 
2526deee69a1SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
2527eb25d10fSHelge Deller 
2528eb25d10fSHelge Deller     /*
2529eb25d10fSHelge Deller      * Page align now, rather than later, so that we can add in the
2530eb25d10fSHelge Deller      * page_size field from pa2.0 from the low 4 bits of GR[b].
2531eb25d10fSHelge Deller      */
2532eb25d10fSHelge Deller     tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK);
2533eb25d10fSHelge Deller     if (ctx->is_pa20) {
2534eb25d10fSHelge Deller         tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4);
253563300a00SRichard Henderson     }
2536eb25d10fSHelge Deller 
2537eb25d10fSHelge Deller     if (local) {
2538eb25d10fSHelge Deller         gen_helper_ptlb_l(tcg_env, addr);
253963300a00SRichard Henderson     } else {
2540ad75a51eSRichard Henderson         gen_helper_ptlb(tcg_env, addr);
254163300a00SRichard Henderson     }
254263300a00SRichard Henderson 
2543eb25d10fSHelge Deller     if (a->m) {
2544eb25d10fSHelge Deller         save_gpr(ctx, a->b, ofs);
2545eb25d10fSHelge Deller     }
2546eb25d10fSHelge Deller 
2547eb25d10fSHelge Deller     /* Exit TB for TLB change if mmu is enabled.  */
2548eb25d10fSHelge Deller     if (ctx->tb_flags & PSW_C) {
2549eb25d10fSHelge Deller         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
2550eb25d10fSHelge Deller     }
2551eb25d10fSHelge Deller     return nullify_end(ctx);
2552eb25d10fSHelge Deller #endif
2553eb25d10fSHelge Deller }
2554eb25d10fSHelge Deller 
2555eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a)
2556eb25d10fSHelge Deller {
2557eb25d10fSHelge Deller     return do_pxtlb(ctx, a, false);
2558eb25d10fSHelge Deller }
2559eb25d10fSHelge Deller 
2560eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a)
2561eb25d10fSHelge Deller {
2562eb25d10fSHelge Deller     return ctx->is_pa20 && do_pxtlb(ctx, a, true);
2563eb25d10fSHelge Deller }
2564eb25d10fSHelge Deller 
2565eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a)
2566eb25d10fSHelge Deller {
2567eb25d10fSHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2568eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY
2569eb25d10fSHelge Deller     nullify_over(ctx);
2570eb25d10fSHelge Deller 
2571eb25d10fSHelge Deller     trans_nop_addrx(ctx, a);
2572eb25d10fSHelge Deller     gen_helper_ptlbe(tcg_env);
2573eb25d10fSHelge Deller 
257463300a00SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
257532dc7569SSven Schnelle     if (ctx->tb_flags & PSW_C) {
257631234768SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
257731234768SRichard Henderson     }
257831234768SRichard Henderson     return nullify_end(ctx);
2579deee69a1SRichard Henderson #endif
258063300a00SRichard Henderson }
25812dfcca9fSRichard Henderson 
25826797c315SNick Hudson /*
25836797c315SNick Hudson  * Implement the pcxl and pcxl2 Fast TLB Insert instructions.
25846797c315SNick Hudson  * See
25856797c315SNick Hudson  *     https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf
25866797c315SNick Hudson  *     page 13-9 (195/206)
25876797c315SNick Hudson  */
25886797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
25896797c315SNick Hudson {
25908577f354SRichard Henderson     if (ctx->is_pa20) {
25918577f354SRichard Henderson         return false;
25928577f354SRichard Henderson     }
25936797c315SNick Hudson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
25946797c315SNick Hudson #ifndef CONFIG_USER_ONLY
25956fd0c7bcSRichard Henderson     TCGv_i64 addr, atl, stl;
25966fd0c7bcSRichard Henderson     TCGv_i64 reg;
25976797c315SNick Hudson 
25986797c315SNick Hudson     nullify_over(ctx);
25996797c315SNick Hudson 
26006797c315SNick Hudson     /*
26016797c315SNick Hudson      * FIXME:
26026797c315SNick Hudson      *  if (not (pcxl or pcxl2))
26036797c315SNick Hudson      *    return gen_illegal(ctx);
26046797c315SNick Hudson      */
26056797c315SNick Hudson 
26066fd0c7bcSRichard Henderson     atl = tcg_temp_new_i64();
26076fd0c7bcSRichard Henderson     stl = tcg_temp_new_i64();
26086fd0c7bcSRichard Henderson     addr = tcg_temp_new_i64();
26096797c315SNick Hudson 
2610ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(stl, tcg_env,
26116797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_ISR])
26126797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIASQ]));
2613ad75a51eSRichard Henderson     tcg_gen_ld32u_i64(atl, tcg_env,
26146797c315SNick Hudson                       a->data ? offsetof(CPUHPPAState, cr[CR_IOR])
26156797c315SNick Hudson                       : offsetof(CPUHPPAState, cr[CR_IIAOQ]));
26166797c315SNick Hudson     tcg_gen_shli_i64(stl, stl, 32);
2617d265360fSRichard Henderson     tcg_gen_or_i64(addr, atl, stl);
26186797c315SNick Hudson 
26196797c315SNick Hudson     reg = load_gpr(ctx, a->r);
26206797c315SNick Hudson     if (a->addr) {
26218577f354SRichard Henderson         gen_helper_itlba_pa11(tcg_env, addr, reg);
26226797c315SNick Hudson     } else {
26238577f354SRichard Henderson         gen_helper_itlbp_pa11(tcg_env, addr, reg);
26246797c315SNick Hudson     }
26256797c315SNick Hudson 
26266797c315SNick Hudson     /* Exit TB for TLB change if mmu is enabled.  */
26276797c315SNick Hudson     if (ctx->tb_flags & PSW_C) {
26286797c315SNick Hudson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26296797c315SNick Hudson     }
26306797c315SNick Hudson     return nullify_end(ctx);
26316797c315SNick Hudson #endif
26326797c315SNick Hudson }
26336797c315SNick Hudson 
26348577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
26358577f354SRichard Henderson {
26368577f354SRichard Henderson     if (!ctx->is_pa20) {
26378577f354SRichard Henderson         return false;
26388577f354SRichard Henderson     }
26398577f354SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
26408577f354SRichard Henderson #ifndef CONFIG_USER_ONLY
26418577f354SRichard Henderson     nullify_over(ctx);
26428577f354SRichard Henderson     {
26438577f354SRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
26448577f354SRichard Henderson         TCGv_i64 src2 = load_gpr(ctx, a->r2);
26458577f354SRichard Henderson 
26468577f354SRichard Henderson         if (a->data) {
26478577f354SRichard Henderson             gen_helper_idtlbt_pa20(tcg_env, src1, src2);
26488577f354SRichard Henderson         } else {
26498577f354SRichard Henderson             gen_helper_iitlbt_pa20(tcg_env, src1, src2);
26508577f354SRichard Henderson         }
26518577f354SRichard Henderson     }
26528577f354SRichard Henderson     /* Exit TB for TLB change if mmu is enabled.  */
26538577f354SRichard Henderson     if (ctx->tb_flags & PSW_C) {
26548577f354SRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
26558577f354SRichard Henderson     }
26568577f354SRichard Henderson     return nullify_end(ctx);
26578577f354SRichard Henderson #endif
26588577f354SRichard Henderson }
26598577f354SRichard Henderson 
2660deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
26612dfcca9fSRichard Henderson {
2662deee69a1SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
2663deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY
26646fd0c7bcSRichard Henderson     TCGv_i64 vaddr;
26656fd0c7bcSRichard Henderson     TCGv_i64 ofs, paddr;
26662dfcca9fSRichard Henderson 
26672dfcca9fSRichard Henderson     nullify_over(ctx);
26682dfcca9fSRichard Henderson 
2669deee69a1SRichard Henderson     form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false);
26702dfcca9fSRichard Henderson 
2671aac0f603SRichard Henderson     paddr = tcg_temp_new_i64();
2672ad75a51eSRichard Henderson     gen_helper_lpa(paddr, tcg_env, vaddr);
26732dfcca9fSRichard Henderson 
26742dfcca9fSRichard Henderson     /* Note that physical address result overrides base modification.  */
2675deee69a1SRichard Henderson     if (a->m) {
2676deee69a1SRichard Henderson         save_gpr(ctx, a->b, ofs);
26772dfcca9fSRichard Henderson     }
2678deee69a1SRichard Henderson     save_gpr(ctx, a->t, paddr);
26792dfcca9fSRichard Henderson 
268031234768SRichard Henderson     return nullify_end(ctx);
2681deee69a1SRichard Henderson #endif
26822dfcca9fSRichard Henderson }
268343a97b81SRichard Henderson 
2684deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a)
268543a97b81SRichard Henderson {
268643a97b81SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
268743a97b81SRichard Henderson 
268843a97b81SRichard Henderson     /* The Coherence Index is an implementation-defined function of the
268943a97b81SRichard Henderson        physical address.  Two addresses with the same CI have a coherent
269043a97b81SRichard Henderson        view of the cache.  Our implementation is to return 0 for all,
269143a97b81SRichard Henderson        since the entire address space is coherent.  */
2692a4db4a78SRichard Henderson     save_gpr(ctx, a->t, ctx->zero);
269343a97b81SRichard Henderson 
2694e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
269531234768SRichard Henderson     return true;
269643a97b81SRichard Henderson }
269798a9cb79SRichard Henderson 
2698faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2699b2167459SRichard Henderson {
27000c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, false);
2701b2167459SRichard Henderson }
2702b2167459SRichard Henderson 
2703faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2704b2167459SRichard Henderson {
27050c982a28SRichard Henderson     return do_add_reg(ctx, a, true, false, false, false);
2706b2167459SRichard Henderson }
2707b2167459SRichard Henderson 
2708faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2709b2167459SRichard Henderson {
27100c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, false);
2711b2167459SRichard Henderson }
2712b2167459SRichard Henderson 
2713faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a)
2714b2167459SRichard Henderson {
27150c982a28SRichard Henderson     return do_add_reg(ctx, a, false, false, false, true);
27160c982a28SRichard Henderson }
2717b2167459SRichard Henderson 
2718faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a)
27190c982a28SRichard Henderson {
27200c982a28SRichard Henderson     return do_add_reg(ctx, a, false, true, false, true);
27210c982a28SRichard Henderson }
27220c982a28SRichard Henderson 
272363c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a)
27240c982a28SRichard Henderson {
27250c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, false);
27260c982a28SRichard Henderson }
27270c982a28SRichard Henderson 
272863c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27290c982a28SRichard Henderson {
27300c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, false);
27310c982a28SRichard Henderson }
27320c982a28SRichard Henderson 
273363c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27340c982a28SRichard Henderson {
27350c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, false, true);
27360c982a28SRichard Henderson }
27370c982a28SRichard Henderson 
273863c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a)
27390c982a28SRichard Henderson {
27400c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, false, true);
27410c982a28SRichard Henderson }
27420c982a28SRichard Henderson 
274363c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a)
27440c982a28SRichard Henderson {
27450c982a28SRichard Henderson     return do_sub_reg(ctx, a, false, true, false);
27460c982a28SRichard Henderson }
27470c982a28SRichard Henderson 
274863c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a)
27490c982a28SRichard Henderson {
27500c982a28SRichard Henderson     return do_sub_reg(ctx, a, true, true, false);
27510c982a28SRichard Henderson }
27520c982a28SRichard Henderson 
2753fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a)
27540c982a28SRichard Henderson {
27556fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_andc_i64);
27560c982a28SRichard Henderson }
27570c982a28SRichard Henderson 
2758fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a)
27590c982a28SRichard Henderson {
27606fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_and_i64);
27610c982a28SRichard Henderson }
27620c982a28SRichard Henderson 
2763fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a)
27640c982a28SRichard Henderson {
27650c982a28SRichard Henderson     if (a->cf == 0) {
27660c982a28SRichard Henderson         unsigned r2 = a->r2;
27670c982a28SRichard Henderson         unsigned r1 = a->r1;
27680c982a28SRichard Henderson         unsigned rt = a->t;
27690c982a28SRichard Henderson 
27707aee8189SRichard Henderson         if (rt == 0) { /* NOP */
2771e0137378SRichard Henderson             ctx->null_cond = cond_make_f();
27727aee8189SRichard Henderson             return true;
27737aee8189SRichard Henderson         }
27747aee8189SRichard Henderson         if (r2 == 0) { /* COPY */
2775b2167459SRichard Henderson             if (r1 == 0) {
27766fd0c7bcSRichard Henderson                 TCGv_i64 dest = dest_gpr(ctx, rt);
27776fd0c7bcSRichard Henderson                 tcg_gen_movi_i64(dest, 0);
2778b2167459SRichard Henderson                 save_gpr(ctx, rt, dest);
2779b2167459SRichard Henderson             } else {
2780b2167459SRichard Henderson                 save_gpr(ctx, rt, cpu_gr[r1]);
2781b2167459SRichard Henderson             }
2782e0137378SRichard Henderson             ctx->null_cond = cond_make_f();
278331234768SRichard Henderson             return true;
2784b2167459SRichard Henderson         }
27857aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY
27867aee8189SRichard Henderson         /* These are QEMU extensions and are nops in the real architecture:
27877aee8189SRichard Henderson          *
27887aee8189SRichard Henderson          * or %r10,%r10,%r10 -- idle loop; wait for interrupt
27897aee8189SRichard Henderson          * or %r31,%r31,%r31 -- death loop; offline cpu
27907aee8189SRichard Henderson          *                      currently implemented as idle.
27917aee8189SRichard Henderson          */
27927aee8189SRichard Henderson         if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */
27937aee8189SRichard Henderson             /* No need to check for supervisor, as userland can only pause
27947aee8189SRichard Henderson                until the next timer interrupt.  */
27957aee8189SRichard Henderson             nullify_over(ctx);
27967aee8189SRichard Henderson 
27977aee8189SRichard Henderson             /* Advance the instruction queue.  */
2798bc921866SRichard Henderson             install_iaq_entries(ctx, &ctx->iaq_b, NULL);
27997aee8189SRichard Henderson             nullify_set(ctx, 0);
28007aee8189SRichard Henderson 
28017aee8189SRichard Henderson             /* Tell the qemu main loop to halt until this cpu has work.  */
2802ad75a51eSRichard Henderson             tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
280329dd6f64SRichard Henderson                            offsetof(CPUState, halted) - offsetof(HPPACPU, env));
28047aee8189SRichard Henderson             gen_excp_1(EXCP_HALTED);
28057aee8189SRichard Henderson             ctx->base.is_jmp = DISAS_NORETURN;
28067aee8189SRichard Henderson 
28077aee8189SRichard Henderson             return nullify_end(ctx);
28087aee8189SRichard Henderson         }
28097aee8189SRichard Henderson #endif
28107aee8189SRichard Henderson     }
28116fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_or_i64);
28127aee8189SRichard Henderson }
2813b2167459SRichard Henderson 
2814fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a)
2815b2167459SRichard Henderson {
28166fd0c7bcSRichard Henderson     return do_log_reg(ctx, a, tcg_gen_xor_i64);
28170c982a28SRichard Henderson }
28180c982a28SRichard Henderson 
2819345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a)
28200c982a28SRichard Henderson {
28216fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2;
2822b2167459SRichard Henderson 
28230c982a28SRichard Henderson     if (a->cf) {
2824b2167459SRichard Henderson         nullify_over(ctx);
2825b2167459SRichard Henderson     }
28260c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28270c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2828345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d);
282931234768SRichard Henderson     return nullify_end(ctx);
2830b2167459SRichard Henderson }
2831b2167459SRichard Henderson 
2832af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a)
2833b2167459SRichard Henderson {
283446bb3d46SRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, dest;
2835b2167459SRichard Henderson 
28360c982a28SRichard Henderson     if (a->cf) {
2837b2167459SRichard Henderson         nullify_over(ctx);
2838b2167459SRichard Henderson     }
283946bb3d46SRichard Henderson 
28400c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28410c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
284246bb3d46SRichard Henderson     dest = dest_gpr(ctx, a->t);
284346bb3d46SRichard Henderson 
284446bb3d46SRichard Henderson     tcg_gen_xor_i64(dest, tcg_r1, tcg_r2);
284546bb3d46SRichard Henderson     save_gpr(ctx, a->t, dest);
284646bb3d46SRichard Henderson 
284746bb3d46SRichard Henderson     ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest);
284831234768SRichard Henderson     return nullify_end(ctx);
2849b2167459SRichard Henderson }
2850b2167459SRichard Henderson 
2851af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc)
2852b2167459SRichard Henderson {
28536fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1, tcg_r2, tmp;
2854b2167459SRichard Henderson 
2855ababac16SRichard Henderson     if (a->cf == 0) {
2856ababac16SRichard Henderson         tcg_r2 = load_gpr(ctx, a->r2);
2857ababac16SRichard Henderson         tmp = dest_gpr(ctx, a->t);
2858ababac16SRichard Henderson 
2859ababac16SRichard Henderson         if (a->r1 == 0) {
2860ababac16SRichard Henderson             /* UADDCM r0,src,dst is the common idiom for dst = ~src. */
2861ababac16SRichard Henderson             tcg_gen_not_i64(tmp, tcg_r2);
2862ababac16SRichard Henderson         } else {
2863ababac16SRichard Henderson             /*
2864ababac16SRichard Henderson              * Recall that r1 - r2 == r1 + ~r2 + 1.
2865ababac16SRichard Henderson              * Thus r1 + ~r2 == r1 - r2 - 1,
2866ababac16SRichard Henderson              * which does not require an extra temporary.
2867ababac16SRichard Henderson              */
2868ababac16SRichard Henderson             tcg_r1 = load_gpr(ctx, a->r1);
2869ababac16SRichard Henderson             tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2);
2870ababac16SRichard Henderson             tcg_gen_subi_i64(tmp, tmp, 1);
2871b2167459SRichard Henderson         }
2872ababac16SRichard Henderson         save_gpr(ctx, a->t, tmp);
2873e0137378SRichard Henderson         ctx->null_cond = cond_make_f();
2874ababac16SRichard Henderson         return true;
2875ababac16SRichard Henderson     }
2876ababac16SRichard Henderson 
2877ababac16SRichard Henderson     nullify_over(ctx);
28780c982a28SRichard Henderson     tcg_r1 = load_gpr(ctx, a->r1);
28790c982a28SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r2);
2880aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
28816fd0c7bcSRichard Henderson     tcg_gen_not_i64(tmp, tcg_r2);
288246bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true);
288331234768SRichard Henderson     return nullify_end(ctx);
2884b2167459SRichard Henderson }
2885b2167459SRichard Henderson 
2886af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a)
2887b2167459SRichard Henderson {
28880c982a28SRichard Henderson     return do_uaddcm(ctx, a, false);
28890c982a28SRichard Henderson }
28900c982a28SRichard Henderson 
2891af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a)
28920c982a28SRichard Henderson {
28930c982a28SRichard Henderson     return do_uaddcm(ctx, a, true);
28940c982a28SRichard Henderson }
28950c982a28SRichard Henderson 
2896af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i)
28970c982a28SRichard Henderson {
28986fd0c7bcSRichard Henderson     TCGv_i64 tmp;
2899b2167459SRichard Henderson 
2900b2167459SRichard Henderson     nullify_over(ctx);
2901b2167459SRichard Henderson 
2902aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
2903d0ae87a2SRichard Henderson     tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4);
2904b2167459SRichard Henderson     if (!is_i) {
29056fd0c7bcSRichard Henderson         tcg_gen_not_i64(tmp, tmp);
2906b2167459SRichard Henderson     }
29076fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull);
29086fd0c7bcSRichard Henderson     tcg_gen_muli_i64(tmp, tmp, 6);
290946bb3d46SRichard Henderson     do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp,
291046bb3d46SRichard Henderson                    a->cf, a->d, false, is_i);
291131234768SRichard Henderson     return nullify_end(ctx);
2912b2167459SRichard Henderson }
2913b2167459SRichard Henderson 
2914af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a)
2915b2167459SRichard Henderson {
29160c982a28SRichard Henderson     return do_dcor(ctx, a, false);
29170c982a28SRichard Henderson }
29180c982a28SRichard Henderson 
2919af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a)
29200c982a28SRichard Henderson {
29210c982a28SRichard Henderson     return do_dcor(ctx, a, true);
29220c982a28SRichard Henderson }
29230c982a28SRichard Henderson 
29240c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a)
29250c982a28SRichard Henderson {
2926a4db4a78SRichard Henderson     TCGv_i64 dest, add1, add2, addc, in1, in2;
2927b2167459SRichard Henderson 
2928b2167459SRichard Henderson     nullify_over(ctx);
2929b2167459SRichard Henderson 
29300c982a28SRichard Henderson     in1 = load_gpr(ctx, a->r1);
29310c982a28SRichard Henderson     in2 = load_gpr(ctx, a->r2);
2932b2167459SRichard Henderson 
2933aac0f603SRichard Henderson     add1 = tcg_temp_new_i64();
2934aac0f603SRichard Henderson     add2 = tcg_temp_new_i64();
2935aac0f603SRichard Henderson     addc = tcg_temp_new_i64();
2936aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
2937b2167459SRichard Henderson 
2938b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
29396fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, in1, in1);
29406fd0c7bcSRichard Henderson     tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false));
2941b2167459SRichard Henderson 
294272ca8753SRichard Henderson     /*
294372ca8753SRichard Henderson      * Add or subtract R2, depending on PSW[V].  Proper computation of
294472ca8753SRichard Henderson      * carry requires that we subtract via + ~R2 + 1, as described in
294572ca8753SRichard Henderson      * the manual.  By extracting and masking V, we can produce the
294672ca8753SRichard Henderson      * proper inputs to the addition without movcond.
294772ca8753SRichard Henderson      */
29486fd0c7bcSRichard Henderson     tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1);
29496fd0c7bcSRichard Henderson     tcg_gen_xor_i64(add2, in2, addc);
29506fd0c7bcSRichard Henderson     tcg_gen_andi_i64(addc, addc, 1);
295172ca8753SRichard Henderson 
2952a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero);
2953a4db4a78SRichard Henderson     tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb,
2954a4db4a78SRichard Henderson                      addc, ctx->zero);
2955b2167459SRichard Henderson 
2956b2167459SRichard Henderson     /* Write back the result register.  */
29570c982a28SRichard Henderson     save_gpr(ctx, a->t, dest);
2958b2167459SRichard Henderson 
2959b2167459SRichard Henderson     /* Write back PSW[CB].  */
29606fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, add1, add2);
29616fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest);
2962b2167459SRichard Henderson 
2963f8f5986eSRichard Henderson     /*
2964f8f5986eSRichard Henderson      * Write back PSW[V] for the division step.
2965f8f5986eSRichard Henderson      * Shift cb{8} from where it lives in bit 32 to bit 31,
2966f8f5986eSRichard Henderson      * so that it overlaps r2{32} in bit 31.
2967f8f5986eSRichard Henderson      */
2968f8f5986eSRichard Henderson     tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1);
29696fd0c7bcSRichard Henderson     tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2);
2970b2167459SRichard Henderson 
2971b2167459SRichard Henderson     /* Install the new nullification.  */
29720c982a28SRichard Henderson     if (a->cf) {
2973f8f5986eSRichard Henderson         TCGv_i64 sv = NULL, uv = NULL;
2974b47a4a02SSven Schnelle         if (cond_need_sv(a->cf >> 1)) {
2975f8f5986eSRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false);
2976f8f5986eSRichard Henderson         } else if (cond_need_cb(a->cf >> 1)) {
2977f8f5986eSRichard Henderson             uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false);
2978b2167459SRichard Henderson         }
2979f8f5986eSRichard Henderson         ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv);
2980b2167459SRichard Henderson     }
2981b2167459SRichard Henderson 
298231234768SRichard Henderson     return nullify_end(ctx);
2983b2167459SRichard Henderson }
2984b2167459SRichard Henderson 
29850588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a)
2986b2167459SRichard Henderson {
29870588e061SRichard Henderson     return do_add_imm(ctx, a, false, false);
29880588e061SRichard Henderson }
29890588e061SRichard Henderson 
29900588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a)
29910588e061SRichard Henderson {
29920588e061SRichard Henderson     return do_add_imm(ctx, a, true, false);
29930588e061SRichard Henderson }
29940588e061SRichard Henderson 
29950588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a)
29960588e061SRichard Henderson {
29970588e061SRichard Henderson     return do_add_imm(ctx, a, false, true);
29980588e061SRichard Henderson }
29990588e061SRichard Henderson 
30000588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a)
30010588e061SRichard Henderson {
30020588e061SRichard Henderson     return do_add_imm(ctx, a, true, true);
30030588e061SRichard Henderson }
30040588e061SRichard Henderson 
30050588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a)
30060588e061SRichard Henderson {
30070588e061SRichard Henderson     return do_sub_imm(ctx, a, false);
30080588e061SRichard Henderson }
30090588e061SRichard Henderson 
30100588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a)
30110588e061SRichard Henderson {
30120588e061SRichard Henderson     return do_sub_imm(ctx, a, true);
30130588e061SRichard Henderson }
30140588e061SRichard Henderson 
3015345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a)
30160588e061SRichard Henderson {
30176fd0c7bcSRichard Henderson     TCGv_i64 tcg_im, tcg_r2;
3018b2167459SRichard Henderson 
30190588e061SRichard Henderson     if (a->cf) {
3020b2167459SRichard Henderson         nullify_over(ctx);
3021b2167459SRichard Henderson     }
3022b2167459SRichard Henderson 
30236fd0c7bcSRichard Henderson     tcg_im = tcg_constant_i64(a->i);
30240588e061SRichard Henderson     tcg_r2 = load_gpr(ctx, a->r);
3025345aa35fSRichard Henderson     do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d);
3026b2167459SRichard Henderson 
302731234768SRichard Henderson     return nullify_end(ctx);
3028b2167459SRichard Henderson }
3029b2167459SRichard Henderson 
30300843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a,
30310843563fSRichard Henderson                           void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64))
30320843563fSRichard Henderson {
30330843563fSRichard Henderson     TCGv_i64 r1, r2, dest;
30340843563fSRichard Henderson 
30350843563fSRichard Henderson     if (!ctx->is_pa20) {
30360843563fSRichard Henderson         return false;
30370843563fSRichard Henderson     }
30380843563fSRichard Henderson 
30390843563fSRichard Henderson     nullify_over(ctx);
30400843563fSRichard Henderson 
30410843563fSRichard Henderson     r1 = load_gpr(ctx, a->r1);
30420843563fSRichard Henderson     r2 = load_gpr(ctx, a->r2);
30430843563fSRichard Henderson     dest = dest_gpr(ctx, a->t);
30440843563fSRichard Henderson 
30450843563fSRichard Henderson     fn(dest, r1, r2);
30460843563fSRichard Henderson     save_gpr(ctx, a->t, dest);
30470843563fSRichard Henderson 
30480843563fSRichard Henderson     return nullify_end(ctx);
30490843563fSRichard Henderson }
30500843563fSRichard Henderson 
3051151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a,
3052151f309bSRichard Henderson                              void (*fn)(TCGv_i64, TCGv_i64, int64_t))
3053151f309bSRichard Henderson {
3054151f309bSRichard Henderson     TCGv_i64 r, dest;
3055151f309bSRichard Henderson 
3056151f309bSRichard Henderson     if (!ctx->is_pa20) {
3057151f309bSRichard Henderson         return false;
3058151f309bSRichard Henderson     }
3059151f309bSRichard Henderson 
3060151f309bSRichard Henderson     nullify_over(ctx);
3061151f309bSRichard Henderson 
3062151f309bSRichard Henderson     r = load_gpr(ctx, a->r);
3063151f309bSRichard Henderson     dest = dest_gpr(ctx, a->t);
3064151f309bSRichard Henderson 
3065151f309bSRichard Henderson     fn(dest, r, a->i);
3066151f309bSRichard Henderson     save_gpr(ctx, a->t, dest);
3067151f309bSRichard Henderson 
3068151f309bSRichard Henderson     return nullify_end(ctx);
3069151f309bSRichard Henderson }
3070151f309bSRichard Henderson 
30713bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a,
30723bbb8e48SRichard Henderson                                 void (*fn)(TCGv_i64, TCGv_i64,
30733bbb8e48SRichard Henderson                                            TCGv_i64, TCGv_i32))
30743bbb8e48SRichard Henderson {
30753bbb8e48SRichard Henderson     TCGv_i64 r1, r2, dest;
30763bbb8e48SRichard Henderson 
30773bbb8e48SRichard Henderson     if (!ctx->is_pa20) {
30783bbb8e48SRichard Henderson         return false;
30793bbb8e48SRichard Henderson     }
30803bbb8e48SRichard Henderson 
30813bbb8e48SRichard Henderson     nullify_over(ctx);
30823bbb8e48SRichard Henderson 
30833bbb8e48SRichard Henderson     r1 = load_gpr(ctx, a->r1);
30843bbb8e48SRichard Henderson     r2 = load_gpr(ctx, a->r2);
30853bbb8e48SRichard Henderson     dest = dest_gpr(ctx, a->t);
30863bbb8e48SRichard Henderson 
30873bbb8e48SRichard Henderson     fn(dest, r1, r2, tcg_constant_i32(a->sh));
30883bbb8e48SRichard Henderson     save_gpr(ctx, a->t, dest);
30893bbb8e48SRichard Henderson 
30903bbb8e48SRichard Henderson     return nullify_end(ctx);
30913bbb8e48SRichard Henderson }
30923bbb8e48SRichard Henderson 
30930843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a)
30940843563fSRichard Henderson {
30950843563fSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_add16_i64);
30960843563fSRichard Henderson }
30970843563fSRichard Henderson 
30980843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a)
30990843563fSRichard Henderson {
31000843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_ss);
31010843563fSRichard Henderson }
31020843563fSRichard Henderson 
31030843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a)
31040843563fSRichard Henderson {
31050843563fSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hadd_us);
31060843563fSRichard Henderson }
31070843563fSRichard Henderson 
31081b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a)
31091b3cb7c8SRichard Henderson {
31101b3cb7c8SRichard Henderson     return do_multimedia(ctx, a, gen_helper_havg);
31111b3cb7c8SRichard Henderson }
31121b3cb7c8SRichard Henderson 
3113151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a)
3114151f309bSRichard Henderson {
3115151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64);
3116151f309bSRichard Henderson }
3117151f309bSRichard Henderson 
3118151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a)
3119151f309bSRichard Henderson {
3120151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64);
3121151f309bSRichard Henderson }
3122151f309bSRichard Henderson 
3123151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a)
3124151f309bSRichard Henderson {
3125151f309bSRichard Henderson     return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64);
3126151f309bSRichard Henderson }
3127151f309bSRichard Henderson 
31283bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a)
31293bbb8e48SRichard Henderson {
31303bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshladd);
31313bbb8e48SRichard Henderson }
31323bbb8e48SRichard Henderson 
31333bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a)
31343bbb8e48SRichard Henderson {
31353bbb8e48SRichard Henderson     return do_multimedia_shadd(ctx, a, gen_helper_hshradd);
31363bbb8e48SRichard Henderson }
31373bbb8e48SRichard Henderson 
313810c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a)
313910c9e58dSRichard Henderson {
314010c9e58dSRichard Henderson     return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64);
314110c9e58dSRichard Henderson }
314210c9e58dSRichard Henderson 
314310c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a)
314410c9e58dSRichard Henderson {
314510c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_ss);
314610c9e58dSRichard Henderson }
314710c9e58dSRichard Henderson 
314810c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a)
314910c9e58dSRichard Henderson {
315010c9e58dSRichard Henderson     return do_multimedia(ctx, a, gen_helper_hsub_us);
315110c9e58dSRichard Henderson }
315210c9e58dSRichard Henderson 
3153c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3154c2a7ee3fSRichard Henderson {
3155c2a7ee3fSRichard Henderson     uint64_t mask = 0xffff0000ffff0000ull;
3156c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3157c2a7ee3fSRichard Henderson 
3158c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r2, mask);
3159c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r1, mask);
3160c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, tmp, 16);
3161c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3162c2a7ee3fSRichard Henderson }
3163c2a7ee3fSRichard Henderson 
3164c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a)
3165c2a7ee3fSRichard Henderson {
3166c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_l);
3167c2a7ee3fSRichard Henderson }
3168c2a7ee3fSRichard Henderson 
3169c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3170c2a7ee3fSRichard Henderson {
3171c2a7ee3fSRichard Henderson     uint64_t mask = 0x0000ffff0000ffffull;
3172c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3173c2a7ee3fSRichard Henderson 
3174c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(tmp, r1, mask);
3175c2a7ee3fSRichard Henderson     tcg_gen_andi_i64(dst, r2, mask);
3176c2a7ee3fSRichard Henderson     tcg_gen_shli_i64(tmp, tmp, 16);
3177c2a7ee3fSRichard Henderson     tcg_gen_or_i64(dst, dst, tmp);
3178c2a7ee3fSRichard Henderson }
3179c2a7ee3fSRichard Henderson 
3180c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a)
3181c2a7ee3fSRichard Henderson {
3182c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixh_r);
3183c2a7ee3fSRichard Henderson }
3184c2a7ee3fSRichard Henderson 
3185c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3186c2a7ee3fSRichard Henderson {
3187c2a7ee3fSRichard Henderson     TCGv_i64 tmp = tcg_temp_new_i64();
3188c2a7ee3fSRichard Henderson 
3189c2a7ee3fSRichard Henderson     tcg_gen_shri_i64(tmp, r2, 32);
3190c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r1, tmp, 0, 32);
3191c2a7ee3fSRichard Henderson }
3192c2a7ee3fSRichard Henderson 
3193c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a)
3194c2a7ee3fSRichard Henderson {
3195c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_l);
3196c2a7ee3fSRichard Henderson }
3197c2a7ee3fSRichard Henderson 
3198c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2)
3199c2a7ee3fSRichard Henderson {
3200c2a7ee3fSRichard Henderson     tcg_gen_deposit_i64(dst, r2, r1, 32, 32);
3201c2a7ee3fSRichard Henderson }
3202c2a7ee3fSRichard Henderson 
3203c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a)
3204c2a7ee3fSRichard Henderson {
3205c2a7ee3fSRichard Henderson     return do_multimedia(ctx, a, gen_mixw_r);
3206c2a7ee3fSRichard Henderson }
3207c2a7ee3fSRichard Henderson 
32084e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a)
32094e7abdb1SRichard Henderson {
32104e7abdb1SRichard Henderson     TCGv_i64 r, t0, t1, t2, t3;
32114e7abdb1SRichard Henderson 
32124e7abdb1SRichard Henderson     if (!ctx->is_pa20) {
32134e7abdb1SRichard Henderson         return false;
32144e7abdb1SRichard Henderson     }
32154e7abdb1SRichard Henderson 
32164e7abdb1SRichard Henderson     nullify_over(ctx);
32174e7abdb1SRichard Henderson 
32184e7abdb1SRichard Henderson     r = load_gpr(ctx, a->r1);
32194e7abdb1SRichard Henderson     t0 = tcg_temp_new_i64();
32204e7abdb1SRichard Henderson     t1 = tcg_temp_new_i64();
32214e7abdb1SRichard Henderson     t2 = tcg_temp_new_i64();
32224e7abdb1SRichard Henderson     t3 = tcg_temp_new_i64();
32234e7abdb1SRichard Henderson 
32244e7abdb1SRichard Henderson     tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16);
32254e7abdb1SRichard Henderson     tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16);
32264e7abdb1SRichard Henderson     tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16);
32274e7abdb1SRichard Henderson     tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16);
32284e7abdb1SRichard Henderson 
32294e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t1, t0, 16, 48);
32304e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t2, t3, t2, 16, 48);
32314e7abdb1SRichard Henderson     tcg_gen_deposit_i64(t0, t2, t0, 32, 32);
32324e7abdb1SRichard Henderson 
32334e7abdb1SRichard Henderson     save_gpr(ctx, a->t, t0);
32344e7abdb1SRichard Henderson     return nullify_end(ctx);
32354e7abdb1SRichard Henderson }
32364e7abdb1SRichard Henderson 
32371cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a)
323896d6407fSRichard Henderson {
3239b5caa17cSRichard Henderson     if (ctx->is_pa20) {
3240b5caa17cSRichard Henderson        /*
3241b5caa17cSRichard Henderson         * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches.
3242b5caa17cSRichard Henderson         * Any base modification still occurs.
3243b5caa17cSRichard Henderson         */
3244b5caa17cSRichard Henderson         if (a->t == 0) {
3245b5caa17cSRichard Henderson             return trans_nop_addrx(ctx, a);
3246b5caa17cSRichard Henderson         }
3247b5caa17cSRichard Henderson     } else if (a->size > MO_32) {
32480786a3b6SHelge Deller         return gen_illegal(ctx);
3249c53e401eSRichard Henderson     }
32501cd012a5SRichard Henderson     return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0,
32511cd012a5SRichard Henderson                    a->disp, a->sp, a->m, a->size | MO_TE);
325296d6407fSRichard Henderson }
325396d6407fSRichard Henderson 
32541cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a)
325596d6407fSRichard Henderson {
32561cd012a5SRichard Henderson     assert(a->x == 0 && a->scale == 0);
3257c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
32580786a3b6SHelge Deller         return gen_illegal(ctx);
325996d6407fSRichard Henderson     }
3260c53e401eSRichard Henderson     return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE);
32610786a3b6SHelge Deller }
326296d6407fSRichard Henderson 
32631cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a)
326496d6407fSRichard Henderson {
3265b1af755cSRichard Henderson     MemOp mop = MO_TE | MO_ALIGN | a->size;
3266a4db4a78SRichard Henderson     TCGv_i64 dest, ofs;
32676fd0c7bcSRichard Henderson     TCGv_i64 addr;
326896d6407fSRichard Henderson 
3269c53e401eSRichard Henderson     if (!ctx->is_pa20 && a->size > MO_32) {
327051416c4eSRichard Henderson         return gen_illegal(ctx);
327151416c4eSRichard Henderson     }
327251416c4eSRichard Henderson 
327396d6407fSRichard Henderson     nullify_over(ctx);
327496d6407fSRichard Henderson 
32751cd012a5SRichard Henderson     if (a->m) {
327686f8d05fSRichard Henderson         /* Base register modification.  Make sure if RT == RB,
327786f8d05fSRichard Henderson            we see the result of the load.  */
3278aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
327996d6407fSRichard Henderson     } else {
32801cd012a5SRichard Henderson         dest = dest_gpr(ctx, a->t);
328196d6407fSRichard Henderson     }
328296d6407fSRichard Henderson 
3283c3ea1996SSven Schnelle     form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0,
328417fe594cSRichard Henderson              a->disp, a->sp, a->m, MMU_DISABLED(ctx));
3285b1af755cSRichard Henderson 
3286b1af755cSRichard Henderson     /*
3287b1af755cSRichard Henderson      * For hppa1.1, LDCW is undefined unless aligned mod 16.
3288b1af755cSRichard Henderson      * However actual hardware succeeds with aligned mod 4.
3289b1af755cSRichard Henderson      * Detect this case and log a GUEST_ERROR.
3290b1af755cSRichard Henderson      *
3291b1af755cSRichard Henderson      * TODO: HPPA64 relaxes the over-alignment requirement
3292b1af755cSRichard Henderson      * with the ,co completer.
3293b1af755cSRichard Henderson      */
3294b1af755cSRichard Henderson     gen_helper_ldc_check(addr);
3295b1af755cSRichard Henderson 
3296a4db4a78SRichard Henderson     tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop);
3297b1af755cSRichard Henderson 
32981cd012a5SRichard Henderson     if (a->m) {
32991cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
330096d6407fSRichard Henderson     }
33011cd012a5SRichard Henderson     save_gpr(ctx, a->t, dest);
330296d6407fSRichard Henderson 
330331234768SRichard Henderson     return nullify_end(ctx);
330496d6407fSRichard Henderson }
330596d6407fSRichard Henderson 
33061cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a)
330796d6407fSRichard Henderson {
33086fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33096fd0c7bcSRichard Henderson     TCGv_i64 addr;
331096d6407fSRichard Henderson 
331196d6407fSRichard Henderson     nullify_over(ctx);
331296d6407fSRichard Henderson 
33131cd012a5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
331417fe594cSRichard Henderson              MMU_DISABLED(ctx));
33151cd012a5SRichard Henderson     val = load_gpr(ctx, a->r);
33161cd012a5SRichard Henderson     if (a->a) {
3317f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3318ad75a51eSRichard Henderson             gen_helper_stby_e_parallel(tcg_env, addr, val);
3319f9f46db4SEmilio G. Cota         } else {
3320ad75a51eSRichard Henderson             gen_helper_stby_e(tcg_env, addr, val);
3321f9f46db4SEmilio G. Cota         }
3322f9f46db4SEmilio G. Cota     } else {
3323f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
3324ad75a51eSRichard Henderson             gen_helper_stby_b_parallel(tcg_env, addr, val);
332596d6407fSRichard Henderson         } else {
3326ad75a51eSRichard Henderson             gen_helper_stby_b(tcg_env, addr, val);
332796d6407fSRichard Henderson         }
3328f9f46db4SEmilio G. Cota     }
33291cd012a5SRichard Henderson     if (a->m) {
33306fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~3);
33311cd012a5SRichard Henderson         save_gpr(ctx, a->b, ofs);
333296d6407fSRichard Henderson     }
333396d6407fSRichard Henderson 
333431234768SRichard Henderson     return nullify_end(ctx);
333596d6407fSRichard Henderson }
333696d6407fSRichard Henderson 
333725460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a)
333825460fc5SRichard Henderson {
33396fd0c7bcSRichard Henderson     TCGv_i64 ofs, val;
33406fd0c7bcSRichard Henderson     TCGv_i64 addr;
334125460fc5SRichard Henderson 
334225460fc5SRichard Henderson     if (!ctx->is_pa20) {
334325460fc5SRichard Henderson         return false;
334425460fc5SRichard Henderson     }
334525460fc5SRichard Henderson     nullify_over(ctx);
334625460fc5SRichard Henderson 
334725460fc5SRichard Henderson     form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m,
334817fe594cSRichard Henderson              MMU_DISABLED(ctx));
334925460fc5SRichard Henderson     val = load_gpr(ctx, a->r);
335025460fc5SRichard Henderson     if (a->a) {
335125460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
335225460fc5SRichard Henderson             gen_helper_stdby_e_parallel(tcg_env, addr, val);
335325460fc5SRichard Henderson         } else {
335425460fc5SRichard Henderson             gen_helper_stdby_e(tcg_env, addr, val);
335525460fc5SRichard Henderson         }
335625460fc5SRichard Henderson     } else {
335725460fc5SRichard Henderson         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
335825460fc5SRichard Henderson             gen_helper_stdby_b_parallel(tcg_env, addr, val);
335925460fc5SRichard Henderson         } else {
336025460fc5SRichard Henderson             gen_helper_stdby_b(tcg_env, addr, val);
336125460fc5SRichard Henderson         }
336225460fc5SRichard Henderson     }
336325460fc5SRichard Henderson     if (a->m) {
33646fd0c7bcSRichard Henderson         tcg_gen_andi_i64(ofs, ofs, ~7);
336525460fc5SRichard Henderson         save_gpr(ctx, a->b, ofs);
336625460fc5SRichard Henderson     }
336725460fc5SRichard Henderson 
336825460fc5SRichard Henderson     return nullify_end(ctx);
336925460fc5SRichard Henderson }
337025460fc5SRichard Henderson 
33711cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a)
3372d0a851ccSRichard Henderson {
3373d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3374d0a851ccSRichard Henderson 
3375d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3376451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33771cd012a5SRichard Henderson     trans_ld(ctx, a);
3378d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
337931234768SRichard Henderson     return true;
3380d0a851ccSRichard Henderson }
3381d0a851ccSRichard Henderson 
33821cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a)
3383d0a851ccSRichard Henderson {
3384d0a851ccSRichard Henderson     int hold_mmu_idx = ctx->mmu_idx;
3385d0a851ccSRichard Henderson 
3386d0a851ccSRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
3387451d993dSRichard Henderson     ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX;
33881cd012a5SRichard Henderson     trans_st(ctx, a);
3389d0a851ccSRichard Henderson     ctx->mmu_idx = hold_mmu_idx;
339031234768SRichard Henderson     return true;
3391d0a851ccSRichard Henderson }
339295412a61SRichard Henderson 
33930588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a)
3394b2167459SRichard Henderson {
33956fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3396b2167459SRichard Henderson 
33976fd0c7bcSRichard Henderson     tcg_gen_movi_i64(tcg_rt, a->i);
33980588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3399e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
340031234768SRichard Henderson     return true;
3401b2167459SRichard Henderson }
3402b2167459SRichard Henderson 
34030588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a)
3404b2167459SRichard Henderson {
34056fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = load_gpr(ctx, a->r);
34066fd0c7bcSRichard Henderson     TCGv_i64 tcg_r1 = dest_gpr(ctx, 1);
3407b2167459SRichard Henderson 
34086fd0c7bcSRichard Henderson     tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i);
3409b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
3410e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
341131234768SRichard Henderson     return true;
3412b2167459SRichard Henderson }
3413b2167459SRichard Henderson 
34140588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a)
3415b2167459SRichard Henderson {
34166fd0c7bcSRichard Henderson     TCGv_i64 tcg_rt = dest_gpr(ctx, a->t);
3417b2167459SRichard Henderson 
3418b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
3419d265360fSRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_i64.  */
34200588e061SRichard Henderson     if (a->b == 0) {
34216fd0c7bcSRichard Henderson         tcg_gen_movi_i64(tcg_rt, a->i);
3422b2167459SRichard Henderson     } else {
34236fd0c7bcSRichard Henderson         tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i);
3424b2167459SRichard Henderson     }
34250588e061SRichard Henderson     save_gpr(ctx, a->t, tcg_rt);
3426e0137378SRichard Henderson     ctx->null_cond = cond_make_f();
342731234768SRichard Henderson     return true;
3428b2167459SRichard Henderson }
3429b2167459SRichard Henderson 
34306fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
3431e9efd4bcSRichard Henderson                     unsigned c, unsigned f, bool d, unsigned n, int disp)
343298cd9ca7SRichard Henderson {
34336fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv;
343498cd9ca7SRichard Henderson     DisasCond cond;
343598cd9ca7SRichard Henderson 
343698cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3437aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
343898cd9ca7SRichard Henderson 
34396fd0c7bcSRichard Henderson     tcg_gen_sub_i64(dest, in1, in2);
344098cd9ca7SRichard Henderson 
3441f764718dSRichard Henderson     sv = NULL;
3442b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
344398cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
344498cd9ca7SRichard Henderson     }
344598cd9ca7SRichard Henderson 
34464fe9533aSRichard Henderson     cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv);
344701afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
344898cd9ca7SRichard Henderson }
344998cd9ca7SRichard Henderson 
345001afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a)
345198cd9ca7SRichard Henderson {
3452e9efd4bcSRichard Henderson     if (!ctx->is_pa20 && a->d) {
3453e9efd4bcSRichard Henderson         return false;
3454e9efd4bcSRichard Henderson     }
345501afb7beSRichard Henderson     nullify_over(ctx);
3456e9efd4bcSRichard Henderson     return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1),
3457e9efd4bcSRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
345801afb7beSRichard Henderson }
345901afb7beSRichard Henderson 
346001afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a)
346101afb7beSRichard Henderson {
3462c65c3ee1SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3463c65c3ee1SRichard Henderson         return false;
3464c65c3ee1SRichard Henderson     }
346501afb7beSRichard Henderson     nullify_over(ctx);
34666fd0c7bcSRichard Henderson     return do_cmpb(ctx, a->r, tcg_constant_i64(a->i),
3467c65c3ee1SRichard Henderson                    a->c, a->f, a->d, a->n, a->disp);
346801afb7beSRichard Henderson }
346901afb7beSRichard Henderson 
34706fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1,
347101afb7beSRichard Henderson                     unsigned c, unsigned f, unsigned n, int disp)
347201afb7beSRichard Henderson {
34736fd0c7bcSRichard Henderson     TCGv_i64 dest, in2, sv, cb_cond;
347498cd9ca7SRichard Henderson     DisasCond cond;
3475bdcccc17SRichard Henderson     bool d = false;
347698cd9ca7SRichard Henderson 
3477f25d3160SRichard Henderson     /*
3478f25d3160SRichard Henderson      * For hppa64, the ADDB conditions change with PSW.W,
3479f25d3160SRichard Henderson      * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE.
3480f25d3160SRichard Henderson      */
3481f25d3160SRichard Henderson     if (ctx->tb_flags & PSW_W) {
3482f25d3160SRichard Henderson         d = c >= 5;
3483f25d3160SRichard Henderson         if (d) {
3484f25d3160SRichard Henderson             c &= 3;
3485f25d3160SRichard Henderson         }
3486f25d3160SRichard Henderson     }
3487f25d3160SRichard Henderson 
348898cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
3489aac0f603SRichard Henderson     dest = tcg_temp_new_i64();
3490f764718dSRichard Henderson     sv = NULL;
3491bdcccc17SRichard Henderson     cb_cond = NULL;
349298cd9ca7SRichard Henderson 
3493b47a4a02SSven Schnelle     if (cond_need_cb(c)) {
3494aac0f603SRichard Henderson         TCGv_i64 cb = tcg_temp_new_i64();
3495aac0f603SRichard Henderson         TCGv_i64 cb_msb = tcg_temp_new_i64();
3496bdcccc17SRichard Henderson 
34976fd0c7bcSRichard Henderson         tcg_gen_movi_i64(cb_msb, 0);
34986fd0c7bcSRichard Henderson         tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb);
34996fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, in1, in2);
35006fd0c7bcSRichard Henderson         tcg_gen_xor_i64(cb, cb, dest);
3501bdcccc17SRichard Henderson         cb_cond = get_carry(ctx, d, cb, cb_msb);
3502b47a4a02SSven Schnelle     } else {
35036fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, in1, in2);
3504b47a4a02SSven Schnelle     }
3505b47a4a02SSven Schnelle     if (cond_need_sv(c)) {
3506f8f5986eSRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d);
350798cd9ca7SRichard Henderson     }
350898cd9ca7SRichard Henderson 
3509a751eb31SRichard Henderson     cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv);
351043675d20SSven Schnelle     save_gpr(ctx, r, dest);
351101afb7beSRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
351298cd9ca7SRichard Henderson }
351398cd9ca7SRichard Henderson 
351401afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a)
351598cd9ca7SRichard Henderson {
351601afb7beSRichard Henderson     nullify_over(ctx);
351701afb7beSRichard Henderson     return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp);
351801afb7beSRichard Henderson }
351901afb7beSRichard Henderson 
352001afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a)
352101afb7beSRichard Henderson {
352201afb7beSRichard Henderson     nullify_over(ctx);
35236fd0c7bcSRichard Henderson     return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp);
352401afb7beSRichard Henderson }
352501afb7beSRichard Henderson 
352601afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a)
352701afb7beSRichard Henderson {
35286fd0c7bcSRichard Henderson     TCGv_i64 tmp, tcg_r;
352998cd9ca7SRichard Henderson     DisasCond cond;
353098cd9ca7SRichard Henderson 
353198cd9ca7SRichard Henderson     nullify_over(ctx);
353298cd9ca7SRichard Henderson 
3533aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
353401afb7beSRichard Henderson     tcg_r = load_gpr(ctx, a->r);
353582d0c831SRichard Henderson     if (a->d) {
353682d0c831SRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, cpu_sar);
353782d0c831SRichard Henderson     } else {
35381e9ab9fbSRichard Henderson         /* Force shift into [32,63] */
35396fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, cpu_sar, 32);
35406fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tcg_r, tmp);
35411e9ab9fbSRichard Henderson     }
354298cd9ca7SRichard Henderson 
35434c42fd0dSRichard Henderson     cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0);
354401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
354598cd9ca7SRichard Henderson }
354698cd9ca7SRichard Henderson 
354701afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a)
354898cd9ca7SRichard Henderson {
354901afb7beSRichard Henderson     DisasCond cond;
3550b041ec9dSRichard Henderson     int p = a->p | (a->d ? 0 : 32);
355101afb7beSRichard Henderson 
355201afb7beSRichard Henderson     nullify_over(ctx);
3553b041ec9dSRichard Henderson     cond = cond_make_vi(a->c ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
3554b041ec9dSRichard Henderson                         load_gpr(ctx, a->r), 1ull << (63 - p));
355501afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
355601afb7beSRichard Henderson }
355701afb7beSRichard Henderson 
355801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a)
355901afb7beSRichard Henderson {
35606fd0c7bcSRichard Henderson     TCGv_i64 dest;
356198cd9ca7SRichard Henderson     DisasCond cond;
356298cd9ca7SRichard Henderson 
356398cd9ca7SRichard Henderson     nullify_over(ctx);
356498cd9ca7SRichard Henderson 
356501afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r2);
356601afb7beSRichard Henderson     if (a->r1 == 0) {
35676fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, 0);
356898cd9ca7SRichard Henderson     } else {
35696fd0c7bcSRichard Henderson         tcg_gen_mov_i64(dest, cpu_gr[a->r1]);
357098cd9ca7SRichard Henderson     }
357198cd9ca7SRichard Henderson 
35724fa52edfSRichard Henderson     /* All MOVB conditions are 32-bit. */
35734fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
357401afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
357501afb7beSRichard Henderson }
357601afb7beSRichard Henderson 
357701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a)
357801afb7beSRichard Henderson {
35796fd0c7bcSRichard Henderson     TCGv_i64 dest;
358001afb7beSRichard Henderson     DisasCond cond;
358101afb7beSRichard Henderson 
358201afb7beSRichard Henderson     nullify_over(ctx);
358301afb7beSRichard Henderson 
358401afb7beSRichard Henderson     dest = dest_gpr(ctx, a->r);
35856fd0c7bcSRichard Henderson     tcg_gen_movi_i64(dest, a->i);
358601afb7beSRichard Henderson 
35874fa52edfSRichard Henderson     /* All MOVBI conditions are 32-bit. */
35884fa52edfSRichard Henderson     cond = do_sed_cond(ctx, a->c, false, dest);
358901afb7beSRichard Henderson     return do_cbranch(ctx, a->disp, a->n, &cond);
359098cd9ca7SRichard Henderson }
359198cd9ca7SRichard Henderson 
3592f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a)
35930b1347d2SRichard Henderson {
35946fd0c7bcSRichard Henderson     TCGv_i64 dest, src2;
35950b1347d2SRichard Henderson 
3596f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3597f7b775a9SRichard Henderson         return false;
3598f7b775a9SRichard Henderson     }
359930878590SRichard Henderson     if (a->c) {
36000b1347d2SRichard Henderson         nullify_over(ctx);
36010b1347d2SRichard Henderson     }
36020b1347d2SRichard Henderson 
360330878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
3604f7b775a9SRichard Henderson     src2 = load_gpr(ctx, a->r2);
360530878590SRichard Henderson     if (a->r1 == 0) {
3606f7b775a9SRichard Henderson         if (a->d) {
36076fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, src2, cpu_sar);
3608f7b775a9SRichard Henderson         } else {
3609aac0f603SRichard Henderson             TCGv_i64 tmp = tcg_temp_new_i64();
3610f7b775a9SRichard Henderson 
36116fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src2);
36126fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, cpu_sar, 31);
36136fd0c7bcSRichard Henderson             tcg_gen_shr_i64(dest, dest, tmp);
3614f7b775a9SRichard Henderson         }
361530878590SRichard Henderson     } else if (a->r1 == a->r2) {
3616f7b775a9SRichard Henderson         if (a->d) {
36176fd0c7bcSRichard Henderson             tcg_gen_rotr_i64(dest, src2, cpu_sar);
3618f7b775a9SRichard Henderson         } else {
36190b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
3620e1d635e8SRichard Henderson             TCGv_i32 s32 = tcg_temp_new_i32();
3621e1d635e8SRichard Henderson 
36226fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, src2);
36236fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(s32, cpu_sar);
3624f7b775a9SRichard Henderson             tcg_gen_andi_i32(s32, s32, 31);
3625e1d635e8SRichard Henderson             tcg_gen_rotr_i32(t32, t32, s32);
36266fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
3627f7b775a9SRichard Henderson         }
3628f7b775a9SRichard Henderson     } else {
36296fd0c7bcSRichard Henderson         TCGv_i64 src1 = load_gpr(ctx, a->r1);
3630f7b775a9SRichard Henderson 
3631f7b775a9SRichard Henderson         if (a->d) {
3632aac0f603SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
3633aac0f603SRichard Henderson             TCGv_i64 n = tcg_temp_new_i64();
3634f7b775a9SRichard Henderson 
36356fd0c7bcSRichard Henderson             tcg_gen_xori_i64(n, cpu_sar, 63);
3636a01491a2SHelge Deller             tcg_gen_shl_i64(t, src1, n);
36376fd0c7bcSRichard Henderson             tcg_gen_shli_i64(t, t, 1);
3638a01491a2SHelge Deller             tcg_gen_shr_i64(dest, src2, cpu_sar);
36396fd0c7bcSRichard Henderson             tcg_gen_or_i64(dest, dest, t);
36400b1347d2SRichard Henderson         } else {
36410b1347d2SRichard Henderson             TCGv_i64 t = tcg_temp_new_i64();
36420b1347d2SRichard Henderson             TCGv_i64 s = tcg_temp_new_i64();
36430b1347d2SRichard Henderson 
36446fd0c7bcSRichard Henderson             tcg_gen_concat32_i64(t, src2, src1);
3645967662cdSRichard Henderson             tcg_gen_andi_i64(s, cpu_sar, 31);
3646967662cdSRichard Henderson             tcg_gen_shr_i64(dest, t, s);
36470b1347d2SRichard Henderson         }
3648f7b775a9SRichard Henderson     }
364930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36500b1347d2SRichard Henderson 
36510b1347d2SRichard Henderson     /* Install the new nullification.  */
3652d37fad0aSSven Schnelle     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
365331234768SRichard Henderson     return nullify_end(ctx);
36540b1347d2SRichard Henderson }
36550b1347d2SRichard Henderson 
3656f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a)
36570b1347d2SRichard Henderson {
3658f7b775a9SRichard Henderson     unsigned width, sa;
36596fd0c7bcSRichard Henderson     TCGv_i64 dest, t2;
36600b1347d2SRichard Henderson 
3661f7b775a9SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3662f7b775a9SRichard Henderson         return false;
3663f7b775a9SRichard Henderson     }
366430878590SRichard Henderson     if (a->c) {
36650b1347d2SRichard Henderson         nullify_over(ctx);
36660b1347d2SRichard Henderson     }
36670b1347d2SRichard Henderson 
3668f7b775a9SRichard Henderson     width = a->d ? 64 : 32;
3669f7b775a9SRichard Henderson     sa = width - 1 - a->cpos;
3670f7b775a9SRichard Henderson 
367130878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
367230878590SRichard Henderson     t2 = load_gpr(ctx, a->r2);
367305bfd4dbSRichard Henderson     if (a->r1 == 0) {
36746fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, t2, sa, width - sa);
3675c53e401eSRichard Henderson     } else if (width == TARGET_LONG_BITS) {
36766fd0c7bcSRichard Henderson         tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa);
3677f7b775a9SRichard Henderson     } else {
3678f7b775a9SRichard Henderson         assert(!a->d);
3679f7b775a9SRichard Henderson         if (a->r1 == a->r2) {
36800b1347d2SRichard Henderson             TCGv_i32 t32 = tcg_temp_new_i32();
36816fd0c7bcSRichard Henderson             tcg_gen_extrl_i64_i32(t32, t2);
36820b1347d2SRichard Henderson             tcg_gen_rotri_i32(t32, t32, sa);
36836fd0c7bcSRichard Henderson             tcg_gen_extu_i32_i64(dest, t32);
36840b1347d2SRichard Henderson         } else {
3685967662cdSRichard Henderson             tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]);
3686967662cdSRichard Henderson             tcg_gen_extract_i64(dest, dest, sa, 32);
36870b1347d2SRichard Henderson         }
3688f7b775a9SRichard Henderson     }
368930878590SRichard Henderson     save_gpr(ctx, a->t, dest);
36900b1347d2SRichard Henderson 
36910b1347d2SRichard Henderson     /* Install the new nullification.  */
3692d37fad0aSSven Schnelle     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
369331234768SRichard Henderson     return nullify_end(ctx);
36940b1347d2SRichard Henderson }
36950b1347d2SRichard Henderson 
3696bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a)
36970b1347d2SRichard Henderson {
3698bd792da3SRichard Henderson     unsigned widthm1 = a->d ? 63 : 31;
36996fd0c7bcSRichard Henderson     TCGv_i64 dest, src, tmp;
37000b1347d2SRichard Henderson 
3701bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3702bd792da3SRichard Henderson         return false;
3703bd792da3SRichard Henderson     }
370430878590SRichard Henderson     if (a->c) {
37050b1347d2SRichard Henderson         nullify_over(ctx);
37060b1347d2SRichard Henderson     }
37070b1347d2SRichard Henderson 
370830878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
370930878590SRichard Henderson     src = load_gpr(ctx, a->r);
3710aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
37110b1347d2SRichard Henderson 
37120b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
37136fd0c7bcSRichard Henderson     tcg_gen_andi_i64(tmp, cpu_sar, widthm1);
37146fd0c7bcSRichard Henderson     tcg_gen_xori_i64(tmp, tmp, widthm1);
3715d781cb77SRichard Henderson 
371630878590SRichard Henderson     if (a->se) {
3717bd792da3SRichard Henderson         if (!a->d) {
37186fd0c7bcSRichard Henderson             tcg_gen_ext32s_i64(dest, src);
3719bd792da3SRichard Henderson             src = dest;
3720bd792da3SRichard Henderson         }
37216fd0c7bcSRichard Henderson         tcg_gen_sar_i64(dest, src, tmp);
37226fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, dest, 0, a->len);
37230b1347d2SRichard Henderson     } else {
3724bd792da3SRichard Henderson         if (!a->d) {
37256fd0c7bcSRichard Henderson             tcg_gen_ext32u_i64(dest, src);
3726bd792da3SRichard Henderson             src = dest;
3727bd792da3SRichard Henderson         }
37286fd0c7bcSRichard Henderson         tcg_gen_shr_i64(dest, src, tmp);
37296fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, dest, 0, a->len);
37300b1347d2SRichard Henderson     }
373130878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37320b1347d2SRichard Henderson 
37330b1347d2SRichard Henderson     /* Install the new nullification.  */
3734bd792da3SRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
373531234768SRichard Henderson     return nullify_end(ctx);
37360b1347d2SRichard Henderson }
37370b1347d2SRichard Henderson 
3738bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a)
37390b1347d2SRichard Henderson {
3740bd792da3SRichard Henderson     unsigned len, cpos, width;
37416fd0c7bcSRichard Henderson     TCGv_i64 dest, src;
37420b1347d2SRichard Henderson 
3743bd792da3SRichard Henderson     if (!ctx->is_pa20 && a->d) {
3744bd792da3SRichard Henderson         return false;
3745bd792da3SRichard Henderson     }
374630878590SRichard Henderson     if (a->c) {
37470b1347d2SRichard Henderson         nullify_over(ctx);
37480b1347d2SRichard Henderson     }
37490b1347d2SRichard Henderson 
3750bd792da3SRichard Henderson     len = a->len;
3751bd792da3SRichard Henderson     width = a->d ? 64 : 32;
3752bd792da3SRichard Henderson     cpos = width - 1 - a->pos;
3753bd792da3SRichard Henderson     if (cpos + len > width) {
3754bd792da3SRichard Henderson         len = width - cpos;
3755bd792da3SRichard Henderson     }
3756bd792da3SRichard Henderson 
375730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
375830878590SRichard Henderson     src = load_gpr(ctx, a->r);
375930878590SRichard Henderson     if (a->se) {
37606fd0c7bcSRichard Henderson         tcg_gen_sextract_i64(dest, src, cpos, len);
37610b1347d2SRichard Henderson     } else {
37626fd0c7bcSRichard Henderson         tcg_gen_extract_i64(dest, src, cpos, len);
37630b1347d2SRichard Henderson     }
376430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
37650b1347d2SRichard Henderson 
37660b1347d2SRichard Henderson     /* Install the new nullification.  */
3767bd792da3SRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
376831234768SRichard Henderson     return nullify_end(ctx);
37690b1347d2SRichard Henderson }
37700b1347d2SRichard Henderson 
377172ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a)
37720b1347d2SRichard Henderson {
377372ae4f2bSRichard Henderson     unsigned len, width;
3774c53e401eSRichard Henderson     uint64_t mask0, mask1;
37756fd0c7bcSRichard Henderson     TCGv_i64 dest;
37760b1347d2SRichard Henderson 
377772ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
377872ae4f2bSRichard Henderson         return false;
377972ae4f2bSRichard Henderson     }
378030878590SRichard Henderson     if (a->c) {
37810b1347d2SRichard Henderson         nullify_over(ctx);
37820b1347d2SRichard Henderson     }
378372ae4f2bSRichard Henderson 
378472ae4f2bSRichard Henderson     len = a->len;
378572ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
378672ae4f2bSRichard Henderson     if (a->cpos + len > width) {
378772ae4f2bSRichard Henderson         len = width - a->cpos;
37880b1347d2SRichard Henderson     }
37890b1347d2SRichard Henderson 
379030878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
379130878590SRichard Henderson     mask0 = deposit64(0, a->cpos, len, a->i);
379230878590SRichard Henderson     mask1 = deposit64(-1, a->cpos, len, a->i);
37930b1347d2SRichard Henderson 
379430878590SRichard Henderson     if (a->nz) {
37956fd0c7bcSRichard Henderson         TCGv_i64 src = load_gpr(ctx, a->t);
37966fd0c7bcSRichard Henderson         tcg_gen_andi_i64(dest, src, mask1);
37976fd0c7bcSRichard Henderson         tcg_gen_ori_i64(dest, dest, mask0);
37980b1347d2SRichard Henderson     } else {
37996fd0c7bcSRichard Henderson         tcg_gen_movi_i64(dest, mask0);
38000b1347d2SRichard Henderson     }
380130878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38020b1347d2SRichard Henderson 
38030b1347d2SRichard Henderson     /* Install the new nullification.  */
380472ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
380531234768SRichard Henderson     return nullify_end(ctx);
38060b1347d2SRichard Henderson }
38070b1347d2SRichard Henderson 
380872ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a)
38090b1347d2SRichard Henderson {
381030878590SRichard Henderson     unsigned rs = a->nz ? a->t : 0;
381172ae4f2bSRichard Henderson     unsigned len, width;
38126fd0c7bcSRichard Henderson     TCGv_i64 dest, val;
38130b1347d2SRichard Henderson 
381472ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
381572ae4f2bSRichard Henderson         return false;
381672ae4f2bSRichard Henderson     }
381730878590SRichard Henderson     if (a->c) {
38180b1347d2SRichard Henderson         nullify_over(ctx);
38190b1347d2SRichard Henderson     }
382072ae4f2bSRichard Henderson 
382172ae4f2bSRichard Henderson     len = a->len;
382272ae4f2bSRichard Henderson     width = a->d ? 64 : 32;
382372ae4f2bSRichard Henderson     if (a->cpos + len > width) {
382472ae4f2bSRichard Henderson         len = width - a->cpos;
38250b1347d2SRichard Henderson     }
38260b1347d2SRichard Henderson 
382730878590SRichard Henderson     dest = dest_gpr(ctx, a->t);
382830878590SRichard Henderson     val = load_gpr(ctx, a->r);
38290b1347d2SRichard Henderson     if (rs == 0) {
38306fd0c7bcSRichard Henderson         tcg_gen_deposit_z_i64(dest, val, a->cpos, len);
38310b1347d2SRichard Henderson     } else {
38326fd0c7bcSRichard Henderson         tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len);
38330b1347d2SRichard Henderson     }
383430878590SRichard Henderson     save_gpr(ctx, a->t, dest);
38350b1347d2SRichard Henderson 
38360b1347d2SRichard Henderson     /* Install the new nullification.  */
383772ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest);
383831234768SRichard Henderson     return nullify_end(ctx);
38390b1347d2SRichard Henderson }
38400b1347d2SRichard Henderson 
384172ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c,
38426fd0c7bcSRichard Henderson                        bool d, bool nz, unsigned len, TCGv_i64 val)
38430b1347d2SRichard Henderson {
38440b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
384572ae4f2bSRichard Henderson     unsigned widthm1 = d ? 63 : 31;
38466fd0c7bcSRichard Henderson     TCGv_i64 mask, tmp, shift, dest;
3847c53e401eSRichard Henderson     uint64_t msb = 1ULL << (len - 1);
38480b1347d2SRichard Henderson 
38490b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
3850aac0f603SRichard Henderson     shift = tcg_temp_new_i64();
3851aac0f603SRichard Henderson     tmp = tcg_temp_new_i64();
38520b1347d2SRichard Henderson 
38530b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
38546fd0c7bcSRichard Henderson     tcg_gen_andi_i64(shift, cpu_sar, widthm1);
38556fd0c7bcSRichard Henderson     tcg_gen_xori_i64(shift, shift, widthm1);
38560b1347d2SRichard Henderson 
3857aac0f603SRichard Henderson     mask = tcg_temp_new_i64();
38586fd0c7bcSRichard Henderson     tcg_gen_movi_i64(mask, msb + (msb - 1));
38596fd0c7bcSRichard Henderson     tcg_gen_and_i64(tmp, val, mask);
38600b1347d2SRichard Henderson     if (rs) {
38616fd0c7bcSRichard Henderson         tcg_gen_shl_i64(mask, mask, shift);
38626fd0c7bcSRichard Henderson         tcg_gen_shl_i64(tmp, tmp, shift);
38636fd0c7bcSRichard Henderson         tcg_gen_andc_i64(dest, cpu_gr[rs], mask);
38646fd0c7bcSRichard Henderson         tcg_gen_or_i64(dest, dest, tmp);
38650b1347d2SRichard Henderson     } else {
38666fd0c7bcSRichard Henderson         tcg_gen_shl_i64(dest, tmp, shift);
38670b1347d2SRichard Henderson     }
38680b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
38690b1347d2SRichard Henderson 
38700b1347d2SRichard Henderson     /* Install the new nullification.  */
387172ae4f2bSRichard Henderson     ctx->null_cond = do_sed_cond(ctx, c, d, dest);
387231234768SRichard Henderson     return nullify_end(ctx);
38730b1347d2SRichard Henderson }
38740b1347d2SRichard Henderson 
387572ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a)
387630878590SRichard Henderson {
387772ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
387872ae4f2bSRichard Henderson         return false;
387972ae4f2bSRichard Henderson     }
3880a6deecceSSven Schnelle     if (a->c) {
3881a6deecceSSven Schnelle         nullify_over(ctx);
3882a6deecceSSven Schnelle     }
388372ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
388472ae4f2bSRichard Henderson                       load_gpr(ctx, a->r));
388530878590SRichard Henderson }
388630878590SRichard Henderson 
388772ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a)
388830878590SRichard Henderson {
388972ae4f2bSRichard Henderson     if (!ctx->is_pa20 && a->d) {
389072ae4f2bSRichard Henderson         return false;
389172ae4f2bSRichard Henderson     }
3892a6deecceSSven Schnelle     if (a->c) {
3893a6deecceSSven Schnelle         nullify_over(ctx);
3894a6deecceSSven Schnelle     }
389572ae4f2bSRichard Henderson     return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len,
38966fd0c7bcSRichard Henderson                       tcg_constant_i64(a->i));
389730878590SRichard Henderson }
38980b1347d2SRichard Henderson 
38998340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a)
390098cd9ca7SRichard Henderson {
3901019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
3902bc921866SRichard Henderson     ctx->iaq_j.space = tcg_temp_new_i64();
3903bc921866SRichard Henderson     load_spr(ctx, ctx->iaq_j.space, a->sp);
3904c301f34eSRichard Henderson #endif
3905019f4159SRichard Henderson 
3906bc921866SRichard Henderson     ctx->iaq_j.base = tcg_temp_new_i64();
3907bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
3908bc921866SRichard Henderson 
3909bc921866SRichard Henderson     tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp);
3910bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base);
3911bc921866SRichard Henderson 
3912bc921866SRichard Henderson     return do_ibranch(ctx, a->l, true, a->n);
391398cd9ca7SRichard Henderson }
391498cd9ca7SRichard Henderson 
39158340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a)
391698cd9ca7SRichard Henderson {
39172644f80bSRichard Henderson     return do_dbranch(ctx, a->disp, a->l, a->n);
391898cd9ca7SRichard Henderson }
391998cd9ca7SRichard Henderson 
39208340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
392143e05652SRichard Henderson {
3922bc921866SRichard Henderson     int64_t disp = a->disp;
392343e05652SRichard Henderson 
39246e5f5300SSven Schnelle     nullify_over(ctx);
39256e5f5300SSven Schnelle 
392643e05652SRichard Henderson     /* Make sure the caller hasn't done something weird with the queue.
392743e05652SRichard Henderson      * ??? This is not quite the same as the PSW[B] bit, which would be
392843e05652SRichard Henderson      * expensive to track.  Real hardware will trap for
392943e05652SRichard Henderson      *    b  gateway
393043e05652SRichard Henderson      *    b  gateway+4  (in delay slot of first branch)
393143e05652SRichard Henderson      * However, checking for a non-sequential instruction queue *will*
393243e05652SRichard Henderson      * diagnose the security hole
393343e05652SRichard Henderson      *    b  gateway
393443e05652SRichard Henderson      *    b  evil
393543e05652SRichard Henderson      * in which instructions at evil would run with increased privs.
393643e05652SRichard Henderson      */
3937bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
393843e05652SRichard Henderson         return gen_illegal(ctx);
393943e05652SRichard Henderson     }
394043e05652SRichard Henderson 
394143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY
394243e05652SRichard Henderson     if (ctx->tb_flags & PSW_C) {
394394956d7bSPhilippe Mathieu-Daudé         int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next);
394443e05652SRichard Henderson         /* If we could not find a TLB entry, then we need to generate an
394543e05652SRichard Henderson            ITLB miss exception so the kernel will provide it.
394643e05652SRichard Henderson            The resulting TLB fill operation will invalidate this TB and
394743e05652SRichard Henderson            we will re-translate, at which point we *will* be able to find
394843e05652SRichard Henderson            the TLB entry and determine if this is in fact a gateway page.  */
394943e05652SRichard Henderson         if (type < 0) {
395031234768SRichard Henderson             gen_excp(ctx, EXCP_ITLB_MISS);
395131234768SRichard Henderson             return true;
395243e05652SRichard Henderson         }
395343e05652SRichard Henderson         /* No change for non-gateway pages or for priv decrease.  */
395443e05652SRichard Henderson         if (type >= 4 && type - 4 < ctx->privilege) {
3955bc921866SRichard Henderson             disp -= ctx->privilege;
3956bc921866SRichard Henderson             disp += type - 4;
395743e05652SRichard Henderson         }
395843e05652SRichard Henderson     } else {
3959bc921866SRichard Henderson         disp -= ctx->privilege;  /* priv = 0 */
396043e05652SRichard Henderson     }
396143e05652SRichard Henderson #endif
396243e05652SRichard Henderson 
39636e5f5300SSven Schnelle     if (a->l) {
39646fd0c7bcSRichard Henderson         TCGv_i64 tmp = dest_gpr(ctx, a->l);
39656e5f5300SSven Schnelle         if (ctx->privilege < 3) {
39666fd0c7bcSRichard Henderson             tcg_gen_andi_i64(tmp, tmp, -4);
39676e5f5300SSven Schnelle         }
39686fd0c7bcSRichard Henderson         tcg_gen_ori_i64(tmp, tmp, ctx->privilege);
39696e5f5300SSven Schnelle         save_gpr(ctx, a->l, tmp);
39706e5f5300SSven Schnelle     }
39716e5f5300SSven Schnelle 
3972bc921866SRichard Henderson     return do_dbranch(ctx, disp, 0, a->n);
397343e05652SRichard Henderson }
397443e05652SRichard Henderson 
39758340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a)
397698cd9ca7SRichard Henderson {
3977b35aec85SRichard Henderson     if (a->x) {
3978bc921866SRichard Henderson         DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8);
3979bc921866SRichard Henderson         TCGv_i64 t0 = tcg_temp_new_i64();
3980bc921866SRichard Henderson         TCGv_i64 t1 = tcg_temp_new_i64();
3981bc921866SRichard Henderson 
3982660eefe1SRichard Henderson         /* The computation here never changes privilege level.  */
3983bc921866SRichard Henderson         copy_iaoq_entry(ctx, t0, &next);
3984bc921866SRichard Henderson         tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3);
3985bc921866SRichard Henderson         tcg_gen_add_i64(t0, t0, t1);
3986bc921866SRichard Henderson 
3987bc921866SRichard Henderson         ctx->iaq_j = iaqe_next_absv(ctx, t0);
3988bc921866SRichard Henderson         return do_ibranch(ctx, a->l, false, a->n);
3989b35aec85SRichard Henderson     } else {
3990b35aec85SRichard Henderson         /* BLR R0,RX is a good way to load PC+8 into RX.  */
39912644f80bSRichard Henderson         return do_dbranch(ctx, 0, a->l, a->n);
3992b35aec85SRichard Henderson     }
399398cd9ca7SRichard Henderson }
399498cd9ca7SRichard Henderson 
39958340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a)
399698cd9ca7SRichard Henderson {
39976fd0c7bcSRichard Henderson     TCGv_i64 dest;
399898cd9ca7SRichard Henderson 
39998340f534SRichard Henderson     if (a->x == 0) {
40008340f534SRichard Henderson         dest = load_gpr(ctx, a->b);
400198cd9ca7SRichard Henderson     } else {
4002aac0f603SRichard Henderson         dest = tcg_temp_new_i64();
40036fd0c7bcSRichard Henderson         tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3);
40046fd0c7bcSRichard Henderson         tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b));
400598cd9ca7SRichard Henderson     }
4006660eefe1SRichard Henderson     dest = do_ibranch_priv(ctx, dest);
4007bc921866SRichard Henderson     ctx->iaq_j = iaqe_next_absv(ctx, dest);
4008bc921866SRichard Henderson 
4009bc921866SRichard Henderson     return do_ibranch(ctx, 0, false, a->n);
401098cd9ca7SRichard Henderson }
401198cd9ca7SRichard Henderson 
40128340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a)
401398cd9ca7SRichard Henderson {
4014019f4159SRichard Henderson     TCGv_i64 b = load_gpr(ctx, a->b);
401598cd9ca7SRichard Henderson 
4016019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY
4017bc921866SRichard Henderson     ctx->iaq_j.space = space_select(ctx, 0, b);
4018c301f34eSRichard Henderson #endif
4019bc921866SRichard Henderson     ctx->iaq_j.base = do_ibranch_priv(ctx, b);
4020bc921866SRichard Henderson     ctx->iaq_j.disp = 0;
4021019f4159SRichard Henderson 
4022bc921866SRichard Henderson     return do_ibranch(ctx, a->l, false, a->n);
402398cd9ca7SRichard Henderson }
402498cd9ca7SRichard Henderson 
4025a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a)
4026a8966ba7SRichard Henderson {
4027a8966ba7SRichard Henderson     /* All branch target stack instructions implement as nop. */
4028a8966ba7SRichard Henderson     return ctx->is_pa20;
4029a8966ba7SRichard Henderson }
4030a8966ba7SRichard Henderson 
40311ca74648SRichard Henderson /*
40321ca74648SRichard Henderson  * Float class 0
40331ca74648SRichard Henderson  */
4034ebe9383cSRichard Henderson 
40351ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4036ebe9383cSRichard Henderson {
4037ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
4038ebe9383cSRichard Henderson }
4039ebe9383cSRichard Henderson 
404059f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a)
404159f8c04bSHelge Deller {
4042a300dad3SRichard Henderson     uint64_t ret;
4043a300dad3SRichard Henderson 
4044c53e401eSRichard Henderson     if (ctx->is_pa20) {
4045a300dad3SRichard Henderson         ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */
4046a300dad3SRichard Henderson     } else {
4047a300dad3SRichard Henderson         ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */
4048a300dad3SRichard Henderson     }
4049a300dad3SRichard Henderson 
405059f8c04bSHelge Deller     nullify_over(ctx);
4051a300dad3SRichard Henderson     save_frd(0, tcg_constant_i64(ret));
405259f8c04bSHelge Deller     return nullify_end(ctx);
405359f8c04bSHelge Deller }
405459f8c04bSHelge Deller 
40551ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a)
40561ca74648SRichard Henderson {
40571ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f);
40581ca74648SRichard Henderson }
40591ca74648SRichard Henderson 
4060ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4061ebe9383cSRichard Henderson {
4062ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
4063ebe9383cSRichard Henderson }
4064ebe9383cSRichard Henderson 
40651ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a)
40661ca74648SRichard Henderson {
40671ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d);
40681ca74648SRichard Henderson }
40691ca74648SRichard Henderson 
40701ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4071ebe9383cSRichard Henderson {
4072ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
4073ebe9383cSRichard Henderson }
4074ebe9383cSRichard Henderson 
40751ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a)
40761ca74648SRichard Henderson {
40771ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fabs_f);
40781ca74648SRichard Henderson }
40791ca74648SRichard Henderson 
4080ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4081ebe9383cSRichard Henderson {
4082ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
4083ebe9383cSRichard Henderson }
4084ebe9383cSRichard Henderson 
40851ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a)
40861ca74648SRichard Henderson {
40871ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fabs_d);
40881ca74648SRichard Henderson }
40891ca74648SRichard Henderson 
40901ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a)
40911ca74648SRichard Henderson {
40921ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s);
40931ca74648SRichard Henderson }
40941ca74648SRichard Henderson 
40951ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a)
40961ca74648SRichard Henderson {
40971ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d);
40981ca74648SRichard Henderson }
40991ca74648SRichard Henderson 
41001ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a)
41011ca74648SRichard Henderson {
41021ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s);
41031ca74648SRichard Henderson }
41041ca74648SRichard Henderson 
41051ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a)
41061ca74648SRichard Henderson {
41071ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d);
41081ca74648SRichard Henderson }
41091ca74648SRichard Henderson 
41101ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4111ebe9383cSRichard Henderson {
4112ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
4113ebe9383cSRichard Henderson }
4114ebe9383cSRichard Henderson 
41151ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a)
41161ca74648SRichard Henderson {
41171ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fneg_f);
41181ca74648SRichard Henderson }
41191ca74648SRichard Henderson 
4120ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4121ebe9383cSRichard Henderson {
4122ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
4123ebe9383cSRichard Henderson }
4124ebe9383cSRichard Henderson 
41251ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a)
41261ca74648SRichard Henderson {
41271ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fneg_d);
41281ca74648SRichard Henderson }
41291ca74648SRichard Henderson 
41301ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
4131ebe9383cSRichard Henderson {
4132ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
4133ebe9383cSRichard Henderson }
4134ebe9383cSRichard Henderson 
41351ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a)
41361ca74648SRichard Henderson {
41371ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f);
41381ca74648SRichard Henderson }
41391ca74648SRichard Henderson 
4140ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
4141ebe9383cSRichard Henderson {
4142ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
4143ebe9383cSRichard Henderson }
4144ebe9383cSRichard Henderson 
41451ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a)
41461ca74648SRichard Henderson {
41471ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d);
41481ca74648SRichard Henderson }
41491ca74648SRichard Henderson 
41501ca74648SRichard Henderson /*
41511ca74648SRichard Henderson  * Float class 1
41521ca74648SRichard Henderson  */
41531ca74648SRichard Henderson 
41541ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a)
41551ca74648SRichard Henderson {
41561ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s);
41571ca74648SRichard Henderson }
41581ca74648SRichard Henderson 
41591ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a)
41601ca74648SRichard Henderson {
41611ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d);
41621ca74648SRichard Henderson }
41631ca74648SRichard Henderson 
41641ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a)
41651ca74648SRichard Henderson {
41661ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s);
41671ca74648SRichard Henderson }
41681ca74648SRichard Henderson 
41691ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a)
41701ca74648SRichard Henderson {
41711ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s);
41721ca74648SRichard Henderson }
41731ca74648SRichard Henderson 
41741ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a)
41751ca74648SRichard Henderson {
41761ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d);
41771ca74648SRichard Henderson }
41781ca74648SRichard Henderson 
41791ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a)
41801ca74648SRichard Henderson {
41811ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d);
41821ca74648SRichard Henderson }
41831ca74648SRichard Henderson 
41841ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a)
41851ca74648SRichard Henderson {
41861ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w);
41871ca74648SRichard Henderson }
41881ca74648SRichard Henderson 
41891ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a)
41901ca74648SRichard Henderson {
41911ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w);
41921ca74648SRichard Henderson }
41931ca74648SRichard Henderson 
41941ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a)
41951ca74648SRichard Henderson {
41961ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw);
41971ca74648SRichard Henderson }
41981ca74648SRichard Henderson 
41991ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a)
42001ca74648SRichard Henderson {
42011ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw);
42021ca74648SRichard Henderson }
42031ca74648SRichard Henderson 
42041ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a)
42051ca74648SRichard Henderson {
42061ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w);
42071ca74648SRichard Henderson }
42081ca74648SRichard Henderson 
42091ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a)
42101ca74648SRichard Henderson {
42111ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w);
42121ca74648SRichard Henderson }
42131ca74648SRichard Henderson 
42141ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a)
42151ca74648SRichard Henderson {
42161ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw);
42171ca74648SRichard Henderson }
42181ca74648SRichard Henderson 
42191ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a)
42201ca74648SRichard Henderson {
42211ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw);
42221ca74648SRichard Henderson }
42231ca74648SRichard Henderson 
42241ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a)
42251ca74648SRichard Henderson {
42261ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s);
42271ca74648SRichard Henderson }
42281ca74648SRichard Henderson 
42291ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a)
42301ca74648SRichard Henderson {
42311ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s);
42321ca74648SRichard Henderson }
42331ca74648SRichard Henderson 
42341ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a)
42351ca74648SRichard Henderson {
42361ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d);
42371ca74648SRichard Henderson }
42381ca74648SRichard Henderson 
42391ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a)
42401ca74648SRichard Henderson {
42411ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d);
42421ca74648SRichard Henderson }
42431ca74648SRichard Henderson 
42441ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a)
42451ca74648SRichard Henderson {
42461ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw);
42471ca74648SRichard Henderson }
42481ca74648SRichard Henderson 
42491ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a)
42501ca74648SRichard Henderson {
42511ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw);
42521ca74648SRichard Henderson }
42531ca74648SRichard Henderson 
42541ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a)
42551ca74648SRichard Henderson {
42561ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw);
42571ca74648SRichard Henderson }
42581ca74648SRichard Henderson 
42591ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a)
42601ca74648SRichard Henderson {
42611ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw);
42621ca74648SRichard Henderson }
42631ca74648SRichard Henderson 
42641ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a)
42651ca74648SRichard Henderson {
42661ca74648SRichard Henderson     return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw);
42671ca74648SRichard Henderson }
42681ca74648SRichard Henderson 
42691ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a)
42701ca74648SRichard Henderson {
42711ca74648SRichard Henderson     return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw);
42721ca74648SRichard Henderson }
42731ca74648SRichard Henderson 
42741ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a)
42751ca74648SRichard Henderson {
42761ca74648SRichard Henderson     return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw);
42771ca74648SRichard Henderson }
42781ca74648SRichard Henderson 
42791ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a)
42801ca74648SRichard Henderson {
42811ca74648SRichard Henderson     return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw);
42821ca74648SRichard Henderson }
42831ca74648SRichard Henderson 
42841ca74648SRichard Henderson /*
42851ca74648SRichard Henderson  * Float class 2
42861ca74648SRichard Henderson  */
42871ca74648SRichard Henderson 
42881ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a)
4289ebe9383cSRichard Henderson {
4290ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
4291ebe9383cSRichard Henderson 
4292ebe9383cSRichard Henderson     nullify_over(ctx);
4293ebe9383cSRichard Henderson 
42941ca74648SRichard Henderson     ta = load_frw0_i32(a->r1);
42951ca74648SRichard Henderson     tb = load_frw0_i32(a->r2);
429629dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
429729dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4298ebe9383cSRichard Henderson 
4299ad75a51eSRichard Henderson     gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc);
4300ebe9383cSRichard Henderson 
43011ca74648SRichard Henderson     return nullify_end(ctx);
4302ebe9383cSRichard Henderson }
4303ebe9383cSRichard Henderson 
43041ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a)
4305ebe9383cSRichard Henderson {
4306ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
4307ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
4308ebe9383cSRichard Henderson 
4309ebe9383cSRichard Henderson     nullify_over(ctx);
4310ebe9383cSRichard Henderson 
43111ca74648SRichard Henderson     ta = load_frd0(a->r1);
43121ca74648SRichard Henderson     tb = load_frd0(a->r2);
431329dd6f64SRichard Henderson     ty = tcg_constant_i32(a->y);
431429dd6f64SRichard Henderson     tc = tcg_constant_i32(a->c);
4315ebe9383cSRichard Henderson 
4316ad75a51eSRichard Henderson     gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc);
4317ebe9383cSRichard Henderson 
431831234768SRichard Henderson     return nullify_end(ctx);
4319ebe9383cSRichard Henderson }
4320ebe9383cSRichard Henderson 
43211ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a)
4322ebe9383cSRichard Henderson {
43233692ad21SRichard Henderson     TCGCond tc = TCG_COND_TSTNE;
43243692ad21SRichard Henderson     uint32_t mask;
43256fd0c7bcSRichard Henderson     TCGv_i64 t;
4326ebe9383cSRichard Henderson 
4327ebe9383cSRichard Henderson     nullify_over(ctx);
4328ebe9383cSRichard Henderson 
4329aac0f603SRichard Henderson     t = tcg_temp_new_i64();
43306fd0c7bcSRichard Henderson     tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow));
4331ebe9383cSRichard Henderson 
43321ca74648SRichard Henderson     if (a->y == 1) {
43331ca74648SRichard Henderson         switch (a->c) {
4334ebe9383cSRichard Henderson         case 0: /* simple */
4335f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK;
4336f33a22c1SRichard Henderson             break;
4337ebe9383cSRichard Henderson         case 2: /* rej */
43383692ad21SRichard Henderson             tc = TCG_COND_TSTEQ;
4339ebe9383cSRichard Henderson             /* fallthru */
4340ebe9383cSRichard Henderson         case 1: /* acc */
4341f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ_MASK;
4342ebe9383cSRichard Henderson             break;
4343ebe9383cSRichard Henderson         case 6: /* rej8 */
43443692ad21SRichard Henderson             tc = TCG_COND_TSTEQ;
4345ebe9383cSRichard Henderson             /* fallthru */
4346ebe9383cSRichard Henderson         case 5: /* acc8 */
4347f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_6_MASK;
4348ebe9383cSRichard Henderson             break;
4349ebe9383cSRichard Henderson         case 9: /* acc6 */
4350f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_4_MASK;
4351ebe9383cSRichard Henderson             break;
4352ebe9383cSRichard Henderson         case 13: /* acc4 */
4353f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_2_MASK;
4354ebe9383cSRichard Henderson             break;
4355ebe9383cSRichard Henderson         case 17: /* acc2 */
4356f33a22c1SRichard Henderson             mask = R_FPSR_C_MASK | R_FPSR_CQ0_MASK;
4357ebe9383cSRichard Henderson             break;
4358ebe9383cSRichard Henderson         default:
43591ca74648SRichard Henderson             gen_illegal(ctx);
43601ca74648SRichard Henderson             return true;
4361ebe9383cSRichard Henderson         }
43621ca74648SRichard Henderson     } else {
43631ca74648SRichard Henderson         unsigned cbit = (a->y ^ 1) - 1;
43643692ad21SRichard Henderson         mask = R_FPSR_CA0_MASK >> cbit;
43651ca74648SRichard Henderson     }
43661ca74648SRichard Henderson 
43673692ad21SRichard Henderson     ctx->null_cond = cond_make_ti(tc, t, mask);
436831234768SRichard Henderson     return nullify_end(ctx);
4369ebe9383cSRichard Henderson }
4370ebe9383cSRichard Henderson 
43711ca74648SRichard Henderson /*
43721ca74648SRichard Henderson  * Float class 2
43731ca74648SRichard Henderson  */
43741ca74648SRichard Henderson 
43751ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a)
4376ebe9383cSRichard Henderson {
43771ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s);
43781ca74648SRichard Henderson }
43791ca74648SRichard Henderson 
43801ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a)
43811ca74648SRichard Henderson {
43821ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d);
43831ca74648SRichard Henderson }
43841ca74648SRichard Henderson 
43851ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a)
43861ca74648SRichard Henderson {
43871ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s);
43881ca74648SRichard Henderson }
43891ca74648SRichard Henderson 
43901ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a)
43911ca74648SRichard Henderson {
43921ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d);
43931ca74648SRichard Henderson }
43941ca74648SRichard Henderson 
43951ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a)
43961ca74648SRichard Henderson {
43971ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s);
43981ca74648SRichard Henderson }
43991ca74648SRichard Henderson 
44001ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a)
44011ca74648SRichard Henderson {
44021ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d);
44031ca74648SRichard Henderson }
44041ca74648SRichard Henderson 
44051ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a)
44061ca74648SRichard Henderson {
44071ca74648SRichard Henderson     return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s);
44081ca74648SRichard Henderson }
44091ca74648SRichard Henderson 
44101ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a)
44111ca74648SRichard Henderson {
44121ca74648SRichard Henderson     return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d);
44131ca74648SRichard Henderson }
44141ca74648SRichard Henderson 
44151ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a)
44161ca74648SRichard Henderson {
44171ca74648SRichard Henderson     TCGv_i64 x, y;
4418ebe9383cSRichard Henderson 
4419ebe9383cSRichard Henderson     nullify_over(ctx);
4420ebe9383cSRichard Henderson 
44211ca74648SRichard Henderson     x = load_frw0_i64(a->r1);
44221ca74648SRichard Henderson     y = load_frw0_i64(a->r2);
44231ca74648SRichard Henderson     tcg_gen_mul_i64(x, x, y);
44241ca74648SRichard Henderson     save_frd(a->t, x);
4425ebe9383cSRichard Henderson 
442631234768SRichard Henderson     return nullify_end(ctx);
4427ebe9383cSRichard Henderson }
4428ebe9383cSRichard Henderson 
4429ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
4430ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
4431ebe9383cSRichard Henderson {
4432ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
4433ebe9383cSRichard Henderson }
4434ebe9383cSRichard Henderson 
4435b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4436ebe9383cSRichard Henderson {
4437b1e2af57SRichard Henderson     int tm = fmpyadd_s_reg(a->tm);
4438b1e2af57SRichard Henderson     int ra = fmpyadd_s_reg(a->ra);
4439b1e2af57SRichard Henderson     int ta = fmpyadd_s_reg(a->ta);
4440b1e2af57SRichard Henderson     int rm2 = fmpyadd_s_reg(a->rm2);
4441b1e2af57SRichard Henderson     int rm1 = fmpyadd_s_reg(a->rm1);
4442ebe9383cSRichard Henderson 
4443ebe9383cSRichard Henderson     nullify_over(ctx);
4444ebe9383cSRichard Henderson 
4445ebe9383cSRichard Henderson     do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
4446ebe9383cSRichard Henderson     do_fop_weww(ctx, ta, ta, ra,
4447ebe9383cSRichard Henderson                 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
4448ebe9383cSRichard Henderson 
444931234768SRichard Henderson     return nullify_end(ctx);
4450ebe9383cSRichard Henderson }
4451ebe9383cSRichard Henderson 
4452b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a)
4453b1e2af57SRichard Henderson {
4454b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, false);
4455b1e2af57SRichard Henderson }
4456b1e2af57SRichard Henderson 
4457b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a)
4458b1e2af57SRichard Henderson {
4459b1e2af57SRichard Henderson     return do_fmpyadd_s(ctx, a, true);
4460b1e2af57SRichard Henderson }
4461b1e2af57SRichard Henderson 
4462b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub)
4463b1e2af57SRichard Henderson {
4464b1e2af57SRichard Henderson     nullify_over(ctx);
4465b1e2af57SRichard Henderson 
4466b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d);
4467b1e2af57SRichard Henderson     do_fop_dedd(ctx, a->ta, a->ta, a->ra,
4468b1e2af57SRichard Henderson                 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
4469b1e2af57SRichard Henderson 
4470b1e2af57SRichard Henderson     return nullify_end(ctx);
4471b1e2af57SRichard Henderson }
4472b1e2af57SRichard Henderson 
4473b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a)
4474b1e2af57SRichard Henderson {
4475b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, false);
4476b1e2af57SRichard Henderson }
4477b1e2af57SRichard Henderson 
4478b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a)
4479b1e2af57SRichard Henderson {
4480b1e2af57SRichard Henderson     return do_fmpyadd_d(ctx, a, true);
4481b1e2af57SRichard Henderson }
4482b1e2af57SRichard Henderson 
4483c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a)
4484ebe9383cSRichard Henderson {
4485c3bad4f8SRichard Henderson     TCGv_i32 x, y, z;
4486ebe9383cSRichard Henderson 
4487ebe9383cSRichard Henderson     nullify_over(ctx);
4488c3bad4f8SRichard Henderson     x = load_frw0_i32(a->rm1);
4489c3bad4f8SRichard Henderson     y = load_frw0_i32(a->rm2);
4490c3bad4f8SRichard Henderson     z = load_frw0_i32(a->ra3);
4491ebe9383cSRichard Henderson 
4492c3bad4f8SRichard Henderson     if (a->neg) {
4493ad75a51eSRichard Henderson         gen_helper_fmpynfadd_s(x, tcg_env, x, y, z);
4494ebe9383cSRichard Henderson     } else {
4495ad75a51eSRichard Henderson         gen_helper_fmpyfadd_s(x, tcg_env, x, y, z);
4496ebe9383cSRichard Henderson     }
4497ebe9383cSRichard Henderson 
4498c3bad4f8SRichard Henderson     save_frw_i32(a->t, x);
449931234768SRichard Henderson     return nullify_end(ctx);
4500ebe9383cSRichard Henderson }
4501ebe9383cSRichard Henderson 
4502c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a)
4503ebe9383cSRichard Henderson {
4504c3bad4f8SRichard Henderson     TCGv_i64 x, y, z;
4505ebe9383cSRichard Henderson 
4506ebe9383cSRichard Henderson     nullify_over(ctx);
4507c3bad4f8SRichard Henderson     x = load_frd0(a->rm1);
4508c3bad4f8SRichard Henderson     y = load_frd0(a->rm2);
4509c3bad4f8SRichard Henderson     z = load_frd0(a->ra3);
4510ebe9383cSRichard Henderson 
4511c3bad4f8SRichard Henderson     if (a->neg) {
4512ad75a51eSRichard Henderson         gen_helper_fmpynfadd_d(x, tcg_env, x, y, z);
4513ebe9383cSRichard Henderson     } else {
4514ad75a51eSRichard Henderson         gen_helper_fmpyfadd_d(x, tcg_env, x, y, z);
4515ebe9383cSRichard Henderson     }
4516ebe9383cSRichard Henderson 
4517c3bad4f8SRichard Henderson     save_frd(a->t, x);
451831234768SRichard Henderson     return nullify_end(ctx);
4519ebe9383cSRichard Henderson }
4520ebe9383cSRichard Henderson 
452138193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */
452238193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a)
452315da177bSSven Schnelle {
4524cf6b28d4SHelge Deller     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4525cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY
4526ad75a51eSRichard Henderson     nullify_over(ctx);
4527ad75a51eSRichard Henderson     gen_helper_diag_btlb(tcg_env);
4528cf6b28d4SHelge Deller     return nullify_end(ctx);
452938193127SRichard Henderson #endif
453015da177bSSven Schnelle }
453138193127SRichard Henderson 
453238193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */
453338193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a)
453438193127SRichard Henderson {
453538193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
453638193127SRichard Henderson #ifndef CONFIG_USER_ONLY
4537dbca0835SHelge Deller     nullify_over(ctx);
4538dbca0835SHelge Deller     gen_helper_diag_console_output(tcg_env);
4539dbca0835SHelge Deller     return nullify_end(ctx);
4540ad75a51eSRichard Henderson #endif
454138193127SRichard Henderson }
454238193127SRichard Henderson 
45433bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45443bdf2081SHelge Deller {
45453bdf2081SHelge Deller     return !ctx->is_pa20 && do_getshadowregs(ctx);
45463bdf2081SHelge Deller }
45473bdf2081SHelge Deller 
45483bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(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_putshadowregs_pa1(DisasContext *ctx, arg_empty *a)
45543bdf2081SHelge Deller {
45553bdf2081SHelge Deller     return !ctx->is_pa20 && do_putshadowregs(ctx);
45563bdf2081SHelge Deller }
45573bdf2081SHelge Deller 
45583bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a)
45593bdf2081SHelge Deller {
45603bdf2081SHelge Deller     return ctx->is_pa20 && do_putshadowregs(ctx);
45613bdf2081SHelge Deller }
45623bdf2081SHelge Deller 
456338193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a)
456438193127SRichard Henderson {
456538193127SRichard Henderson     CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
4566ad75a51eSRichard Henderson     qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i);
4567ad75a51eSRichard Henderson     return true;
4568ad75a51eSRichard Henderson }
456915da177bSSven Schnelle 
4570b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
457161766fe9SRichard Henderson {
457251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
45739dfcd243SRichard Henderson     uint64_t cs_base, iaoq_f, iaoq_b;
4574f764718dSRichard Henderson     int bound;
457561766fe9SRichard Henderson 
457651b061fbSRichard Henderson     ctx->cs = cs;
4577494737b7SRichard Henderson     ctx->tb_flags = ctx->base.tb->flags;
4578bd6243a3SRichard Henderson     ctx->is_pa20 = hppa_is_pa20(cpu_env(cs));
45793d68ee7bSRichard Henderson 
45803d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY
45813c13b0ffSRichard Henderson     ctx->privilege = PRIV_USER;
45823d68ee7bSRichard Henderson     ctx->mmu_idx = MMU_USER_IDX;
4583217d1a5eSRichard Henderson     ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN);
4584c301f34eSRichard Henderson #else
4585494737b7SRichard Henderson     ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3;
4586bb67ec32SRichard Henderson     ctx->mmu_idx = (ctx->tb_flags & PSW_D
4587bb67ec32SRichard Henderson                     ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P)
4588451d993dSRichard Henderson                     : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
45899dfcd243SRichard Henderson #endif
45903d68ee7bSRichard Henderson 
4591c301f34eSRichard Henderson     /* Recover the IAOQ values from the GVA + PRIV.  */
45929dfcd243SRichard Henderson     cs_base = ctx->base.tb->cs_base;
45939dfcd243SRichard Henderson     iaoq_f = cs_base & MAKE_64BIT_MASK(32, 32);
45949dfcd243SRichard Henderson     iaoq_f |= ctx->base.pc_first & MAKE_64BIT_MASK(2, 30);
45959dfcd243SRichard Henderson     iaoq_f |= ctx->privilege;
45969dfcd243SRichard Henderson     ctx->iaoq_first = iaoq_f;
4597c301f34eSRichard Henderson 
45989dfcd243SRichard Henderson     if (unlikely(cs_base & CS_BASE_DIFFSPACE)) {
4599bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
46009dfcd243SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
46019dfcd243SRichard Henderson     } else if (unlikely(cs_base & CS_BASE_DIFFPAGE)) {
46029dfcd243SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
46039dfcd243SRichard Henderson     } else {
46049dfcd243SRichard Henderson         iaoq_b = (iaoq_f & TARGET_PAGE_MASK) | (cs_base & ~TARGET_PAGE_MASK);
46059dfcd243SRichard Henderson         ctx->iaq_b.disp = iaoq_b - iaoq_f;
4606bc921866SRichard Henderson     }
460761766fe9SRichard Henderson 
4608a4db4a78SRichard Henderson     ctx->zero = tcg_constant_i64(0);
4609a4db4a78SRichard Henderson 
46103d68ee7bSRichard Henderson     /* Bound the number of instructions by those left on the page.  */
46113d68ee7bSRichard Henderson     bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
4612b542683dSEmilio G. Cota     ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
461361766fe9SRichard Henderson }
461461766fe9SRichard Henderson 
461551b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
461651b061fbSRichard Henderson {
461751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
461861766fe9SRichard Henderson 
46193d68ee7bSRichard Henderson     /* Seed the nullification status from PSW[N], as saved in TB->FLAGS.  */
462051b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
462151b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
4622494737b7SRichard Henderson     if (ctx->tb_flags & PSW_N) {
462351b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
462451b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
4625129e9cc3SRichard Henderson     }
462651b061fbSRichard Henderson     ctx->null_lab = NULL;
462761766fe9SRichard Henderson }
462861766fe9SRichard Henderson 
462951b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
463051b061fbSRichard Henderson {
463151b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
463251b061fbSRichard Henderson 
4633bc921866SRichard Henderson     tcg_debug_assert(!iaqe_variable(&ctx->iaq_f));
46340d89cb7cSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp,
46350d89cb7cSRichard Henderson                        (iaqe_variable(&ctx->iaq_b) ? -1 :
46360d89cb7cSRichard Henderson                         ctx->iaoq_first + ctx->iaq_b.disp), 0);
463724638bd1SRichard Henderson     ctx->insn_start_updated = false;
463851b061fbSRichard Henderson }
463951b061fbSRichard Henderson 
464051b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
464151b061fbSRichard Henderson {
464251b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4643b77af26eSRichard Henderson     CPUHPPAState *env = cpu_env(cs);
464451b061fbSRichard Henderson     DisasJumpType ret;
464551b061fbSRichard Henderson 
464651b061fbSRichard Henderson     /* Execute one insn.  */
4647ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4648c301f34eSRichard Henderson     if (ctx->base.pc_next < TARGET_PAGE_SIZE) {
464931234768SRichard Henderson         do_page_zero(ctx);
465031234768SRichard Henderson         ret = ctx->base.is_jmp;
4651869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
4652ba1d0b44SRichard Henderson     } else
4653ba1d0b44SRichard Henderson #endif
4654ba1d0b44SRichard Henderson     {
465561766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
465661766fe9SRichard Henderson            the page permissions for execute.  */
46574e116893SIlya Leoshkevich         uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next);
465861766fe9SRichard Henderson 
4659bc921866SRichard Henderson         /*
4660bc921866SRichard Henderson          * Set up the IA queue for the next insn.
4661bc921866SRichard Henderson          * This will be overwritten by a branch.
4662bc921866SRichard Henderson          */
4663bc921866SRichard Henderson         ctx->iaq_n = NULL;
4664bc921866SRichard Henderson         memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j));
466561766fe9SRichard Henderson 
466651b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
466751b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
4668869051eaSRichard Henderson             ret = DISAS_NEXT;
4669129e9cc3SRichard Henderson         } else {
46701a19da0dSRichard Henderson             ctx->insn = insn;
467131274b46SRichard Henderson             if (!decode(ctx, insn)) {
467231274b46SRichard Henderson                 gen_illegal(ctx);
467331274b46SRichard Henderson             }
467431234768SRichard Henderson             ret = ctx->base.is_jmp;
467551b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
4676129e9cc3SRichard Henderson         }
467761766fe9SRichard Henderson     }
467861766fe9SRichard Henderson 
4679dbdccbdfSRichard Henderson     /* If the TranslationBlock must end, do so. */
4680dbdccbdfSRichard Henderson     ctx->base.pc_next += 4;
4681dbdccbdfSRichard Henderson     if (ret != DISAS_NEXT) {
4682dbdccbdfSRichard Henderson         return;
468361766fe9SRichard Henderson     }
4684dbdccbdfSRichard Henderson     /* Note this also detects a priority change. */
4685bc921866SRichard Henderson     if (iaqe_variable(&ctx->iaq_b)
4686bc921866SRichard Henderson         || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) {
4687dbdccbdfSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_STALE;
4688dbdccbdfSRichard Henderson         return;
4689129e9cc3SRichard Henderson     }
4690dbdccbdfSRichard Henderson 
4691dbdccbdfSRichard Henderson     /*
4692dbdccbdfSRichard Henderson      * Advance the insn queue.
4693dbdccbdfSRichard Henderson      * The only exit now is DISAS_TOO_MANY from the translator loop.
4694dbdccbdfSRichard Henderson      */
4695bc921866SRichard Henderson     ctx->iaq_f.disp = ctx->iaq_b.disp;
4696bc921866SRichard Henderson     if (!ctx->iaq_n) {
4697bc921866SRichard Henderson         ctx->iaq_b.disp += 4;
4698bc921866SRichard Henderson         return;
4699bc921866SRichard Henderson     }
4700bc921866SRichard Henderson     /*
4701bc921866SRichard Henderson      * If IAQ_Next is variable in any way, we need to copy into the
4702bc921866SRichard Henderson      * IAQ_Back globals, in case the next insn raises an exception.
4703bc921866SRichard Henderson      */
4704bc921866SRichard Henderson     if (ctx->iaq_n->base) {
4705bc921866SRichard Henderson         copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n);
4706bc921866SRichard Henderson         ctx->iaq_b.base = cpu_iaoq_b;
4707bc921866SRichard Henderson         ctx->iaq_b.disp = 0;
47080dcd6640SRichard Henderson     } else {
4709bc921866SRichard Henderson         ctx->iaq_b.disp = ctx->iaq_n->disp;
47100dcd6640SRichard Henderson     }
4711bc921866SRichard Henderson     if (ctx->iaq_n->space) {
4712bc921866SRichard Henderson         tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space);
4713bc921866SRichard Henderson         ctx->iaq_b.space = cpu_iasq_b;
4714142faf5fSRichard Henderson     }
471561766fe9SRichard Henderson }
471661766fe9SRichard Henderson 
471751b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
471851b061fbSRichard Henderson {
471951b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
4720e1b5a5edSRichard Henderson     DisasJumpType is_jmp = ctx->base.is_jmp;
4721dbdccbdfSRichard Henderson     /* Assume the insn queue has not been advanced. */
4722bc921866SRichard Henderson     DisasIAQE *f = &ctx->iaq_b;
4723bc921866SRichard Henderson     DisasIAQE *b = ctx->iaq_n;
472451b061fbSRichard Henderson 
4725e1b5a5edSRichard Henderson     switch (is_jmp) {
4726869051eaSRichard Henderson     case DISAS_NORETURN:
472761766fe9SRichard Henderson         break;
472851b061fbSRichard Henderson     case DISAS_TOO_MANY:
4729dbdccbdfSRichard Henderson         /* The insn queue has not been advanced. */
4730bc921866SRichard Henderson         f = &ctx->iaq_f;
4731bc921866SRichard Henderson         b = &ctx->iaq_b;
473261766fe9SRichard Henderson         /* FALLTHRU */
4733dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE:
4734bc921866SRichard Henderson         if (use_goto_tb(ctx, f, b)
4735dbdccbdfSRichard Henderson             && (ctx->null_cond.c == TCG_COND_NEVER
4736dbdccbdfSRichard Henderson                 || ctx->null_cond.c == TCG_COND_ALWAYS)) {
4737dbdccbdfSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
4738bc921866SRichard Henderson             gen_goto_tb(ctx, 0, f, b);
47398532a14eSRichard Henderson             break;
474061766fe9SRichard Henderson         }
4741c5d0aec2SRichard Henderson         /* FALLTHRU */
4742dbdccbdfSRichard Henderson     case DISAS_IAQ_N_STALE_EXIT:
4743bc921866SRichard Henderson         install_iaq_entries(ctx, f, b);
4744dbdccbdfSRichard Henderson         nullify_save(ctx);
4745dbdccbdfSRichard Henderson         if (is_jmp == DISAS_IAQ_N_STALE_EXIT) {
4746dbdccbdfSRichard Henderson             tcg_gen_exit_tb(NULL, 0);
4747dbdccbdfSRichard Henderson             break;
4748dbdccbdfSRichard Henderson         }
4749dbdccbdfSRichard Henderson         /* FALLTHRU */
4750dbdccbdfSRichard Henderson     case DISAS_IAQ_N_UPDATED:
4751dbdccbdfSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
4752dbdccbdfSRichard Henderson         break;
4753c5d0aec2SRichard Henderson     case DISAS_EXIT:
4754c5d0aec2SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
475561766fe9SRichard Henderson         break;
475661766fe9SRichard Henderson     default:
475751b061fbSRichard Henderson         g_assert_not_reached();
475861766fe9SRichard Henderson     }
475980603007SRichard Henderson 
476080603007SRichard Henderson     for (DisasDelayException *e = ctx->delay_excp_list; e ; e = e->next) {
476180603007SRichard Henderson         gen_set_label(e->lab);
476280603007SRichard Henderson         if (e->set_n >= 0) {
476380603007SRichard Henderson             tcg_gen_movi_i64(cpu_psw_n, e->set_n);
476480603007SRichard Henderson         }
476580603007SRichard Henderson         if (e->set_iir) {
476680603007SRichard Henderson             tcg_gen_st_i64(tcg_constant_i64(e->insn), tcg_env,
476780603007SRichard Henderson                            offsetof(CPUHPPAState, cr[CR_IIR]));
476880603007SRichard Henderson         }
476980603007SRichard Henderson         install_iaq_entries(ctx, &e->iaq_f, &e->iaq_b);
477080603007SRichard Henderson         gen_excp_1(e->excp);
477180603007SRichard Henderson     }
477251b061fbSRichard Henderson }
477361766fe9SRichard Henderson 
47748eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase,
47758eb806a7SRichard Henderson                               CPUState *cs, FILE *logfile)
477651b061fbSRichard Henderson {
4777c301f34eSRichard Henderson     target_ulong pc = dcbase->pc_first;
477861766fe9SRichard Henderson 
4779ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY
4780ba1d0b44SRichard Henderson     switch (pc) {
47817ad439dfSRichard Henderson     case 0x00:
47828eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000000:  (null)\n");
4783ba1d0b44SRichard Henderson         return;
47847ad439dfSRichard Henderson     case 0xb0:
47858eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000b0:  light-weight-syscall\n");
4786ba1d0b44SRichard Henderson         return;
47877ad439dfSRichard Henderson     case 0xe0:
47888eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x000000e0:  set-thread-pointer-syscall\n");
4789ba1d0b44SRichard Henderson         return;
47907ad439dfSRichard Henderson     case 0x100:
47918eb806a7SRichard Henderson         fprintf(logfile, "IN:\n0x00000100:  syscall\n");
4792ba1d0b44SRichard Henderson         return;
47937ad439dfSRichard Henderson     }
4794ba1d0b44SRichard Henderson #endif
4795ba1d0b44SRichard Henderson 
47968eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(pc));
47978eb806a7SRichard Henderson     target_disas(logfile, cs, pc, dcbase->tb->size);
479861766fe9SRichard Henderson }
479951b061fbSRichard Henderson 
480051b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
480151b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
480251b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
480351b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
480451b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
480551b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
480651b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
480751b061fbSRichard Henderson };
480851b061fbSRichard Henderson 
4809597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
481032f0c394SAnton Johansson                            vaddr pc, void *host_pc)
481151b061fbSRichard Henderson {
4812bc921866SRichard Henderson     DisasContext ctx = { };
4813306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
481461766fe9SRichard Henderson }
4815