xref: /openbmc/qemu/target/hppa/translate.c (revision f764718d0cb30af9f1f8e1d6a33622cc05ca4155)
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
961766fe9SRichard Henderson  * version 2 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"
2561766fe9SRichard Henderson #include "tcg-op.h"
2661766fe9SRichard Henderson #include "exec/cpu_ldst.h"
2761766fe9SRichard Henderson #include "exec/helper-proto.h"
2861766fe9SRichard Henderson #include "exec/helper-gen.h"
29869051eaSRichard Henderson #include "exec/translator.h"
3061766fe9SRichard Henderson #include "trace-tcg.h"
3161766fe9SRichard Henderson #include "exec/log.h"
3261766fe9SRichard Henderson 
3361766fe9SRichard Henderson typedef struct DisasCond {
3461766fe9SRichard Henderson     TCGCond c;
3561766fe9SRichard Henderson     TCGv a0, a1;
3661766fe9SRichard Henderson     bool a0_is_n;
3761766fe9SRichard Henderson     bool a1_is_0;
3861766fe9SRichard Henderson } DisasCond;
3961766fe9SRichard Henderson 
4061766fe9SRichard Henderson typedef struct DisasContext {
41d01a3625SRichard Henderson     DisasContextBase base;
4261766fe9SRichard Henderson     CPUState *cs;
4361766fe9SRichard Henderson 
4461766fe9SRichard Henderson     target_ulong iaoq_f;
4561766fe9SRichard Henderson     target_ulong iaoq_b;
4661766fe9SRichard Henderson     target_ulong iaoq_n;
4761766fe9SRichard Henderson     TCGv iaoq_n_var;
4861766fe9SRichard Henderson 
4961766fe9SRichard Henderson     int ntemps;
5061766fe9SRichard Henderson     TCGv temps[8];
5161766fe9SRichard Henderson 
5261766fe9SRichard Henderson     DisasCond null_cond;
5361766fe9SRichard Henderson     TCGLabel *null_lab;
5461766fe9SRichard Henderson 
5561766fe9SRichard Henderson     bool psw_n_nonzero;
5661766fe9SRichard Henderson } DisasContext;
5761766fe9SRichard Henderson 
58869051eaSRichard Henderson /* Target-specific return values from translate_one, indicating the
59869051eaSRichard Henderson    state of the TB.  Note that DISAS_NEXT indicates that we are not
60869051eaSRichard Henderson    exiting the TB.  */
6161766fe9SRichard Henderson 
6261766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated
6361766fe9SRichard Henderson    the iaq (for whatever reason), so don't do it again on exit.  */
64869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED  DISAS_TARGET_0
6561766fe9SRichard Henderson 
6661766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor
6761766fe9SRichard Henderson    updated the iaq for the next instruction to be executed.  */
68869051eaSRichard Henderson #define DISAS_IAQ_N_STALE    DISAS_TARGET_1
6961766fe9SRichard Henderson 
7061766fe9SRichard Henderson typedef struct DisasInsn {
7161766fe9SRichard Henderson     uint32_t insn, mask;
72869051eaSRichard Henderson     DisasJumpType (*trans)(DisasContext *ctx, uint32_t insn,
7361766fe9SRichard Henderson                            const struct DisasInsn *f);
74b2167459SRichard Henderson     union {
75eff235ebSPaolo Bonzini         void (*ttt)(TCGv, TCGv, TCGv);
76eff235ebSPaolo Bonzini         void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
77eff235ebSPaolo Bonzini         void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
78eff235ebSPaolo Bonzini         void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
79eff235ebSPaolo Bonzini         void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
80eff235ebSPaolo Bonzini         void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
81eff235ebSPaolo Bonzini         void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
82eff235ebSPaolo Bonzini     } f;
8361766fe9SRichard Henderson } DisasInsn;
8461766fe9SRichard Henderson 
8561766fe9SRichard Henderson /* global register indexes */
8661766fe9SRichard Henderson static TCGv cpu_gr[32];
8761766fe9SRichard Henderson static TCGv cpu_iaoq_f;
8861766fe9SRichard Henderson static TCGv cpu_iaoq_b;
8961766fe9SRichard Henderson static TCGv cpu_sar;
9061766fe9SRichard Henderson static TCGv cpu_psw_n;
9161766fe9SRichard Henderson static TCGv cpu_psw_v;
9261766fe9SRichard Henderson static TCGv cpu_psw_cb;
9361766fe9SRichard Henderson static TCGv cpu_psw_cb_msb;
9461766fe9SRichard Henderson static TCGv cpu_cr26;
9561766fe9SRichard Henderson static TCGv cpu_cr27;
9661766fe9SRichard Henderson 
9761766fe9SRichard Henderson #include "exec/gen-icount.h"
9861766fe9SRichard Henderson 
9961766fe9SRichard Henderson void hppa_translate_init(void)
10061766fe9SRichard Henderson {
10161766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
10261766fe9SRichard Henderson 
10361766fe9SRichard Henderson     typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
10461766fe9SRichard Henderson     static const GlobalVar vars[] = {
10561766fe9SRichard Henderson         DEF_VAR(sar),
10661766fe9SRichard Henderson         DEF_VAR(cr26),
10761766fe9SRichard Henderson         DEF_VAR(cr27),
10861766fe9SRichard Henderson         DEF_VAR(psw_n),
10961766fe9SRichard Henderson         DEF_VAR(psw_v),
11061766fe9SRichard Henderson         DEF_VAR(psw_cb),
11161766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
11261766fe9SRichard Henderson         DEF_VAR(iaoq_f),
11361766fe9SRichard Henderson         DEF_VAR(iaoq_b),
11461766fe9SRichard Henderson     };
11561766fe9SRichard Henderson 
11661766fe9SRichard Henderson #undef DEF_VAR
11761766fe9SRichard Henderson 
11861766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
11961766fe9SRichard Henderson     static const char gr_names[32][4] = {
12061766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
12161766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
12261766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
12361766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
12461766fe9SRichard Henderson     };
12561766fe9SRichard Henderson 
12661766fe9SRichard Henderson     int i;
12761766fe9SRichard Henderson 
128*f764718dSRichard Henderson     cpu_gr[0] = NULL;
12961766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
13061766fe9SRichard Henderson         cpu_gr[i] = tcg_global_mem_new(cpu_env,
13161766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
13261766fe9SRichard Henderson                                        gr_names[i]);
13361766fe9SRichard Henderson     }
13461766fe9SRichard Henderson 
13561766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
13661766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
13761766fe9SRichard Henderson         *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
13861766fe9SRichard Henderson     }
13961766fe9SRichard Henderson }
14061766fe9SRichard Henderson 
141129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
142129e9cc3SRichard Henderson {
143*f764718dSRichard Henderson     return (DisasCond){
144*f764718dSRichard Henderson         .c = TCG_COND_NEVER,
145*f764718dSRichard Henderson         .a0 = NULL,
146*f764718dSRichard Henderson         .a1 = NULL,
147*f764718dSRichard Henderson     };
148129e9cc3SRichard Henderson }
149129e9cc3SRichard Henderson 
150129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
151129e9cc3SRichard Henderson {
152*f764718dSRichard Henderson     return (DisasCond){
153*f764718dSRichard Henderson         .c = TCG_COND_NE,
154*f764718dSRichard Henderson         .a0 = cpu_psw_n,
155*f764718dSRichard Henderson         .a0_is_n = true,
156*f764718dSRichard Henderson         .a1 = NULL,
157*f764718dSRichard Henderson         .a1_is_0 = true
158*f764718dSRichard Henderson     };
159129e9cc3SRichard Henderson }
160129e9cc3SRichard Henderson 
161129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0)
162129e9cc3SRichard Henderson {
163*f764718dSRichard Henderson     DisasCond r = { .c = c, .a1 = NULL, .a1_is_0 = true };
164129e9cc3SRichard Henderson 
165129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
166129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
167129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
168129e9cc3SRichard Henderson 
169129e9cc3SRichard Henderson     return r;
170129e9cc3SRichard Henderson }
171129e9cc3SRichard Henderson 
172129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
173129e9cc3SRichard Henderson {
174129e9cc3SRichard Henderson     DisasCond r = { .c = c };
175129e9cc3SRichard Henderson 
176129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
177129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
178129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
179129e9cc3SRichard Henderson     r.a1 = tcg_temp_new();
180129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a1, a1);
181129e9cc3SRichard Henderson 
182129e9cc3SRichard Henderson     return r;
183129e9cc3SRichard Henderson }
184129e9cc3SRichard Henderson 
185129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond)
186129e9cc3SRichard Henderson {
187129e9cc3SRichard Henderson     if (cond->a1_is_0) {
188129e9cc3SRichard Henderson         cond->a1_is_0 = false;
189129e9cc3SRichard Henderson         cond->a1 = tcg_const_tl(0);
190129e9cc3SRichard Henderson     }
191129e9cc3SRichard Henderson }
192129e9cc3SRichard Henderson 
193129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
194129e9cc3SRichard Henderson {
195129e9cc3SRichard Henderson     switch (cond->c) {
196129e9cc3SRichard Henderson     default:
197129e9cc3SRichard Henderson         if (!cond->a0_is_n) {
198129e9cc3SRichard Henderson             tcg_temp_free(cond->a0);
199129e9cc3SRichard Henderson         }
200129e9cc3SRichard Henderson         if (!cond->a1_is_0) {
201129e9cc3SRichard Henderson             tcg_temp_free(cond->a1);
202129e9cc3SRichard Henderson         }
203129e9cc3SRichard Henderson         cond->a0_is_n = false;
204129e9cc3SRichard Henderson         cond->a1_is_0 = false;
205*f764718dSRichard Henderson         cond->a0 = NULL;
206*f764718dSRichard Henderson         cond->a1 = NULL;
207129e9cc3SRichard Henderson         /* fallthru */
208129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
209129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
210129e9cc3SRichard Henderson         break;
211129e9cc3SRichard Henderson     case TCG_COND_NEVER:
212129e9cc3SRichard Henderson         break;
213129e9cc3SRichard Henderson     }
214129e9cc3SRichard Henderson }
215129e9cc3SRichard Henderson 
21661766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx)
21761766fe9SRichard Henderson {
21861766fe9SRichard Henderson     unsigned i = ctx->ntemps++;
21961766fe9SRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->temps));
22061766fe9SRichard Henderson     return ctx->temps[i] = tcg_temp_new();
22161766fe9SRichard Henderson }
22261766fe9SRichard Henderson 
22361766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v)
22461766fe9SRichard Henderson {
22561766fe9SRichard Henderson     TCGv t = get_temp(ctx);
22661766fe9SRichard Henderson     tcg_gen_movi_tl(t, v);
22761766fe9SRichard Henderson     return t;
22861766fe9SRichard Henderson }
22961766fe9SRichard Henderson 
23061766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg)
23161766fe9SRichard Henderson {
23261766fe9SRichard Henderson     if (reg == 0) {
23361766fe9SRichard Henderson         TCGv t = get_temp(ctx);
23461766fe9SRichard Henderson         tcg_gen_movi_tl(t, 0);
23561766fe9SRichard Henderson         return t;
23661766fe9SRichard Henderson     } else {
23761766fe9SRichard Henderson         return cpu_gr[reg];
23861766fe9SRichard Henderson     }
23961766fe9SRichard Henderson }
24061766fe9SRichard Henderson 
24161766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
24261766fe9SRichard Henderson {
243129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
24461766fe9SRichard Henderson         return get_temp(ctx);
24561766fe9SRichard Henderson     } else {
24661766fe9SRichard Henderson         return cpu_gr[reg];
24761766fe9SRichard Henderson     }
24861766fe9SRichard Henderson }
24961766fe9SRichard Henderson 
250129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
251129e9cc3SRichard Henderson {
252129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
253129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
254129e9cc3SRichard Henderson         tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
255129e9cc3SRichard Henderson                            ctx->null_cond.a1, dest, t);
256129e9cc3SRichard Henderson     } else {
257129e9cc3SRichard Henderson         tcg_gen_mov_tl(dest, t);
258129e9cc3SRichard Henderson     }
259129e9cc3SRichard Henderson }
260129e9cc3SRichard Henderson 
261129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
262129e9cc3SRichard Henderson {
263129e9cc3SRichard Henderson     if (reg != 0) {
264129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
265129e9cc3SRichard Henderson     }
266129e9cc3SRichard Henderson }
267129e9cc3SRichard Henderson 
26896d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
26996d6407fSRichard Henderson # define HI_OFS  0
27096d6407fSRichard Henderson # define LO_OFS  4
27196d6407fSRichard Henderson #else
27296d6407fSRichard Henderson # define HI_OFS  4
27396d6407fSRichard Henderson # define LO_OFS  0
27496d6407fSRichard Henderson #endif
27596d6407fSRichard Henderson 
27696d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
27796d6407fSRichard Henderson {
27896d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
27996d6407fSRichard Henderson     tcg_gen_ld_i32(ret, cpu_env,
28096d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
28196d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
28296d6407fSRichard Henderson     return ret;
28396d6407fSRichard Henderson }
28496d6407fSRichard Henderson 
285ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
286ebe9383cSRichard Henderson {
287ebe9383cSRichard Henderson     if (rt == 0) {
288ebe9383cSRichard Henderson         return tcg_const_i32(0);
289ebe9383cSRichard Henderson     } else {
290ebe9383cSRichard Henderson         return load_frw_i32(rt);
291ebe9383cSRichard Henderson     }
292ebe9383cSRichard Henderson }
293ebe9383cSRichard Henderson 
294ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
295ebe9383cSRichard Henderson {
296ebe9383cSRichard Henderson     if (rt == 0) {
297ebe9383cSRichard Henderson         return tcg_const_i64(0);
298ebe9383cSRichard Henderson     } else {
299ebe9383cSRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
300ebe9383cSRichard Henderson         tcg_gen_ld32u_i64(ret, cpu_env,
301ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
302ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
303ebe9383cSRichard Henderson         return ret;
304ebe9383cSRichard Henderson     }
305ebe9383cSRichard Henderson }
306ebe9383cSRichard Henderson 
30796d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
30896d6407fSRichard Henderson {
30996d6407fSRichard Henderson     tcg_gen_st_i32(val, cpu_env,
31096d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
31196d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
31296d6407fSRichard Henderson }
31396d6407fSRichard Henderson 
31496d6407fSRichard Henderson #undef HI_OFS
31596d6407fSRichard Henderson #undef LO_OFS
31696d6407fSRichard Henderson 
31796d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
31896d6407fSRichard Henderson {
31996d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
32096d6407fSRichard Henderson     tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
32196d6407fSRichard Henderson     return ret;
32296d6407fSRichard Henderson }
32396d6407fSRichard Henderson 
324ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
325ebe9383cSRichard Henderson {
326ebe9383cSRichard Henderson     if (rt == 0) {
327ebe9383cSRichard Henderson         return tcg_const_i64(0);
328ebe9383cSRichard Henderson     } else {
329ebe9383cSRichard Henderson         return load_frd(rt);
330ebe9383cSRichard Henderson     }
331ebe9383cSRichard Henderson }
332ebe9383cSRichard Henderson 
33396d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
33496d6407fSRichard Henderson {
33596d6407fSRichard Henderson     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
33696d6407fSRichard Henderson }
33796d6407fSRichard Henderson 
338129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
339129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
340129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
341129e9cc3SRichard Henderson {
342129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
343129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
344129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
345129e9cc3SRichard Henderson 
346129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
347129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
348129e9cc3SRichard Henderson 
349129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
350129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
351129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
352129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
353129e9cc3SRichard Henderson             tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
354129e9cc3SRichard Henderson         }
355129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
356129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
357129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
358129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
359129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
360129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
361129e9cc3SRichard Henderson         }
362129e9cc3SRichard Henderson 
363129e9cc3SRichard Henderson         tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
364129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
365129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
366129e9cc3SRichard Henderson     }
367129e9cc3SRichard Henderson }
368129e9cc3SRichard Henderson 
369129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
370129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
371129e9cc3SRichard Henderson {
372129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
373129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
374129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
375129e9cc3SRichard Henderson         }
376129e9cc3SRichard Henderson         return;
377129e9cc3SRichard Henderson     }
378129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
379129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
380129e9cc3SRichard Henderson         tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
381129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
382129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
383129e9cc3SRichard Henderson     }
384129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
385129e9cc3SRichard Henderson }
386129e9cc3SRichard Henderson 
387129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
388129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
389129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
390129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
391129e9cc3SRichard Henderson {
392129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
393129e9cc3SRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, x);
394129e9cc3SRichard Henderson     }
395129e9cc3SRichard Henderson }
396129e9cc3SRichard Henderson 
397129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
398129e9cc3SRichard Henderson    This is the pair to nullify_over.  */
399869051eaSRichard Henderson static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status)
400129e9cc3SRichard Henderson {
401129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
402129e9cc3SRichard Henderson 
403129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
404129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
405129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
406129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
407129e9cc3SRichard Henderson         return status;
408129e9cc3SRichard Henderson     }
409129e9cc3SRichard Henderson     ctx->null_lab = NULL;
410129e9cc3SRichard Henderson 
411129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
412129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
413129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
414129e9cc3SRichard Henderson         gen_set_label(null_lab);
415129e9cc3SRichard Henderson     } else {
416129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
417129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
418129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
419129e9cc3SRichard Henderson            label we have the proper value in place.  */
420129e9cc3SRichard Henderson         nullify_save(ctx);
421129e9cc3SRichard Henderson         gen_set_label(null_lab);
422129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
423129e9cc3SRichard Henderson     }
424129e9cc3SRichard Henderson 
425869051eaSRichard Henderson     assert(status != DISAS_NORETURN && status != DISAS_IAQ_N_UPDATED);
426869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
427869051eaSRichard Henderson         status = DISAS_NEXT;
428129e9cc3SRichard Henderson     }
429129e9cc3SRichard Henderson     return status;
430129e9cc3SRichard Henderson }
431129e9cc3SRichard Henderson 
43261766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
43361766fe9SRichard Henderson {
43461766fe9SRichard Henderson     if (unlikely(ival == -1)) {
43561766fe9SRichard Henderson         tcg_gen_mov_tl(dest, vval);
43661766fe9SRichard Henderson     } else {
43761766fe9SRichard Henderson         tcg_gen_movi_tl(dest, ival);
43861766fe9SRichard Henderson     }
43961766fe9SRichard Henderson }
44061766fe9SRichard Henderson 
44161766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
44261766fe9SRichard Henderson {
44361766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
44461766fe9SRichard Henderson }
44561766fe9SRichard Henderson 
44661766fe9SRichard Henderson static void gen_excp_1(int exception)
44761766fe9SRichard Henderson {
44861766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
44961766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
45061766fe9SRichard Henderson     tcg_temp_free_i32(t);
45161766fe9SRichard Henderson }
45261766fe9SRichard Henderson 
453869051eaSRichard Henderson static DisasJumpType gen_excp(DisasContext *ctx, int exception)
45461766fe9SRichard Henderson {
45561766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
45661766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
457129e9cc3SRichard Henderson     nullify_save(ctx);
45861766fe9SRichard Henderson     gen_excp_1(exception);
459869051eaSRichard Henderson     return DISAS_NORETURN;
46061766fe9SRichard Henderson }
46161766fe9SRichard Henderson 
462869051eaSRichard Henderson static DisasJumpType gen_illegal(DisasContext *ctx)
46361766fe9SRichard Henderson {
464129e9cc3SRichard Henderson     nullify_over(ctx);
465129e9cc3SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
46661766fe9SRichard Henderson }
46761766fe9SRichard Henderson 
46861766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
46961766fe9SRichard Henderson {
47061766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
471c5a49c63SEmilio G. Cota     if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ctx->base.singlestep_enabled) {
47261766fe9SRichard Henderson         return false;
47361766fe9SRichard Henderson     }
47461766fe9SRichard Henderson     return true;
47561766fe9SRichard Henderson }
47661766fe9SRichard Henderson 
477129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
478129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
479129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
480129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
481129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
482129e9cc3SRichard Henderson {
483129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
484129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
485129e9cc3SRichard Henderson }
486129e9cc3SRichard Henderson 
48761766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
48861766fe9SRichard Henderson                         target_ulong f, target_ulong b)
48961766fe9SRichard Henderson {
49061766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
49161766fe9SRichard Henderson         tcg_gen_goto_tb(which);
49261766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_f, f);
49361766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_b, b);
494d01a3625SRichard Henderson         tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which);
49561766fe9SRichard Henderson     } else {
49661766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
49761766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
498d01a3625SRichard Henderson         if (ctx->base.singlestep_enabled) {
49961766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
50061766fe9SRichard Henderson         } else {
5017f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
50261766fe9SRichard Henderson         }
50361766fe9SRichard Henderson     }
50461766fe9SRichard Henderson }
50561766fe9SRichard Henderson 
506b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
507b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
508b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
509b2167459SRichard Henderson {
510b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
511b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
512b2167459SRichard Henderson     return x;
513b2167459SRichard Henderson }
514b2167459SRichard Henderson 
515ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn)
516ebe9383cSRichard Henderson {
517ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 6, 1);
518ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 0, 5);
519ebe9383cSRichard Henderson     return r1 * 32 + r0;
520ebe9383cSRichard Henderson }
521ebe9383cSRichard Henderson 
522ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn)
523ebe9383cSRichard Henderson {
524ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 7, 1);
525ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 21, 5);
526ebe9383cSRichard Henderson     return r1 * 32 + r0;
527ebe9383cSRichard Henderson }
528ebe9383cSRichard Henderson 
529ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn)
530ebe9383cSRichard Henderson {
531ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 12, 1);
532ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 16, 5);
533ebe9383cSRichard Henderson     return r1 * 32 + r0;
534ebe9383cSRichard Henderson }
535ebe9383cSRichard Henderson 
536ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn)
537ebe9383cSRichard Henderson {
538ebe9383cSRichard Henderson     unsigned r2 = extract32(insn, 8, 1);
539ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 13, 3);
540ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 9, 2);
541ebe9383cSRichard Henderson     return r2 * 32 + r1 * 4 + r0;
542ebe9383cSRichard Henderson }
543ebe9383cSRichard Henderson 
54498cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn)
54598cd9ca7SRichard Henderson {
54698cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
54798cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
54898cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
54998cd9ca7SRichard Henderson     return x;
55098cd9ca7SRichard Henderson }
55198cd9ca7SRichard Henderson 
552b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
553b2167459SRichard Henderson {
554b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
555b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
556b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
557b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
558b2167459SRichard Henderson }
559b2167459SRichard Henderson 
56096d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn)
56196d6407fSRichard Henderson {
56296d6407fSRichard Henderson     /* Take the name from PA2.0, which produces a 14-bit shifted number
56396d6407fSRichard Henderson        only with wide mode; otherwise a 12-bit shifted number.  Since we
56496d6407fSRichard Henderson        don't implement wide mode, this is always the 12-bit number.  */
56596d6407fSRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
56696d6407fSRichard Henderson     x = (x << 11) | extract32(insn, 2, 11);
56796d6407fSRichard Henderson     return x << 2;
56896d6407fSRichard Henderson }
56996d6407fSRichard Henderson 
57098cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn)
57198cd9ca7SRichard Henderson {
57298cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
57398cd9ca7SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
57498cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
57598cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
57698cd9ca7SRichard Henderson     return x << 2;
57798cd9ca7SRichard Henderson }
57898cd9ca7SRichard Henderson 
579b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
580b2167459SRichard Henderson {
581b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
582b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
583b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
584b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
585b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
586b2167459SRichard Henderson     return x << 11;
587b2167459SRichard Henderson }
588b2167459SRichard Henderson 
58998cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn)
59098cd9ca7SRichard Henderson {
59198cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
59298cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 16, 10);
59398cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
59498cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
59598cd9ca7SRichard Henderson     return x << 2;
59698cd9ca7SRichard Henderson }
59798cd9ca7SRichard Henderson 
598b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
599b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
600b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
601b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
602b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
603b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
604b2167459SRichard Henderson 
605b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
606b2167459SRichard Henderson {
607b2167459SRichard Henderson     DisasCond cond;
608b2167459SRichard Henderson     TCGv tmp;
609b2167459SRichard Henderson 
610b2167459SRichard Henderson     switch (cf >> 1) {
611b2167459SRichard Henderson     case 0: /* Never / TR */
612b2167459SRichard Henderson         cond = cond_make_f();
613b2167459SRichard Henderson         break;
614b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
615b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
616b2167459SRichard Henderson         break;
617b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
618b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
619b2167459SRichard Henderson         break;
620b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
621b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
622b2167459SRichard Henderson         break;
623b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
624b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
625b2167459SRichard Henderson         break;
626b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
627b2167459SRichard Henderson         tmp = tcg_temp_new();
628b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
629b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
630b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
631b2167459SRichard Henderson         tcg_temp_free(tmp);
632b2167459SRichard Henderson         break;
633b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
634b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
635b2167459SRichard Henderson         break;
636b2167459SRichard Henderson     case 7: /* OD / EV */
637b2167459SRichard Henderson         tmp = tcg_temp_new();
638b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
639b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
640b2167459SRichard Henderson         tcg_temp_free(tmp);
641b2167459SRichard Henderson         break;
642b2167459SRichard Henderson     default:
643b2167459SRichard Henderson         g_assert_not_reached();
644b2167459SRichard Henderson     }
645b2167459SRichard Henderson     if (cf & 1) {
646b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
647b2167459SRichard Henderson     }
648b2167459SRichard Henderson 
649b2167459SRichard Henderson     return cond;
650b2167459SRichard Henderson }
651b2167459SRichard Henderson 
652b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
653b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
654b2167459SRichard Henderson    deleted as unused.  */
655b2167459SRichard Henderson 
656b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
657b2167459SRichard Henderson {
658b2167459SRichard Henderson     DisasCond cond;
659b2167459SRichard Henderson 
660b2167459SRichard Henderson     switch (cf >> 1) {
661b2167459SRichard Henderson     case 1: /* = / <> */
662b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
663b2167459SRichard Henderson         break;
664b2167459SRichard Henderson     case 2: /* < / >= */
665b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
666b2167459SRichard Henderson         break;
667b2167459SRichard Henderson     case 3: /* <= / > */
668b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
669b2167459SRichard Henderson         break;
670b2167459SRichard Henderson     case 4: /* << / >>= */
671b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
672b2167459SRichard Henderson         break;
673b2167459SRichard Henderson     case 5: /* <<= / >> */
674b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
675b2167459SRichard Henderson         break;
676b2167459SRichard Henderson     default:
677b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
678b2167459SRichard Henderson     }
679b2167459SRichard Henderson     if (cf & 1) {
680b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
681b2167459SRichard Henderson     }
682b2167459SRichard Henderson 
683b2167459SRichard Henderson     return cond;
684b2167459SRichard Henderson }
685b2167459SRichard Henderson 
686b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
687b2167459SRichard Henderson    computed, and use of them is undefined.  */
688b2167459SRichard Henderson 
689b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
690b2167459SRichard Henderson {
691b2167459SRichard Henderson     switch (cf >> 1) {
692b2167459SRichard Henderson     case 4: case 5: case 6:
693b2167459SRichard Henderson         cf &= 1;
694b2167459SRichard Henderson         break;
695b2167459SRichard Henderson     }
696b2167459SRichard Henderson     return do_cond(cf, res, res, res);
697b2167459SRichard Henderson }
698b2167459SRichard Henderson 
69998cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
70098cd9ca7SRichard Henderson 
70198cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res)
70298cd9ca7SRichard Henderson {
70398cd9ca7SRichard Henderson     unsigned c, f;
70498cd9ca7SRichard Henderson 
70598cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
70698cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
70798cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
70898cd9ca7SRichard Henderson     c = orig & 3;
70998cd9ca7SRichard Henderson     if (c == 3) {
71098cd9ca7SRichard Henderson         c = 7;
71198cd9ca7SRichard Henderson     }
71298cd9ca7SRichard Henderson     f = (orig & 4) / 4;
71398cd9ca7SRichard Henderson 
71498cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
71598cd9ca7SRichard Henderson }
71698cd9ca7SRichard Henderson 
717b2167459SRichard Henderson /* Similar, but for unit conditions.  */
718b2167459SRichard Henderson 
719b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
720b2167459SRichard Henderson {
721b2167459SRichard Henderson     DisasCond cond;
722*f764718dSRichard Henderson     TCGv tmp, cb = NULL;
723b2167459SRichard Henderson 
724b2167459SRichard Henderson     if (cf & 8) {
725b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
726b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
727b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
728b2167459SRichard Henderson          */
729b2167459SRichard Henderson         cb = tcg_temp_new();
730b2167459SRichard Henderson         tmp = tcg_temp_new();
731b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
732b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
733b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
734b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
735b2167459SRichard Henderson         tcg_temp_free(tmp);
736b2167459SRichard Henderson     }
737b2167459SRichard Henderson 
738b2167459SRichard Henderson     switch (cf >> 1) {
739b2167459SRichard Henderson     case 0: /* never / TR */
740b2167459SRichard Henderson     case 1: /* undefined */
741b2167459SRichard Henderson     case 5: /* undefined */
742b2167459SRichard Henderson         cond = cond_make_f();
743b2167459SRichard Henderson         break;
744b2167459SRichard Henderson 
745b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
746b2167459SRichard Henderson         /* See hasless(v,1) from
747b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
748b2167459SRichard Henderson          */
749b2167459SRichard Henderson         tmp = tcg_temp_new();
750b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
751b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
752b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
753b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
754b2167459SRichard Henderson         tcg_temp_free(tmp);
755b2167459SRichard Henderson         break;
756b2167459SRichard Henderson 
757b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
758b2167459SRichard Henderson         tmp = tcg_temp_new();
759b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
760b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
761b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
762b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
763b2167459SRichard Henderson         tcg_temp_free(tmp);
764b2167459SRichard Henderson         break;
765b2167459SRichard Henderson 
766b2167459SRichard Henderson     case 4: /* SDC / NDC */
767b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
768b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
769b2167459SRichard Henderson         break;
770b2167459SRichard Henderson 
771b2167459SRichard Henderson     case 6: /* SBC / NBC */
772b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
773b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
774b2167459SRichard Henderson         break;
775b2167459SRichard Henderson 
776b2167459SRichard Henderson     case 7: /* SHC / NHC */
777b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
778b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
779b2167459SRichard Henderson         break;
780b2167459SRichard Henderson 
781b2167459SRichard Henderson     default:
782b2167459SRichard Henderson         g_assert_not_reached();
783b2167459SRichard Henderson     }
784b2167459SRichard Henderson     if (cf & 8) {
785b2167459SRichard Henderson         tcg_temp_free(cb);
786b2167459SRichard Henderson     }
787b2167459SRichard Henderson     if (cf & 1) {
788b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
789b2167459SRichard Henderson     }
790b2167459SRichard Henderson 
791b2167459SRichard Henderson     return cond;
792b2167459SRichard Henderson }
793b2167459SRichard Henderson 
794b2167459SRichard Henderson /* Compute signed overflow for addition.  */
795b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
796b2167459SRichard Henderson {
797b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
798b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
799b2167459SRichard Henderson 
800b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
801b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
802b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
803b2167459SRichard Henderson     tcg_temp_free(tmp);
804b2167459SRichard Henderson 
805b2167459SRichard Henderson     return sv;
806b2167459SRichard Henderson }
807b2167459SRichard Henderson 
808b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
809b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
810b2167459SRichard Henderson {
811b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
812b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
813b2167459SRichard Henderson 
814b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
815b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
816b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
817b2167459SRichard Henderson     tcg_temp_free(tmp);
818b2167459SRichard Henderson 
819b2167459SRichard Henderson     return sv;
820b2167459SRichard Henderson }
821b2167459SRichard Henderson 
822869051eaSRichard Henderson static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
823b2167459SRichard Henderson                             unsigned shift, bool is_l, bool is_tsv, bool is_tc,
824b2167459SRichard Henderson                             bool is_c, unsigned cf)
825b2167459SRichard Henderson {
826b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
827b2167459SRichard Henderson     unsigned c = cf >> 1;
828b2167459SRichard Henderson     DisasCond cond;
829b2167459SRichard Henderson 
830b2167459SRichard Henderson     dest = tcg_temp_new();
831*f764718dSRichard Henderson     cb = NULL;
832*f764718dSRichard Henderson     cb_msb = NULL;
833b2167459SRichard Henderson 
834b2167459SRichard Henderson     if (shift) {
835b2167459SRichard Henderson         tmp = get_temp(ctx);
836b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
837b2167459SRichard Henderson         in1 = tmp;
838b2167459SRichard Henderson     }
839b2167459SRichard Henderson 
840b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
841b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
842b2167459SRichard Henderson         cb_msb = get_temp(ctx);
843b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
844b2167459SRichard Henderson         if (is_c) {
845b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
846b2167459SRichard Henderson         }
847b2167459SRichard Henderson         tcg_temp_free(zero);
848b2167459SRichard Henderson         if (!is_l) {
849b2167459SRichard Henderson             cb = get_temp(ctx);
850b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
851b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
852b2167459SRichard Henderson         }
853b2167459SRichard Henderson     } else {
854b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
855b2167459SRichard Henderson         if (is_c) {
856b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
857b2167459SRichard Henderson         }
858b2167459SRichard Henderson     }
859b2167459SRichard Henderson 
860b2167459SRichard Henderson     /* Compute signed overflow if required.  */
861*f764718dSRichard Henderson     sv = NULL;
862b2167459SRichard Henderson     if (is_tsv || c == 6) {
863b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
864b2167459SRichard Henderson         if (is_tsv) {
865b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
866b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
867b2167459SRichard Henderson         }
868b2167459SRichard Henderson     }
869b2167459SRichard Henderson 
870b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
871b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
872b2167459SRichard Henderson     if (is_tc) {
873b2167459SRichard Henderson         cond_prep(&cond);
874b2167459SRichard Henderson         tmp = tcg_temp_new();
875b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
876b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
877b2167459SRichard Henderson         tcg_temp_free(tmp);
878b2167459SRichard Henderson     }
879b2167459SRichard Henderson 
880b2167459SRichard Henderson     /* Write back the result.  */
881b2167459SRichard Henderson     if (!is_l) {
882b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
883b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
884b2167459SRichard Henderson     }
885b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
886b2167459SRichard Henderson     tcg_temp_free(dest);
887b2167459SRichard Henderson 
888b2167459SRichard Henderson     /* Install the new nullification.  */
889b2167459SRichard Henderson     cond_free(&ctx->null_cond);
890b2167459SRichard Henderson     ctx->null_cond = cond;
891869051eaSRichard Henderson     return DISAS_NEXT;
892b2167459SRichard Henderson }
893b2167459SRichard Henderson 
894869051eaSRichard Henderson static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
895b2167459SRichard Henderson                             bool is_tsv, bool is_b, bool is_tc, unsigned cf)
896b2167459SRichard Henderson {
897b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
898b2167459SRichard Henderson     unsigned c = cf >> 1;
899b2167459SRichard Henderson     DisasCond cond;
900b2167459SRichard Henderson 
901b2167459SRichard Henderson     dest = tcg_temp_new();
902b2167459SRichard Henderson     cb = tcg_temp_new();
903b2167459SRichard Henderson     cb_msb = tcg_temp_new();
904b2167459SRichard Henderson 
905b2167459SRichard Henderson     zero = tcg_const_tl(0);
906b2167459SRichard Henderson     if (is_b) {
907b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
908b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
909b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
910b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
911b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
912b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
913b2167459SRichard Henderson     } else {
914b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
915b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
916b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
917b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
918b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
919b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
920b2167459SRichard Henderson     }
921b2167459SRichard Henderson     tcg_temp_free(zero);
922b2167459SRichard Henderson 
923b2167459SRichard Henderson     /* Compute signed overflow if required.  */
924*f764718dSRichard Henderson     sv = NULL;
925b2167459SRichard Henderson     if (is_tsv || c == 6) {
926b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
927b2167459SRichard Henderson         if (is_tsv) {
928b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
929b2167459SRichard Henderson         }
930b2167459SRichard Henderson     }
931b2167459SRichard Henderson 
932b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
933b2167459SRichard Henderson     if (!is_b) {
934b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
935b2167459SRichard Henderson     } else {
936b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
937b2167459SRichard Henderson     }
938b2167459SRichard Henderson 
939b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
940b2167459SRichard Henderson     if (is_tc) {
941b2167459SRichard Henderson         cond_prep(&cond);
942b2167459SRichard Henderson         tmp = tcg_temp_new();
943b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
944b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
945b2167459SRichard Henderson         tcg_temp_free(tmp);
946b2167459SRichard Henderson     }
947b2167459SRichard Henderson 
948b2167459SRichard Henderson     /* Write back the result.  */
949b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
950b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
951b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
952b2167459SRichard Henderson     tcg_temp_free(dest);
953b2167459SRichard Henderson 
954b2167459SRichard Henderson     /* Install the new nullification.  */
955b2167459SRichard Henderson     cond_free(&ctx->null_cond);
956b2167459SRichard Henderson     ctx->null_cond = cond;
957869051eaSRichard Henderson     return DISAS_NEXT;
958b2167459SRichard Henderson }
959b2167459SRichard Henderson 
960869051eaSRichard Henderson static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
961b2167459SRichard Henderson                                TCGv in2, unsigned cf)
962b2167459SRichard Henderson {
963b2167459SRichard Henderson     TCGv dest, sv;
964b2167459SRichard Henderson     DisasCond cond;
965b2167459SRichard Henderson 
966b2167459SRichard Henderson     dest = tcg_temp_new();
967b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
968b2167459SRichard Henderson 
969b2167459SRichard Henderson     /* Compute signed overflow if required.  */
970*f764718dSRichard Henderson     sv = NULL;
971b2167459SRichard Henderson     if ((cf >> 1) == 6) {
972b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
973b2167459SRichard Henderson     }
974b2167459SRichard Henderson 
975b2167459SRichard Henderson     /* Form the condition for the compare.  */
976b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
977b2167459SRichard Henderson 
978b2167459SRichard Henderson     /* Clear.  */
979b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
980b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
981b2167459SRichard Henderson     tcg_temp_free(dest);
982b2167459SRichard Henderson 
983b2167459SRichard Henderson     /* Install the new nullification.  */
984b2167459SRichard Henderson     cond_free(&ctx->null_cond);
985b2167459SRichard Henderson     ctx->null_cond = cond;
986869051eaSRichard Henderson     return DISAS_NEXT;
987b2167459SRichard Henderson }
988b2167459SRichard Henderson 
989869051eaSRichard Henderson static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
990b2167459SRichard Henderson                             unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
991b2167459SRichard Henderson {
992b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
993b2167459SRichard Henderson 
994b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
995b2167459SRichard Henderson     fn(dest, in1, in2);
996b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
997b2167459SRichard Henderson 
998b2167459SRichard Henderson     /* Install the new nullification.  */
999b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1000b2167459SRichard Henderson     if (cf) {
1001b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
1002b2167459SRichard Henderson     }
1003869051eaSRichard Henderson     return DISAS_NEXT;
1004b2167459SRichard Henderson }
1005b2167459SRichard Henderson 
1006869051eaSRichard Henderson static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1007b2167459SRichard Henderson                              TCGv in2, unsigned cf, bool is_tc,
1008b2167459SRichard Henderson                              void (*fn)(TCGv, TCGv, TCGv))
1009b2167459SRichard Henderson {
1010b2167459SRichard Henderson     TCGv dest;
1011b2167459SRichard Henderson     DisasCond cond;
1012b2167459SRichard Henderson 
1013b2167459SRichard Henderson     if (cf == 0) {
1014b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1015b2167459SRichard Henderson         fn(dest, in1, in2);
1016b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1017b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1018b2167459SRichard Henderson     } else {
1019b2167459SRichard Henderson         dest = tcg_temp_new();
1020b2167459SRichard Henderson         fn(dest, in1, in2);
1021b2167459SRichard Henderson 
1022b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
1023b2167459SRichard Henderson 
1024b2167459SRichard Henderson         if (is_tc) {
1025b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
1026b2167459SRichard Henderson             cond_prep(&cond);
1027b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1028b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
1029b2167459SRichard Henderson             tcg_temp_free(tmp);
1030b2167459SRichard Henderson         }
1031b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1032b2167459SRichard Henderson 
1033b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1034b2167459SRichard Henderson         ctx->null_cond = cond;
1035b2167459SRichard Henderson     }
1036869051eaSRichard Henderson     return DISAS_NEXT;
1037b2167459SRichard Henderson }
1038b2167459SRichard Henderson 
103996d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
104096d6407fSRichard Henderson  * < 0 for pre-modify,
104196d6407fSRichard Henderson  * > 0 for post-modify,
104296d6407fSRichard Henderson  * = 0 for no base register update.
104396d6407fSRichard Henderson  */
104496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
104596d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
104696d6407fSRichard Henderson                        int modify, TCGMemOp mop)
104796d6407fSRichard Henderson {
104896d6407fSRichard Henderson     TCGv addr, base;
104996d6407fSRichard Henderson 
105096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
105196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
105296d6407fSRichard Henderson 
105396d6407fSRichard Henderson     addr = tcg_temp_new();
105496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
105596d6407fSRichard Henderson 
105696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
105796d6407fSRichard Henderson     if (rx) {
105896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
105996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
106096d6407fSRichard Henderson     } else {
106196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
106296d6407fSRichard Henderson     }
106396d6407fSRichard Henderson 
106496d6407fSRichard Henderson     if (modify == 0) {
106596d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
106696d6407fSRichard Henderson     } else {
106796d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
106896d6407fSRichard Henderson                             MMU_USER_IDX, mop);
106996d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
107096d6407fSRichard Henderson     }
107196d6407fSRichard Henderson     tcg_temp_free(addr);
107296d6407fSRichard Henderson }
107396d6407fSRichard Henderson 
107496d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
107596d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
107696d6407fSRichard Henderson                        int modify, TCGMemOp mop)
107796d6407fSRichard Henderson {
107896d6407fSRichard Henderson     TCGv addr, base;
107996d6407fSRichard Henderson 
108096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
108196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
108296d6407fSRichard Henderson 
108396d6407fSRichard Henderson     addr = tcg_temp_new();
108496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
108596d6407fSRichard Henderson 
108696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
108796d6407fSRichard Henderson     if (rx) {
108896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
108996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
109096d6407fSRichard Henderson     } else {
109196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
109296d6407fSRichard Henderson     }
109396d6407fSRichard Henderson 
109496d6407fSRichard Henderson     if (modify == 0) {
109596d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
109696d6407fSRichard Henderson     } else {
109796d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
109896d6407fSRichard Henderson                             MMU_USER_IDX, mop);
109996d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
110096d6407fSRichard Henderson     }
110196d6407fSRichard Henderson     tcg_temp_free(addr);
110296d6407fSRichard Henderson }
110396d6407fSRichard Henderson 
110496d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
110596d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
110696d6407fSRichard Henderson                         int modify, TCGMemOp mop)
110796d6407fSRichard Henderson {
110896d6407fSRichard Henderson     TCGv addr, base;
110996d6407fSRichard Henderson 
111096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
111196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
111296d6407fSRichard Henderson 
111396d6407fSRichard Henderson     addr = tcg_temp_new();
111496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
111596d6407fSRichard Henderson 
111696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
111796d6407fSRichard Henderson     if (rx) {
111896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
111996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
112096d6407fSRichard Henderson     } else {
112196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
112296d6407fSRichard Henderson     }
112396d6407fSRichard Henderson 
112496d6407fSRichard Henderson     tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
112596d6407fSRichard Henderson 
112696d6407fSRichard Henderson     if (modify != 0) {
112796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
112896d6407fSRichard Henderson     }
112996d6407fSRichard Henderson     tcg_temp_free(addr);
113096d6407fSRichard Henderson }
113196d6407fSRichard Henderson 
113296d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
113396d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
113496d6407fSRichard Henderson                         int modify, TCGMemOp mop)
113596d6407fSRichard Henderson {
113696d6407fSRichard Henderson     TCGv addr, base;
113796d6407fSRichard Henderson 
113896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
113996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
114096d6407fSRichard Henderson 
114196d6407fSRichard Henderson     addr = tcg_temp_new();
114296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
114396d6407fSRichard Henderson 
114496d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
114596d6407fSRichard Henderson     if (rx) {
114696d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
114796d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
114896d6407fSRichard Henderson     } else {
114996d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
115096d6407fSRichard Henderson     }
115196d6407fSRichard Henderson 
115296d6407fSRichard Henderson     tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
115396d6407fSRichard Henderson 
115496d6407fSRichard Henderson     if (modify != 0) {
115596d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
115696d6407fSRichard Henderson     }
115796d6407fSRichard Henderson     tcg_temp_free(addr);
115896d6407fSRichard Henderson }
115996d6407fSRichard Henderson 
116096d6407fSRichard Henderson #if TARGET_LONG_BITS == 64
116196d6407fSRichard Henderson #define do_load_tl  do_load_64
116296d6407fSRichard Henderson #define do_store_tl do_store_64
116396d6407fSRichard Henderson #else
116496d6407fSRichard Henderson #define do_load_tl  do_load_32
116596d6407fSRichard Henderson #define do_store_tl do_store_32
116696d6407fSRichard Henderson #endif
116796d6407fSRichard Henderson 
1168869051eaSRichard Henderson static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb,
116996d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
117096d6407fSRichard Henderson                              int modify, TCGMemOp mop)
117196d6407fSRichard Henderson {
117296d6407fSRichard Henderson     TCGv dest;
117396d6407fSRichard Henderson 
117496d6407fSRichard Henderson     nullify_over(ctx);
117596d6407fSRichard Henderson 
117696d6407fSRichard Henderson     if (modify == 0) {
117796d6407fSRichard Henderson         /* No base register update.  */
117896d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
117996d6407fSRichard Henderson     } else {
118096d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
118196d6407fSRichard Henderson         dest = get_temp(ctx);
118296d6407fSRichard Henderson     }
118396d6407fSRichard Henderson     do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
118496d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
118596d6407fSRichard Henderson 
1186869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
118796d6407fSRichard Henderson }
118896d6407fSRichard Henderson 
1189869051eaSRichard Henderson static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
119096d6407fSRichard Henderson                                unsigned rx, int scale, target_long disp,
119196d6407fSRichard Henderson                                int modify)
119296d6407fSRichard Henderson {
119396d6407fSRichard Henderson     TCGv_i32 tmp;
119496d6407fSRichard Henderson 
119596d6407fSRichard Henderson     nullify_over(ctx);
119696d6407fSRichard Henderson 
119796d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
119896d6407fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
119996d6407fSRichard Henderson     save_frw_i32(rt, tmp);
120096d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
120196d6407fSRichard Henderson 
120296d6407fSRichard Henderson     if (rt == 0) {
120396d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
120496d6407fSRichard Henderson     }
120596d6407fSRichard Henderson 
1206869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
120796d6407fSRichard Henderson }
120896d6407fSRichard Henderson 
1209869051eaSRichard Henderson static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
121096d6407fSRichard Henderson                                unsigned rx, int scale, target_long disp,
121196d6407fSRichard Henderson                                int modify)
121296d6407fSRichard Henderson {
121396d6407fSRichard Henderson     TCGv_i64 tmp;
121496d6407fSRichard Henderson 
121596d6407fSRichard Henderson     nullify_over(ctx);
121696d6407fSRichard Henderson 
121796d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
121896d6407fSRichard Henderson     do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
121996d6407fSRichard Henderson     save_frd(rt, tmp);
122096d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
122196d6407fSRichard Henderson 
122296d6407fSRichard Henderson     if (rt == 0) {
122396d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
122496d6407fSRichard Henderson     }
122596d6407fSRichard Henderson 
1226869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
122796d6407fSRichard Henderson }
122896d6407fSRichard Henderson 
1229869051eaSRichard Henderson static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb,
123096d6407fSRichard Henderson                               target_long disp, int modify, TCGMemOp mop)
123196d6407fSRichard Henderson {
123296d6407fSRichard Henderson     nullify_over(ctx);
123396d6407fSRichard Henderson     do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1234869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
123596d6407fSRichard Henderson }
123696d6407fSRichard Henderson 
1237869051eaSRichard Henderson static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
123896d6407fSRichard Henderson                                 unsigned rx, int scale, target_long disp,
123996d6407fSRichard Henderson                                 int modify)
124096d6407fSRichard Henderson {
124196d6407fSRichard Henderson     TCGv_i32 tmp;
124296d6407fSRichard Henderson 
124396d6407fSRichard Henderson     nullify_over(ctx);
124496d6407fSRichard Henderson 
124596d6407fSRichard Henderson     tmp = load_frw_i32(rt);
124696d6407fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
124796d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
124896d6407fSRichard Henderson 
1249869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
125096d6407fSRichard Henderson }
125196d6407fSRichard Henderson 
1252869051eaSRichard Henderson static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
125396d6407fSRichard Henderson                                 unsigned rx, int scale, target_long disp,
125496d6407fSRichard Henderson                                 int modify)
125596d6407fSRichard Henderson {
125696d6407fSRichard Henderson     TCGv_i64 tmp;
125796d6407fSRichard Henderson 
125896d6407fSRichard Henderson     nullify_over(ctx);
125996d6407fSRichard Henderson 
126096d6407fSRichard Henderson     tmp = load_frd(rt);
126196d6407fSRichard Henderson     do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
126296d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
126396d6407fSRichard Henderson 
1264869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
126596d6407fSRichard Henderson }
126696d6407fSRichard Henderson 
1267869051eaSRichard Henderson static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1268ebe9383cSRichard Henderson                                 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1269ebe9383cSRichard Henderson {
1270ebe9383cSRichard Henderson     TCGv_i32 tmp;
1271ebe9383cSRichard Henderson 
1272ebe9383cSRichard Henderson     nullify_over(ctx);
1273ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1274ebe9383cSRichard Henderson 
1275ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1276ebe9383cSRichard Henderson 
1277ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
1278ebe9383cSRichard Henderson     tcg_temp_free_i32(tmp);
1279869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1280ebe9383cSRichard Henderson }
1281ebe9383cSRichard Henderson 
1282869051eaSRichard Henderson static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1283ebe9383cSRichard Henderson                                 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1284ebe9383cSRichard Henderson {
1285ebe9383cSRichard Henderson     TCGv_i32 dst;
1286ebe9383cSRichard Henderson     TCGv_i64 src;
1287ebe9383cSRichard Henderson 
1288ebe9383cSRichard Henderson     nullify_over(ctx);
1289ebe9383cSRichard Henderson     src = load_frd(ra);
1290ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1291ebe9383cSRichard Henderson 
1292ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1293ebe9383cSRichard Henderson 
1294ebe9383cSRichard Henderson     tcg_temp_free_i64(src);
1295ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
1296ebe9383cSRichard Henderson     tcg_temp_free_i32(dst);
1297869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1298ebe9383cSRichard Henderson }
1299ebe9383cSRichard Henderson 
1300869051eaSRichard Henderson static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1301ebe9383cSRichard Henderson                                 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1302ebe9383cSRichard Henderson {
1303ebe9383cSRichard Henderson     TCGv_i64 tmp;
1304ebe9383cSRichard Henderson 
1305ebe9383cSRichard Henderson     nullify_over(ctx);
1306ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1307ebe9383cSRichard Henderson 
1308ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1309ebe9383cSRichard Henderson 
1310ebe9383cSRichard Henderson     save_frd(rt, tmp);
1311ebe9383cSRichard Henderson     tcg_temp_free_i64(tmp);
1312869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1313ebe9383cSRichard Henderson }
1314ebe9383cSRichard Henderson 
1315869051eaSRichard Henderson static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1316ebe9383cSRichard Henderson                                 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1317ebe9383cSRichard Henderson {
1318ebe9383cSRichard Henderson     TCGv_i32 src;
1319ebe9383cSRichard Henderson     TCGv_i64 dst;
1320ebe9383cSRichard Henderson 
1321ebe9383cSRichard Henderson     nullify_over(ctx);
1322ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1323ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1324ebe9383cSRichard Henderson 
1325ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1326ebe9383cSRichard Henderson 
1327ebe9383cSRichard Henderson     tcg_temp_free_i32(src);
1328ebe9383cSRichard Henderson     save_frd(rt, dst);
1329ebe9383cSRichard Henderson     tcg_temp_free_i64(dst);
1330869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1331ebe9383cSRichard Henderson }
1332ebe9383cSRichard Henderson 
1333869051eaSRichard Henderson static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt,
1334ebe9383cSRichard Henderson                                  unsigned ra, unsigned rb,
1335ebe9383cSRichard Henderson                                  void (*func)(TCGv_i32, TCGv_env,
1336ebe9383cSRichard Henderson                                               TCGv_i32, TCGv_i32))
1337ebe9383cSRichard Henderson {
1338ebe9383cSRichard Henderson     TCGv_i32 a, b;
1339ebe9383cSRichard Henderson 
1340ebe9383cSRichard Henderson     nullify_over(ctx);
1341ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1342ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1343ebe9383cSRichard Henderson 
1344ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1345ebe9383cSRichard Henderson 
1346ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
1347ebe9383cSRichard Henderson     save_frw_i32(rt, a);
1348ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
1349869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1350ebe9383cSRichard Henderson }
1351ebe9383cSRichard Henderson 
1352869051eaSRichard Henderson static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt,
1353ebe9383cSRichard Henderson                                  unsigned ra, unsigned rb,
1354ebe9383cSRichard Henderson                                  void (*func)(TCGv_i64, TCGv_env,
1355ebe9383cSRichard Henderson                                               TCGv_i64, TCGv_i64))
1356ebe9383cSRichard Henderson {
1357ebe9383cSRichard Henderson     TCGv_i64 a, b;
1358ebe9383cSRichard Henderson 
1359ebe9383cSRichard Henderson     nullify_over(ctx);
1360ebe9383cSRichard Henderson     a = load_frd0(ra);
1361ebe9383cSRichard Henderson     b = load_frd0(rb);
1362ebe9383cSRichard Henderson 
1363ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1364ebe9383cSRichard Henderson 
1365ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
1366ebe9383cSRichard Henderson     save_frd(rt, a);
1367ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
1368869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1369ebe9383cSRichard Henderson }
1370ebe9383cSRichard Henderson 
137198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
137298cd9ca7SRichard Henderson    have already had nullification handled.  */
1373869051eaSRichard Henderson static DisasJumpType do_dbranch(DisasContext *ctx, target_ulong dest,
137498cd9ca7SRichard Henderson                                 unsigned link, bool is_n)
137598cd9ca7SRichard Henderson {
137698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
137798cd9ca7SRichard Henderson         if (link != 0) {
137898cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
137998cd9ca7SRichard Henderson         }
138098cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
138198cd9ca7SRichard Henderson         if (is_n) {
138298cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
138398cd9ca7SRichard Henderson         }
1384869051eaSRichard Henderson         return DISAS_NEXT;
138598cd9ca7SRichard Henderson     } else {
138698cd9ca7SRichard Henderson         nullify_over(ctx);
138798cd9ca7SRichard Henderson 
138898cd9ca7SRichard Henderson         if (link != 0) {
138998cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
139098cd9ca7SRichard Henderson         }
139198cd9ca7SRichard Henderson 
139298cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
139398cd9ca7SRichard Henderson             nullify_set(ctx, 0);
139498cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
139598cd9ca7SRichard Henderson         } else {
139698cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
139798cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
139898cd9ca7SRichard Henderson         }
139998cd9ca7SRichard Henderson 
1400869051eaSRichard Henderson         nullify_end(ctx, DISAS_NEXT);
140198cd9ca7SRichard Henderson 
140298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
140398cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1404869051eaSRichard Henderson         return DISAS_NORETURN;
140598cd9ca7SRichard Henderson     }
140698cd9ca7SRichard Henderson }
140798cd9ca7SRichard Henderson 
140898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
140998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1410869051eaSRichard Henderson static DisasJumpType do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
141198cd9ca7SRichard Henderson                                 DisasCond *cond)
141298cd9ca7SRichard Henderson {
141398cd9ca7SRichard Henderson     target_ulong dest = iaoq_dest(ctx, disp);
141498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
141598cd9ca7SRichard Henderson     TCGCond c = cond->c;
141698cd9ca7SRichard Henderson     bool n;
141798cd9ca7SRichard Henderson 
141898cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
141998cd9ca7SRichard Henderson 
142098cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
142198cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
142298cd9ca7SRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
142398cd9ca7SRichard Henderson     }
142498cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
142598cd9ca7SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
142698cd9ca7SRichard Henderson     }
142798cd9ca7SRichard Henderson 
142898cd9ca7SRichard Henderson     taken = gen_new_label();
142998cd9ca7SRichard Henderson     cond_prep(cond);
143098cd9ca7SRichard Henderson     tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
143198cd9ca7SRichard Henderson     cond_free(cond);
143298cd9ca7SRichard Henderson 
143398cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
143498cd9ca7SRichard Henderson     n = is_n && disp < 0;
143598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
143698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1437a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
143898cd9ca7SRichard Henderson     } else {
143998cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
144098cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
144198cd9ca7SRichard Henderson             ctx->null_lab = NULL;
144298cd9ca7SRichard Henderson         }
144398cd9ca7SRichard Henderson         nullify_set(ctx, n);
1444a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
144598cd9ca7SRichard Henderson     }
144698cd9ca7SRichard Henderson 
144798cd9ca7SRichard Henderson     gen_set_label(taken);
144898cd9ca7SRichard Henderson 
144998cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
145098cd9ca7SRichard Henderson     n = is_n && disp >= 0;
145198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
145298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1453a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
145498cd9ca7SRichard Henderson     } else {
145598cd9ca7SRichard Henderson         nullify_set(ctx, n);
1456a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
145798cd9ca7SRichard Henderson     }
145898cd9ca7SRichard Henderson 
145998cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
146098cd9ca7SRichard Henderson     if (ctx->null_lab) {
146198cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
146298cd9ca7SRichard Henderson         ctx->null_lab = NULL;
1463869051eaSRichard Henderson         return DISAS_IAQ_N_STALE;
146498cd9ca7SRichard Henderson     } else {
1465869051eaSRichard Henderson         return DISAS_NORETURN;
146698cd9ca7SRichard Henderson     }
146798cd9ca7SRichard Henderson }
146898cd9ca7SRichard Henderson 
146998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
147098cd9ca7SRichard Henderson    nullification of the branch itself.  */
1471869051eaSRichard Henderson static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest,
147298cd9ca7SRichard Henderson                                 unsigned link, bool is_n)
147398cd9ca7SRichard Henderson {
147498cd9ca7SRichard Henderson     TCGv a0, a1, next, tmp;
147598cd9ca7SRichard Henderson     TCGCond c;
147698cd9ca7SRichard Henderson 
147798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
147898cd9ca7SRichard Henderson 
147998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
148098cd9ca7SRichard Henderson         if (link != 0) {
148198cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
148298cd9ca7SRichard Henderson         }
148398cd9ca7SRichard Henderson         next = get_temp(ctx);
148498cd9ca7SRichard Henderson         tcg_gen_mov_tl(next, dest);
148598cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
148698cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
148798cd9ca7SRichard Henderson         if (is_n) {
148898cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
148998cd9ca7SRichard Henderson         }
149098cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
149198cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
149298cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
14934137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
149498cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
149598cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
149698cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
149798cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
149898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
149998cd9ca7SRichard Henderson 
150098cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
150198cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
150298cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
150398cd9ca7SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, dest);
150498cd9ca7SRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
150598cd9ca7SRichard Henderson 
150698cd9ca7SRichard Henderson         nullify_over(ctx);
150798cd9ca7SRichard Henderson         if (link != 0) {
150898cd9ca7SRichard Henderson             tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
150998cd9ca7SRichard Henderson         }
15107f11636dSEmilio G. Cota         tcg_gen_lookup_and_goto_ptr();
1511869051eaSRichard Henderson         return nullify_end(ctx, DISAS_NEXT);
151298cd9ca7SRichard Henderson     } else {
151398cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
151498cd9ca7SRichard Henderson         c = ctx->null_cond.c;
151598cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
151698cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
151798cd9ca7SRichard Henderson 
151898cd9ca7SRichard Henderson         tmp = tcg_temp_new();
151998cd9ca7SRichard Henderson         next = get_temp(ctx);
152098cd9ca7SRichard Henderson 
152198cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
152298cd9ca7SRichard Henderson         tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
152398cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
152498cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
152598cd9ca7SRichard Henderson 
152698cd9ca7SRichard Henderson         if (link != 0) {
152798cd9ca7SRichard Henderson             tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
152898cd9ca7SRichard Henderson         }
152998cd9ca7SRichard Henderson 
153098cd9ca7SRichard Henderson         if (is_n) {
153198cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
153298cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
153398cd9ca7SRichard Henderson                to the branch.  */
153498cd9ca7SRichard Henderson             tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
153598cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
153698cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
153798cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
153898cd9ca7SRichard Henderson         } else {
153998cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
154098cd9ca7SRichard Henderson         }
154198cd9ca7SRichard Henderson     }
154298cd9ca7SRichard Henderson 
1543869051eaSRichard Henderson     return DISAS_NEXT;
154498cd9ca7SRichard Henderson }
154598cd9ca7SRichard Henderson 
15467ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
15477ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
15487ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
15497ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
15507ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
15517ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
15527ad439dfSRichard Henderson    aforementioned BE.  */
1553869051eaSRichard Henderson static DisasJumpType do_page_zero(DisasContext *ctx)
15547ad439dfSRichard Henderson {
15557ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
15567ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
15577ad439dfSRichard Henderson        next insn within the privilaged page.  */
15587ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
15597ad439dfSRichard Henderson     case TCG_COND_NEVER:
15607ad439dfSRichard Henderson         break;
15617ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
15627ad439dfSRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, 0);
15637ad439dfSRichard Henderson         goto do_sigill;
15647ad439dfSRichard Henderson     default:
15657ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
15667ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
15677ad439dfSRichard Henderson         g_assert_not_reached();
15687ad439dfSRichard Henderson     }
15697ad439dfSRichard Henderson 
15707ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
15717ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
15727ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
15737ad439dfSRichard Henderson        under such conditions.  */
15747ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
15757ad439dfSRichard Henderson         goto do_sigill;
15767ad439dfSRichard Henderson     }
15777ad439dfSRichard Henderson 
15787ad439dfSRichard Henderson     switch (ctx->iaoq_f) {
15797ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
15807ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGSEGV);
1581869051eaSRichard Henderson         return DISAS_NORETURN;
15827ad439dfSRichard Henderson 
15837ad439dfSRichard Henderson     case 0xb0: /* LWS */
15847ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
1585869051eaSRichard Henderson         return DISAS_NORETURN;
15867ad439dfSRichard Henderson 
15877ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
15887ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
15897ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
15907ad439dfSRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1591869051eaSRichard Henderson         return DISAS_IAQ_N_UPDATED;
15927ad439dfSRichard Henderson 
15937ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
15947ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
1595869051eaSRichard Henderson         return DISAS_NORETURN;
15967ad439dfSRichard Henderson 
15977ad439dfSRichard Henderson     default:
15987ad439dfSRichard Henderson     do_sigill:
15997ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGILL);
1600869051eaSRichard Henderson         return DISAS_NORETURN;
16017ad439dfSRichard Henderson     }
16027ad439dfSRichard Henderson }
16037ad439dfSRichard Henderson 
1604869051eaSRichard Henderson static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn,
1605b2167459SRichard Henderson                                const DisasInsn *di)
1606b2167459SRichard Henderson {
1607b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1608869051eaSRichard Henderson     return DISAS_NEXT;
1609b2167459SRichard Henderson }
1610b2167459SRichard Henderson 
1611869051eaSRichard Henderson static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn,
161298a9cb79SRichard Henderson                                  const DisasInsn *di)
161398a9cb79SRichard Henderson {
161498a9cb79SRichard Henderson     nullify_over(ctx);
161598a9cb79SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
161698a9cb79SRichard Henderson }
161798a9cb79SRichard Henderson 
1618869051eaSRichard Henderson static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn,
161998a9cb79SRichard Henderson                                 const DisasInsn *di)
162098a9cb79SRichard Henderson {
162198a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
162298a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
162398a9cb79SRichard Henderson 
162498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1625869051eaSRichard Henderson     return DISAS_NEXT;
162698a9cb79SRichard Henderson }
162798a9cb79SRichard Henderson 
1628869051eaSRichard Henderson static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn,
162998a9cb79SRichard Henderson                                 const DisasInsn *di)
163098a9cb79SRichard Henderson {
163198a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
163298a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
163398a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, ctx->iaoq_f);
163498a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
163598a9cb79SRichard Henderson 
163698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1637869051eaSRichard Henderson     return DISAS_NEXT;
163898a9cb79SRichard Henderson }
163998a9cb79SRichard Henderson 
1640869051eaSRichard Henderson static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn,
164198a9cb79SRichard Henderson                                 const DisasInsn *di)
164298a9cb79SRichard Henderson {
164398a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
164498a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
164598a9cb79SRichard Henderson 
164698a9cb79SRichard Henderson     /* ??? We don't implement space registers.  */
164798a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, 0);
164898a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
164998a9cb79SRichard Henderson 
165098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1651869051eaSRichard Henderson     return DISAS_NEXT;
165298a9cb79SRichard Henderson }
165398a9cb79SRichard Henderson 
1654869051eaSRichard Henderson static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn,
165598a9cb79SRichard Henderson                                  const DisasInsn *di)
165698a9cb79SRichard Henderson {
165798a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
165898a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
165998a9cb79SRichard Henderson     TCGv tmp;
166098a9cb79SRichard Henderson 
166198a9cb79SRichard Henderson     switch (ctl) {
166298a9cb79SRichard Henderson     case 11: /* SAR */
166398a9cb79SRichard Henderson #ifdef TARGET_HPPA64
166498a9cb79SRichard Henderson         if (extract32(insn, 14, 1) == 0) {
166598a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
166698a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
166798a9cb79SRichard Henderson             tcg_gen_andi_tl(tmp, cpu_sar, 31);
166898a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
166998a9cb79SRichard Henderson             break;
167098a9cb79SRichard Henderson         }
167198a9cb79SRichard Henderson #endif
167298a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
167398a9cb79SRichard Henderson         break;
167498a9cb79SRichard Henderson     case 16: /* Interval Timer */
167598a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
167698a9cb79SRichard Henderson         tcg_gen_movi_tl(tmp, 0); /* FIXME */
167798a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
167898a9cb79SRichard Henderson         break;
167998a9cb79SRichard Henderson     case 26:
168098a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr26);
168198a9cb79SRichard Henderson         break;
168298a9cb79SRichard Henderson     case 27:
168398a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr27);
168498a9cb79SRichard Henderson         break;
168598a9cb79SRichard Henderson     default:
168698a9cb79SRichard Henderson         /* All other control registers are privileged.  */
168798a9cb79SRichard Henderson         return gen_illegal(ctx);
168898a9cb79SRichard Henderson     }
168998a9cb79SRichard Henderson 
169098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1691869051eaSRichard Henderson     return DISAS_NEXT;
169298a9cb79SRichard Henderson }
169398a9cb79SRichard Henderson 
1694869051eaSRichard Henderson static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn,
169598a9cb79SRichard Henderson                                  const DisasInsn *di)
169698a9cb79SRichard Henderson {
169798a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
169898a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
169998a9cb79SRichard Henderson     TCGv tmp;
170098a9cb79SRichard Henderson 
170198a9cb79SRichard Henderson     if (ctl == 11) { /* SAR */
170298a9cb79SRichard Henderson         tmp = tcg_temp_new();
170398a9cb79SRichard Henderson         tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
170498a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
170598a9cb79SRichard Henderson         tcg_temp_free(tmp);
170698a9cb79SRichard Henderson     } else {
170798a9cb79SRichard Henderson         /* All other control registers are privileged or read-only.  */
170898a9cb79SRichard Henderson         return gen_illegal(ctx);
170998a9cb79SRichard Henderson     }
171098a9cb79SRichard Henderson 
171198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1712869051eaSRichard Henderson     return DISAS_NEXT;
171398a9cb79SRichard Henderson }
171498a9cb79SRichard Henderson 
1715869051eaSRichard Henderson static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn,
171698a9cb79SRichard Henderson                                    const DisasInsn *di)
171798a9cb79SRichard Henderson {
171898a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
171998a9cb79SRichard Henderson     TCGv tmp = tcg_temp_new();
172098a9cb79SRichard Henderson 
172198a9cb79SRichard Henderson     tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
172298a9cb79SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
172398a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
172498a9cb79SRichard Henderson     tcg_temp_free(tmp);
172598a9cb79SRichard Henderson 
172698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1727869051eaSRichard Henderson     return DISAS_NEXT;
172898a9cb79SRichard Henderson }
172998a9cb79SRichard Henderson 
1730869051eaSRichard Henderson static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn,
173198a9cb79SRichard Henderson                                  const DisasInsn *di)
173298a9cb79SRichard Henderson {
173398a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
173498a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
173598a9cb79SRichard Henderson 
173698a9cb79SRichard Henderson     /* Since we don't implement space registers, this returns zero.  */
173798a9cb79SRichard Henderson     tcg_gen_movi_tl(dest, 0);
173898a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
173998a9cb79SRichard Henderson 
174098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1741869051eaSRichard Henderson     return DISAS_NEXT;
174298a9cb79SRichard Henderson }
174398a9cb79SRichard Henderson 
174498a9cb79SRichard Henderson static const DisasInsn table_system[] = {
174598a9cb79SRichard Henderson     { 0x00000000u, 0xfc001fe0u, trans_break },
174698a9cb79SRichard Henderson     /* We don't implement space register, so MTSP is a nop.  */
174798a9cb79SRichard Henderson     { 0x00001820u, 0xffe01fffu, trans_nop },
174898a9cb79SRichard Henderson     { 0x00001840u, 0xfc00ffffu, trans_mtctl },
174998a9cb79SRichard Henderson     { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
175098a9cb79SRichard Henderson     { 0x000014a0u, 0xffffffe0u, trans_mfia },
175198a9cb79SRichard Henderson     { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
175298a9cb79SRichard Henderson     { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
175398a9cb79SRichard Henderson     { 0x00000400u, 0xffffffffu, trans_sync },
175498a9cb79SRichard Henderson     { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
175598a9cb79SRichard Henderson };
175698a9cb79SRichard Henderson 
1757869051eaSRichard Henderson static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
175898a9cb79SRichard Henderson                                         const DisasInsn *di)
175998a9cb79SRichard Henderson {
176098a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
176198a9cb79SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
176298a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rb);
176398a9cb79SRichard Henderson     TCGv src1 = load_gpr(ctx, rb);
176498a9cb79SRichard Henderson     TCGv src2 = load_gpr(ctx, rx);
176598a9cb79SRichard Henderson 
176698a9cb79SRichard Henderson     /* The only thing we need to do is the base register modification.  */
176798a9cb79SRichard Henderson     tcg_gen_add_tl(dest, src1, src2);
176898a9cb79SRichard Henderson     save_gpr(ctx, rb, dest);
176998a9cb79SRichard Henderson 
177098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1771869051eaSRichard Henderson     return DISAS_NEXT;
177298a9cb79SRichard Henderson }
177398a9cb79SRichard Henderson 
1774869051eaSRichard Henderson static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
177598a9cb79SRichard Henderson                                  const DisasInsn *di)
177698a9cb79SRichard Henderson {
177798a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
177898a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
177998a9cb79SRichard Henderson     unsigned is_write = extract32(insn, 6, 1);
178098a9cb79SRichard Henderson     TCGv dest;
178198a9cb79SRichard Henderson 
178298a9cb79SRichard Henderson     nullify_over(ctx);
178398a9cb79SRichard Henderson 
178498a9cb79SRichard Henderson     /* ??? Do something with priv level operand.  */
178598a9cb79SRichard Henderson     dest = dest_gpr(ctx, rt);
178698a9cb79SRichard Henderson     if (is_write) {
178798a9cb79SRichard Henderson         gen_helper_probe_w(dest, load_gpr(ctx, rb));
178898a9cb79SRichard Henderson     } else {
178998a9cb79SRichard Henderson         gen_helper_probe_r(dest, load_gpr(ctx, rb));
179098a9cb79SRichard Henderson     }
179198a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
1792869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
179398a9cb79SRichard Henderson }
179498a9cb79SRichard Henderson 
179598a9cb79SRichard Henderson static const DisasInsn table_mem_mgmt[] = {
179698a9cb79SRichard Henderson     { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
179798a9cb79SRichard Henderson     { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
179898a9cb79SRichard Henderson     { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
179998a9cb79SRichard Henderson     { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
180098a9cb79SRichard Henderson     { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
180198a9cb79SRichard Henderson     { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
180298a9cb79SRichard Henderson     { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
180398a9cb79SRichard Henderson     { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
180498a9cb79SRichard Henderson     { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
180598a9cb79SRichard Henderson     { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
180698a9cb79SRichard Henderson     { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
180798a9cb79SRichard Henderson     { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
180898a9cb79SRichard Henderson     { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
180998a9cb79SRichard Henderson     { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
181098a9cb79SRichard Henderson     { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
181198a9cb79SRichard Henderson };
181298a9cb79SRichard Henderson 
1813869051eaSRichard Henderson static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
1814b2167459SRichard Henderson                                const DisasInsn *di)
1815b2167459SRichard Henderson {
1816b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1817b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1818b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1819b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
1820b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
1821b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1822b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1823b2167459SRichard Henderson     bool is_c = false;
1824b2167459SRichard Henderson     bool is_l = false;
1825b2167459SRichard Henderson     bool is_tc = false;
1826b2167459SRichard Henderson     bool is_tsv = false;
1827869051eaSRichard Henderson     DisasJumpType ret;
1828b2167459SRichard Henderson 
1829b2167459SRichard Henderson     switch (ext) {
1830b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
1831b2167459SRichard Henderson         break;
1832b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
1833b2167459SRichard Henderson         is_l = true;
1834b2167459SRichard Henderson         break;
1835b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1836b2167459SRichard Henderson         is_tsv = true;
1837b2167459SRichard Henderson         break;
1838b2167459SRichard Henderson     case 0x7: /* ADD,C */
1839b2167459SRichard Henderson         is_c = true;
1840b2167459SRichard Henderson         break;
1841b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
1842b2167459SRichard Henderson         is_c = is_tsv = true;
1843b2167459SRichard Henderson         break;
1844b2167459SRichard Henderson     default:
1845b2167459SRichard Henderson         return gen_illegal(ctx);
1846b2167459SRichard Henderson     }
1847b2167459SRichard Henderson 
1848b2167459SRichard Henderson     if (cf) {
1849b2167459SRichard Henderson         nullify_over(ctx);
1850b2167459SRichard Henderson     }
1851b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1852b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1853b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1854b2167459SRichard Henderson     return nullify_end(ctx, ret);
1855b2167459SRichard Henderson }
1856b2167459SRichard Henderson 
1857869051eaSRichard Henderson static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
1858b2167459SRichard Henderson                                const DisasInsn *di)
1859b2167459SRichard Henderson {
1860b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1861b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1862b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1863b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
1864b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1865b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1866b2167459SRichard Henderson     bool is_b = false;
1867b2167459SRichard Henderson     bool is_tc = false;
1868b2167459SRichard Henderson     bool is_tsv = false;
1869869051eaSRichard Henderson     DisasJumpType ret;
1870b2167459SRichard Henderson 
1871b2167459SRichard Henderson     switch (ext) {
1872b2167459SRichard Henderson     case 0x10: /* SUB */
1873b2167459SRichard Henderson         break;
1874b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
1875b2167459SRichard Henderson         is_tsv = true;
1876b2167459SRichard Henderson         break;
1877b2167459SRichard Henderson     case 0x14: /* SUB,B */
1878b2167459SRichard Henderson         is_b = true;
1879b2167459SRichard Henderson         break;
1880b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
1881b2167459SRichard Henderson         is_b = is_tsv = true;
1882b2167459SRichard Henderson         break;
1883b2167459SRichard Henderson     case 0x13: /* SUB,TC */
1884b2167459SRichard Henderson         is_tc = true;
1885b2167459SRichard Henderson         break;
1886b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
1887b2167459SRichard Henderson         is_tc = is_tsv = true;
1888b2167459SRichard Henderson         break;
1889b2167459SRichard Henderson     default:
1890b2167459SRichard Henderson         return gen_illegal(ctx);
1891b2167459SRichard Henderson     }
1892b2167459SRichard Henderson 
1893b2167459SRichard Henderson     if (cf) {
1894b2167459SRichard Henderson         nullify_over(ctx);
1895b2167459SRichard Henderson     }
1896b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1897b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1898b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1899b2167459SRichard Henderson     return nullify_end(ctx, ret);
1900b2167459SRichard Henderson }
1901b2167459SRichard Henderson 
1902869051eaSRichard Henderson static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
1903b2167459SRichard Henderson                                const DisasInsn *di)
1904b2167459SRichard Henderson {
1905b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1906b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1907b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1908b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1909b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1910869051eaSRichard Henderson     DisasJumpType ret;
1911b2167459SRichard Henderson 
1912b2167459SRichard Henderson     if (cf) {
1913b2167459SRichard Henderson         nullify_over(ctx);
1914b2167459SRichard Henderson     }
1915b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1916b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1917eff235ebSPaolo Bonzini     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1918b2167459SRichard Henderson     return nullify_end(ctx, ret);
1919b2167459SRichard Henderson }
1920b2167459SRichard Henderson 
1921b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1922869051eaSRichard Henderson static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
1923b2167459SRichard Henderson                                 const DisasInsn *di)
1924b2167459SRichard Henderson {
1925b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1926b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1927b2167459SRichard Henderson 
1928b2167459SRichard Henderson     if (r1 == 0) {
1929b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1930b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1931b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1932b2167459SRichard Henderson     } else {
1933b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1934b2167459SRichard Henderson     }
1935b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1936869051eaSRichard Henderson     return DISAS_NEXT;
1937b2167459SRichard Henderson }
1938b2167459SRichard Henderson 
1939869051eaSRichard Henderson static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
1940b2167459SRichard Henderson                                   const DisasInsn *di)
1941b2167459SRichard Henderson {
1942b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1943b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1944b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1945b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1946b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1947869051eaSRichard Henderson     DisasJumpType ret;
1948b2167459SRichard Henderson 
1949b2167459SRichard Henderson     if (cf) {
1950b2167459SRichard Henderson         nullify_over(ctx);
1951b2167459SRichard Henderson     }
1952b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1953b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1954b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1955b2167459SRichard Henderson     return nullify_end(ctx, ret);
1956b2167459SRichard Henderson }
1957b2167459SRichard Henderson 
1958869051eaSRichard Henderson static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
1959b2167459SRichard Henderson                                 const DisasInsn *di)
1960b2167459SRichard Henderson {
1961b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1962b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1963b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1964b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1965b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1966869051eaSRichard Henderson     DisasJumpType ret;
1967b2167459SRichard Henderson 
1968b2167459SRichard Henderson     if (cf) {
1969b2167459SRichard Henderson         nullify_over(ctx);
1970b2167459SRichard Henderson     }
1971b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1972b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1973b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1974b2167459SRichard Henderson     return nullify_end(ctx, ret);
1975b2167459SRichard Henderson }
1976b2167459SRichard Henderson 
1977869051eaSRichard Henderson static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
1978b2167459SRichard Henderson                                   const DisasInsn *di)
1979b2167459SRichard Henderson {
1980b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1981b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1982b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1983b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
1984b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1985b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
1986869051eaSRichard Henderson     DisasJumpType ret;
1987b2167459SRichard Henderson 
1988b2167459SRichard Henderson     if (cf) {
1989b2167459SRichard Henderson         nullify_over(ctx);
1990b2167459SRichard Henderson     }
1991b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1992b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1993b2167459SRichard Henderson     tmp = get_temp(ctx);
1994b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
1995b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
1996b2167459SRichard Henderson     return nullify_end(ctx, ret);
1997b2167459SRichard Henderson }
1998b2167459SRichard Henderson 
1999869051eaSRichard Henderson static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
2000b2167459SRichard Henderson                                 const DisasInsn *di)
2001b2167459SRichard Henderson {
2002b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2003b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2004b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
2005b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2006b2167459SRichard Henderson     TCGv tmp;
2007869051eaSRichard Henderson     DisasJumpType ret;
2008b2167459SRichard Henderson 
2009b2167459SRichard Henderson     nullify_over(ctx);
2010b2167459SRichard Henderson 
2011b2167459SRichard Henderson     tmp = get_temp(ctx);
2012b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2013b2167459SRichard Henderson     if (!is_i) {
2014b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
2015b2167459SRichard Henderson     }
2016b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2017b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
2018b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2019b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2020b2167459SRichard Henderson 
2021b2167459SRichard Henderson     return nullify_end(ctx, ret);
2022b2167459SRichard Henderson }
2023b2167459SRichard Henderson 
2024869051eaSRichard Henderson static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2025b2167459SRichard Henderson                               const DisasInsn *di)
2026b2167459SRichard Henderson {
2027b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2028b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
2029b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2030b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2031b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
2032b2167459SRichard Henderson 
2033b2167459SRichard Henderson     nullify_over(ctx);
2034b2167459SRichard Henderson 
2035b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
2036b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
2037b2167459SRichard Henderson 
2038b2167459SRichard Henderson     add1 = tcg_temp_new();
2039b2167459SRichard Henderson     add2 = tcg_temp_new();
2040b2167459SRichard Henderson     addc = tcg_temp_new();
2041b2167459SRichard Henderson     dest = tcg_temp_new();
2042b2167459SRichard Henderson     zero = tcg_const_tl(0);
2043b2167459SRichard Henderson 
2044b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
2045b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
2046b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2047b2167459SRichard Henderson 
2048b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
2049b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
2050b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
2051b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
2052b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2053b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
2054b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
2055b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
2056b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2057b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2058b2167459SRichard Henderson 
2059b2167459SRichard Henderson     tcg_temp_free(addc);
2060b2167459SRichard Henderson     tcg_temp_free(zero);
2061b2167459SRichard Henderson 
2062b2167459SRichard Henderson     /* Write back the result register.  */
2063b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
2064b2167459SRichard Henderson 
2065b2167459SRichard Henderson     /* Write back PSW[CB].  */
2066b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2067b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2068b2167459SRichard Henderson 
2069b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
2070b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2071b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2072b2167459SRichard Henderson 
2073b2167459SRichard Henderson     /* Install the new nullification.  */
2074b2167459SRichard Henderson     if (cf) {
2075*f764718dSRichard Henderson         TCGv sv = NULL;
2076b2167459SRichard Henderson         if (cf >> 1 == 6) {
2077b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2078b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2079b2167459SRichard Henderson         }
2080b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2081b2167459SRichard Henderson     }
2082b2167459SRichard Henderson 
2083b2167459SRichard Henderson     tcg_temp_free(add1);
2084b2167459SRichard Henderson     tcg_temp_free(add2);
2085b2167459SRichard Henderson     tcg_temp_free(dest);
2086b2167459SRichard Henderson 
2087869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
2088b2167459SRichard Henderson }
2089b2167459SRichard Henderson 
2090b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
2091b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
2092b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2093eff235ebSPaolo Bonzini     { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2094eff235ebSPaolo Bonzini     { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2095eff235ebSPaolo Bonzini     { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2096eff235ebSPaolo Bonzini     { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2097b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2098b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
2099b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2100b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2101b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
2102b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2103b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2104b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2105b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2106b2167459SRichard Henderson };
2107b2167459SRichard Henderson 
2108869051eaSRichard Henderson static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
2109b2167459SRichard Henderson {
2110b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2111b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2112b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2113b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2114b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2115b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
2116b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2117869051eaSRichard Henderson     DisasJumpType ret;
2118b2167459SRichard Henderson 
2119b2167459SRichard Henderson     if (cf) {
2120b2167459SRichard Henderson         nullify_over(ctx);
2121b2167459SRichard Henderson     }
2122b2167459SRichard Henderson 
2123b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2124b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2125b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2126b2167459SRichard Henderson 
2127b2167459SRichard Henderson     return nullify_end(ctx, ret);
2128b2167459SRichard Henderson }
2129b2167459SRichard Henderson 
2130869051eaSRichard Henderson static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
2131b2167459SRichard Henderson {
2132b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2133b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2134b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2135b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2136b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2137b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2138869051eaSRichard Henderson     DisasJumpType ret;
2139b2167459SRichard Henderson 
2140b2167459SRichard Henderson     if (cf) {
2141b2167459SRichard Henderson         nullify_over(ctx);
2142b2167459SRichard Henderson     }
2143b2167459SRichard Henderson 
2144b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2145b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2146b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2147b2167459SRichard Henderson 
2148b2167459SRichard Henderson     return nullify_end(ctx, ret);
2149b2167459SRichard Henderson }
2150b2167459SRichard Henderson 
2151869051eaSRichard Henderson static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2152b2167459SRichard Henderson {
2153b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2154b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2155b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2156b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2157b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2158869051eaSRichard Henderson     DisasJumpType ret;
2159b2167459SRichard Henderson 
2160b2167459SRichard Henderson     if (cf) {
2161b2167459SRichard Henderson         nullify_over(ctx);
2162b2167459SRichard Henderson     }
2163b2167459SRichard Henderson 
2164b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2165b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2166b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2167b2167459SRichard Henderson 
2168b2167459SRichard Henderson     return nullify_end(ctx, ret);
2169b2167459SRichard Henderson }
2170b2167459SRichard Henderson 
2171869051eaSRichard Henderson static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
217296d6407fSRichard Henderson                                     const DisasInsn *di)
217396d6407fSRichard Henderson {
217496d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
217596d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
217696d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
217796d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
217896d6407fSRichard Henderson     int disp = low_sextract(insn, 16, 5);
217996d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
218096d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
218196d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
218296d6407fSRichard Henderson 
218396d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
218496d6407fSRichard Henderson }
218596d6407fSRichard Henderson 
2186869051eaSRichard Henderson static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
218796d6407fSRichard Henderson                                     const DisasInsn *di)
218896d6407fSRichard Henderson {
218996d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
219096d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
219196d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
219296d6407fSRichard Henderson     unsigned u = extract32(insn, 13, 1);
219396d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
219496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
219596d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
219696d6407fSRichard Henderson 
219796d6407fSRichard Henderson     return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
219896d6407fSRichard Henderson }
219996d6407fSRichard Henderson 
2200869051eaSRichard Henderson static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
220196d6407fSRichard Henderson                                     const DisasInsn *di)
220296d6407fSRichard Henderson {
220396d6407fSRichard Henderson     int disp = low_sextract(insn, 0, 5);
220496d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
220596d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
220696d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
220796d6407fSRichard Henderson     unsigned rr = extract32(insn, 16, 5);
220896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
220996d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
221096d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
221196d6407fSRichard Henderson 
221296d6407fSRichard Henderson     return do_store(ctx, rr, rb, disp, modify, mop);
221396d6407fSRichard Henderson }
221496d6407fSRichard Henderson 
2215869051eaSRichard Henderson static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
221696d6407fSRichard Henderson                                 const DisasInsn *di)
221796d6407fSRichard Henderson {
221896d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
221996d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
222096d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
222196d6407fSRichard Henderson     unsigned au = extract32(insn, 13, 1);
222296d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
222396d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
222496d6407fSRichard Henderson     TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
222596d6407fSRichard Henderson     TCGv zero, addr, base, dest;
222696d6407fSRichard Henderson     int modify, disp = 0, scale = 0;
222796d6407fSRichard Henderson 
222896d6407fSRichard Henderson     nullify_over(ctx);
222996d6407fSRichard Henderson 
223096d6407fSRichard Henderson     /* ??? Share more code with do_load and do_load_{32,64}.  */
223196d6407fSRichard Henderson 
223296d6407fSRichard Henderson     if (i) {
223396d6407fSRichard Henderson         modify = (m ? (au ? -1 : 1) : 0);
223496d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
223596d6407fSRichard Henderson         rx = 0;
223696d6407fSRichard Henderson     } else {
223796d6407fSRichard Henderson         modify = m;
223896d6407fSRichard Henderson         if (au) {
223996d6407fSRichard Henderson             scale = mop & MO_SIZE;
224096d6407fSRichard Henderson         }
224196d6407fSRichard Henderson     }
224296d6407fSRichard Henderson     if (modify) {
224396d6407fSRichard Henderson         /* Base register modification.  Make sure if RT == RB, we see
224496d6407fSRichard Henderson            the result of the load.  */
224596d6407fSRichard Henderson         dest = get_temp(ctx);
224696d6407fSRichard Henderson     } else {
224796d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
224896d6407fSRichard Henderson     }
224996d6407fSRichard Henderson 
225096d6407fSRichard Henderson     addr = tcg_temp_new();
225196d6407fSRichard Henderson     base = load_gpr(ctx, rb);
225296d6407fSRichard Henderson     if (rx) {
225396d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
225496d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
225596d6407fSRichard Henderson     } else {
225696d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
225796d6407fSRichard Henderson     }
225896d6407fSRichard Henderson 
225996d6407fSRichard Henderson     zero = tcg_const_tl(0);
226096d6407fSRichard Henderson     tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
226196d6407fSRichard Henderson                            zero, MMU_USER_IDX, mop);
226296d6407fSRichard Henderson     if (modify) {
226396d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
226496d6407fSRichard Henderson     }
226596d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
226696d6407fSRichard Henderson 
2267869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
226896d6407fSRichard Henderson }
226996d6407fSRichard Henderson 
2270869051eaSRichard Henderson static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
227196d6407fSRichard Henderson                                 const DisasInsn *di)
227296d6407fSRichard Henderson {
227396d6407fSRichard Henderson     target_long disp = low_sextract(insn, 0, 5);
227496d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
227596d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
227696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
227796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
227896d6407fSRichard Henderson     TCGv addr, val;
227996d6407fSRichard Henderson 
228096d6407fSRichard Henderson     nullify_over(ctx);
228196d6407fSRichard Henderson 
228296d6407fSRichard Henderson     addr = tcg_temp_new();
228396d6407fSRichard Henderson     if (m || disp == 0) {
228496d6407fSRichard Henderson         tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
228596d6407fSRichard Henderson     } else {
228696d6407fSRichard Henderson         tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
228796d6407fSRichard Henderson     }
228896d6407fSRichard Henderson     val = load_gpr(ctx, rt);
228996d6407fSRichard Henderson 
229096d6407fSRichard Henderson     if (a) {
2291f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2292f9f46db4SEmilio G. Cota             gen_helper_stby_e_parallel(cpu_env, addr, val);
2293f9f46db4SEmilio G. Cota         } else {
229496d6407fSRichard Henderson             gen_helper_stby_e(cpu_env, addr, val);
2295f9f46db4SEmilio G. Cota         }
2296f9f46db4SEmilio G. Cota     } else {
2297f9f46db4SEmilio G. Cota         if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
2298f9f46db4SEmilio G. Cota             gen_helper_stby_b_parallel(cpu_env, addr, val);
229996d6407fSRichard Henderson         } else {
230096d6407fSRichard Henderson             gen_helper_stby_b(cpu_env, addr, val);
230196d6407fSRichard Henderson         }
2302f9f46db4SEmilio G. Cota     }
230396d6407fSRichard Henderson 
230496d6407fSRichard Henderson     if (m) {
230596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, addr, disp);
230696d6407fSRichard Henderson         tcg_gen_andi_tl(addr, addr, ~3);
230796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
230896d6407fSRichard Henderson     }
230996d6407fSRichard Henderson     tcg_temp_free(addr);
231096d6407fSRichard Henderson 
2311869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
231296d6407fSRichard Henderson }
231396d6407fSRichard Henderson 
231496d6407fSRichard Henderson static const DisasInsn table_index_mem[] = {
231596d6407fSRichard Henderson     { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
231696d6407fSRichard Henderson     { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
231796d6407fSRichard Henderson     { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
231896d6407fSRichard Henderson     { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
231996d6407fSRichard Henderson     { 0x0c001300u, 0xfc0013c0, trans_stby },
232096d6407fSRichard Henderson };
232196d6407fSRichard Henderson 
2322869051eaSRichard Henderson static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
2323b2167459SRichard Henderson {
2324b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2325b2167459SRichard Henderson     target_long i = assemble_21(insn);
2326b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2327b2167459SRichard Henderson 
2328b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
2329b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2330b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2331b2167459SRichard Henderson 
2332869051eaSRichard Henderson     return DISAS_NEXT;
2333b2167459SRichard Henderson }
2334b2167459SRichard Henderson 
2335869051eaSRichard Henderson static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
2336b2167459SRichard Henderson {
2337b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2338b2167459SRichard Henderson     target_long i = assemble_21(insn);
2339b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
2340b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
2341b2167459SRichard Henderson 
2342b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2343b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2344b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2345b2167459SRichard Henderson 
2346869051eaSRichard Henderson     return DISAS_NEXT;
2347b2167459SRichard Henderson }
2348b2167459SRichard Henderson 
2349869051eaSRichard Henderson static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
2350b2167459SRichard Henderson {
2351b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
2352b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2353b2167459SRichard Henderson     target_long i = assemble_16(insn);
2354b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2355b2167459SRichard Henderson 
2356b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2357b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2358b2167459SRichard Henderson     if (rb == 0) {
2359b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
2360b2167459SRichard Henderson     } else {
2361b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2362b2167459SRichard Henderson     }
2363b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2364b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2365b2167459SRichard Henderson 
2366869051eaSRichard Henderson     return DISAS_NEXT;
2367b2167459SRichard Henderson }
2368b2167459SRichard Henderson 
2369869051eaSRichard Henderson static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
237096d6407fSRichard Henderson                                 bool is_mod, TCGMemOp mop)
237196d6407fSRichard Henderson {
237296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
237396d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
237496d6407fSRichard Henderson     target_long i = assemble_16(insn);
237596d6407fSRichard Henderson 
237696d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
237796d6407fSRichard Henderson }
237896d6407fSRichard Henderson 
2379869051eaSRichard Henderson static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
238096d6407fSRichard Henderson {
238196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
238296d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
238396d6407fSRichard Henderson     target_long i = assemble_16a(insn);
238496d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
238596d6407fSRichard Henderson 
238696d6407fSRichard Henderson     switch (ext2) {
238796d6407fSRichard Henderson     case 0:
238896d6407fSRichard Henderson     case 1:
238996d6407fSRichard Henderson         /* FLDW without modification.  */
239096d6407fSRichard Henderson         return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
239196d6407fSRichard Henderson     case 2:
239296d6407fSRichard Henderson         /* LDW with modification.  Note that the sign of I selects
239396d6407fSRichard Henderson            post-dec vs pre-inc.  */
239496d6407fSRichard Henderson         return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
239596d6407fSRichard Henderson     default:
239696d6407fSRichard Henderson         return gen_illegal(ctx);
239796d6407fSRichard Henderson     }
239896d6407fSRichard Henderson }
239996d6407fSRichard Henderson 
2400869051eaSRichard Henderson static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
240196d6407fSRichard Henderson {
240296d6407fSRichard Henderson     target_long i = assemble_16a(insn);
240396d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
240496d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
240596d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
240696d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
240796d6407fSRichard Henderson 
240896d6407fSRichard Henderson     /* FLDW with modification.  */
240996d6407fSRichard Henderson     return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
241096d6407fSRichard Henderson }
241196d6407fSRichard Henderson 
2412869051eaSRichard Henderson static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
241396d6407fSRichard Henderson                                  bool is_mod, TCGMemOp mop)
241496d6407fSRichard Henderson {
241596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
241696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
241796d6407fSRichard Henderson     target_long i = assemble_16(insn);
241896d6407fSRichard Henderson 
241996d6407fSRichard Henderson     return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
242096d6407fSRichard Henderson }
242196d6407fSRichard Henderson 
2422869051eaSRichard Henderson static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
242396d6407fSRichard Henderson {
242496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
242596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
242696d6407fSRichard Henderson     target_long i = assemble_16a(insn);
242796d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
242896d6407fSRichard Henderson 
242996d6407fSRichard Henderson     switch (ext2) {
243096d6407fSRichard Henderson     case 0:
243196d6407fSRichard Henderson     case 1:
243296d6407fSRichard Henderson         /* FSTW without modification.  */
243396d6407fSRichard Henderson         return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
243496d6407fSRichard Henderson     case 2:
243596d6407fSRichard Henderson         /* LDW with modification.  */
243696d6407fSRichard Henderson         return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
243796d6407fSRichard Henderson     default:
243896d6407fSRichard Henderson         return gen_illegal(ctx);
243996d6407fSRichard Henderson     }
244096d6407fSRichard Henderson }
244196d6407fSRichard Henderson 
2442869051eaSRichard Henderson static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
244396d6407fSRichard Henderson {
244496d6407fSRichard Henderson     target_long i = assemble_16a(insn);
244596d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
244696d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
244796d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
244896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
244996d6407fSRichard Henderson 
245096d6407fSRichard Henderson     /* FSTW with modification.  */
245196d6407fSRichard Henderson     return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
245296d6407fSRichard Henderson }
245396d6407fSRichard Henderson 
2454869051eaSRichard Henderson static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
245596d6407fSRichard Henderson {
245696d6407fSRichard Henderson     unsigned t0 = extract32(insn, 0, 5);
245796d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
245896d6407fSRichard Henderson     unsigned t1 = extract32(insn, 6, 1);
245996d6407fSRichard Henderson     unsigned ext3 = extract32(insn, 7, 3);
246096d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
246196d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
246296d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
246396d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
246496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
246596d6407fSRichard Henderson     unsigned rt = t1 * 32 + t0;
246696d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
246796d6407fSRichard Henderson     int disp, scale;
246896d6407fSRichard Henderson 
246996d6407fSRichard Henderson     if (i == 0) {
247096d6407fSRichard Henderson         scale = (ua ? 2 : 0);
247196d6407fSRichard Henderson         disp = 0;
247296d6407fSRichard Henderson         modify = m;
247396d6407fSRichard Henderson     } else {
247496d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
247596d6407fSRichard Henderson         scale = 0;
247696d6407fSRichard Henderson         rx = 0;
247796d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
247896d6407fSRichard Henderson     }
247996d6407fSRichard Henderson 
248096d6407fSRichard Henderson     switch (ext3) {
248196d6407fSRichard Henderson     case 0: /* FLDW */
248296d6407fSRichard Henderson         return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
248396d6407fSRichard Henderson     case 4: /* FSTW */
248496d6407fSRichard Henderson         return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
248596d6407fSRichard Henderson     }
248696d6407fSRichard Henderson     return gen_illegal(ctx);
248796d6407fSRichard Henderson }
248896d6407fSRichard Henderson 
2489869051eaSRichard Henderson static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
249096d6407fSRichard Henderson {
249196d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
249296d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
249396d6407fSRichard Henderson     unsigned ext4 = extract32(insn, 6, 4);
249496d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
249596d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
249696d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
249796d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
249896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
249996d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
250096d6407fSRichard Henderson     int disp, scale;
250196d6407fSRichard Henderson 
250296d6407fSRichard Henderson     if (i == 0) {
250396d6407fSRichard Henderson         scale = (ua ? 3 : 0);
250496d6407fSRichard Henderson         disp = 0;
250596d6407fSRichard Henderson         modify = m;
250696d6407fSRichard Henderson     } else {
250796d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
250896d6407fSRichard Henderson         scale = 0;
250996d6407fSRichard Henderson         rx = 0;
251096d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
251196d6407fSRichard Henderson     }
251296d6407fSRichard Henderson 
251396d6407fSRichard Henderson     switch (ext4) {
251496d6407fSRichard Henderson     case 0: /* FLDD */
251596d6407fSRichard Henderson         return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
251696d6407fSRichard Henderson     case 8: /* FSTD */
251796d6407fSRichard Henderson         return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
251896d6407fSRichard Henderson     default:
251996d6407fSRichard Henderson         return gen_illegal(ctx);
252096d6407fSRichard Henderson     }
252196d6407fSRichard Henderson }
252296d6407fSRichard Henderson 
2523869051eaSRichard Henderson static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
252498cd9ca7SRichard Henderson                                 bool is_true, bool is_imm, bool is_dw)
252598cd9ca7SRichard Henderson {
252698cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
252798cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
252898cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
252998cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
253098cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
253198cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv;
253298cd9ca7SRichard Henderson     DisasCond cond;
253398cd9ca7SRichard Henderson 
253498cd9ca7SRichard Henderson     nullify_over(ctx);
253598cd9ca7SRichard Henderson 
253698cd9ca7SRichard Henderson     if (is_imm) {
253798cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
253898cd9ca7SRichard Henderson     } else {
253998cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
254098cd9ca7SRichard Henderson     }
254198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
254298cd9ca7SRichard Henderson     dest = get_temp(ctx);
254398cd9ca7SRichard Henderson 
254498cd9ca7SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
254598cd9ca7SRichard Henderson 
2546*f764718dSRichard Henderson     sv = NULL;
254798cd9ca7SRichard Henderson     if (c == 6) {
254898cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
254998cd9ca7SRichard Henderson     }
255098cd9ca7SRichard Henderson 
255198cd9ca7SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
255298cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
255398cd9ca7SRichard Henderson }
255498cd9ca7SRichard Henderson 
2555869051eaSRichard Henderson static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
255698cd9ca7SRichard Henderson                                 bool is_true, bool is_imm)
255798cd9ca7SRichard Henderson {
255898cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
255998cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
256098cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
256198cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
256298cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
256398cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv, cb_msb;
256498cd9ca7SRichard Henderson     DisasCond cond;
256598cd9ca7SRichard Henderson 
256698cd9ca7SRichard Henderson     nullify_over(ctx);
256798cd9ca7SRichard Henderson 
256898cd9ca7SRichard Henderson     if (is_imm) {
256998cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
257098cd9ca7SRichard Henderson     } else {
257198cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
257298cd9ca7SRichard Henderson     }
257398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
257498cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
2575*f764718dSRichard Henderson     sv = NULL;
2576*f764718dSRichard Henderson     cb_msb = NULL;
257798cd9ca7SRichard Henderson 
257898cd9ca7SRichard Henderson     switch (c) {
257998cd9ca7SRichard Henderson     default:
258098cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
258198cd9ca7SRichard Henderson         break;
258298cd9ca7SRichard Henderson     case 4: case 5:
258398cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
258498cd9ca7SRichard Henderson         tcg_gen_movi_tl(cb_msb, 0);
258598cd9ca7SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
258698cd9ca7SRichard Henderson         break;
258798cd9ca7SRichard Henderson     case 6:
258898cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
258998cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
259098cd9ca7SRichard Henderson         break;
259198cd9ca7SRichard Henderson     }
259298cd9ca7SRichard Henderson 
259398cd9ca7SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
259498cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
259598cd9ca7SRichard Henderson }
259698cd9ca7SRichard Henderson 
2597869051eaSRichard Henderson static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
259898cd9ca7SRichard Henderson {
259998cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
260098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
260198cd9ca7SRichard Henderson     unsigned c = extract32(insn, 15, 1);
260298cd9ca7SRichard Henderson     unsigned r = extract32(insn, 16, 5);
260398cd9ca7SRichard Henderson     unsigned p = extract32(insn, 21, 5);
260498cd9ca7SRichard Henderson     unsigned i = extract32(insn, 26, 1);
260598cd9ca7SRichard Henderson     TCGv tmp, tcg_r;
260698cd9ca7SRichard Henderson     DisasCond cond;
260798cd9ca7SRichard Henderson 
260898cd9ca7SRichard Henderson     nullify_over(ctx);
260998cd9ca7SRichard Henderson 
261098cd9ca7SRichard Henderson     tmp = tcg_temp_new();
261198cd9ca7SRichard Henderson     tcg_r = load_gpr(ctx, r);
261298cd9ca7SRichard Henderson     if (i) {
261398cd9ca7SRichard Henderson         tcg_gen_shli_tl(tmp, tcg_r, p);
261498cd9ca7SRichard Henderson     } else {
261598cd9ca7SRichard Henderson         tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
261698cd9ca7SRichard Henderson     }
261798cd9ca7SRichard Henderson 
261898cd9ca7SRichard Henderson     cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
261998cd9ca7SRichard Henderson     tcg_temp_free(tmp);
262098cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
262198cd9ca7SRichard Henderson }
262298cd9ca7SRichard Henderson 
2623869051eaSRichard Henderson static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
262498cd9ca7SRichard Henderson {
262598cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
262698cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
262798cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
262898cd9ca7SRichard Henderson     unsigned t = extract32(insn, 16, 5);
262998cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
263098cd9ca7SRichard Henderson     TCGv dest;
263198cd9ca7SRichard Henderson     DisasCond cond;
263298cd9ca7SRichard Henderson 
263398cd9ca7SRichard Henderson     nullify_over(ctx);
263498cd9ca7SRichard Henderson 
263598cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
263698cd9ca7SRichard Henderson     if (is_imm) {
263798cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
263898cd9ca7SRichard Henderson     } else if (t == 0) {
263998cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, 0);
264098cd9ca7SRichard Henderson     } else {
264198cd9ca7SRichard Henderson         tcg_gen_mov_tl(dest, cpu_gr[t]);
264298cd9ca7SRichard Henderson     }
264398cd9ca7SRichard Henderson 
264498cd9ca7SRichard Henderson     cond = do_sed_cond(c, dest);
264598cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
264698cd9ca7SRichard Henderson }
264798cd9ca7SRichard Henderson 
2648869051eaSRichard Henderson static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
26490b1347d2SRichard Henderson                                     const DisasInsn *di)
26500b1347d2SRichard Henderson {
26510b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
26520b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26530b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
26540b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
26550b1347d2SRichard Henderson     TCGv dest;
26560b1347d2SRichard Henderson 
26570b1347d2SRichard Henderson     if (c) {
26580b1347d2SRichard Henderson         nullify_over(ctx);
26590b1347d2SRichard Henderson     }
26600b1347d2SRichard Henderson 
26610b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26620b1347d2SRichard Henderson     if (r1 == 0) {
26630b1347d2SRichard Henderson         tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
26640b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, dest, cpu_sar);
26650b1347d2SRichard Henderson     } else if (r1 == r2) {
26660b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
26670b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
26680b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
26690b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
26700b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
26710b1347d2SRichard Henderson     } else {
26720b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
26730b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
26740b1347d2SRichard Henderson 
26750b1347d2SRichard Henderson         tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
26760b1347d2SRichard Henderson         tcg_gen_extu_tl_i64(s, cpu_sar);
26770b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
26780b1347d2SRichard Henderson         tcg_gen_trunc_i64_tl(dest, t);
26790b1347d2SRichard Henderson 
26800b1347d2SRichard Henderson         tcg_temp_free_i64(t);
26810b1347d2SRichard Henderson         tcg_temp_free_i64(s);
26820b1347d2SRichard Henderson     }
26830b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26840b1347d2SRichard Henderson 
26850b1347d2SRichard Henderson     /* Install the new nullification.  */
26860b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
26870b1347d2SRichard Henderson     if (c) {
26880b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
26890b1347d2SRichard Henderson     }
2690869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
26910b1347d2SRichard Henderson }
26920b1347d2SRichard Henderson 
2693869051eaSRichard Henderson static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
26940b1347d2SRichard Henderson                                      const DisasInsn *di)
26950b1347d2SRichard Henderson {
26960b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
26970b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
26980b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26990b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
27000b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
27010b1347d2SRichard Henderson     unsigned sa = 31 - cpos;
27020b1347d2SRichard Henderson     TCGv dest, t2;
27030b1347d2SRichard Henderson 
27040b1347d2SRichard Henderson     if (c) {
27050b1347d2SRichard Henderson         nullify_over(ctx);
27060b1347d2SRichard Henderson     }
27070b1347d2SRichard Henderson 
27080b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27090b1347d2SRichard Henderson     t2 = load_gpr(ctx, r2);
27100b1347d2SRichard Henderson     if (r1 == r2) {
27110b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
27120b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, t2);
27130b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
27140b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
27150b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
27160b1347d2SRichard Henderson     } else if (r1 == 0) {
27170b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
27180b1347d2SRichard Henderson     } else {
27190b1347d2SRichard Henderson         TCGv t0 = tcg_temp_new();
27200b1347d2SRichard Henderson         tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
27210b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
27220b1347d2SRichard Henderson         tcg_temp_free(t0);
27230b1347d2SRichard Henderson     }
27240b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27250b1347d2SRichard Henderson 
27260b1347d2SRichard Henderson     /* Install the new nullification.  */
27270b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27280b1347d2SRichard Henderson     if (c) {
27290b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27300b1347d2SRichard Henderson     }
2731869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
27320b1347d2SRichard Henderson }
27330b1347d2SRichard Henderson 
2734869051eaSRichard Henderson static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
27350b1347d2SRichard Henderson                                      const DisasInsn *di)
27360b1347d2SRichard Henderson {
27370b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27380b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27390b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27400b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27410b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27420b1347d2SRichard Henderson     unsigned len = 32 - clen;
27430b1347d2SRichard Henderson     TCGv dest, src, tmp;
27440b1347d2SRichard Henderson 
27450b1347d2SRichard Henderson     if (c) {
27460b1347d2SRichard Henderson         nullify_over(ctx);
27470b1347d2SRichard Henderson     }
27480b1347d2SRichard Henderson 
27490b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27500b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
27510b1347d2SRichard Henderson     tmp = tcg_temp_new();
27520b1347d2SRichard Henderson 
27530b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
27540b1347d2SRichard Henderson     tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
27550b1347d2SRichard Henderson     if (is_se) {
27560b1347d2SRichard Henderson         tcg_gen_sar_tl(dest, src, tmp);
27570b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, dest, 0, len);
27580b1347d2SRichard Henderson     } else {
27590b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, src, tmp);
27600b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, dest, 0, len);
27610b1347d2SRichard Henderson     }
27620b1347d2SRichard Henderson     tcg_temp_free(tmp);
27630b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27640b1347d2SRichard Henderson 
27650b1347d2SRichard Henderson     /* Install the new nullification.  */
27660b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27670b1347d2SRichard Henderson     if (c) {
27680b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27690b1347d2SRichard Henderson     }
2770869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
27710b1347d2SRichard Henderson }
27720b1347d2SRichard Henderson 
2773869051eaSRichard Henderson static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
27740b1347d2SRichard Henderson                                      const DisasInsn *di)
27750b1347d2SRichard Henderson {
27760b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27770b1347d2SRichard Henderson     unsigned pos = extract32(insn, 5, 5);
27780b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27790b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27800b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27810b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27820b1347d2SRichard Henderson     unsigned len = 32 - clen;
27830b1347d2SRichard Henderson     unsigned cpos = 31 - pos;
27840b1347d2SRichard Henderson     TCGv dest, src;
27850b1347d2SRichard Henderson 
27860b1347d2SRichard Henderson     if (c) {
27870b1347d2SRichard Henderson         nullify_over(ctx);
27880b1347d2SRichard Henderson     }
27890b1347d2SRichard Henderson 
27900b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27910b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
27920b1347d2SRichard Henderson     if (is_se) {
27930b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, src, cpos, len);
27940b1347d2SRichard Henderson     } else {
27950b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, src, cpos, len);
27960b1347d2SRichard Henderson     }
27970b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27980b1347d2SRichard Henderson 
27990b1347d2SRichard Henderson     /* Install the new nullification.  */
28000b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28010b1347d2SRichard Henderson     if (c) {
28020b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28030b1347d2SRichard Henderson     }
2804869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28050b1347d2SRichard Henderson }
28060b1347d2SRichard Henderson 
28070b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = {
28080b1347d2SRichard Henderson     { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
28090b1347d2SRichard Henderson     { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
28100b1347d2SRichard Henderson     { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
28110b1347d2SRichard Henderson     { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
28120b1347d2SRichard Henderson };
28130b1347d2SRichard Henderson 
2814869051eaSRichard Henderson static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
28150b1347d2SRichard Henderson                                       const DisasInsn *di)
28160b1347d2SRichard Henderson {
28170b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28180b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28190b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28200b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28210b1347d2SRichard Henderson     target_long val = low_sextract(insn, 16, 5);
28220b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28230b1347d2SRichard Henderson     unsigned len = 32 - clen;
28240b1347d2SRichard Henderson     target_long mask0, mask1;
28250b1347d2SRichard Henderson     TCGv dest;
28260b1347d2SRichard Henderson 
28270b1347d2SRichard Henderson     if (c) {
28280b1347d2SRichard Henderson         nullify_over(ctx);
28290b1347d2SRichard Henderson     }
28300b1347d2SRichard Henderson     if (cpos + len > 32) {
28310b1347d2SRichard Henderson         len = 32 - cpos;
28320b1347d2SRichard Henderson     }
28330b1347d2SRichard Henderson 
28340b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28350b1347d2SRichard Henderson     mask0 = deposit64(0, cpos, len, val);
28360b1347d2SRichard Henderson     mask1 = deposit64(-1, cpos, len, val);
28370b1347d2SRichard Henderson 
28380b1347d2SRichard Henderson     if (nz) {
28390b1347d2SRichard Henderson         TCGv src = load_gpr(ctx, rt);
28400b1347d2SRichard Henderson         if (mask1 != -1) {
28410b1347d2SRichard Henderson             tcg_gen_andi_tl(dest, src, mask1);
28420b1347d2SRichard Henderson             src = dest;
28430b1347d2SRichard Henderson         }
28440b1347d2SRichard Henderson         tcg_gen_ori_tl(dest, src, mask0);
28450b1347d2SRichard Henderson     } else {
28460b1347d2SRichard Henderson         tcg_gen_movi_tl(dest, mask0);
28470b1347d2SRichard Henderson     }
28480b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28490b1347d2SRichard Henderson 
28500b1347d2SRichard Henderson     /* Install the new nullification.  */
28510b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28520b1347d2SRichard Henderson     if (c) {
28530b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28540b1347d2SRichard Henderson     }
2855869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28560b1347d2SRichard Henderson }
28570b1347d2SRichard Henderson 
2858869051eaSRichard Henderson static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
28590b1347d2SRichard Henderson                                     const DisasInsn *di)
28600b1347d2SRichard Henderson {
28610b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28620b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28630b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28640b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28650b1347d2SRichard Henderson     unsigned rr = extract32(insn, 16, 5);
28660b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28670b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
28680b1347d2SRichard Henderson     unsigned len = 32 - clen;
28690b1347d2SRichard Henderson     TCGv dest, val;
28700b1347d2SRichard Henderson 
28710b1347d2SRichard Henderson     if (c) {
28720b1347d2SRichard Henderson         nullify_over(ctx);
28730b1347d2SRichard Henderson     }
28740b1347d2SRichard Henderson     if (cpos + len > 32) {
28750b1347d2SRichard Henderson         len = 32 - cpos;
28760b1347d2SRichard Henderson     }
28770b1347d2SRichard Henderson 
28780b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28790b1347d2SRichard Henderson     val = load_gpr(ctx, rr);
28800b1347d2SRichard Henderson     if (rs == 0) {
28810b1347d2SRichard Henderson         tcg_gen_deposit_z_tl(dest, val, cpos, len);
28820b1347d2SRichard Henderson     } else {
28830b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
28840b1347d2SRichard Henderson     }
28850b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28860b1347d2SRichard Henderson 
28870b1347d2SRichard Henderson     /* Install the new nullification.  */
28880b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28890b1347d2SRichard Henderson     if (c) {
28900b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28910b1347d2SRichard Henderson     }
2892869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28930b1347d2SRichard Henderson }
28940b1347d2SRichard Henderson 
2895869051eaSRichard Henderson static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
28960b1347d2SRichard Henderson                                     const DisasInsn *di)
28970b1347d2SRichard Henderson {
28980b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28990b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
29000b1347d2SRichard Henderson     unsigned i = extract32(insn, 12, 1);
29010b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
29020b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
29030b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
29040b1347d2SRichard Henderson     unsigned len = 32 - clen;
29050b1347d2SRichard Henderson     TCGv val, mask, tmp, shift, dest;
29060b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
29070b1347d2SRichard Henderson 
29080b1347d2SRichard Henderson     if (c) {
29090b1347d2SRichard Henderson         nullify_over(ctx);
29100b1347d2SRichard Henderson     }
29110b1347d2SRichard Henderson 
29120b1347d2SRichard Henderson     if (i) {
29130b1347d2SRichard Henderson         val = load_const(ctx, low_sextract(insn, 16, 5));
29140b1347d2SRichard Henderson     } else {
29150b1347d2SRichard Henderson         val = load_gpr(ctx, extract32(insn, 16, 5));
29160b1347d2SRichard Henderson     }
29170b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
29180b1347d2SRichard Henderson     shift = tcg_temp_new();
29190b1347d2SRichard Henderson     tmp = tcg_temp_new();
29200b1347d2SRichard Henderson 
29210b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
29220b1347d2SRichard Henderson     tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
29230b1347d2SRichard Henderson 
29240b1347d2SRichard Henderson     mask = tcg_const_tl(msb + (msb - 1));
29250b1347d2SRichard Henderson     tcg_gen_and_tl(tmp, val, mask);
29260b1347d2SRichard Henderson     if (rs) {
29270b1347d2SRichard Henderson         tcg_gen_shl_tl(mask, mask, shift);
29280b1347d2SRichard Henderson         tcg_gen_shl_tl(tmp, tmp, shift);
29290b1347d2SRichard Henderson         tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
29300b1347d2SRichard Henderson         tcg_gen_or_tl(dest, dest, tmp);
29310b1347d2SRichard Henderson     } else {
29320b1347d2SRichard Henderson         tcg_gen_shl_tl(dest, tmp, shift);
29330b1347d2SRichard Henderson     }
29340b1347d2SRichard Henderson     tcg_temp_free(shift);
29350b1347d2SRichard Henderson     tcg_temp_free(mask);
29360b1347d2SRichard Henderson     tcg_temp_free(tmp);
29370b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
29380b1347d2SRichard Henderson 
29390b1347d2SRichard Henderson     /* Install the new nullification.  */
29400b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
29410b1347d2SRichard Henderson     if (c) {
29420b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
29430b1347d2SRichard Henderson     }
2944869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
29450b1347d2SRichard Henderson }
29460b1347d2SRichard Henderson 
29470b1347d2SRichard Henderson static const DisasInsn table_depw[] = {
29480b1347d2SRichard Henderson     { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
29490b1347d2SRichard Henderson     { 0xd4000800u, 0xfc001800u, trans_depw_imm },
29500b1347d2SRichard Henderson     { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
29510b1347d2SRichard Henderson };
29520b1347d2SRichard Henderson 
2953869051eaSRichard Henderson static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
295498cd9ca7SRichard Henderson {
295598cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
295698cd9ca7SRichard Henderson     unsigned b = extract32(insn, 21, 5);
295798cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
295898cd9ca7SRichard Henderson 
295998cd9ca7SRichard Henderson     /* unsigned s = low_uextract(insn, 13, 3); */
296098cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
296198cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
296298cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
296398cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
296498cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
296598cd9ca7SRichard Henderson 
296698cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
296798cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
296898cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
296998cd9ca7SRichard Henderson     if (b == 0) {
297098cd9ca7SRichard Henderson         return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
297198cd9ca7SRichard Henderson     } else {
297298cd9ca7SRichard Henderson         TCGv tmp = get_temp(ctx);
297398cd9ca7SRichard Henderson         tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
297498cd9ca7SRichard Henderson         return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
297598cd9ca7SRichard Henderson     }
297698cd9ca7SRichard Henderson }
297798cd9ca7SRichard Henderson 
2978869051eaSRichard Henderson static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
297998cd9ca7SRichard Henderson                               const DisasInsn *di)
298098cd9ca7SRichard Henderson {
298198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
298298cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
298398cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
298498cd9ca7SRichard Henderson 
298598cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
298698cd9ca7SRichard Henderson }
298798cd9ca7SRichard Henderson 
2988869051eaSRichard Henderson static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
298998cd9ca7SRichard Henderson                                    const DisasInsn *di)
299098cd9ca7SRichard Henderson {
299198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
299298cd9ca7SRichard Henderson     target_long disp = assemble_22(insn);
299398cd9ca7SRichard Henderson 
299498cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
299598cd9ca7SRichard Henderson }
299698cd9ca7SRichard Henderson 
2997869051eaSRichard Henderson static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
299898cd9ca7SRichard Henderson                                const DisasInsn *di)
299998cd9ca7SRichard Henderson {
300098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
300198cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
300298cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
300398cd9ca7SRichard Henderson     TCGv tmp = get_temp(ctx);
300498cd9ca7SRichard Henderson 
300598cd9ca7SRichard Henderson     tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
300698cd9ca7SRichard Henderson     tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
300798cd9ca7SRichard Henderson     return do_ibranch(ctx, tmp, link, n);
300898cd9ca7SRichard Henderson }
300998cd9ca7SRichard Henderson 
3010869051eaSRichard Henderson static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
301198cd9ca7SRichard Henderson                               const DisasInsn *di)
301298cd9ca7SRichard Henderson {
301398cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
301498cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
301598cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
301698cd9ca7SRichard Henderson     TCGv dest;
301798cd9ca7SRichard Henderson 
301898cd9ca7SRichard Henderson     if (rx == 0) {
301998cd9ca7SRichard Henderson         dest = load_gpr(ctx, rb);
302098cd9ca7SRichard Henderson     } else {
302198cd9ca7SRichard Henderson         dest = get_temp(ctx);
302298cd9ca7SRichard Henderson         tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
302398cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
302498cd9ca7SRichard Henderson     }
302598cd9ca7SRichard Henderson     return do_ibranch(ctx, dest, 0, n);
302698cd9ca7SRichard Henderson }
302798cd9ca7SRichard Henderson 
3028869051eaSRichard Henderson static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
302998cd9ca7SRichard Henderson                                const DisasInsn *di)
303098cd9ca7SRichard Henderson {
303198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
303298cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
303398cd9ca7SRichard Henderson     unsigned link = extract32(insn, 13, 1) ? 2 : 0;
303498cd9ca7SRichard Henderson 
303598cd9ca7SRichard Henderson     return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
303698cd9ca7SRichard Henderson }
303798cd9ca7SRichard Henderson 
303898cd9ca7SRichard Henderson static const DisasInsn table_branch[] = {
303998cd9ca7SRichard Henderson     { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
304098cd9ca7SRichard Henderson     { 0xe800a000u, 0xfc00e000u, trans_bl_long },
304198cd9ca7SRichard Henderson     { 0xe8004000u, 0xfc00fffdu, trans_blr },
304298cd9ca7SRichard Henderson     { 0xe800c000u, 0xfc00fffdu, trans_bv },
304398cd9ca7SRichard Henderson     { 0xe800d000u, 0xfc00dffcu, trans_bve },
304498cd9ca7SRichard Henderson };
304598cd9ca7SRichard Henderson 
3046869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3047ebe9383cSRichard Henderson                                       const DisasInsn *di)
3048ebe9383cSRichard Henderson {
3049ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3050ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3051eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3052ebe9383cSRichard Henderson }
3053ebe9383cSRichard Henderson 
3054869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3055ebe9383cSRichard Henderson                                       const DisasInsn *di)
3056ebe9383cSRichard Henderson {
3057ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3058ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3059eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3060ebe9383cSRichard Henderson }
3061ebe9383cSRichard Henderson 
3062869051eaSRichard Henderson static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
3063ebe9383cSRichard Henderson                                    const DisasInsn *di)
3064ebe9383cSRichard Henderson {
3065ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3066ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3067eff235ebSPaolo Bonzini     return do_fop_ded(ctx, rt, ra, di->f.ded);
3068ebe9383cSRichard Henderson }
3069ebe9383cSRichard Henderson 
3070869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3071ebe9383cSRichard Henderson                                       const DisasInsn *di)
3072ebe9383cSRichard Henderson {
3073ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3074ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3075eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3076ebe9383cSRichard Henderson }
3077ebe9383cSRichard Henderson 
3078869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3079ebe9383cSRichard Henderson                                       const DisasInsn *di)
3080ebe9383cSRichard Henderson {
3081ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3082ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3083eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3084ebe9383cSRichard Henderson }
3085ebe9383cSRichard Henderson 
3086869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3087ebe9383cSRichard Henderson                                       const DisasInsn *di)
3088ebe9383cSRichard Henderson {
3089ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3090ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3091eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3092ebe9383cSRichard Henderson }
3093ebe9383cSRichard Henderson 
3094869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3095ebe9383cSRichard Henderson                                       const DisasInsn *di)
3096ebe9383cSRichard Henderson {
3097ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3098ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3099eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3100ebe9383cSRichard Henderson }
3101ebe9383cSRichard Henderson 
3102869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3103ebe9383cSRichard Henderson                                        const DisasInsn *di)
3104ebe9383cSRichard Henderson {
3105ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3106ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3107ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3108eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3109ebe9383cSRichard Henderson }
3110ebe9383cSRichard Henderson 
3111869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3112ebe9383cSRichard Henderson                                        const DisasInsn *di)
3113ebe9383cSRichard Henderson {
3114ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3115ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3116ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3117eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3118ebe9383cSRichard Henderson }
3119ebe9383cSRichard Henderson 
3120869051eaSRichard Henderson static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3121ebe9383cSRichard Henderson                                     const DisasInsn *di)
3122ebe9383cSRichard Henderson {
3123ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3124ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3125ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3126eff235ebSPaolo Bonzini     return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3127ebe9383cSRichard Henderson }
3128ebe9383cSRichard Henderson 
3129ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3130ebe9383cSRichard Henderson {
3131ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3132ebe9383cSRichard Henderson }
3133ebe9383cSRichard Henderson 
3134ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3135ebe9383cSRichard Henderson {
3136ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3137ebe9383cSRichard Henderson }
3138ebe9383cSRichard Henderson 
3139ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3140ebe9383cSRichard Henderson {
3141ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3142ebe9383cSRichard Henderson }
3143ebe9383cSRichard Henderson 
3144ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3145ebe9383cSRichard Henderson {
3146ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3147ebe9383cSRichard Henderson }
3148ebe9383cSRichard Henderson 
3149ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3150ebe9383cSRichard Henderson {
3151ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3152ebe9383cSRichard Henderson }
3153ebe9383cSRichard Henderson 
3154ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3155ebe9383cSRichard Henderson {
3156ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3157ebe9383cSRichard Henderson }
3158ebe9383cSRichard Henderson 
3159ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3160ebe9383cSRichard Henderson {
3161ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3162ebe9383cSRichard Henderson }
3163ebe9383cSRichard Henderson 
3164ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3165ebe9383cSRichard Henderson {
3166ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3167ebe9383cSRichard Henderson }
3168ebe9383cSRichard Henderson 
3169869051eaSRichard Henderson static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3170ebe9383cSRichard Henderson                                unsigned y, unsigned c)
3171ebe9383cSRichard Henderson {
3172ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3173ebe9383cSRichard Henderson 
3174ebe9383cSRichard Henderson     nullify_over(ctx);
3175ebe9383cSRichard Henderson 
3176ebe9383cSRichard Henderson     ta = load_frw0_i32(ra);
3177ebe9383cSRichard Henderson     tb = load_frw0_i32(rb);
3178ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3179ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3180ebe9383cSRichard Henderson 
3181ebe9383cSRichard Henderson     gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3182ebe9383cSRichard Henderson 
3183ebe9383cSRichard Henderson     tcg_temp_free_i32(ta);
3184ebe9383cSRichard Henderson     tcg_temp_free_i32(tb);
3185ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3186ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3187ebe9383cSRichard Henderson 
3188869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3189ebe9383cSRichard Henderson }
3190ebe9383cSRichard Henderson 
3191869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3192ebe9383cSRichard Henderson                                      const DisasInsn *di)
3193ebe9383cSRichard Henderson {
3194ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3195ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3196ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3197ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3198ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3199ebe9383cSRichard Henderson }
3200ebe9383cSRichard Henderson 
3201869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3202ebe9383cSRichard Henderson                                      const DisasInsn *di)
3203ebe9383cSRichard Henderson {
3204ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3205ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3206ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3207ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3208ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3209ebe9383cSRichard Henderson }
3210ebe9383cSRichard Henderson 
3211869051eaSRichard Henderson static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3212ebe9383cSRichard Henderson                                   const DisasInsn *di)
3213ebe9383cSRichard Henderson {
3214ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3215ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3216ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3217ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3218ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3219ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3220ebe9383cSRichard Henderson 
3221ebe9383cSRichard Henderson     nullify_over(ctx);
3222ebe9383cSRichard Henderson 
3223ebe9383cSRichard Henderson     ta = load_frd0(ra);
3224ebe9383cSRichard Henderson     tb = load_frd0(rb);
3225ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3226ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3227ebe9383cSRichard Henderson 
3228ebe9383cSRichard Henderson     gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3229ebe9383cSRichard Henderson 
3230ebe9383cSRichard Henderson     tcg_temp_free_i64(ta);
3231ebe9383cSRichard Henderson     tcg_temp_free_i64(tb);
3232ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3233ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3234ebe9383cSRichard Henderson 
3235869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3236ebe9383cSRichard Henderson }
3237ebe9383cSRichard Henderson 
3238869051eaSRichard Henderson static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
3239ebe9383cSRichard Henderson                                    const DisasInsn *di)
3240ebe9383cSRichard Henderson {
3241ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3242ebe9383cSRichard Henderson     unsigned cbit = (y ^ 1) - 1;
3243ebe9383cSRichard Henderson     TCGv t;
3244ebe9383cSRichard Henderson 
3245ebe9383cSRichard Henderson     nullify_over(ctx);
3246ebe9383cSRichard Henderson 
3247ebe9383cSRichard Henderson     t = tcg_temp_new();
3248ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3249ebe9383cSRichard Henderson     tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3250ebe9383cSRichard Henderson     ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3251ebe9383cSRichard Henderson     tcg_temp_free(t);
3252ebe9383cSRichard Henderson 
3253869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3254ebe9383cSRichard Henderson }
3255ebe9383cSRichard Henderson 
3256869051eaSRichard Henderson static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
3257ebe9383cSRichard Henderson                                    const DisasInsn *di)
3258ebe9383cSRichard Henderson {
3259ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3260ebe9383cSRichard Henderson     int mask;
3261ebe9383cSRichard Henderson     bool inv = false;
3262ebe9383cSRichard Henderson     TCGv t;
3263ebe9383cSRichard Henderson 
3264ebe9383cSRichard Henderson     nullify_over(ctx);
3265ebe9383cSRichard Henderson 
3266ebe9383cSRichard Henderson     t = tcg_temp_new();
3267ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3268ebe9383cSRichard Henderson 
3269ebe9383cSRichard Henderson     switch (c) {
3270ebe9383cSRichard Henderson     case 0: /* simple */
3271ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, 0x4000000);
3272ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3273ebe9383cSRichard Henderson         goto done;
3274ebe9383cSRichard Henderson     case 2: /* rej */
3275ebe9383cSRichard Henderson         inv = true;
3276ebe9383cSRichard Henderson         /* fallthru */
3277ebe9383cSRichard Henderson     case 1: /* acc */
3278ebe9383cSRichard Henderson         mask = 0x43ff800;
3279ebe9383cSRichard Henderson         break;
3280ebe9383cSRichard Henderson     case 6: /* rej8 */
3281ebe9383cSRichard Henderson         inv = true;
3282ebe9383cSRichard Henderson         /* fallthru */
3283ebe9383cSRichard Henderson     case 5: /* acc8 */
3284ebe9383cSRichard Henderson         mask = 0x43f8000;
3285ebe9383cSRichard Henderson         break;
3286ebe9383cSRichard Henderson     case 9: /* acc6 */
3287ebe9383cSRichard Henderson         mask = 0x43e0000;
3288ebe9383cSRichard Henderson         break;
3289ebe9383cSRichard Henderson     case 13: /* acc4 */
3290ebe9383cSRichard Henderson         mask = 0x4380000;
3291ebe9383cSRichard Henderson         break;
3292ebe9383cSRichard Henderson     case 17: /* acc2 */
3293ebe9383cSRichard Henderson         mask = 0x4200000;
3294ebe9383cSRichard Henderson         break;
3295ebe9383cSRichard Henderson     default:
3296ebe9383cSRichard Henderson         return gen_illegal(ctx);
3297ebe9383cSRichard Henderson     }
3298ebe9383cSRichard Henderson     if (inv) {
3299ebe9383cSRichard Henderson         TCGv c = load_const(ctx, mask);
3300ebe9383cSRichard Henderson         tcg_gen_or_tl(t, t, c);
3301ebe9383cSRichard Henderson         ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3302ebe9383cSRichard Henderson     } else {
3303ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, mask);
3304ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3305ebe9383cSRichard Henderson     }
3306ebe9383cSRichard Henderson  done:
3307869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3308ebe9383cSRichard Henderson }
3309ebe9383cSRichard Henderson 
3310869051eaSRichard Henderson static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
3311ebe9383cSRichard Henderson                                  const DisasInsn *di)
3312ebe9383cSRichard Henderson {
3313ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3314ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3315ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3316ebe9383cSRichard Henderson     TCGv_i64 a, b;
3317ebe9383cSRichard Henderson 
3318ebe9383cSRichard Henderson     nullify_over(ctx);
3319ebe9383cSRichard Henderson 
3320ebe9383cSRichard Henderson     a = load_frw0_i64(ra);
3321ebe9383cSRichard Henderson     b = load_frw0_i64(rb);
3322ebe9383cSRichard Henderson     tcg_gen_mul_i64(a, a, b);
3323ebe9383cSRichard Henderson     save_frd(rt, a);
3324ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3325ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3326ebe9383cSRichard Henderson 
3327869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3328ebe9383cSRichard Henderson }
3329ebe9383cSRichard Henderson 
3330eff235ebSPaolo Bonzini #define FOP_DED  trans_fop_ded, .f.ded
3331eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd
3332ebe9383cSRichard Henderson 
3333eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0c, .f.wew
3334eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0c, .f.dew
3335eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0c, .f.wed
3336eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww
3337ebe9383cSRichard Henderson 
3338ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = {
3339ebe9383cSRichard Henderson     /* floating point class zero */
3340ebe9383cSRichard Henderson     { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3341ebe9383cSRichard Henderson     { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3342ebe9383cSRichard Henderson     { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3343ebe9383cSRichard Henderson     { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3344ebe9383cSRichard Henderson     { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3345ebe9383cSRichard Henderson     { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3346ebe9383cSRichard Henderson 
3347ebe9383cSRichard Henderson     { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3348ebe9383cSRichard Henderson     { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3349ebe9383cSRichard Henderson     { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3350ebe9383cSRichard Henderson     { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3351ebe9383cSRichard Henderson     { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3352ebe9383cSRichard Henderson     { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3353ebe9383cSRichard Henderson 
3354ebe9383cSRichard Henderson     /* floating point class three */
3355ebe9383cSRichard Henderson     { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3356ebe9383cSRichard Henderson     { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3357ebe9383cSRichard Henderson     { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3358ebe9383cSRichard Henderson     { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3359ebe9383cSRichard Henderson 
3360ebe9383cSRichard Henderson     { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3361ebe9383cSRichard Henderson     { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3362ebe9383cSRichard Henderson     { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3363ebe9383cSRichard Henderson     { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3364ebe9383cSRichard Henderson 
3365ebe9383cSRichard Henderson     /* floating point class one */
3366ebe9383cSRichard Henderson     /* float/float */
3367ebe9383cSRichard Henderson     { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3368ebe9383cSRichard Henderson     { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3369ebe9383cSRichard Henderson     /* int/float */
3370ebe9383cSRichard Henderson     { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3371ebe9383cSRichard Henderson     { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3372ebe9383cSRichard Henderson     { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3373ebe9383cSRichard Henderson     { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3374ebe9383cSRichard Henderson     /* float/int */
3375ebe9383cSRichard Henderson     { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3376ebe9383cSRichard Henderson     { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3377ebe9383cSRichard Henderson     { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3378ebe9383cSRichard Henderson     { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3379ebe9383cSRichard Henderson     /* float/int truncate */
3380ebe9383cSRichard Henderson     { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3381ebe9383cSRichard Henderson     { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3382ebe9383cSRichard Henderson     { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3383ebe9383cSRichard Henderson     { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3384ebe9383cSRichard Henderson     /* uint/float */
3385ebe9383cSRichard Henderson     { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3386ebe9383cSRichard Henderson     { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3387ebe9383cSRichard Henderson     { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3388ebe9383cSRichard Henderson     { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3389ebe9383cSRichard Henderson     /* float/uint */
3390ebe9383cSRichard Henderson     { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3391ebe9383cSRichard Henderson     { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3392ebe9383cSRichard Henderson     { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3393ebe9383cSRichard Henderson     { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3394ebe9383cSRichard Henderson     /* float/uint truncate */
3395ebe9383cSRichard Henderson     { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3396ebe9383cSRichard Henderson     { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3397ebe9383cSRichard Henderson     { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3398ebe9383cSRichard Henderson     { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3399ebe9383cSRichard Henderson 
3400ebe9383cSRichard Henderson     /* floating point class two */
3401ebe9383cSRichard Henderson     { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3402ebe9383cSRichard Henderson     { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3403ebe9383cSRichard Henderson     { 0x30002420, 0xffffffe0, trans_ftest_q },
3404ebe9383cSRichard Henderson     { 0x30000420, 0xffff1fff, trans_ftest_t },
3405ebe9383cSRichard Henderson 
3406ebe9383cSRichard Henderson     /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3407ebe9383cSRichard Henderson        This is machine/revision == 0, which is reserved for simulator.  */
3408ebe9383cSRichard Henderson     { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3409ebe9383cSRichard Henderson };
3410ebe9383cSRichard Henderson 
3411ebe9383cSRichard Henderson #undef FOP_WEW
3412ebe9383cSRichard Henderson #undef FOP_DEW
3413ebe9383cSRichard Henderson #undef FOP_WED
3414ebe9383cSRichard Henderson #undef FOP_WEWW
3415eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0e, .f.wew
3416eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0e, .f.dew
3417eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0e, .f.wed
3418eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww
3419ebe9383cSRichard Henderson 
3420ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = {
3421ebe9383cSRichard Henderson     /* floating point class zero */
3422ebe9383cSRichard Henderson     { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3423ebe9383cSRichard Henderson     { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3424ebe9383cSRichard Henderson     { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3425ebe9383cSRichard Henderson     { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3426ebe9383cSRichard Henderson     { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3427ebe9383cSRichard Henderson     { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3428ebe9383cSRichard Henderson 
3429ebe9383cSRichard Henderson     { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3430ebe9383cSRichard Henderson     { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3431ebe9383cSRichard Henderson     { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3432ebe9383cSRichard Henderson     { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3433ebe9383cSRichard Henderson     { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3434ebe9383cSRichard Henderson     { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3435ebe9383cSRichard Henderson 
3436ebe9383cSRichard Henderson     /* floating point class three */
3437ebe9383cSRichard Henderson     { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3438ebe9383cSRichard Henderson     { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3439ebe9383cSRichard Henderson     { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3440ebe9383cSRichard Henderson     { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3441ebe9383cSRichard Henderson 
3442ebe9383cSRichard Henderson     { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3443ebe9383cSRichard Henderson     { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3444ebe9383cSRichard Henderson     { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3445ebe9383cSRichard Henderson     { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3446ebe9383cSRichard Henderson 
3447ebe9383cSRichard Henderson     { 0x38004700, 0xfc00ef60, trans_xmpyu },
3448ebe9383cSRichard Henderson 
3449ebe9383cSRichard Henderson     /* floating point class one */
3450ebe9383cSRichard Henderson     /* float/float */
3451ebe9383cSRichard Henderson     { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3452ebe9383cSRichard Henderson     { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3453ebe9383cSRichard Henderson     /* int/float */
3454ebe9383cSRichard Henderson     { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3455ebe9383cSRichard Henderson     { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3456ebe9383cSRichard Henderson     { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3457ebe9383cSRichard Henderson     { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3458ebe9383cSRichard Henderson     /* float/int */
3459ebe9383cSRichard Henderson     { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3460ebe9383cSRichard Henderson     { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3461ebe9383cSRichard Henderson     { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3462ebe9383cSRichard Henderson     { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3463ebe9383cSRichard Henderson     /* float/int truncate */
3464ebe9383cSRichard Henderson     { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3465ebe9383cSRichard Henderson     { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3466ebe9383cSRichard Henderson     { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3467ebe9383cSRichard Henderson     { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3468ebe9383cSRichard Henderson     /* uint/float */
3469ebe9383cSRichard Henderson     { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3470ebe9383cSRichard Henderson     { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3471ebe9383cSRichard Henderson     { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3472ebe9383cSRichard Henderson     { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3473ebe9383cSRichard Henderson     /* float/uint */
3474ebe9383cSRichard Henderson     { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3475ebe9383cSRichard Henderson     { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3476ebe9383cSRichard Henderson     { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3477ebe9383cSRichard Henderson     { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3478ebe9383cSRichard Henderson     /* float/uint truncate */
3479ebe9383cSRichard Henderson     { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3480ebe9383cSRichard Henderson     { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3481ebe9383cSRichard Henderson     { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3482ebe9383cSRichard Henderson     { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3483ebe9383cSRichard Henderson 
3484ebe9383cSRichard Henderson     /* floating point class two */
3485ebe9383cSRichard Henderson     { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3486ebe9383cSRichard Henderson     { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3487ebe9383cSRichard Henderson };
3488ebe9383cSRichard Henderson 
3489ebe9383cSRichard Henderson #undef FOP_WEW
3490ebe9383cSRichard Henderson #undef FOP_DEW
3491ebe9383cSRichard Henderson #undef FOP_WED
3492ebe9383cSRichard Henderson #undef FOP_WEWW
3493ebe9383cSRichard Henderson #undef FOP_DED
3494ebe9383cSRichard Henderson #undef FOP_DEDD
3495ebe9383cSRichard Henderson 
3496ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
3497ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
3498ebe9383cSRichard Henderson {
3499ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
3500ebe9383cSRichard Henderson }
3501ebe9383cSRichard Henderson 
3502869051eaSRichard Henderson static DisasJumpType trans_fmpyadd(DisasContext *ctx,
3503869051eaSRichard Henderson                                    uint32_t insn, bool is_sub)
3504ebe9383cSRichard Henderson {
3505ebe9383cSRichard Henderson     unsigned tm = extract32(insn, 0, 5);
3506ebe9383cSRichard Henderson     unsigned f = extract32(insn, 5, 1);
3507ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 6, 5);
3508ebe9383cSRichard Henderson     unsigned ta = extract32(insn, 11, 5);
3509ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3510ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3511ebe9383cSRichard Henderson 
3512ebe9383cSRichard Henderson     nullify_over(ctx);
3513ebe9383cSRichard Henderson 
3514ebe9383cSRichard Henderson     /* Independent multiply & add/sub, with undefined behaviour
3515ebe9383cSRichard Henderson        if outputs overlap inputs.  */
3516ebe9383cSRichard Henderson     if (f == 0) {
3517ebe9383cSRichard Henderson         tm = fmpyadd_s_reg(tm);
3518ebe9383cSRichard Henderson         ra = fmpyadd_s_reg(ra);
3519ebe9383cSRichard Henderson         ta = fmpyadd_s_reg(ta);
3520ebe9383cSRichard Henderson         rm2 = fmpyadd_s_reg(rm2);
3521ebe9383cSRichard Henderson         rm1 = fmpyadd_s_reg(rm1);
3522ebe9383cSRichard Henderson         do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3523ebe9383cSRichard Henderson         do_fop_weww(ctx, ta, ta, ra,
3524ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3525ebe9383cSRichard Henderson     } else {
3526ebe9383cSRichard Henderson         do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3527ebe9383cSRichard Henderson         do_fop_dedd(ctx, ta, ta, ra,
3528ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3529ebe9383cSRichard Henderson     }
3530ebe9383cSRichard Henderson 
3531869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3532ebe9383cSRichard Henderson }
3533ebe9383cSRichard Henderson 
3534869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3535ebe9383cSRichard Henderson                                       const DisasInsn *di)
3536ebe9383cSRichard Henderson {
3537ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3538ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3539ebe9383cSRichard Henderson     unsigned rm1 = assemble_ra64(insn);
3540ebe9383cSRichard Henderson     unsigned rm2 = assemble_rb64(insn);
3541ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3542ebe9383cSRichard Henderson     TCGv_i32 a, b, c;
3543ebe9383cSRichard Henderson 
3544ebe9383cSRichard Henderson     nullify_over(ctx);
3545ebe9383cSRichard Henderson     a = load_frw0_i32(rm1);
3546ebe9383cSRichard Henderson     b = load_frw0_i32(rm2);
3547ebe9383cSRichard Henderson     c = load_frw0_i32(ra3);
3548ebe9383cSRichard Henderson 
3549ebe9383cSRichard Henderson     if (neg) {
3550ebe9383cSRichard Henderson         gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3551ebe9383cSRichard Henderson     } else {
3552ebe9383cSRichard Henderson         gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3553ebe9383cSRichard Henderson     }
3554ebe9383cSRichard Henderson 
3555ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
3556ebe9383cSRichard Henderson     tcg_temp_free_i32(c);
3557ebe9383cSRichard Henderson     save_frw_i32(rt, a);
3558ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
3559869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3560ebe9383cSRichard Henderson }
3561ebe9383cSRichard Henderson 
3562869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3563ebe9383cSRichard Henderson                                       const DisasInsn *di)
3564ebe9383cSRichard Henderson {
3565ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3566ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3567ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3568ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3569ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3570ebe9383cSRichard Henderson     TCGv_i64 a, b, c;
3571ebe9383cSRichard Henderson 
3572ebe9383cSRichard Henderson     nullify_over(ctx);
3573ebe9383cSRichard Henderson     a = load_frd0(rm1);
3574ebe9383cSRichard Henderson     b = load_frd0(rm2);
3575ebe9383cSRichard Henderson     c = load_frd0(ra3);
3576ebe9383cSRichard Henderson 
3577ebe9383cSRichard Henderson     if (neg) {
3578ebe9383cSRichard Henderson         gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3579ebe9383cSRichard Henderson     } else {
3580ebe9383cSRichard Henderson         gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3581ebe9383cSRichard Henderson     }
3582ebe9383cSRichard Henderson 
3583ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3584ebe9383cSRichard Henderson     tcg_temp_free_i64(c);
3585ebe9383cSRichard Henderson     save_frd(rt, a);
3586ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3587869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3588ebe9383cSRichard Henderson }
3589ebe9383cSRichard Henderson 
3590ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = {
3591ebe9383cSRichard Henderson     { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3592ebe9383cSRichard Henderson     { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3593ebe9383cSRichard Henderson };
3594ebe9383cSRichard Henderson 
3595869051eaSRichard Henderson static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
359661766fe9SRichard Henderson                                          const DisasInsn table[], size_t n)
359761766fe9SRichard Henderson {
359861766fe9SRichard Henderson     size_t i;
359961766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
360061766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
360161766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
360261766fe9SRichard Henderson         }
360361766fe9SRichard Henderson     }
360461766fe9SRichard Henderson     return gen_illegal(ctx);
360561766fe9SRichard Henderson }
360661766fe9SRichard Henderson 
360761766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
360861766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
360961766fe9SRichard Henderson 
3610869051eaSRichard Henderson static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
361161766fe9SRichard Henderson {
361261766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
361361766fe9SRichard Henderson 
361461766fe9SRichard Henderson     switch (opc) {
361598a9cb79SRichard Henderson     case 0x00: /* system op */
361698a9cb79SRichard Henderson         return translate_table(ctx, insn, table_system);
361798a9cb79SRichard Henderson     case 0x01:
361898a9cb79SRichard Henderson         return translate_table(ctx, insn, table_mem_mgmt);
3619b2167459SRichard Henderson     case 0x02:
3620b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
362196d6407fSRichard Henderson     case 0x03:
362296d6407fSRichard Henderson         return translate_table(ctx, insn, table_index_mem);
3623ebe9383cSRichard Henderson     case 0x06:
3624ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, false);
3625b2167459SRichard Henderson     case 0x08:
3626b2167459SRichard Henderson         return trans_ldil(ctx, insn);
362796d6407fSRichard Henderson     case 0x09:
362896d6407fSRichard Henderson         return trans_copr_w(ctx, insn);
3629b2167459SRichard Henderson     case 0x0A:
3630b2167459SRichard Henderson         return trans_addil(ctx, insn);
363196d6407fSRichard Henderson     case 0x0B:
363296d6407fSRichard Henderson         return trans_copr_dw(ctx, insn);
3633ebe9383cSRichard Henderson     case 0x0C:
3634ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0c);
3635b2167459SRichard Henderson     case 0x0D:
3636b2167459SRichard Henderson         return trans_ldo(ctx, insn);
3637ebe9383cSRichard Henderson     case 0x0E:
3638ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0e);
363996d6407fSRichard Henderson 
364096d6407fSRichard Henderson     case 0x10:
364196d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_UB);
364296d6407fSRichard Henderson     case 0x11:
364396d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUW);
364496d6407fSRichard Henderson     case 0x12:
364596d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUL);
364696d6407fSRichard Henderson     case 0x13:
364796d6407fSRichard Henderson         return trans_load(ctx, insn, true, MO_TEUL);
364896d6407fSRichard Henderson     case 0x16:
364996d6407fSRichard Henderson         return trans_fload_mod(ctx, insn);
365096d6407fSRichard Henderson     case 0x17:
365196d6407fSRichard Henderson         return trans_load_w(ctx, insn);
365296d6407fSRichard Henderson     case 0x18:
365396d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_UB);
365496d6407fSRichard Henderson     case 0x19:
365596d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUW);
365696d6407fSRichard Henderson     case 0x1A:
365796d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUL);
365896d6407fSRichard Henderson     case 0x1B:
365996d6407fSRichard Henderson         return trans_store(ctx, insn, true, MO_TEUL);
366096d6407fSRichard Henderson     case 0x1E:
366196d6407fSRichard Henderson         return trans_fstore_mod(ctx, insn);
366296d6407fSRichard Henderson     case 0x1F:
366396d6407fSRichard Henderson         return trans_store_w(ctx, insn);
366496d6407fSRichard Henderson 
366598cd9ca7SRichard Henderson     case 0x20:
366698cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, false);
366798cd9ca7SRichard Henderson     case 0x21:
366898cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, true, false);
366998cd9ca7SRichard Henderson     case 0x22:
367098cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, false);
367198cd9ca7SRichard Henderson     case 0x23:
367298cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, true, false);
3673b2167459SRichard Henderson     case 0x24:
3674b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
3675b2167459SRichard Henderson     case 0x25:
3676b2167459SRichard Henderson         return trans_subi(ctx, insn);
3677ebe9383cSRichard Henderson     case 0x26:
3678ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, true);
367998cd9ca7SRichard Henderson     case 0x27:
368098cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, true);
368198cd9ca7SRichard Henderson     case 0x28:
368298cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, false);
368398cd9ca7SRichard Henderson     case 0x29:
368498cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, true);
368598cd9ca7SRichard Henderson     case 0x2A:
368698cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, false);
368798cd9ca7SRichard Henderson     case 0x2B:
368898cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, true);
3689b2167459SRichard Henderson     case 0x2C:
3690b2167459SRichard Henderson     case 0x2D:
3691b2167459SRichard Henderson         return trans_addi(ctx, insn);
3692ebe9383cSRichard Henderson     case 0x2E:
3693ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_fp_fused);
369498cd9ca7SRichard Henderson     case 0x2F:
369598cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, true);
369696d6407fSRichard Henderson 
369798cd9ca7SRichard Henderson     case 0x30:
369898cd9ca7SRichard Henderson     case 0x31:
369998cd9ca7SRichard Henderson         return trans_bb(ctx, insn);
370098cd9ca7SRichard Henderson     case 0x32:
370198cd9ca7SRichard Henderson         return trans_movb(ctx, insn, false);
370298cd9ca7SRichard Henderson     case 0x33:
370398cd9ca7SRichard Henderson         return trans_movb(ctx, insn, true);
37040b1347d2SRichard Henderson     case 0x34:
37050b1347d2SRichard Henderson         return translate_table(ctx, insn, table_sh_ex);
37060b1347d2SRichard Henderson     case 0x35:
37070b1347d2SRichard Henderson         return translate_table(ctx, insn, table_depw);
370898cd9ca7SRichard Henderson     case 0x38:
370998cd9ca7SRichard Henderson         return trans_be(ctx, insn, false);
371098cd9ca7SRichard Henderson     case 0x39:
371198cd9ca7SRichard Henderson         return trans_be(ctx, insn, true);
371298cd9ca7SRichard Henderson     case 0x3A:
371398cd9ca7SRichard Henderson         return translate_table(ctx, insn, table_branch);
371496d6407fSRichard Henderson 
371596d6407fSRichard Henderson     case 0x04: /* spopn */
371696d6407fSRichard Henderson     case 0x05: /* diag */
371796d6407fSRichard Henderson     case 0x0F: /* product specific */
371896d6407fSRichard Henderson         break;
371996d6407fSRichard Henderson 
372096d6407fSRichard Henderson     case 0x07: /* unassigned */
372196d6407fSRichard Henderson     case 0x15: /* unassigned */
372296d6407fSRichard Henderson     case 0x1D: /* unassigned */
372396d6407fSRichard Henderson     case 0x37: /* unassigned */
372496d6407fSRichard Henderson     case 0x3F: /* unassigned */
372561766fe9SRichard Henderson     default:
372661766fe9SRichard Henderson         break;
372761766fe9SRichard Henderson     }
372861766fe9SRichard Henderson     return gen_illegal(ctx);
372961766fe9SRichard Henderson }
373061766fe9SRichard Henderson 
373151b061fbSRichard Henderson static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
373251b061fbSRichard Henderson                                       CPUState *cs, int max_insns)
373361766fe9SRichard Henderson {
373451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
373551b061fbSRichard Henderson     TranslationBlock *tb = ctx->base.tb;
3736*f764718dSRichard Henderson     int bound;
373761766fe9SRichard Henderson 
373851b061fbSRichard Henderson     ctx->cs = cs;
373951b061fbSRichard Henderson     ctx->iaoq_f = tb->pc;
374051b061fbSRichard Henderson     ctx->iaoq_b = tb->cs_base;
374151b061fbSRichard Henderson     ctx->iaoq_n = -1;
3742*f764718dSRichard Henderson     ctx->iaoq_n_var = NULL;
374361766fe9SRichard Henderson 
374451b061fbSRichard Henderson     ctx->ntemps = 0;
3745*f764718dSRichard Henderson     memset(ctx->temps, 0, sizeof(ctx->temps));
374661766fe9SRichard Henderson 
374751b061fbSRichard Henderson     bound = -(tb->pc | TARGET_PAGE_MASK) / 4;
374851b061fbSRichard Henderson     return MIN(max_insns, bound);
374961766fe9SRichard Henderson }
375061766fe9SRichard Henderson 
375151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
375251b061fbSRichard Henderson {
375351b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
375461766fe9SRichard Henderson 
3755129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
375651b061fbSRichard Henderson     ctx->null_cond = cond_make_f();
375751b061fbSRichard Henderson     ctx->psw_n_nonzero = false;
375851b061fbSRichard Henderson     if (ctx->base.tb->flags & 1) {
375951b061fbSRichard Henderson         ctx->null_cond.c = TCG_COND_ALWAYS;
376051b061fbSRichard Henderson         ctx->psw_n_nonzero = true;
3761129e9cc3SRichard Henderson     }
376251b061fbSRichard Henderson     ctx->null_lab = NULL;
376361766fe9SRichard Henderson }
376461766fe9SRichard Henderson 
376551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
376651b061fbSRichard Henderson {
376751b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
376851b061fbSRichard Henderson 
376951b061fbSRichard Henderson     tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
377051b061fbSRichard Henderson }
377151b061fbSRichard Henderson 
377251b061fbSRichard Henderson static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
377351b061fbSRichard Henderson                                       const CPUBreakpoint *bp)
377451b061fbSRichard Henderson {
377551b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
377651b061fbSRichard Henderson 
377751b061fbSRichard Henderson     ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
377851b061fbSRichard Henderson     ctx->base.pc_next = ctx->iaoq_f + 4;
377951b061fbSRichard Henderson     return true;
378051b061fbSRichard Henderson }
378151b061fbSRichard Henderson 
378251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
378351b061fbSRichard Henderson {
378451b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
378551b061fbSRichard Henderson     CPUHPPAState *env = cs->env_ptr;
378651b061fbSRichard Henderson     DisasJumpType ret;
378751b061fbSRichard Henderson     int i, n;
378851b061fbSRichard Henderson 
378951b061fbSRichard Henderson     /* Execute one insn.  */
379051b061fbSRichard Henderson     if (ctx->iaoq_f < TARGET_PAGE_SIZE) {
379151b061fbSRichard Henderson         ret = do_page_zero(ctx);
3792869051eaSRichard Henderson         assert(ret != DISAS_NEXT);
37937ad439dfSRichard Henderson     } else {
379461766fe9SRichard Henderson         /* Always fetch the insn, even if nullified, so that we check
379561766fe9SRichard Henderson            the page permissions for execute.  */
379651b061fbSRichard Henderson         uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f);
379761766fe9SRichard Henderson 
379861766fe9SRichard Henderson         /* Set up the IA queue for the next insn.
379961766fe9SRichard Henderson            This will be overwritten by a branch.  */
380051b061fbSRichard Henderson         if (ctx->iaoq_b == -1) {
380151b061fbSRichard Henderson             ctx->iaoq_n = -1;
380251b061fbSRichard Henderson             ctx->iaoq_n_var = get_temp(ctx);
380351b061fbSRichard Henderson             tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4);
380461766fe9SRichard Henderson         } else {
380551b061fbSRichard Henderson             ctx->iaoq_n = ctx->iaoq_b + 4;
3806*f764718dSRichard Henderson             ctx->iaoq_n_var = NULL;
380761766fe9SRichard Henderson         }
380861766fe9SRichard Henderson 
380951b061fbSRichard Henderson         if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
381051b061fbSRichard Henderson             ctx->null_cond.c = TCG_COND_NEVER;
3811869051eaSRichard Henderson             ret = DISAS_NEXT;
3812129e9cc3SRichard Henderson         } else {
381351b061fbSRichard Henderson             ret = translate_one(ctx, insn);
381451b061fbSRichard Henderson             assert(ctx->null_lab == NULL);
3815129e9cc3SRichard Henderson         }
381661766fe9SRichard Henderson     }
381761766fe9SRichard Henderson 
381851b061fbSRichard Henderson     /* Free any temporaries allocated.  */
381951b061fbSRichard Henderson     for (i = 0, n = ctx->ntemps; i < n; ++i) {
382051b061fbSRichard Henderson         tcg_temp_free(ctx->temps[i]);
3821*f764718dSRichard Henderson         ctx->temps[i] = NULL;
382261766fe9SRichard Henderson     }
382351b061fbSRichard Henderson     ctx->ntemps = 0;
382461766fe9SRichard Henderson 
382551b061fbSRichard Henderson     /* Advance the insn queue.  */
382661766fe9SRichard Henderson     /* ??? The non-linear instruction restriction is purely due to
382761766fe9SRichard Henderson        the debugging dump.  Otherwise we *could* follow unconditional
382861766fe9SRichard Henderson        branches within the same page.  */
382951b061fbSRichard Henderson     if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
383051b061fbSRichard Henderson         if (ctx->null_cond.c == TCG_COND_NEVER
383151b061fbSRichard Henderson             || ctx->null_cond.c == TCG_COND_ALWAYS) {
383251b061fbSRichard Henderson             nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
383351b061fbSRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
3834869051eaSRichard Henderson             ret = DISAS_NORETURN;
3835129e9cc3SRichard Henderson         } else {
3836869051eaSRichard Henderson             ret = DISAS_IAQ_N_STALE;
383761766fe9SRichard Henderson        }
3838129e9cc3SRichard Henderson     }
383951b061fbSRichard Henderson     ctx->iaoq_f = ctx->iaoq_b;
384051b061fbSRichard Henderson     ctx->iaoq_b = ctx->iaoq_n;
384151b061fbSRichard Henderson     ctx->base.is_jmp = ret;
384261766fe9SRichard Henderson 
3843869051eaSRichard Henderson     if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
384451b061fbSRichard Henderson         return;
384561766fe9SRichard Henderson     }
384651b061fbSRichard Henderson     if (ctx->iaoq_f == -1) {
384761766fe9SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
384851b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
384951b061fbSRichard Henderson         nullify_save(ctx);
385051b061fbSRichard Henderson         ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
385151b061fbSRichard Henderson     } else if (ctx->iaoq_b == -1) {
385251b061fbSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_b, ctx->iaoq_n_var);
385361766fe9SRichard Henderson     }
385461766fe9SRichard Henderson }
385561766fe9SRichard Henderson 
385651b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
385751b061fbSRichard Henderson {
385851b061fbSRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
385951b061fbSRichard Henderson 
386051b061fbSRichard Henderson     switch (ctx->base.is_jmp) {
3861869051eaSRichard Henderson     case DISAS_NORETURN:
386261766fe9SRichard Henderson         break;
386351b061fbSRichard Henderson     case DISAS_TOO_MANY:
3864869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
386551b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
386651b061fbSRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
386751b061fbSRichard Henderson         nullify_save(ctx);
386861766fe9SRichard Henderson         /* FALLTHRU */
3869869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
387051b061fbSRichard Henderson         if (ctx->base.singlestep_enabled) {
387161766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
387261766fe9SRichard Henderson         } else {
38737f11636dSEmilio G. Cota             tcg_gen_lookup_and_goto_ptr();
387461766fe9SRichard Henderson         }
387561766fe9SRichard Henderson         break;
387661766fe9SRichard Henderson     default:
387751b061fbSRichard Henderson         g_assert_not_reached();
387861766fe9SRichard Henderson     }
387961766fe9SRichard Henderson 
388051b061fbSRichard Henderson     /* We don't actually use this during normal translation,
388151b061fbSRichard Henderson        but we should interact with the generic main loop.  */
388251b061fbSRichard Henderson     ctx->base.pc_next = ctx->base.tb->pc + 4 * ctx->base.num_insns;
388351b061fbSRichard Henderson }
388461766fe9SRichard Henderson 
388551b061fbSRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
388651b061fbSRichard Henderson {
388751b061fbSRichard Henderson     TranslationBlock *tb = dcbase->tb;
388861766fe9SRichard Henderson 
38897ad439dfSRichard Henderson     switch (tb->pc) {
38907ad439dfSRichard Henderson     case 0x00:
389151b061fbSRichard Henderson         qemu_log("IN:\n0x00000000:  (null)\n");
38927ad439dfSRichard Henderson         break;
38937ad439dfSRichard Henderson     case 0xb0:
389451b061fbSRichard Henderson         qemu_log("IN:\n0x000000b0:  light-weight-syscall\n");
38957ad439dfSRichard Henderson         break;
38967ad439dfSRichard Henderson     case 0xe0:
389751b061fbSRichard Henderson         qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n");
38987ad439dfSRichard Henderson         break;
38997ad439dfSRichard Henderson     case 0x100:
390051b061fbSRichard Henderson         qemu_log("IN:\n0x00000100:  syscall\n");
39017ad439dfSRichard Henderson         break;
39027ad439dfSRichard Henderson     default:
390361766fe9SRichard Henderson         qemu_log("IN: %s\n", lookup_symbol(tb->pc));
39041d48474dSRichard Henderson         log_target_disas(cs, tb->pc, tb->size);
39057ad439dfSRichard Henderson         break;
39067ad439dfSRichard Henderson     }
390761766fe9SRichard Henderson }
390851b061fbSRichard Henderson 
390951b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = {
391051b061fbSRichard Henderson     .init_disas_context = hppa_tr_init_disas_context,
391151b061fbSRichard Henderson     .tb_start           = hppa_tr_tb_start,
391251b061fbSRichard Henderson     .insn_start         = hppa_tr_insn_start,
391351b061fbSRichard Henderson     .breakpoint_check   = hppa_tr_breakpoint_check,
391451b061fbSRichard Henderson     .translate_insn     = hppa_tr_translate_insn,
391551b061fbSRichard Henderson     .tb_stop            = hppa_tr_tb_stop,
391651b061fbSRichard Henderson     .disas_log          = hppa_tr_disas_log,
391751b061fbSRichard Henderson };
391851b061fbSRichard Henderson 
391951b061fbSRichard Henderson void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
392051b061fbSRichard Henderson 
392151b061fbSRichard Henderson {
392251b061fbSRichard Henderson     DisasContext ctx;
392351b061fbSRichard Henderson     translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
392461766fe9SRichard Henderson }
392561766fe9SRichard Henderson 
392661766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
392761766fe9SRichard Henderson                           target_ulong *data)
392861766fe9SRichard Henderson {
392961766fe9SRichard Henderson     env->iaoq_f = data[0];
393061766fe9SRichard Henderson     if (data[1] != -1) {
393161766fe9SRichard Henderson         env->iaoq_b = data[1];
393261766fe9SRichard Henderson     }
393361766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
393461766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
393561766fe9SRichard Henderson        that the instruction was not nullified.  */
393661766fe9SRichard Henderson     env->psw_n = 0;
393761766fe9SRichard Henderson }
3938