xref: /openbmc/qemu/target/hppa/translate.c (revision d01a362528c1606299f4ff4730f39d2b363635e6)
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 {
41*d01a3625SRichard 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_env cpu_env;
8761766fe9SRichard Henderson static TCGv cpu_gr[32];
8861766fe9SRichard Henderson static TCGv cpu_iaoq_f;
8961766fe9SRichard Henderson static TCGv cpu_iaoq_b;
9061766fe9SRichard Henderson static TCGv cpu_sar;
9161766fe9SRichard Henderson static TCGv cpu_psw_n;
9261766fe9SRichard Henderson static TCGv cpu_psw_v;
9361766fe9SRichard Henderson static TCGv cpu_psw_cb;
9461766fe9SRichard Henderson static TCGv cpu_psw_cb_msb;
9561766fe9SRichard Henderson static TCGv cpu_cr26;
9661766fe9SRichard Henderson static TCGv cpu_cr27;
9761766fe9SRichard Henderson 
9861766fe9SRichard Henderson #include "exec/gen-icount.h"
9961766fe9SRichard Henderson 
10061766fe9SRichard Henderson void hppa_translate_init(void)
10161766fe9SRichard Henderson {
10261766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
10361766fe9SRichard Henderson 
10461766fe9SRichard Henderson     typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
10561766fe9SRichard Henderson     static const GlobalVar vars[] = {
10661766fe9SRichard Henderson         DEF_VAR(sar),
10761766fe9SRichard Henderson         DEF_VAR(cr26),
10861766fe9SRichard Henderson         DEF_VAR(cr27),
10961766fe9SRichard Henderson         DEF_VAR(psw_n),
11061766fe9SRichard Henderson         DEF_VAR(psw_v),
11161766fe9SRichard Henderson         DEF_VAR(psw_cb),
11261766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
11361766fe9SRichard Henderson         DEF_VAR(iaoq_f),
11461766fe9SRichard Henderson         DEF_VAR(iaoq_b),
11561766fe9SRichard Henderson     };
11661766fe9SRichard Henderson 
11761766fe9SRichard Henderson #undef DEF_VAR
11861766fe9SRichard Henderson 
11961766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
12061766fe9SRichard Henderson     static const char gr_names[32][4] = {
12161766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
12261766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
12361766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
12461766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
12561766fe9SRichard Henderson     };
12661766fe9SRichard Henderson 
12761766fe9SRichard Henderson     static bool done_init = 0;
12861766fe9SRichard Henderson     int i;
12961766fe9SRichard Henderson 
13061766fe9SRichard Henderson     if (done_init) {
13161766fe9SRichard Henderson         return;
13261766fe9SRichard Henderson     }
13361766fe9SRichard Henderson     done_init = 1;
13461766fe9SRichard Henderson 
13561766fe9SRichard Henderson     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
13661766fe9SRichard Henderson     tcg_ctx.tcg_env = cpu_env;
13761766fe9SRichard Henderson 
13861766fe9SRichard Henderson     TCGV_UNUSED(cpu_gr[0]);
13961766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
14061766fe9SRichard Henderson         cpu_gr[i] = tcg_global_mem_new(cpu_env,
14161766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
14261766fe9SRichard Henderson                                        gr_names[i]);
14361766fe9SRichard Henderson     }
14461766fe9SRichard Henderson 
14561766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
14661766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
14761766fe9SRichard Henderson         *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
14861766fe9SRichard Henderson     }
14961766fe9SRichard Henderson }
15061766fe9SRichard Henderson 
151129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
152129e9cc3SRichard Henderson {
153129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NEVER };
154129e9cc3SRichard Henderson     TCGV_UNUSED(r.a0);
155129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
156129e9cc3SRichard Henderson     return r;
157129e9cc3SRichard Henderson }
158129e9cc3SRichard Henderson 
159129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
160129e9cc3SRichard Henderson {
161129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
162129e9cc3SRichard Henderson     r.a0 = cpu_psw_n;
163129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
164129e9cc3SRichard Henderson     return r;
165129e9cc3SRichard Henderson }
166129e9cc3SRichard Henderson 
167129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0)
168129e9cc3SRichard Henderson {
169129e9cc3SRichard Henderson     DisasCond r = { .c = c, .a1_is_0 = true };
170129e9cc3SRichard Henderson 
171129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
172129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
173129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
174129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
175129e9cc3SRichard Henderson 
176129e9cc3SRichard Henderson     return r;
177129e9cc3SRichard Henderson }
178129e9cc3SRichard Henderson 
179129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
180129e9cc3SRichard Henderson {
181129e9cc3SRichard Henderson     DisasCond r = { .c = c };
182129e9cc3SRichard Henderson 
183129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
184129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
185129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
186129e9cc3SRichard Henderson     r.a1 = tcg_temp_new();
187129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a1, a1);
188129e9cc3SRichard Henderson 
189129e9cc3SRichard Henderson     return r;
190129e9cc3SRichard Henderson }
191129e9cc3SRichard Henderson 
192129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond)
193129e9cc3SRichard Henderson {
194129e9cc3SRichard Henderson     if (cond->a1_is_0) {
195129e9cc3SRichard Henderson         cond->a1_is_0 = false;
196129e9cc3SRichard Henderson         cond->a1 = tcg_const_tl(0);
197129e9cc3SRichard Henderson     }
198129e9cc3SRichard Henderson }
199129e9cc3SRichard Henderson 
200129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
201129e9cc3SRichard Henderson {
202129e9cc3SRichard Henderson     switch (cond->c) {
203129e9cc3SRichard Henderson     default:
204129e9cc3SRichard Henderson         if (!cond->a0_is_n) {
205129e9cc3SRichard Henderson             tcg_temp_free(cond->a0);
206129e9cc3SRichard Henderson         }
207129e9cc3SRichard Henderson         if (!cond->a1_is_0) {
208129e9cc3SRichard Henderson             tcg_temp_free(cond->a1);
209129e9cc3SRichard Henderson         }
210129e9cc3SRichard Henderson         cond->a0_is_n = false;
211129e9cc3SRichard Henderson         cond->a1_is_0 = false;
212129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a0);
213129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a1);
214129e9cc3SRichard Henderson         /* fallthru */
215129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
216129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
217129e9cc3SRichard Henderson         break;
218129e9cc3SRichard Henderson     case TCG_COND_NEVER:
219129e9cc3SRichard Henderson         break;
220129e9cc3SRichard Henderson     }
221129e9cc3SRichard Henderson }
222129e9cc3SRichard Henderson 
22361766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx)
22461766fe9SRichard Henderson {
22561766fe9SRichard Henderson     unsigned i = ctx->ntemps++;
22661766fe9SRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->temps));
22761766fe9SRichard Henderson     return ctx->temps[i] = tcg_temp_new();
22861766fe9SRichard Henderson }
22961766fe9SRichard Henderson 
23061766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v)
23161766fe9SRichard Henderson {
23261766fe9SRichard Henderson     TCGv t = get_temp(ctx);
23361766fe9SRichard Henderson     tcg_gen_movi_tl(t, v);
23461766fe9SRichard Henderson     return t;
23561766fe9SRichard Henderson }
23661766fe9SRichard Henderson 
23761766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg)
23861766fe9SRichard Henderson {
23961766fe9SRichard Henderson     if (reg == 0) {
24061766fe9SRichard Henderson         TCGv t = get_temp(ctx);
24161766fe9SRichard Henderson         tcg_gen_movi_tl(t, 0);
24261766fe9SRichard Henderson         return t;
24361766fe9SRichard Henderson     } else {
24461766fe9SRichard Henderson         return cpu_gr[reg];
24561766fe9SRichard Henderson     }
24661766fe9SRichard Henderson }
24761766fe9SRichard Henderson 
24861766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
24961766fe9SRichard Henderson {
250129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
25161766fe9SRichard Henderson         return get_temp(ctx);
25261766fe9SRichard Henderson     } else {
25361766fe9SRichard Henderson         return cpu_gr[reg];
25461766fe9SRichard Henderson     }
25561766fe9SRichard Henderson }
25661766fe9SRichard Henderson 
257129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
258129e9cc3SRichard Henderson {
259129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
260129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
261129e9cc3SRichard Henderson         tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
262129e9cc3SRichard Henderson                            ctx->null_cond.a1, dest, t);
263129e9cc3SRichard Henderson     } else {
264129e9cc3SRichard Henderson         tcg_gen_mov_tl(dest, t);
265129e9cc3SRichard Henderson     }
266129e9cc3SRichard Henderson }
267129e9cc3SRichard Henderson 
268129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
269129e9cc3SRichard Henderson {
270129e9cc3SRichard Henderson     if (reg != 0) {
271129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
272129e9cc3SRichard Henderson     }
273129e9cc3SRichard Henderson }
274129e9cc3SRichard Henderson 
27596d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
27696d6407fSRichard Henderson # define HI_OFS  0
27796d6407fSRichard Henderson # define LO_OFS  4
27896d6407fSRichard Henderson #else
27996d6407fSRichard Henderson # define HI_OFS  4
28096d6407fSRichard Henderson # define LO_OFS  0
28196d6407fSRichard Henderson #endif
28296d6407fSRichard Henderson 
28396d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
28496d6407fSRichard Henderson {
28596d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
28696d6407fSRichard Henderson     tcg_gen_ld_i32(ret, cpu_env,
28796d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
28896d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
28996d6407fSRichard Henderson     return ret;
29096d6407fSRichard Henderson }
29196d6407fSRichard Henderson 
292ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
293ebe9383cSRichard Henderson {
294ebe9383cSRichard Henderson     if (rt == 0) {
295ebe9383cSRichard Henderson         return tcg_const_i32(0);
296ebe9383cSRichard Henderson     } else {
297ebe9383cSRichard Henderson         return load_frw_i32(rt);
298ebe9383cSRichard Henderson     }
299ebe9383cSRichard Henderson }
300ebe9383cSRichard Henderson 
301ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
302ebe9383cSRichard Henderson {
303ebe9383cSRichard Henderson     if (rt == 0) {
304ebe9383cSRichard Henderson         return tcg_const_i64(0);
305ebe9383cSRichard Henderson     } else {
306ebe9383cSRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
307ebe9383cSRichard Henderson         tcg_gen_ld32u_i64(ret, cpu_env,
308ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
309ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
310ebe9383cSRichard Henderson         return ret;
311ebe9383cSRichard Henderson     }
312ebe9383cSRichard Henderson }
313ebe9383cSRichard Henderson 
31496d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
31596d6407fSRichard Henderson {
31696d6407fSRichard Henderson     tcg_gen_st_i32(val, cpu_env,
31796d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
31896d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
31996d6407fSRichard Henderson }
32096d6407fSRichard Henderson 
32196d6407fSRichard Henderson #undef HI_OFS
32296d6407fSRichard Henderson #undef LO_OFS
32396d6407fSRichard Henderson 
32496d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
32596d6407fSRichard Henderson {
32696d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
32796d6407fSRichard Henderson     tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
32896d6407fSRichard Henderson     return ret;
32996d6407fSRichard Henderson }
33096d6407fSRichard Henderson 
331ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
332ebe9383cSRichard Henderson {
333ebe9383cSRichard Henderson     if (rt == 0) {
334ebe9383cSRichard Henderson         return tcg_const_i64(0);
335ebe9383cSRichard Henderson     } else {
336ebe9383cSRichard Henderson         return load_frd(rt);
337ebe9383cSRichard Henderson     }
338ebe9383cSRichard Henderson }
339ebe9383cSRichard Henderson 
34096d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
34196d6407fSRichard Henderson {
34296d6407fSRichard Henderson     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
34396d6407fSRichard Henderson }
34496d6407fSRichard Henderson 
345129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
346129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
347129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
348129e9cc3SRichard Henderson {
349129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
350129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
351129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
352129e9cc3SRichard Henderson 
353129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
354129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
355129e9cc3SRichard Henderson 
356129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
357129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
358129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
359129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
360129e9cc3SRichard Henderson             tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
361129e9cc3SRichard Henderson         }
362129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
363129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
364129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
365129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
366129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
367129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
368129e9cc3SRichard Henderson         }
369129e9cc3SRichard Henderson 
370129e9cc3SRichard Henderson         tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
371129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
372129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
373129e9cc3SRichard Henderson     }
374129e9cc3SRichard Henderson }
375129e9cc3SRichard Henderson 
376129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
377129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
378129e9cc3SRichard Henderson {
379129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
380129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
381129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
382129e9cc3SRichard Henderson         }
383129e9cc3SRichard Henderson         return;
384129e9cc3SRichard Henderson     }
385129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
386129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
387129e9cc3SRichard Henderson         tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
388129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
389129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
390129e9cc3SRichard Henderson     }
391129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
392129e9cc3SRichard Henderson }
393129e9cc3SRichard Henderson 
394129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
395129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
396129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
397129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
398129e9cc3SRichard Henderson {
399129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
400129e9cc3SRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, x);
401129e9cc3SRichard Henderson     }
402129e9cc3SRichard Henderson }
403129e9cc3SRichard Henderson 
404129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
405129e9cc3SRichard Henderson    This is the pair to nullify_over.  */
406869051eaSRichard Henderson static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status)
407129e9cc3SRichard Henderson {
408129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
409129e9cc3SRichard Henderson 
410129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
411129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
412129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
413129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
414129e9cc3SRichard Henderson         return status;
415129e9cc3SRichard Henderson     }
416129e9cc3SRichard Henderson     ctx->null_lab = NULL;
417129e9cc3SRichard Henderson 
418129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
419129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
420129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
421129e9cc3SRichard Henderson         gen_set_label(null_lab);
422129e9cc3SRichard Henderson     } else {
423129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
424129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
425129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
426129e9cc3SRichard Henderson            label we have the proper value in place.  */
427129e9cc3SRichard Henderson         nullify_save(ctx);
428129e9cc3SRichard Henderson         gen_set_label(null_lab);
429129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
430129e9cc3SRichard Henderson     }
431129e9cc3SRichard Henderson 
432869051eaSRichard Henderson     assert(status != DISAS_NORETURN && status != DISAS_IAQ_N_UPDATED);
433869051eaSRichard Henderson     if (status == DISAS_NORETURN) {
434869051eaSRichard Henderson         status = DISAS_NEXT;
435129e9cc3SRichard Henderson     }
436129e9cc3SRichard Henderson     return status;
437129e9cc3SRichard Henderson }
438129e9cc3SRichard Henderson 
43961766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
44061766fe9SRichard Henderson {
44161766fe9SRichard Henderson     if (unlikely(ival == -1)) {
44261766fe9SRichard Henderson         tcg_gen_mov_tl(dest, vval);
44361766fe9SRichard Henderson     } else {
44461766fe9SRichard Henderson         tcg_gen_movi_tl(dest, ival);
44561766fe9SRichard Henderson     }
44661766fe9SRichard Henderson }
44761766fe9SRichard Henderson 
44861766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
44961766fe9SRichard Henderson {
45061766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
45161766fe9SRichard Henderson }
45261766fe9SRichard Henderson 
45361766fe9SRichard Henderson static void gen_excp_1(int exception)
45461766fe9SRichard Henderson {
45561766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
45661766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
45761766fe9SRichard Henderson     tcg_temp_free_i32(t);
45861766fe9SRichard Henderson }
45961766fe9SRichard Henderson 
460869051eaSRichard Henderson static DisasJumpType gen_excp(DisasContext *ctx, int exception)
46161766fe9SRichard Henderson {
46261766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
46361766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
464129e9cc3SRichard Henderson     nullify_save(ctx);
46561766fe9SRichard Henderson     gen_excp_1(exception);
466869051eaSRichard Henderson     return DISAS_NORETURN;
46761766fe9SRichard Henderson }
46861766fe9SRichard Henderson 
469869051eaSRichard Henderson static DisasJumpType gen_illegal(DisasContext *ctx)
47061766fe9SRichard Henderson {
471129e9cc3SRichard Henderson     nullify_over(ctx);
472129e9cc3SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
47361766fe9SRichard Henderson }
47461766fe9SRichard Henderson 
47561766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
47661766fe9SRichard Henderson {
47761766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
478*d01a3625SRichard Henderson     if ((ctx->base.tb->cflags & CF_LAST_IO) || ctx->base.singlestep_enabled) {
47961766fe9SRichard Henderson         return false;
48061766fe9SRichard Henderson     }
48161766fe9SRichard Henderson     return true;
48261766fe9SRichard Henderson }
48361766fe9SRichard Henderson 
484129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
485129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
486129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
487129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
488129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
489129e9cc3SRichard Henderson {
490129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
491129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
492129e9cc3SRichard Henderson }
493129e9cc3SRichard Henderson 
49461766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
49561766fe9SRichard Henderson                         target_ulong f, target_ulong b)
49661766fe9SRichard Henderson {
49761766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
49861766fe9SRichard Henderson         tcg_gen_goto_tb(which);
49961766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_f, f);
50061766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_b, b);
501*d01a3625SRichard Henderson         tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which);
50261766fe9SRichard Henderson     } else {
50361766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
50461766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
505*d01a3625SRichard Henderson         if (ctx->base.singlestep_enabled) {
50661766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
50761766fe9SRichard Henderson         } else {
5084137cb83SRichard Henderson             tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
50961766fe9SRichard Henderson         }
51061766fe9SRichard Henderson     }
51161766fe9SRichard Henderson }
51261766fe9SRichard Henderson 
513b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
514b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
515b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
516b2167459SRichard Henderson {
517b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
518b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
519b2167459SRichard Henderson     return x;
520b2167459SRichard Henderson }
521b2167459SRichard Henderson 
522ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn)
523ebe9383cSRichard Henderson {
524ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 6, 1);
525ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 0, 5);
526ebe9383cSRichard Henderson     return r1 * 32 + r0;
527ebe9383cSRichard Henderson }
528ebe9383cSRichard Henderson 
529ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn)
530ebe9383cSRichard Henderson {
531ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 7, 1);
532ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 21, 5);
533ebe9383cSRichard Henderson     return r1 * 32 + r0;
534ebe9383cSRichard Henderson }
535ebe9383cSRichard Henderson 
536ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn)
537ebe9383cSRichard Henderson {
538ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 12, 1);
539ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 16, 5);
540ebe9383cSRichard Henderson     return r1 * 32 + r0;
541ebe9383cSRichard Henderson }
542ebe9383cSRichard Henderson 
543ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn)
544ebe9383cSRichard Henderson {
545ebe9383cSRichard Henderson     unsigned r2 = extract32(insn, 8, 1);
546ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 13, 3);
547ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 9, 2);
548ebe9383cSRichard Henderson     return r2 * 32 + r1 * 4 + r0;
549ebe9383cSRichard Henderson }
550ebe9383cSRichard Henderson 
55198cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn)
55298cd9ca7SRichard Henderson {
55398cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
55498cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
55598cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
55698cd9ca7SRichard Henderson     return x;
55798cd9ca7SRichard Henderson }
55898cd9ca7SRichard Henderson 
559b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
560b2167459SRichard Henderson {
561b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
562b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
563b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
564b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
565b2167459SRichard Henderson }
566b2167459SRichard Henderson 
56796d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn)
56896d6407fSRichard Henderson {
56996d6407fSRichard Henderson     /* Take the name from PA2.0, which produces a 14-bit shifted number
57096d6407fSRichard Henderson        only with wide mode; otherwise a 12-bit shifted number.  Since we
57196d6407fSRichard Henderson        don't implement wide mode, this is always the 12-bit number.  */
57296d6407fSRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
57396d6407fSRichard Henderson     x = (x << 11) | extract32(insn, 2, 11);
57496d6407fSRichard Henderson     return x << 2;
57596d6407fSRichard Henderson }
57696d6407fSRichard Henderson 
57798cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn)
57898cd9ca7SRichard Henderson {
57998cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
58098cd9ca7SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
58198cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
58298cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
58398cd9ca7SRichard Henderson     return x << 2;
58498cd9ca7SRichard Henderson }
58598cd9ca7SRichard Henderson 
586b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
587b2167459SRichard Henderson {
588b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
589b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
590b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
591b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
592b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
593b2167459SRichard Henderson     return x << 11;
594b2167459SRichard Henderson }
595b2167459SRichard Henderson 
59698cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn)
59798cd9ca7SRichard Henderson {
59898cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
59998cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 16, 10);
60098cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
60198cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
60298cd9ca7SRichard Henderson     return x << 2;
60398cd9ca7SRichard Henderson }
60498cd9ca7SRichard Henderson 
605b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
606b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
607b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
608b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
609b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
610b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
611b2167459SRichard Henderson 
612b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
613b2167459SRichard Henderson {
614b2167459SRichard Henderson     DisasCond cond;
615b2167459SRichard Henderson     TCGv tmp;
616b2167459SRichard Henderson 
617b2167459SRichard Henderson     switch (cf >> 1) {
618b2167459SRichard Henderson     case 0: /* Never / TR */
619b2167459SRichard Henderson         cond = cond_make_f();
620b2167459SRichard Henderson         break;
621b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
622b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
623b2167459SRichard Henderson         break;
624b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
625b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
626b2167459SRichard Henderson         break;
627b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
628b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
629b2167459SRichard Henderson         break;
630b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
631b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
632b2167459SRichard Henderson         break;
633b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
634b2167459SRichard Henderson         tmp = tcg_temp_new();
635b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
636b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
637b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
638b2167459SRichard Henderson         tcg_temp_free(tmp);
639b2167459SRichard Henderson         break;
640b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
641b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
642b2167459SRichard Henderson         break;
643b2167459SRichard Henderson     case 7: /* OD / EV */
644b2167459SRichard Henderson         tmp = tcg_temp_new();
645b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
646b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
647b2167459SRichard Henderson         tcg_temp_free(tmp);
648b2167459SRichard Henderson         break;
649b2167459SRichard Henderson     default:
650b2167459SRichard Henderson         g_assert_not_reached();
651b2167459SRichard Henderson     }
652b2167459SRichard Henderson     if (cf & 1) {
653b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
654b2167459SRichard Henderson     }
655b2167459SRichard Henderson 
656b2167459SRichard Henderson     return cond;
657b2167459SRichard Henderson }
658b2167459SRichard Henderson 
659b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
660b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
661b2167459SRichard Henderson    deleted as unused.  */
662b2167459SRichard Henderson 
663b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
664b2167459SRichard Henderson {
665b2167459SRichard Henderson     DisasCond cond;
666b2167459SRichard Henderson 
667b2167459SRichard Henderson     switch (cf >> 1) {
668b2167459SRichard Henderson     case 1: /* = / <> */
669b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
670b2167459SRichard Henderson         break;
671b2167459SRichard Henderson     case 2: /* < / >= */
672b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
673b2167459SRichard Henderson         break;
674b2167459SRichard Henderson     case 3: /* <= / > */
675b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
676b2167459SRichard Henderson         break;
677b2167459SRichard Henderson     case 4: /* << / >>= */
678b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
679b2167459SRichard Henderson         break;
680b2167459SRichard Henderson     case 5: /* <<= / >> */
681b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
682b2167459SRichard Henderson         break;
683b2167459SRichard Henderson     default:
684b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
685b2167459SRichard Henderson     }
686b2167459SRichard Henderson     if (cf & 1) {
687b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
688b2167459SRichard Henderson     }
689b2167459SRichard Henderson 
690b2167459SRichard Henderson     return cond;
691b2167459SRichard Henderson }
692b2167459SRichard Henderson 
693b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
694b2167459SRichard Henderson    computed, and use of them is undefined.  */
695b2167459SRichard Henderson 
696b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
697b2167459SRichard Henderson {
698b2167459SRichard Henderson     switch (cf >> 1) {
699b2167459SRichard Henderson     case 4: case 5: case 6:
700b2167459SRichard Henderson         cf &= 1;
701b2167459SRichard Henderson         break;
702b2167459SRichard Henderson     }
703b2167459SRichard Henderson     return do_cond(cf, res, res, res);
704b2167459SRichard Henderson }
705b2167459SRichard Henderson 
70698cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
70798cd9ca7SRichard Henderson 
70898cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res)
70998cd9ca7SRichard Henderson {
71098cd9ca7SRichard Henderson     unsigned c, f;
71198cd9ca7SRichard Henderson 
71298cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
71398cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
71498cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
71598cd9ca7SRichard Henderson     c = orig & 3;
71698cd9ca7SRichard Henderson     if (c == 3) {
71798cd9ca7SRichard Henderson         c = 7;
71898cd9ca7SRichard Henderson     }
71998cd9ca7SRichard Henderson     f = (orig & 4) / 4;
72098cd9ca7SRichard Henderson 
72198cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
72298cd9ca7SRichard Henderson }
72398cd9ca7SRichard Henderson 
724b2167459SRichard Henderson /* Similar, but for unit conditions.  */
725b2167459SRichard Henderson 
726b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
727b2167459SRichard Henderson {
728b2167459SRichard Henderson     DisasCond cond;
729b2167459SRichard Henderson     TCGv tmp, cb;
730b2167459SRichard Henderson 
731b2167459SRichard Henderson     TCGV_UNUSED(cb);
732b2167459SRichard Henderson     if (cf & 8) {
733b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
734b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
735b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
736b2167459SRichard Henderson          */
737b2167459SRichard Henderson         cb = tcg_temp_new();
738b2167459SRichard Henderson         tmp = tcg_temp_new();
739b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
740b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
741b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
742b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
743b2167459SRichard Henderson         tcg_temp_free(tmp);
744b2167459SRichard Henderson     }
745b2167459SRichard Henderson 
746b2167459SRichard Henderson     switch (cf >> 1) {
747b2167459SRichard Henderson     case 0: /* never / TR */
748b2167459SRichard Henderson     case 1: /* undefined */
749b2167459SRichard Henderson     case 5: /* undefined */
750b2167459SRichard Henderson         cond = cond_make_f();
751b2167459SRichard Henderson         break;
752b2167459SRichard Henderson 
753b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
754b2167459SRichard Henderson         /* See hasless(v,1) from
755b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
756b2167459SRichard Henderson          */
757b2167459SRichard Henderson         tmp = tcg_temp_new();
758b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
759b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
760b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
761b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
762b2167459SRichard Henderson         tcg_temp_free(tmp);
763b2167459SRichard Henderson         break;
764b2167459SRichard Henderson 
765b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
766b2167459SRichard Henderson         tmp = tcg_temp_new();
767b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
768b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
769b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
770b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
771b2167459SRichard Henderson         tcg_temp_free(tmp);
772b2167459SRichard Henderson         break;
773b2167459SRichard Henderson 
774b2167459SRichard Henderson     case 4: /* SDC / NDC */
775b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
776b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
777b2167459SRichard Henderson         break;
778b2167459SRichard Henderson 
779b2167459SRichard Henderson     case 6: /* SBC / NBC */
780b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
781b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
782b2167459SRichard Henderson         break;
783b2167459SRichard Henderson 
784b2167459SRichard Henderson     case 7: /* SHC / NHC */
785b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
786b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
787b2167459SRichard Henderson         break;
788b2167459SRichard Henderson 
789b2167459SRichard Henderson     default:
790b2167459SRichard Henderson         g_assert_not_reached();
791b2167459SRichard Henderson     }
792b2167459SRichard Henderson     if (cf & 8) {
793b2167459SRichard Henderson         tcg_temp_free(cb);
794b2167459SRichard Henderson     }
795b2167459SRichard Henderson     if (cf & 1) {
796b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
797b2167459SRichard Henderson     }
798b2167459SRichard Henderson 
799b2167459SRichard Henderson     return cond;
800b2167459SRichard Henderson }
801b2167459SRichard Henderson 
802b2167459SRichard Henderson /* Compute signed overflow for addition.  */
803b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
804b2167459SRichard Henderson {
805b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
806b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
807b2167459SRichard Henderson 
808b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
809b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
810b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
811b2167459SRichard Henderson     tcg_temp_free(tmp);
812b2167459SRichard Henderson 
813b2167459SRichard Henderson     return sv;
814b2167459SRichard Henderson }
815b2167459SRichard Henderson 
816b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
817b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
818b2167459SRichard Henderson {
819b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
820b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
821b2167459SRichard Henderson 
822b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
823b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
824b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
825b2167459SRichard Henderson     tcg_temp_free(tmp);
826b2167459SRichard Henderson 
827b2167459SRichard Henderson     return sv;
828b2167459SRichard Henderson }
829b2167459SRichard Henderson 
830869051eaSRichard Henderson static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
831b2167459SRichard Henderson                             unsigned shift, bool is_l, bool is_tsv, bool is_tc,
832b2167459SRichard Henderson                             bool is_c, unsigned cf)
833b2167459SRichard Henderson {
834b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
835b2167459SRichard Henderson     unsigned c = cf >> 1;
836b2167459SRichard Henderson     DisasCond cond;
837b2167459SRichard Henderson 
838b2167459SRichard Henderson     dest = tcg_temp_new();
839b2167459SRichard Henderson     TCGV_UNUSED(cb);
840b2167459SRichard Henderson     TCGV_UNUSED(cb_msb);
841b2167459SRichard Henderson 
842b2167459SRichard Henderson     if (shift) {
843b2167459SRichard Henderson         tmp = get_temp(ctx);
844b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
845b2167459SRichard Henderson         in1 = tmp;
846b2167459SRichard Henderson     }
847b2167459SRichard Henderson 
848b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
849b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
850b2167459SRichard Henderson         cb_msb = get_temp(ctx);
851b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
852b2167459SRichard Henderson         if (is_c) {
853b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
854b2167459SRichard Henderson         }
855b2167459SRichard Henderson         tcg_temp_free(zero);
856b2167459SRichard Henderson         if (!is_l) {
857b2167459SRichard Henderson             cb = get_temp(ctx);
858b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
859b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
860b2167459SRichard Henderson         }
861b2167459SRichard Henderson     } else {
862b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
863b2167459SRichard Henderson         if (is_c) {
864b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
865b2167459SRichard Henderson         }
866b2167459SRichard Henderson     }
867b2167459SRichard Henderson 
868b2167459SRichard Henderson     /* Compute signed overflow if required.  */
869b2167459SRichard Henderson     TCGV_UNUSED(sv);
870b2167459SRichard Henderson     if (is_tsv || c == 6) {
871b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
872b2167459SRichard Henderson         if (is_tsv) {
873b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
874b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
875b2167459SRichard Henderson         }
876b2167459SRichard Henderson     }
877b2167459SRichard Henderson 
878b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
879b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
880b2167459SRichard Henderson     if (is_tc) {
881b2167459SRichard Henderson         cond_prep(&cond);
882b2167459SRichard Henderson         tmp = tcg_temp_new();
883b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
884b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
885b2167459SRichard Henderson         tcg_temp_free(tmp);
886b2167459SRichard Henderson     }
887b2167459SRichard Henderson 
888b2167459SRichard Henderson     /* Write back the result.  */
889b2167459SRichard Henderson     if (!is_l) {
890b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
891b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
892b2167459SRichard Henderson     }
893b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
894b2167459SRichard Henderson     tcg_temp_free(dest);
895b2167459SRichard Henderson 
896b2167459SRichard Henderson     /* Install the new nullification.  */
897b2167459SRichard Henderson     cond_free(&ctx->null_cond);
898b2167459SRichard Henderson     ctx->null_cond = cond;
899869051eaSRichard Henderson     return DISAS_NEXT;
900b2167459SRichard Henderson }
901b2167459SRichard Henderson 
902869051eaSRichard Henderson static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
903b2167459SRichard Henderson                             bool is_tsv, bool is_b, bool is_tc, unsigned cf)
904b2167459SRichard Henderson {
905b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
906b2167459SRichard Henderson     unsigned c = cf >> 1;
907b2167459SRichard Henderson     DisasCond cond;
908b2167459SRichard Henderson 
909b2167459SRichard Henderson     dest = tcg_temp_new();
910b2167459SRichard Henderson     cb = tcg_temp_new();
911b2167459SRichard Henderson     cb_msb = tcg_temp_new();
912b2167459SRichard Henderson 
913b2167459SRichard Henderson     zero = tcg_const_tl(0);
914b2167459SRichard Henderson     if (is_b) {
915b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
916b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
917b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
918b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
919b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
920b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
921b2167459SRichard Henderson     } else {
922b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
923b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
924b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
925b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
926b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
927b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
928b2167459SRichard Henderson     }
929b2167459SRichard Henderson     tcg_temp_free(zero);
930b2167459SRichard Henderson 
931b2167459SRichard Henderson     /* Compute signed overflow if required.  */
932b2167459SRichard Henderson     TCGV_UNUSED(sv);
933b2167459SRichard Henderson     if (is_tsv || c == 6) {
934b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
935b2167459SRichard Henderson         if (is_tsv) {
936b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
937b2167459SRichard Henderson         }
938b2167459SRichard Henderson     }
939b2167459SRichard Henderson 
940b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
941b2167459SRichard Henderson     if (!is_b) {
942b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
943b2167459SRichard Henderson     } else {
944b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
945b2167459SRichard Henderson     }
946b2167459SRichard Henderson 
947b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
948b2167459SRichard Henderson     if (is_tc) {
949b2167459SRichard Henderson         cond_prep(&cond);
950b2167459SRichard Henderson         tmp = tcg_temp_new();
951b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
952b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
953b2167459SRichard Henderson         tcg_temp_free(tmp);
954b2167459SRichard Henderson     }
955b2167459SRichard Henderson 
956b2167459SRichard Henderson     /* Write back the result.  */
957b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
958b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
959b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
960b2167459SRichard Henderson     tcg_temp_free(dest);
961b2167459SRichard Henderson 
962b2167459SRichard Henderson     /* Install the new nullification.  */
963b2167459SRichard Henderson     cond_free(&ctx->null_cond);
964b2167459SRichard Henderson     ctx->null_cond = cond;
965869051eaSRichard Henderson     return DISAS_NEXT;
966b2167459SRichard Henderson }
967b2167459SRichard Henderson 
968869051eaSRichard Henderson static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
969b2167459SRichard Henderson                                TCGv in2, unsigned cf)
970b2167459SRichard Henderson {
971b2167459SRichard Henderson     TCGv dest, sv;
972b2167459SRichard Henderson     DisasCond cond;
973b2167459SRichard Henderson 
974b2167459SRichard Henderson     dest = tcg_temp_new();
975b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
976b2167459SRichard Henderson 
977b2167459SRichard Henderson     /* Compute signed overflow if required.  */
978b2167459SRichard Henderson     TCGV_UNUSED(sv);
979b2167459SRichard Henderson     if ((cf >> 1) == 6) {
980b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
981b2167459SRichard Henderson     }
982b2167459SRichard Henderson 
983b2167459SRichard Henderson     /* Form the condition for the compare.  */
984b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
985b2167459SRichard Henderson 
986b2167459SRichard Henderson     /* Clear.  */
987b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
988b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
989b2167459SRichard Henderson     tcg_temp_free(dest);
990b2167459SRichard Henderson 
991b2167459SRichard Henderson     /* Install the new nullification.  */
992b2167459SRichard Henderson     cond_free(&ctx->null_cond);
993b2167459SRichard Henderson     ctx->null_cond = cond;
994869051eaSRichard Henderson     return DISAS_NEXT;
995b2167459SRichard Henderson }
996b2167459SRichard Henderson 
997869051eaSRichard Henderson static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
998b2167459SRichard Henderson                             unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
999b2167459SRichard Henderson {
1000b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
1001b2167459SRichard Henderson 
1002b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1003b2167459SRichard Henderson     fn(dest, in1, in2);
1004b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1005b2167459SRichard Henderson 
1006b2167459SRichard Henderson     /* Install the new nullification.  */
1007b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1008b2167459SRichard Henderson     if (cf) {
1009b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
1010b2167459SRichard Henderson     }
1011869051eaSRichard Henderson     return DISAS_NEXT;
1012b2167459SRichard Henderson }
1013b2167459SRichard Henderson 
1014869051eaSRichard Henderson static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1015b2167459SRichard Henderson                              TCGv in2, unsigned cf, bool is_tc,
1016b2167459SRichard Henderson                              void (*fn)(TCGv, TCGv, TCGv))
1017b2167459SRichard Henderson {
1018b2167459SRichard Henderson     TCGv dest;
1019b2167459SRichard Henderson     DisasCond cond;
1020b2167459SRichard Henderson 
1021b2167459SRichard Henderson     if (cf == 0) {
1022b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1023b2167459SRichard Henderson         fn(dest, in1, in2);
1024b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1025b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1026b2167459SRichard Henderson     } else {
1027b2167459SRichard Henderson         dest = tcg_temp_new();
1028b2167459SRichard Henderson         fn(dest, in1, in2);
1029b2167459SRichard Henderson 
1030b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
1031b2167459SRichard Henderson 
1032b2167459SRichard Henderson         if (is_tc) {
1033b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
1034b2167459SRichard Henderson             cond_prep(&cond);
1035b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1036b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
1037b2167459SRichard Henderson             tcg_temp_free(tmp);
1038b2167459SRichard Henderson         }
1039b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1040b2167459SRichard Henderson 
1041b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1042b2167459SRichard Henderson         ctx->null_cond = cond;
1043b2167459SRichard Henderson     }
1044869051eaSRichard Henderson     return DISAS_NEXT;
1045b2167459SRichard Henderson }
1046b2167459SRichard Henderson 
104796d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
104896d6407fSRichard Henderson  * < 0 for pre-modify,
104996d6407fSRichard Henderson  * > 0 for post-modify,
105096d6407fSRichard Henderson  * = 0 for no base register update.
105196d6407fSRichard Henderson  */
105296d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
105396d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
105496d6407fSRichard Henderson                        int modify, TCGMemOp mop)
105596d6407fSRichard Henderson {
105696d6407fSRichard Henderson     TCGv addr, base;
105796d6407fSRichard Henderson 
105896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
105996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
106096d6407fSRichard Henderson 
106196d6407fSRichard Henderson     addr = tcg_temp_new();
106296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
106396d6407fSRichard Henderson 
106496d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
106596d6407fSRichard Henderson     if (rx) {
106696d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
106796d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
106896d6407fSRichard Henderson     } else {
106996d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
107096d6407fSRichard Henderson     }
107196d6407fSRichard Henderson 
107296d6407fSRichard Henderson     if (modify == 0) {
107396d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
107496d6407fSRichard Henderson     } else {
107596d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
107696d6407fSRichard Henderson                             MMU_USER_IDX, mop);
107796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
107896d6407fSRichard Henderson     }
107996d6407fSRichard Henderson     tcg_temp_free(addr);
108096d6407fSRichard Henderson }
108196d6407fSRichard Henderson 
108296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
108396d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
108496d6407fSRichard Henderson                        int modify, TCGMemOp mop)
108596d6407fSRichard Henderson {
108696d6407fSRichard Henderson     TCGv addr, base;
108796d6407fSRichard Henderson 
108896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
108996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
109096d6407fSRichard Henderson 
109196d6407fSRichard Henderson     addr = tcg_temp_new();
109296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
109396d6407fSRichard Henderson 
109496d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
109596d6407fSRichard Henderson     if (rx) {
109696d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
109796d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
109896d6407fSRichard Henderson     } else {
109996d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
110096d6407fSRichard Henderson     }
110196d6407fSRichard Henderson 
110296d6407fSRichard Henderson     if (modify == 0) {
110396d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
110496d6407fSRichard Henderson     } else {
110596d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
110696d6407fSRichard Henderson                             MMU_USER_IDX, mop);
110796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
110896d6407fSRichard Henderson     }
110996d6407fSRichard Henderson     tcg_temp_free(addr);
111096d6407fSRichard Henderson }
111196d6407fSRichard Henderson 
111296d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
111396d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
111496d6407fSRichard Henderson                         int modify, TCGMemOp mop)
111596d6407fSRichard Henderson {
111696d6407fSRichard Henderson     TCGv addr, base;
111796d6407fSRichard Henderson 
111896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
111996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
112096d6407fSRichard Henderson 
112196d6407fSRichard Henderson     addr = tcg_temp_new();
112296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
112396d6407fSRichard Henderson 
112496d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
112596d6407fSRichard Henderson     if (rx) {
112696d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
112796d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
112896d6407fSRichard Henderson     } else {
112996d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
113096d6407fSRichard Henderson     }
113196d6407fSRichard Henderson 
113296d6407fSRichard Henderson     tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
113396d6407fSRichard Henderson 
113496d6407fSRichard Henderson     if (modify != 0) {
113596d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
113696d6407fSRichard Henderson     }
113796d6407fSRichard Henderson     tcg_temp_free(addr);
113896d6407fSRichard Henderson }
113996d6407fSRichard Henderson 
114096d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
114196d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
114296d6407fSRichard Henderson                         int modify, TCGMemOp mop)
114396d6407fSRichard Henderson {
114496d6407fSRichard Henderson     TCGv addr, base;
114596d6407fSRichard Henderson 
114696d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
114796d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
114896d6407fSRichard Henderson 
114996d6407fSRichard Henderson     addr = tcg_temp_new();
115096d6407fSRichard Henderson     base = load_gpr(ctx, rb);
115196d6407fSRichard Henderson 
115296d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
115396d6407fSRichard Henderson     if (rx) {
115496d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
115596d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
115696d6407fSRichard Henderson     } else {
115796d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
115896d6407fSRichard Henderson     }
115996d6407fSRichard Henderson 
116096d6407fSRichard Henderson     tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
116196d6407fSRichard Henderson 
116296d6407fSRichard Henderson     if (modify != 0) {
116396d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
116496d6407fSRichard Henderson     }
116596d6407fSRichard Henderson     tcg_temp_free(addr);
116696d6407fSRichard Henderson }
116796d6407fSRichard Henderson 
116896d6407fSRichard Henderson #if TARGET_LONG_BITS == 64
116996d6407fSRichard Henderson #define do_load_tl  do_load_64
117096d6407fSRichard Henderson #define do_store_tl do_store_64
117196d6407fSRichard Henderson #else
117296d6407fSRichard Henderson #define do_load_tl  do_load_32
117396d6407fSRichard Henderson #define do_store_tl do_store_32
117496d6407fSRichard Henderson #endif
117596d6407fSRichard Henderson 
1176869051eaSRichard Henderson static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb,
117796d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
117896d6407fSRichard Henderson                              int modify, TCGMemOp mop)
117996d6407fSRichard Henderson {
118096d6407fSRichard Henderson     TCGv dest;
118196d6407fSRichard Henderson 
118296d6407fSRichard Henderson     nullify_over(ctx);
118396d6407fSRichard Henderson 
118496d6407fSRichard Henderson     if (modify == 0) {
118596d6407fSRichard Henderson         /* No base register update.  */
118696d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
118796d6407fSRichard Henderson     } else {
118896d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
118996d6407fSRichard Henderson         dest = get_temp(ctx);
119096d6407fSRichard Henderson     }
119196d6407fSRichard Henderson     do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
119296d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
119396d6407fSRichard Henderson 
1194869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
119596d6407fSRichard Henderson }
119696d6407fSRichard Henderson 
1197869051eaSRichard Henderson static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
119896d6407fSRichard Henderson                                unsigned rx, int scale, target_long disp,
119996d6407fSRichard Henderson                                int modify)
120096d6407fSRichard Henderson {
120196d6407fSRichard Henderson     TCGv_i32 tmp;
120296d6407fSRichard Henderson 
120396d6407fSRichard Henderson     nullify_over(ctx);
120496d6407fSRichard Henderson 
120596d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
120696d6407fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
120796d6407fSRichard Henderson     save_frw_i32(rt, tmp);
120896d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
120996d6407fSRichard Henderson 
121096d6407fSRichard Henderson     if (rt == 0) {
121196d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
121296d6407fSRichard Henderson     }
121396d6407fSRichard Henderson 
1214869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
121596d6407fSRichard Henderson }
121696d6407fSRichard Henderson 
1217869051eaSRichard Henderson static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
121896d6407fSRichard Henderson                                unsigned rx, int scale, target_long disp,
121996d6407fSRichard Henderson                                int modify)
122096d6407fSRichard Henderson {
122196d6407fSRichard Henderson     TCGv_i64 tmp;
122296d6407fSRichard Henderson 
122396d6407fSRichard Henderson     nullify_over(ctx);
122496d6407fSRichard Henderson 
122596d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
122696d6407fSRichard Henderson     do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
122796d6407fSRichard Henderson     save_frd(rt, tmp);
122896d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
122996d6407fSRichard Henderson 
123096d6407fSRichard Henderson     if (rt == 0) {
123196d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
123296d6407fSRichard Henderson     }
123396d6407fSRichard Henderson 
1234869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
123596d6407fSRichard Henderson }
123696d6407fSRichard Henderson 
1237869051eaSRichard Henderson static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb,
123896d6407fSRichard Henderson                               target_long disp, int modify, TCGMemOp mop)
123996d6407fSRichard Henderson {
124096d6407fSRichard Henderson     nullify_over(ctx);
124196d6407fSRichard Henderson     do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1242869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
124396d6407fSRichard Henderson }
124496d6407fSRichard Henderson 
1245869051eaSRichard Henderson static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
124696d6407fSRichard Henderson                                 unsigned rx, int scale, target_long disp,
124796d6407fSRichard Henderson                                 int modify)
124896d6407fSRichard Henderson {
124996d6407fSRichard Henderson     TCGv_i32 tmp;
125096d6407fSRichard Henderson 
125196d6407fSRichard Henderson     nullify_over(ctx);
125296d6407fSRichard Henderson 
125396d6407fSRichard Henderson     tmp = load_frw_i32(rt);
125496d6407fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
125596d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
125696d6407fSRichard Henderson 
1257869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
125896d6407fSRichard Henderson }
125996d6407fSRichard Henderson 
1260869051eaSRichard Henderson static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
126196d6407fSRichard Henderson                                 unsigned rx, int scale, target_long disp,
126296d6407fSRichard Henderson                                 int modify)
126396d6407fSRichard Henderson {
126496d6407fSRichard Henderson     TCGv_i64 tmp;
126596d6407fSRichard Henderson 
126696d6407fSRichard Henderson     nullify_over(ctx);
126796d6407fSRichard Henderson 
126896d6407fSRichard Henderson     tmp = load_frd(rt);
126996d6407fSRichard Henderson     do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
127096d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
127196d6407fSRichard Henderson 
1272869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
127396d6407fSRichard Henderson }
127496d6407fSRichard Henderson 
1275869051eaSRichard Henderson static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1276ebe9383cSRichard Henderson                                 void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1277ebe9383cSRichard Henderson {
1278ebe9383cSRichard Henderson     TCGv_i32 tmp;
1279ebe9383cSRichard Henderson 
1280ebe9383cSRichard Henderson     nullify_over(ctx);
1281ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1282ebe9383cSRichard Henderson 
1283ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1284ebe9383cSRichard Henderson 
1285ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
1286ebe9383cSRichard Henderson     tcg_temp_free_i32(tmp);
1287869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1288ebe9383cSRichard Henderson }
1289ebe9383cSRichard Henderson 
1290869051eaSRichard Henderson static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1291ebe9383cSRichard Henderson                                 void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1292ebe9383cSRichard Henderson {
1293ebe9383cSRichard Henderson     TCGv_i32 dst;
1294ebe9383cSRichard Henderson     TCGv_i64 src;
1295ebe9383cSRichard Henderson 
1296ebe9383cSRichard Henderson     nullify_over(ctx);
1297ebe9383cSRichard Henderson     src = load_frd(ra);
1298ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1299ebe9383cSRichard Henderson 
1300ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1301ebe9383cSRichard Henderson 
1302ebe9383cSRichard Henderson     tcg_temp_free_i64(src);
1303ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
1304ebe9383cSRichard Henderson     tcg_temp_free_i32(dst);
1305869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1306ebe9383cSRichard Henderson }
1307ebe9383cSRichard Henderson 
1308869051eaSRichard Henderson static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1309ebe9383cSRichard Henderson                                 void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1310ebe9383cSRichard Henderson {
1311ebe9383cSRichard Henderson     TCGv_i64 tmp;
1312ebe9383cSRichard Henderson 
1313ebe9383cSRichard Henderson     nullify_over(ctx);
1314ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1315ebe9383cSRichard Henderson 
1316ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1317ebe9383cSRichard Henderson 
1318ebe9383cSRichard Henderson     save_frd(rt, tmp);
1319ebe9383cSRichard Henderson     tcg_temp_free_i64(tmp);
1320869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1321ebe9383cSRichard Henderson }
1322ebe9383cSRichard Henderson 
1323869051eaSRichard Henderson static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1324ebe9383cSRichard Henderson                                 void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1325ebe9383cSRichard Henderson {
1326ebe9383cSRichard Henderson     TCGv_i32 src;
1327ebe9383cSRichard Henderson     TCGv_i64 dst;
1328ebe9383cSRichard Henderson 
1329ebe9383cSRichard Henderson     nullify_over(ctx);
1330ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1331ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1332ebe9383cSRichard Henderson 
1333ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1334ebe9383cSRichard Henderson 
1335ebe9383cSRichard Henderson     tcg_temp_free_i32(src);
1336ebe9383cSRichard Henderson     save_frd(rt, dst);
1337ebe9383cSRichard Henderson     tcg_temp_free_i64(dst);
1338869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1339ebe9383cSRichard Henderson }
1340ebe9383cSRichard Henderson 
1341869051eaSRichard Henderson static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt,
1342ebe9383cSRichard Henderson                                  unsigned ra, unsigned rb,
1343ebe9383cSRichard Henderson                                  void (*func)(TCGv_i32, TCGv_env,
1344ebe9383cSRichard Henderson                                               TCGv_i32, TCGv_i32))
1345ebe9383cSRichard Henderson {
1346ebe9383cSRichard Henderson     TCGv_i32 a, b;
1347ebe9383cSRichard Henderson 
1348ebe9383cSRichard Henderson     nullify_over(ctx);
1349ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1350ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1351ebe9383cSRichard Henderson 
1352ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1353ebe9383cSRichard Henderson 
1354ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
1355ebe9383cSRichard Henderson     save_frw_i32(rt, a);
1356ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
1357869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1358ebe9383cSRichard Henderson }
1359ebe9383cSRichard Henderson 
1360869051eaSRichard Henderson static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt,
1361ebe9383cSRichard Henderson                                  unsigned ra, unsigned rb,
1362ebe9383cSRichard Henderson                                  void (*func)(TCGv_i64, TCGv_env,
1363ebe9383cSRichard Henderson                                               TCGv_i64, TCGv_i64))
1364ebe9383cSRichard Henderson {
1365ebe9383cSRichard Henderson     TCGv_i64 a, b;
1366ebe9383cSRichard Henderson 
1367ebe9383cSRichard Henderson     nullify_over(ctx);
1368ebe9383cSRichard Henderson     a = load_frd0(ra);
1369ebe9383cSRichard Henderson     b = load_frd0(rb);
1370ebe9383cSRichard Henderson 
1371ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1372ebe9383cSRichard Henderson 
1373ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
1374ebe9383cSRichard Henderson     save_frd(rt, a);
1375ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
1376869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
1377ebe9383cSRichard Henderson }
1378ebe9383cSRichard Henderson 
137998cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
138098cd9ca7SRichard Henderson    have already had nullification handled.  */
1381869051eaSRichard Henderson static DisasJumpType do_dbranch(DisasContext *ctx, target_ulong dest,
138298cd9ca7SRichard Henderson                                 unsigned link, bool is_n)
138398cd9ca7SRichard Henderson {
138498cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
138598cd9ca7SRichard Henderson         if (link != 0) {
138698cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
138798cd9ca7SRichard Henderson         }
138898cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
138998cd9ca7SRichard Henderson         if (is_n) {
139098cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
139198cd9ca7SRichard Henderson         }
1392869051eaSRichard Henderson         return DISAS_NEXT;
139398cd9ca7SRichard Henderson     } else {
139498cd9ca7SRichard Henderson         nullify_over(ctx);
139598cd9ca7SRichard Henderson 
139698cd9ca7SRichard Henderson         if (link != 0) {
139798cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
139898cd9ca7SRichard Henderson         }
139998cd9ca7SRichard Henderson 
140098cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
140198cd9ca7SRichard Henderson             nullify_set(ctx, 0);
140298cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
140398cd9ca7SRichard Henderson         } else {
140498cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
140598cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
140698cd9ca7SRichard Henderson         }
140798cd9ca7SRichard Henderson 
1408869051eaSRichard Henderson         nullify_end(ctx, DISAS_NEXT);
140998cd9ca7SRichard Henderson 
141098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
141198cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1412869051eaSRichard Henderson         return DISAS_NORETURN;
141398cd9ca7SRichard Henderson     }
141498cd9ca7SRichard Henderson }
141598cd9ca7SRichard Henderson 
141698cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
141798cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
1418869051eaSRichard Henderson static DisasJumpType do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
141998cd9ca7SRichard Henderson                                 DisasCond *cond)
142098cd9ca7SRichard Henderson {
142198cd9ca7SRichard Henderson     target_ulong dest = iaoq_dest(ctx, disp);
142298cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
142398cd9ca7SRichard Henderson     TCGCond c = cond->c;
142498cd9ca7SRichard Henderson     bool n;
142598cd9ca7SRichard Henderson 
142698cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
142798cd9ca7SRichard Henderson 
142898cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
142998cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
143098cd9ca7SRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
143198cd9ca7SRichard Henderson     }
143298cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
143398cd9ca7SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
143498cd9ca7SRichard Henderson     }
143598cd9ca7SRichard Henderson 
143698cd9ca7SRichard Henderson     taken = gen_new_label();
143798cd9ca7SRichard Henderson     cond_prep(cond);
143898cd9ca7SRichard Henderson     tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
143998cd9ca7SRichard Henderson     cond_free(cond);
144098cd9ca7SRichard Henderson 
144198cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
144298cd9ca7SRichard Henderson     n = is_n && disp < 0;
144398cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
144498cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1445a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
144698cd9ca7SRichard Henderson     } else {
144798cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
144898cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
144998cd9ca7SRichard Henderson             ctx->null_lab = NULL;
145098cd9ca7SRichard Henderson         }
145198cd9ca7SRichard Henderson         nullify_set(ctx, n);
1452a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
145398cd9ca7SRichard Henderson     }
145498cd9ca7SRichard Henderson 
145598cd9ca7SRichard Henderson     gen_set_label(taken);
145698cd9ca7SRichard Henderson 
145798cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
145898cd9ca7SRichard Henderson     n = is_n && disp >= 0;
145998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
146098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1461a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
146298cd9ca7SRichard Henderson     } else {
146398cd9ca7SRichard Henderson         nullify_set(ctx, n);
1464a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
146598cd9ca7SRichard Henderson     }
146698cd9ca7SRichard Henderson 
146798cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
146898cd9ca7SRichard Henderson     if (ctx->null_lab) {
146998cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
147098cd9ca7SRichard Henderson         ctx->null_lab = NULL;
1471869051eaSRichard Henderson         return DISAS_IAQ_N_STALE;
147298cd9ca7SRichard Henderson     } else {
1473869051eaSRichard Henderson         return DISAS_NORETURN;
147498cd9ca7SRichard Henderson     }
147598cd9ca7SRichard Henderson }
147698cd9ca7SRichard Henderson 
147798cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
147898cd9ca7SRichard Henderson    nullification of the branch itself.  */
1479869051eaSRichard Henderson static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest,
148098cd9ca7SRichard Henderson                                 unsigned link, bool is_n)
148198cd9ca7SRichard Henderson {
148298cd9ca7SRichard Henderson     TCGv a0, a1, next, tmp;
148398cd9ca7SRichard Henderson     TCGCond c;
148498cd9ca7SRichard Henderson 
148598cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
148698cd9ca7SRichard Henderson 
148798cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
148898cd9ca7SRichard Henderson         if (link != 0) {
148998cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
149098cd9ca7SRichard Henderson         }
149198cd9ca7SRichard Henderson         next = get_temp(ctx);
149298cd9ca7SRichard Henderson         tcg_gen_mov_tl(next, dest);
149398cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
149498cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
149598cd9ca7SRichard Henderson         if (is_n) {
149698cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
149798cd9ca7SRichard Henderson         }
149898cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
149998cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
150098cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
15014137cb83SRichard Henderson            tracepoint in effect).  Since the goto_ptr that we must use
150298cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
150398cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
150498cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
150598cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
150698cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
150798cd9ca7SRichard Henderson 
150898cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
150998cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
151098cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
151198cd9ca7SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, dest);
151298cd9ca7SRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
151398cd9ca7SRichard Henderson 
151498cd9ca7SRichard Henderson         nullify_over(ctx);
151598cd9ca7SRichard Henderson         if (link != 0) {
151698cd9ca7SRichard Henderson             tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
151798cd9ca7SRichard Henderson         }
15184137cb83SRichard Henderson         tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
1519869051eaSRichard Henderson         return nullify_end(ctx, DISAS_NEXT);
152098cd9ca7SRichard Henderson     } else {
152198cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
152298cd9ca7SRichard Henderson         c = ctx->null_cond.c;
152398cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
152498cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
152598cd9ca7SRichard Henderson 
152698cd9ca7SRichard Henderson         tmp = tcg_temp_new();
152798cd9ca7SRichard Henderson         next = get_temp(ctx);
152898cd9ca7SRichard Henderson 
152998cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
153098cd9ca7SRichard Henderson         tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
153198cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
153298cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
153398cd9ca7SRichard Henderson 
153498cd9ca7SRichard Henderson         if (link != 0) {
153598cd9ca7SRichard Henderson             tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
153698cd9ca7SRichard Henderson         }
153798cd9ca7SRichard Henderson 
153898cd9ca7SRichard Henderson         if (is_n) {
153998cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
154098cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
154198cd9ca7SRichard Henderson                to the branch.  */
154298cd9ca7SRichard Henderson             tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
154398cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
154498cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
154598cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
154698cd9ca7SRichard Henderson         } else {
154798cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
154898cd9ca7SRichard Henderson         }
154998cd9ca7SRichard Henderson     }
155098cd9ca7SRichard Henderson 
1551869051eaSRichard Henderson     return DISAS_NEXT;
155298cd9ca7SRichard Henderson }
155398cd9ca7SRichard Henderson 
15547ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
15557ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
15567ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
15577ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
15587ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
15597ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
15607ad439dfSRichard Henderson    aforementioned BE.  */
1561869051eaSRichard Henderson static DisasJumpType do_page_zero(DisasContext *ctx)
15627ad439dfSRichard Henderson {
15637ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
15647ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
15657ad439dfSRichard Henderson        next insn within the privilaged page.  */
15667ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
15677ad439dfSRichard Henderson     case TCG_COND_NEVER:
15687ad439dfSRichard Henderson         break;
15697ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
15707ad439dfSRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, 0);
15717ad439dfSRichard Henderson         goto do_sigill;
15727ad439dfSRichard Henderson     default:
15737ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
15747ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
15757ad439dfSRichard Henderson         g_assert_not_reached();
15767ad439dfSRichard Henderson     }
15777ad439dfSRichard Henderson 
15787ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
15797ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
15807ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
15817ad439dfSRichard Henderson        under such conditions.  */
15827ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
15837ad439dfSRichard Henderson         goto do_sigill;
15847ad439dfSRichard Henderson     }
15857ad439dfSRichard Henderson 
15867ad439dfSRichard Henderson     switch (ctx->iaoq_f) {
15877ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
15887ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGSEGV);
1589869051eaSRichard Henderson         return DISAS_NORETURN;
15907ad439dfSRichard Henderson 
15917ad439dfSRichard Henderson     case 0xb0: /* LWS */
15927ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
1593869051eaSRichard Henderson         return DISAS_NORETURN;
15947ad439dfSRichard Henderson 
15957ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
15967ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
15977ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
15987ad439dfSRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1599869051eaSRichard Henderson         return DISAS_IAQ_N_UPDATED;
16007ad439dfSRichard Henderson 
16017ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
16027ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
1603869051eaSRichard Henderson         return DISAS_NORETURN;
16047ad439dfSRichard Henderson 
16057ad439dfSRichard Henderson     default:
16067ad439dfSRichard Henderson     do_sigill:
16077ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGILL);
1608869051eaSRichard Henderson         return DISAS_NORETURN;
16097ad439dfSRichard Henderson     }
16107ad439dfSRichard Henderson }
16117ad439dfSRichard Henderson 
1612869051eaSRichard Henderson static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn,
1613b2167459SRichard Henderson                                const DisasInsn *di)
1614b2167459SRichard Henderson {
1615b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1616869051eaSRichard Henderson     return DISAS_NEXT;
1617b2167459SRichard Henderson }
1618b2167459SRichard Henderson 
1619869051eaSRichard Henderson static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn,
162098a9cb79SRichard Henderson                                  const DisasInsn *di)
162198a9cb79SRichard Henderson {
162298a9cb79SRichard Henderson     nullify_over(ctx);
162398a9cb79SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
162498a9cb79SRichard Henderson }
162598a9cb79SRichard Henderson 
1626869051eaSRichard Henderson static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn,
162798a9cb79SRichard Henderson                                 const DisasInsn *di)
162898a9cb79SRichard Henderson {
162998a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
163098a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
163198a9cb79SRichard Henderson 
163298a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1633869051eaSRichard Henderson     return DISAS_NEXT;
163498a9cb79SRichard Henderson }
163598a9cb79SRichard Henderson 
1636869051eaSRichard Henderson static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn,
163798a9cb79SRichard Henderson                                 const DisasInsn *di)
163898a9cb79SRichard Henderson {
163998a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
164098a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
164198a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, ctx->iaoq_f);
164298a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
164398a9cb79SRichard Henderson 
164498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1645869051eaSRichard Henderson     return DISAS_NEXT;
164698a9cb79SRichard Henderson }
164798a9cb79SRichard Henderson 
1648869051eaSRichard Henderson static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn,
164998a9cb79SRichard Henderson                                 const DisasInsn *di)
165098a9cb79SRichard Henderson {
165198a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
165298a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
165398a9cb79SRichard Henderson 
165498a9cb79SRichard Henderson     /* ??? We don't implement space registers.  */
165598a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, 0);
165698a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
165798a9cb79SRichard Henderson 
165898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1659869051eaSRichard Henderson     return DISAS_NEXT;
166098a9cb79SRichard Henderson }
166198a9cb79SRichard Henderson 
1662869051eaSRichard Henderson static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn,
166398a9cb79SRichard Henderson                                  const DisasInsn *di)
166498a9cb79SRichard Henderson {
166598a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
166698a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
166798a9cb79SRichard Henderson     TCGv tmp;
166898a9cb79SRichard Henderson 
166998a9cb79SRichard Henderson     switch (ctl) {
167098a9cb79SRichard Henderson     case 11: /* SAR */
167198a9cb79SRichard Henderson #ifdef TARGET_HPPA64
167298a9cb79SRichard Henderson         if (extract32(insn, 14, 1) == 0) {
167398a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
167498a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
167598a9cb79SRichard Henderson             tcg_gen_andi_tl(tmp, cpu_sar, 31);
167698a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
167798a9cb79SRichard Henderson             break;
167898a9cb79SRichard Henderson         }
167998a9cb79SRichard Henderson #endif
168098a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
168198a9cb79SRichard Henderson         break;
168298a9cb79SRichard Henderson     case 16: /* Interval Timer */
168398a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
168498a9cb79SRichard Henderson         tcg_gen_movi_tl(tmp, 0); /* FIXME */
168598a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
168698a9cb79SRichard Henderson         break;
168798a9cb79SRichard Henderson     case 26:
168898a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr26);
168998a9cb79SRichard Henderson         break;
169098a9cb79SRichard Henderson     case 27:
169198a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr27);
169298a9cb79SRichard Henderson         break;
169398a9cb79SRichard Henderson     default:
169498a9cb79SRichard Henderson         /* All other control registers are privileged.  */
169598a9cb79SRichard Henderson         return gen_illegal(ctx);
169698a9cb79SRichard Henderson     }
169798a9cb79SRichard Henderson 
169898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1699869051eaSRichard Henderson     return DISAS_NEXT;
170098a9cb79SRichard Henderson }
170198a9cb79SRichard Henderson 
1702869051eaSRichard Henderson static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn,
170398a9cb79SRichard Henderson                                  const DisasInsn *di)
170498a9cb79SRichard Henderson {
170598a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
170698a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
170798a9cb79SRichard Henderson     TCGv tmp;
170898a9cb79SRichard Henderson 
170998a9cb79SRichard Henderson     if (ctl == 11) { /* SAR */
171098a9cb79SRichard Henderson         tmp = tcg_temp_new();
171198a9cb79SRichard Henderson         tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
171298a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
171398a9cb79SRichard Henderson         tcg_temp_free(tmp);
171498a9cb79SRichard Henderson     } else {
171598a9cb79SRichard Henderson         /* All other control registers are privileged or read-only.  */
171698a9cb79SRichard Henderson         return gen_illegal(ctx);
171798a9cb79SRichard Henderson     }
171898a9cb79SRichard Henderson 
171998a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1720869051eaSRichard Henderson     return DISAS_NEXT;
172198a9cb79SRichard Henderson }
172298a9cb79SRichard Henderson 
1723869051eaSRichard Henderson static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn,
172498a9cb79SRichard Henderson                                    const DisasInsn *di)
172598a9cb79SRichard Henderson {
172698a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
172798a9cb79SRichard Henderson     TCGv tmp = tcg_temp_new();
172898a9cb79SRichard Henderson 
172998a9cb79SRichard Henderson     tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
173098a9cb79SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
173198a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
173298a9cb79SRichard Henderson     tcg_temp_free(tmp);
173398a9cb79SRichard Henderson 
173498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1735869051eaSRichard Henderson     return DISAS_NEXT;
173698a9cb79SRichard Henderson }
173798a9cb79SRichard Henderson 
1738869051eaSRichard Henderson static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn,
173998a9cb79SRichard Henderson                                  const DisasInsn *di)
174098a9cb79SRichard Henderson {
174198a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
174298a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
174398a9cb79SRichard Henderson 
174498a9cb79SRichard Henderson     /* Since we don't implement space registers, this returns zero.  */
174598a9cb79SRichard Henderson     tcg_gen_movi_tl(dest, 0);
174698a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
174798a9cb79SRichard Henderson 
174898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1749869051eaSRichard Henderson     return DISAS_NEXT;
175098a9cb79SRichard Henderson }
175198a9cb79SRichard Henderson 
175298a9cb79SRichard Henderson static const DisasInsn table_system[] = {
175398a9cb79SRichard Henderson     { 0x00000000u, 0xfc001fe0u, trans_break },
175498a9cb79SRichard Henderson     /* We don't implement space register, so MTSP is a nop.  */
175598a9cb79SRichard Henderson     { 0x00001820u, 0xffe01fffu, trans_nop },
175698a9cb79SRichard Henderson     { 0x00001840u, 0xfc00ffffu, trans_mtctl },
175798a9cb79SRichard Henderson     { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
175898a9cb79SRichard Henderson     { 0x000014a0u, 0xffffffe0u, trans_mfia },
175998a9cb79SRichard Henderson     { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
176098a9cb79SRichard Henderson     { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
176198a9cb79SRichard Henderson     { 0x00000400u, 0xffffffffu, trans_sync },
176298a9cb79SRichard Henderson     { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
176398a9cb79SRichard Henderson };
176498a9cb79SRichard Henderson 
1765869051eaSRichard Henderson static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
176698a9cb79SRichard Henderson                                         const DisasInsn *di)
176798a9cb79SRichard Henderson {
176898a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
176998a9cb79SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
177098a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rb);
177198a9cb79SRichard Henderson     TCGv src1 = load_gpr(ctx, rb);
177298a9cb79SRichard Henderson     TCGv src2 = load_gpr(ctx, rx);
177398a9cb79SRichard Henderson 
177498a9cb79SRichard Henderson     /* The only thing we need to do is the base register modification.  */
177598a9cb79SRichard Henderson     tcg_gen_add_tl(dest, src1, src2);
177698a9cb79SRichard Henderson     save_gpr(ctx, rb, dest);
177798a9cb79SRichard Henderson 
177898a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1779869051eaSRichard Henderson     return DISAS_NEXT;
178098a9cb79SRichard Henderson }
178198a9cb79SRichard Henderson 
1782869051eaSRichard Henderson static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn,
178398a9cb79SRichard Henderson                                  const DisasInsn *di)
178498a9cb79SRichard Henderson {
178598a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
178698a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
178798a9cb79SRichard Henderson     unsigned is_write = extract32(insn, 6, 1);
178898a9cb79SRichard Henderson     TCGv dest;
178998a9cb79SRichard Henderson 
179098a9cb79SRichard Henderson     nullify_over(ctx);
179198a9cb79SRichard Henderson 
179298a9cb79SRichard Henderson     /* ??? Do something with priv level operand.  */
179398a9cb79SRichard Henderson     dest = dest_gpr(ctx, rt);
179498a9cb79SRichard Henderson     if (is_write) {
179598a9cb79SRichard Henderson         gen_helper_probe_w(dest, load_gpr(ctx, rb));
179698a9cb79SRichard Henderson     } else {
179798a9cb79SRichard Henderson         gen_helper_probe_r(dest, load_gpr(ctx, rb));
179898a9cb79SRichard Henderson     }
179998a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
1800869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
180198a9cb79SRichard Henderson }
180298a9cb79SRichard Henderson 
180398a9cb79SRichard Henderson static const DisasInsn table_mem_mgmt[] = {
180498a9cb79SRichard Henderson     { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
180598a9cb79SRichard Henderson     { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
180698a9cb79SRichard Henderson     { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
180798a9cb79SRichard Henderson     { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
180898a9cb79SRichard Henderson     { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
180998a9cb79SRichard Henderson     { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
181098a9cb79SRichard Henderson     { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
181198a9cb79SRichard Henderson     { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
181298a9cb79SRichard Henderson     { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
181398a9cb79SRichard Henderson     { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
181498a9cb79SRichard Henderson     { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
181598a9cb79SRichard Henderson     { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
181698a9cb79SRichard Henderson     { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
181798a9cb79SRichard Henderson     { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
181898a9cb79SRichard Henderson     { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
181998a9cb79SRichard Henderson };
182098a9cb79SRichard Henderson 
1821869051eaSRichard Henderson static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn,
1822b2167459SRichard Henderson                                const DisasInsn *di)
1823b2167459SRichard Henderson {
1824b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1825b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1826b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1827b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
1828b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
1829b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1830b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1831b2167459SRichard Henderson     bool is_c = false;
1832b2167459SRichard Henderson     bool is_l = false;
1833b2167459SRichard Henderson     bool is_tc = false;
1834b2167459SRichard Henderson     bool is_tsv = false;
1835869051eaSRichard Henderson     DisasJumpType ret;
1836b2167459SRichard Henderson 
1837b2167459SRichard Henderson     switch (ext) {
1838b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
1839b2167459SRichard Henderson         break;
1840b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
1841b2167459SRichard Henderson         is_l = true;
1842b2167459SRichard Henderson         break;
1843b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1844b2167459SRichard Henderson         is_tsv = true;
1845b2167459SRichard Henderson         break;
1846b2167459SRichard Henderson     case 0x7: /* ADD,C */
1847b2167459SRichard Henderson         is_c = true;
1848b2167459SRichard Henderson         break;
1849b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
1850b2167459SRichard Henderson         is_c = is_tsv = true;
1851b2167459SRichard Henderson         break;
1852b2167459SRichard Henderson     default:
1853b2167459SRichard Henderson         return gen_illegal(ctx);
1854b2167459SRichard Henderson     }
1855b2167459SRichard Henderson 
1856b2167459SRichard Henderson     if (cf) {
1857b2167459SRichard Henderson         nullify_over(ctx);
1858b2167459SRichard Henderson     }
1859b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1860b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1861b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1862b2167459SRichard Henderson     return nullify_end(ctx, ret);
1863b2167459SRichard Henderson }
1864b2167459SRichard Henderson 
1865869051eaSRichard Henderson static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn,
1866b2167459SRichard Henderson                                const DisasInsn *di)
1867b2167459SRichard Henderson {
1868b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1869b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1870b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1871b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
1872b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1873b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1874b2167459SRichard Henderson     bool is_b = false;
1875b2167459SRichard Henderson     bool is_tc = false;
1876b2167459SRichard Henderson     bool is_tsv = false;
1877869051eaSRichard Henderson     DisasJumpType ret;
1878b2167459SRichard Henderson 
1879b2167459SRichard Henderson     switch (ext) {
1880b2167459SRichard Henderson     case 0x10: /* SUB */
1881b2167459SRichard Henderson         break;
1882b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
1883b2167459SRichard Henderson         is_tsv = true;
1884b2167459SRichard Henderson         break;
1885b2167459SRichard Henderson     case 0x14: /* SUB,B */
1886b2167459SRichard Henderson         is_b = true;
1887b2167459SRichard Henderson         break;
1888b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
1889b2167459SRichard Henderson         is_b = is_tsv = true;
1890b2167459SRichard Henderson         break;
1891b2167459SRichard Henderson     case 0x13: /* SUB,TC */
1892b2167459SRichard Henderson         is_tc = true;
1893b2167459SRichard Henderson         break;
1894b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
1895b2167459SRichard Henderson         is_tc = is_tsv = true;
1896b2167459SRichard Henderson         break;
1897b2167459SRichard Henderson     default:
1898b2167459SRichard Henderson         return gen_illegal(ctx);
1899b2167459SRichard Henderson     }
1900b2167459SRichard Henderson 
1901b2167459SRichard Henderson     if (cf) {
1902b2167459SRichard Henderson         nullify_over(ctx);
1903b2167459SRichard Henderson     }
1904b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1905b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1906b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1907b2167459SRichard Henderson     return nullify_end(ctx, ret);
1908b2167459SRichard Henderson }
1909b2167459SRichard Henderson 
1910869051eaSRichard Henderson static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn,
1911b2167459SRichard Henderson                                const DisasInsn *di)
1912b2167459SRichard Henderson {
1913b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1914b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1915b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1916b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1917b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1918869051eaSRichard Henderson     DisasJumpType ret;
1919b2167459SRichard Henderson 
1920b2167459SRichard Henderson     if (cf) {
1921b2167459SRichard Henderson         nullify_over(ctx);
1922b2167459SRichard Henderson     }
1923b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1924b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1925eff235ebSPaolo Bonzini     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1926b2167459SRichard Henderson     return nullify_end(ctx, ret);
1927b2167459SRichard Henderson }
1928b2167459SRichard Henderson 
1929b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1930869051eaSRichard Henderson static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn,
1931b2167459SRichard Henderson                                 const DisasInsn *di)
1932b2167459SRichard Henderson {
1933b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1934b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1935b2167459SRichard Henderson 
1936b2167459SRichard Henderson     if (r1 == 0) {
1937b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1938b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1939b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1940b2167459SRichard Henderson     } else {
1941b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1942b2167459SRichard Henderson     }
1943b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1944869051eaSRichard Henderson     return DISAS_NEXT;
1945b2167459SRichard Henderson }
1946b2167459SRichard Henderson 
1947869051eaSRichard Henderson static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn,
1948b2167459SRichard Henderson                                   const DisasInsn *di)
1949b2167459SRichard Henderson {
1950b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1951b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1952b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1953b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1954b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1955869051eaSRichard Henderson     DisasJumpType ret;
1956b2167459SRichard Henderson 
1957b2167459SRichard Henderson     if (cf) {
1958b2167459SRichard Henderson         nullify_over(ctx);
1959b2167459SRichard Henderson     }
1960b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1961b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1962b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1963b2167459SRichard Henderson     return nullify_end(ctx, ret);
1964b2167459SRichard Henderson }
1965b2167459SRichard Henderson 
1966869051eaSRichard Henderson static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn,
1967b2167459SRichard Henderson                                 const DisasInsn *di)
1968b2167459SRichard Henderson {
1969b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1970b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1971b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1972b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1973b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1974869051eaSRichard Henderson     DisasJumpType ret;
1975b2167459SRichard Henderson 
1976b2167459SRichard Henderson     if (cf) {
1977b2167459SRichard Henderson         nullify_over(ctx);
1978b2167459SRichard Henderson     }
1979b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1980b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1981b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1982b2167459SRichard Henderson     return nullify_end(ctx, ret);
1983b2167459SRichard Henderson }
1984b2167459SRichard Henderson 
1985869051eaSRichard Henderson static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn,
1986b2167459SRichard Henderson                                   const DisasInsn *di)
1987b2167459SRichard Henderson {
1988b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1989b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1990b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1991b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
1992b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1993b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
1994869051eaSRichard Henderson     DisasJumpType ret;
1995b2167459SRichard Henderson 
1996b2167459SRichard Henderson     if (cf) {
1997b2167459SRichard Henderson         nullify_over(ctx);
1998b2167459SRichard Henderson     }
1999b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
2000b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2001b2167459SRichard Henderson     tmp = get_temp(ctx);
2002b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
2003b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
2004b2167459SRichard Henderson     return nullify_end(ctx, ret);
2005b2167459SRichard Henderson }
2006b2167459SRichard Henderson 
2007869051eaSRichard Henderson static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn,
2008b2167459SRichard Henderson                                 const DisasInsn *di)
2009b2167459SRichard Henderson {
2010b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2011b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2012b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
2013b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2014b2167459SRichard Henderson     TCGv tmp;
2015869051eaSRichard Henderson     DisasJumpType ret;
2016b2167459SRichard Henderson 
2017b2167459SRichard Henderson     nullify_over(ctx);
2018b2167459SRichard Henderson 
2019b2167459SRichard Henderson     tmp = get_temp(ctx);
2020b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2021b2167459SRichard Henderson     if (!is_i) {
2022b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
2023b2167459SRichard Henderson     }
2024b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2025b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
2026b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2027b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2028b2167459SRichard Henderson 
2029b2167459SRichard Henderson     return nullify_end(ctx, ret);
2030b2167459SRichard Henderson }
2031b2167459SRichard Henderson 
2032869051eaSRichard Henderson static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn,
2033b2167459SRichard Henderson                               const DisasInsn *di)
2034b2167459SRichard Henderson {
2035b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2036b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
2037b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2038b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2039b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
2040b2167459SRichard Henderson 
2041b2167459SRichard Henderson     nullify_over(ctx);
2042b2167459SRichard Henderson 
2043b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
2044b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
2045b2167459SRichard Henderson 
2046b2167459SRichard Henderson     add1 = tcg_temp_new();
2047b2167459SRichard Henderson     add2 = tcg_temp_new();
2048b2167459SRichard Henderson     addc = tcg_temp_new();
2049b2167459SRichard Henderson     dest = tcg_temp_new();
2050b2167459SRichard Henderson     zero = tcg_const_tl(0);
2051b2167459SRichard Henderson 
2052b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
2053b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
2054b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2055b2167459SRichard Henderson 
2056b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
2057b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
2058b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
2059b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
2060b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2061b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
2062b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
2063b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
2064b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2065b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2066b2167459SRichard Henderson 
2067b2167459SRichard Henderson     tcg_temp_free(addc);
2068b2167459SRichard Henderson     tcg_temp_free(zero);
2069b2167459SRichard Henderson 
2070b2167459SRichard Henderson     /* Write back the result register.  */
2071b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
2072b2167459SRichard Henderson 
2073b2167459SRichard Henderson     /* Write back PSW[CB].  */
2074b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2075b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2076b2167459SRichard Henderson 
2077b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
2078b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2079b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2080b2167459SRichard Henderson 
2081b2167459SRichard Henderson     /* Install the new nullification.  */
2082b2167459SRichard Henderson     if (cf) {
2083b2167459SRichard Henderson         TCGv sv;
2084b2167459SRichard Henderson         TCGV_UNUSED(sv);
2085b2167459SRichard Henderson         if (cf >> 1 == 6) {
2086b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2087b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2088b2167459SRichard Henderson         }
2089b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2090b2167459SRichard Henderson     }
2091b2167459SRichard Henderson 
2092b2167459SRichard Henderson     tcg_temp_free(add1);
2093b2167459SRichard Henderson     tcg_temp_free(add2);
2094b2167459SRichard Henderson     tcg_temp_free(dest);
2095b2167459SRichard Henderson 
2096869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
2097b2167459SRichard Henderson }
2098b2167459SRichard Henderson 
2099b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
2100b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
2101b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2102eff235ebSPaolo Bonzini     { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2103eff235ebSPaolo Bonzini     { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2104eff235ebSPaolo Bonzini     { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2105eff235ebSPaolo Bonzini     { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2106b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2107b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
2108b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2109b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2110b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
2111b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2112b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2113b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2114b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2115b2167459SRichard Henderson };
2116b2167459SRichard Henderson 
2117869051eaSRichard Henderson static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn)
2118b2167459SRichard Henderson {
2119b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2120b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2121b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2122b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2123b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2124b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
2125b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2126869051eaSRichard Henderson     DisasJumpType ret;
2127b2167459SRichard Henderson 
2128b2167459SRichard Henderson     if (cf) {
2129b2167459SRichard Henderson         nullify_over(ctx);
2130b2167459SRichard Henderson     }
2131b2167459SRichard Henderson 
2132b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2133b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2134b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2135b2167459SRichard Henderson 
2136b2167459SRichard Henderson     return nullify_end(ctx, ret);
2137b2167459SRichard Henderson }
2138b2167459SRichard Henderson 
2139869051eaSRichard Henderson static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn)
2140b2167459SRichard Henderson {
2141b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2142b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2143b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2144b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2145b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2146b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2147869051eaSRichard Henderson     DisasJumpType ret;
2148b2167459SRichard Henderson 
2149b2167459SRichard Henderson     if (cf) {
2150b2167459SRichard Henderson         nullify_over(ctx);
2151b2167459SRichard Henderson     }
2152b2167459SRichard Henderson 
2153b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2154b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2155b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2156b2167459SRichard Henderson 
2157b2167459SRichard Henderson     return nullify_end(ctx, ret);
2158b2167459SRichard Henderson }
2159b2167459SRichard Henderson 
2160869051eaSRichard Henderson static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2161b2167459SRichard Henderson {
2162b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2163b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2164b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2165b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2166b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2167869051eaSRichard Henderson     DisasJumpType ret;
2168b2167459SRichard Henderson 
2169b2167459SRichard Henderson     if (cf) {
2170b2167459SRichard Henderson         nullify_over(ctx);
2171b2167459SRichard Henderson     }
2172b2167459SRichard Henderson 
2173b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2174b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2175b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2176b2167459SRichard Henderson 
2177b2167459SRichard Henderson     return nullify_end(ctx, ret);
2178b2167459SRichard Henderson }
2179b2167459SRichard Henderson 
2180869051eaSRichard Henderson static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
218196d6407fSRichard Henderson                                     const DisasInsn *di)
218296d6407fSRichard Henderson {
218396d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
218496d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
218596d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
218696d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
218796d6407fSRichard Henderson     int disp = low_sextract(insn, 16, 5);
218896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
218996d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
219096d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
219196d6407fSRichard Henderson 
219296d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
219396d6407fSRichard Henderson }
219496d6407fSRichard Henderson 
2195869051eaSRichard Henderson static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
219696d6407fSRichard Henderson                                     const DisasInsn *di)
219796d6407fSRichard Henderson {
219896d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
219996d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
220096d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
220196d6407fSRichard Henderson     unsigned u = extract32(insn, 13, 1);
220296d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
220396d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
220496d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
220596d6407fSRichard Henderson 
220696d6407fSRichard Henderson     return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
220796d6407fSRichard Henderson }
220896d6407fSRichard Henderson 
2209869051eaSRichard Henderson static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn,
221096d6407fSRichard Henderson                                     const DisasInsn *di)
221196d6407fSRichard Henderson {
221296d6407fSRichard Henderson     int disp = low_sextract(insn, 0, 5);
221396d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
221496d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
221596d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
221696d6407fSRichard Henderson     unsigned rr = extract32(insn, 16, 5);
221796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
221896d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
221996d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
222096d6407fSRichard Henderson 
222196d6407fSRichard Henderson     return do_store(ctx, rr, rb, disp, modify, mop);
222296d6407fSRichard Henderson }
222396d6407fSRichard Henderson 
2224869051eaSRichard Henderson static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn,
222596d6407fSRichard Henderson                                 const DisasInsn *di)
222696d6407fSRichard Henderson {
222796d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
222896d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
222996d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
223096d6407fSRichard Henderson     unsigned au = extract32(insn, 13, 1);
223196d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
223296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
223396d6407fSRichard Henderson     TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
223496d6407fSRichard Henderson     TCGv zero, addr, base, dest;
223596d6407fSRichard Henderson     int modify, disp = 0, scale = 0;
223696d6407fSRichard Henderson 
223796d6407fSRichard Henderson     nullify_over(ctx);
223896d6407fSRichard Henderson 
223996d6407fSRichard Henderson     /* ??? Share more code with do_load and do_load_{32,64}.  */
224096d6407fSRichard Henderson 
224196d6407fSRichard Henderson     if (i) {
224296d6407fSRichard Henderson         modify = (m ? (au ? -1 : 1) : 0);
224396d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
224496d6407fSRichard Henderson         rx = 0;
224596d6407fSRichard Henderson     } else {
224696d6407fSRichard Henderson         modify = m;
224796d6407fSRichard Henderson         if (au) {
224896d6407fSRichard Henderson             scale = mop & MO_SIZE;
224996d6407fSRichard Henderson         }
225096d6407fSRichard Henderson     }
225196d6407fSRichard Henderson     if (modify) {
225296d6407fSRichard Henderson         /* Base register modification.  Make sure if RT == RB, we see
225396d6407fSRichard Henderson            the result of the load.  */
225496d6407fSRichard Henderson         dest = get_temp(ctx);
225596d6407fSRichard Henderson     } else {
225696d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
225796d6407fSRichard Henderson     }
225896d6407fSRichard Henderson 
225996d6407fSRichard Henderson     addr = tcg_temp_new();
226096d6407fSRichard Henderson     base = load_gpr(ctx, rb);
226196d6407fSRichard Henderson     if (rx) {
226296d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
226396d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
226496d6407fSRichard Henderson     } else {
226596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
226696d6407fSRichard Henderson     }
226796d6407fSRichard Henderson 
226896d6407fSRichard Henderson     zero = tcg_const_tl(0);
226996d6407fSRichard Henderson     tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
227096d6407fSRichard Henderson                            zero, MMU_USER_IDX, mop);
227196d6407fSRichard Henderson     if (modify) {
227296d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
227396d6407fSRichard Henderson     }
227496d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
227596d6407fSRichard Henderson 
2276869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
227796d6407fSRichard Henderson }
227896d6407fSRichard Henderson 
2279869051eaSRichard Henderson static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn,
228096d6407fSRichard Henderson                                 const DisasInsn *di)
228196d6407fSRichard Henderson {
228296d6407fSRichard Henderson     target_long disp = low_sextract(insn, 0, 5);
228396d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
228496d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
228596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
228696d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
228796d6407fSRichard Henderson     TCGv addr, val;
228896d6407fSRichard Henderson 
228996d6407fSRichard Henderson     nullify_over(ctx);
229096d6407fSRichard Henderson 
229196d6407fSRichard Henderson     addr = tcg_temp_new();
229296d6407fSRichard Henderson     if (m || disp == 0) {
229396d6407fSRichard Henderson         tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
229496d6407fSRichard Henderson     } else {
229596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
229696d6407fSRichard Henderson     }
229796d6407fSRichard Henderson     val = load_gpr(ctx, rt);
229896d6407fSRichard Henderson 
229996d6407fSRichard Henderson     if (a) {
230096d6407fSRichard Henderson         gen_helper_stby_e(cpu_env, addr, val);
230196d6407fSRichard Henderson     } else {
230296d6407fSRichard Henderson         gen_helper_stby_b(cpu_env, addr, val);
230396d6407fSRichard Henderson     }
230496d6407fSRichard Henderson 
230596d6407fSRichard Henderson     if (m) {
230696d6407fSRichard Henderson         tcg_gen_addi_tl(addr, addr, disp);
230796d6407fSRichard Henderson         tcg_gen_andi_tl(addr, addr, ~3);
230896d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
230996d6407fSRichard Henderson     }
231096d6407fSRichard Henderson     tcg_temp_free(addr);
231196d6407fSRichard Henderson 
2312869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
231396d6407fSRichard Henderson }
231496d6407fSRichard Henderson 
231596d6407fSRichard Henderson static const DisasInsn table_index_mem[] = {
231696d6407fSRichard Henderson     { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
231796d6407fSRichard Henderson     { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
231896d6407fSRichard Henderson     { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
231996d6407fSRichard Henderson     { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
232096d6407fSRichard Henderson     { 0x0c001300u, 0xfc0013c0, trans_stby },
232196d6407fSRichard Henderson };
232296d6407fSRichard Henderson 
2323869051eaSRichard Henderson static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn)
2324b2167459SRichard Henderson {
2325b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2326b2167459SRichard Henderson     target_long i = assemble_21(insn);
2327b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2328b2167459SRichard Henderson 
2329b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
2330b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2331b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2332b2167459SRichard Henderson 
2333869051eaSRichard Henderson     return DISAS_NEXT;
2334b2167459SRichard Henderson }
2335b2167459SRichard Henderson 
2336869051eaSRichard Henderson static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn)
2337b2167459SRichard Henderson {
2338b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2339b2167459SRichard Henderson     target_long i = assemble_21(insn);
2340b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
2341b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
2342b2167459SRichard Henderson 
2343b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2344b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2345b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2346b2167459SRichard Henderson 
2347869051eaSRichard Henderson     return DISAS_NEXT;
2348b2167459SRichard Henderson }
2349b2167459SRichard Henderson 
2350869051eaSRichard Henderson static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn)
2351b2167459SRichard Henderson {
2352b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
2353b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2354b2167459SRichard Henderson     target_long i = assemble_16(insn);
2355b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2356b2167459SRichard Henderson 
2357b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2358b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2359b2167459SRichard Henderson     if (rb == 0) {
2360b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
2361b2167459SRichard Henderson     } else {
2362b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2363b2167459SRichard Henderson     }
2364b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2365b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2366b2167459SRichard Henderson 
2367869051eaSRichard Henderson     return DISAS_NEXT;
2368b2167459SRichard Henderson }
2369b2167459SRichard Henderson 
2370869051eaSRichard Henderson static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn,
237196d6407fSRichard Henderson                                 bool is_mod, TCGMemOp mop)
237296d6407fSRichard Henderson {
237396d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
237496d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
237596d6407fSRichard Henderson     target_long i = assemble_16(insn);
237696d6407fSRichard Henderson 
237796d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
237896d6407fSRichard Henderson }
237996d6407fSRichard Henderson 
2380869051eaSRichard Henderson static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn)
238196d6407fSRichard Henderson {
238296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
238396d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
238496d6407fSRichard Henderson     target_long i = assemble_16a(insn);
238596d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
238696d6407fSRichard Henderson 
238796d6407fSRichard Henderson     switch (ext2) {
238896d6407fSRichard Henderson     case 0:
238996d6407fSRichard Henderson     case 1:
239096d6407fSRichard Henderson         /* FLDW without modification.  */
239196d6407fSRichard Henderson         return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
239296d6407fSRichard Henderson     case 2:
239396d6407fSRichard Henderson         /* LDW with modification.  Note that the sign of I selects
239496d6407fSRichard Henderson            post-dec vs pre-inc.  */
239596d6407fSRichard Henderson         return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
239696d6407fSRichard Henderson     default:
239796d6407fSRichard Henderson         return gen_illegal(ctx);
239896d6407fSRichard Henderson     }
239996d6407fSRichard Henderson }
240096d6407fSRichard Henderson 
2401869051eaSRichard Henderson static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn)
240296d6407fSRichard Henderson {
240396d6407fSRichard Henderson     target_long i = assemble_16a(insn);
240496d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
240596d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
240696d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
240796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
240896d6407fSRichard Henderson 
240996d6407fSRichard Henderson     /* FLDW with modification.  */
241096d6407fSRichard Henderson     return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
241196d6407fSRichard Henderson }
241296d6407fSRichard Henderson 
2413869051eaSRichard Henderson static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn,
241496d6407fSRichard Henderson                                  bool is_mod, TCGMemOp mop)
241596d6407fSRichard Henderson {
241696d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
241796d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
241896d6407fSRichard Henderson     target_long i = assemble_16(insn);
241996d6407fSRichard Henderson 
242096d6407fSRichard Henderson     return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
242196d6407fSRichard Henderson }
242296d6407fSRichard Henderson 
2423869051eaSRichard Henderson static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn)
242496d6407fSRichard Henderson {
242596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
242696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
242796d6407fSRichard Henderson     target_long i = assemble_16a(insn);
242896d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
242996d6407fSRichard Henderson 
243096d6407fSRichard Henderson     switch (ext2) {
243196d6407fSRichard Henderson     case 0:
243296d6407fSRichard Henderson     case 1:
243396d6407fSRichard Henderson         /* FSTW without modification.  */
243496d6407fSRichard Henderson         return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
243596d6407fSRichard Henderson     case 2:
243696d6407fSRichard Henderson         /* LDW with modification.  */
243796d6407fSRichard Henderson         return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
243896d6407fSRichard Henderson     default:
243996d6407fSRichard Henderson         return gen_illegal(ctx);
244096d6407fSRichard Henderson     }
244196d6407fSRichard Henderson }
244296d6407fSRichard Henderson 
2443869051eaSRichard Henderson static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn)
244496d6407fSRichard Henderson {
244596d6407fSRichard Henderson     target_long i = assemble_16a(insn);
244696d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
244796d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
244896d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
244996d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
245096d6407fSRichard Henderson 
245196d6407fSRichard Henderson     /* FSTW with modification.  */
245296d6407fSRichard Henderson     return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
245396d6407fSRichard Henderson }
245496d6407fSRichard Henderson 
2455869051eaSRichard Henderson static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn)
245696d6407fSRichard Henderson {
245796d6407fSRichard Henderson     unsigned t0 = extract32(insn, 0, 5);
245896d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
245996d6407fSRichard Henderson     unsigned t1 = extract32(insn, 6, 1);
246096d6407fSRichard Henderson     unsigned ext3 = extract32(insn, 7, 3);
246196d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
246296d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
246396d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
246496d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
246596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
246696d6407fSRichard Henderson     unsigned rt = t1 * 32 + t0;
246796d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
246896d6407fSRichard Henderson     int disp, scale;
246996d6407fSRichard Henderson 
247096d6407fSRichard Henderson     if (i == 0) {
247196d6407fSRichard Henderson         scale = (ua ? 2 : 0);
247296d6407fSRichard Henderson         disp = 0;
247396d6407fSRichard Henderson         modify = m;
247496d6407fSRichard Henderson     } else {
247596d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
247696d6407fSRichard Henderson         scale = 0;
247796d6407fSRichard Henderson         rx = 0;
247896d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
247996d6407fSRichard Henderson     }
248096d6407fSRichard Henderson 
248196d6407fSRichard Henderson     switch (ext3) {
248296d6407fSRichard Henderson     case 0: /* FLDW */
248396d6407fSRichard Henderson         return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
248496d6407fSRichard Henderson     case 4: /* FSTW */
248596d6407fSRichard Henderson         return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
248696d6407fSRichard Henderson     }
248796d6407fSRichard Henderson     return gen_illegal(ctx);
248896d6407fSRichard Henderson }
248996d6407fSRichard Henderson 
2490869051eaSRichard Henderson static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn)
249196d6407fSRichard Henderson {
249296d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
249396d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
249496d6407fSRichard Henderson     unsigned ext4 = extract32(insn, 6, 4);
249596d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
249696d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
249796d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
249896d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
249996d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
250096d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
250196d6407fSRichard Henderson     int disp, scale;
250296d6407fSRichard Henderson 
250396d6407fSRichard Henderson     if (i == 0) {
250496d6407fSRichard Henderson         scale = (ua ? 3 : 0);
250596d6407fSRichard Henderson         disp = 0;
250696d6407fSRichard Henderson         modify = m;
250796d6407fSRichard Henderson     } else {
250896d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
250996d6407fSRichard Henderson         scale = 0;
251096d6407fSRichard Henderson         rx = 0;
251196d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
251296d6407fSRichard Henderson     }
251396d6407fSRichard Henderson 
251496d6407fSRichard Henderson     switch (ext4) {
251596d6407fSRichard Henderson     case 0: /* FLDD */
251696d6407fSRichard Henderson         return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
251796d6407fSRichard Henderson     case 8: /* FSTD */
251896d6407fSRichard Henderson         return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
251996d6407fSRichard Henderson     default:
252096d6407fSRichard Henderson         return gen_illegal(ctx);
252196d6407fSRichard Henderson     }
252296d6407fSRichard Henderson }
252396d6407fSRichard Henderson 
2524869051eaSRichard Henderson static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn,
252598cd9ca7SRichard Henderson                                 bool is_true, bool is_imm, bool is_dw)
252698cd9ca7SRichard Henderson {
252798cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
252898cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
252998cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
253098cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
253198cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
253298cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv;
253398cd9ca7SRichard Henderson     DisasCond cond;
253498cd9ca7SRichard Henderson 
253598cd9ca7SRichard Henderson     nullify_over(ctx);
253698cd9ca7SRichard Henderson 
253798cd9ca7SRichard Henderson     if (is_imm) {
253898cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
253998cd9ca7SRichard Henderson     } else {
254098cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
254198cd9ca7SRichard Henderson     }
254298cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
254398cd9ca7SRichard Henderson     dest = get_temp(ctx);
254498cd9ca7SRichard Henderson 
254598cd9ca7SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
254698cd9ca7SRichard Henderson 
254798cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
254898cd9ca7SRichard Henderson     if (c == 6) {
254998cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
255098cd9ca7SRichard Henderson     }
255198cd9ca7SRichard Henderson 
255298cd9ca7SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
255398cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
255498cd9ca7SRichard Henderson }
255598cd9ca7SRichard Henderson 
2556869051eaSRichard Henderson static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn,
255798cd9ca7SRichard Henderson                                 bool is_true, bool is_imm)
255898cd9ca7SRichard Henderson {
255998cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
256098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
256198cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
256298cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
256398cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
256498cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv, cb_msb;
256598cd9ca7SRichard Henderson     DisasCond cond;
256698cd9ca7SRichard Henderson 
256798cd9ca7SRichard Henderson     nullify_over(ctx);
256898cd9ca7SRichard Henderson 
256998cd9ca7SRichard Henderson     if (is_imm) {
257098cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
257198cd9ca7SRichard Henderson     } else {
257298cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
257398cd9ca7SRichard Henderson     }
257498cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
257598cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
257698cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
257798cd9ca7SRichard Henderson     TCGV_UNUSED(cb_msb);
257898cd9ca7SRichard Henderson 
257998cd9ca7SRichard Henderson     switch (c) {
258098cd9ca7SRichard Henderson     default:
258198cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
258298cd9ca7SRichard Henderson         break;
258398cd9ca7SRichard Henderson     case 4: case 5:
258498cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
258598cd9ca7SRichard Henderson         tcg_gen_movi_tl(cb_msb, 0);
258698cd9ca7SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
258798cd9ca7SRichard Henderson         break;
258898cd9ca7SRichard Henderson     case 6:
258998cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
259098cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
259198cd9ca7SRichard Henderson         break;
259298cd9ca7SRichard Henderson     }
259398cd9ca7SRichard Henderson 
259498cd9ca7SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
259598cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
259698cd9ca7SRichard Henderson }
259798cd9ca7SRichard Henderson 
2598869051eaSRichard Henderson static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn)
259998cd9ca7SRichard Henderson {
260098cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
260198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
260298cd9ca7SRichard Henderson     unsigned c = extract32(insn, 15, 1);
260398cd9ca7SRichard Henderson     unsigned r = extract32(insn, 16, 5);
260498cd9ca7SRichard Henderson     unsigned p = extract32(insn, 21, 5);
260598cd9ca7SRichard Henderson     unsigned i = extract32(insn, 26, 1);
260698cd9ca7SRichard Henderson     TCGv tmp, tcg_r;
260798cd9ca7SRichard Henderson     DisasCond cond;
260898cd9ca7SRichard Henderson 
260998cd9ca7SRichard Henderson     nullify_over(ctx);
261098cd9ca7SRichard Henderson 
261198cd9ca7SRichard Henderson     tmp = tcg_temp_new();
261298cd9ca7SRichard Henderson     tcg_r = load_gpr(ctx, r);
261398cd9ca7SRichard Henderson     if (i) {
261498cd9ca7SRichard Henderson         tcg_gen_shli_tl(tmp, tcg_r, p);
261598cd9ca7SRichard Henderson     } else {
261698cd9ca7SRichard Henderson         tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
261798cd9ca7SRichard Henderson     }
261898cd9ca7SRichard Henderson 
261998cd9ca7SRichard Henderson     cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
262098cd9ca7SRichard Henderson     tcg_temp_free(tmp);
262198cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
262298cd9ca7SRichard Henderson }
262398cd9ca7SRichard Henderson 
2624869051eaSRichard Henderson static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
262598cd9ca7SRichard Henderson {
262698cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
262798cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
262898cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
262998cd9ca7SRichard Henderson     unsigned t = extract32(insn, 16, 5);
263098cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
263198cd9ca7SRichard Henderson     TCGv dest;
263298cd9ca7SRichard Henderson     DisasCond cond;
263398cd9ca7SRichard Henderson 
263498cd9ca7SRichard Henderson     nullify_over(ctx);
263598cd9ca7SRichard Henderson 
263698cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
263798cd9ca7SRichard Henderson     if (is_imm) {
263898cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
263998cd9ca7SRichard Henderson     } else if (t == 0) {
264098cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, 0);
264198cd9ca7SRichard Henderson     } else {
264298cd9ca7SRichard Henderson         tcg_gen_mov_tl(dest, cpu_gr[t]);
264398cd9ca7SRichard Henderson     }
264498cd9ca7SRichard Henderson 
264598cd9ca7SRichard Henderson     cond = do_sed_cond(c, dest);
264698cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
264798cd9ca7SRichard Henderson }
264898cd9ca7SRichard Henderson 
2649869051eaSRichard Henderson static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
26500b1347d2SRichard Henderson                                     const DisasInsn *di)
26510b1347d2SRichard Henderson {
26520b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
26530b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26540b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
26550b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
26560b1347d2SRichard Henderson     TCGv dest;
26570b1347d2SRichard Henderson 
26580b1347d2SRichard Henderson     if (c) {
26590b1347d2SRichard Henderson         nullify_over(ctx);
26600b1347d2SRichard Henderson     }
26610b1347d2SRichard Henderson 
26620b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26630b1347d2SRichard Henderson     if (r1 == 0) {
26640b1347d2SRichard Henderson         tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
26650b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, dest, cpu_sar);
26660b1347d2SRichard Henderson     } else if (r1 == r2) {
26670b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
26680b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
26690b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
26700b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
26710b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
26720b1347d2SRichard Henderson     } else {
26730b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
26740b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
26750b1347d2SRichard Henderson 
26760b1347d2SRichard Henderson         tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
26770b1347d2SRichard Henderson         tcg_gen_extu_tl_i64(s, cpu_sar);
26780b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
26790b1347d2SRichard Henderson         tcg_gen_trunc_i64_tl(dest, t);
26800b1347d2SRichard Henderson 
26810b1347d2SRichard Henderson         tcg_temp_free_i64(t);
26820b1347d2SRichard Henderson         tcg_temp_free_i64(s);
26830b1347d2SRichard Henderson     }
26840b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26850b1347d2SRichard Henderson 
26860b1347d2SRichard Henderson     /* Install the new nullification.  */
26870b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
26880b1347d2SRichard Henderson     if (c) {
26890b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
26900b1347d2SRichard Henderson     }
2691869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
26920b1347d2SRichard Henderson }
26930b1347d2SRichard Henderson 
2694869051eaSRichard Henderson static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
26950b1347d2SRichard Henderson                                      const DisasInsn *di)
26960b1347d2SRichard Henderson {
26970b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
26980b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
26990b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27000b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
27010b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
27020b1347d2SRichard Henderson     unsigned sa = 31 - cpos;
27030b1347d2SRichard Henderson     TCGv dest, t2;
27040b1347d2SRichard Henderson 
27050b1347d2SRichard Henderson     if (c) {
27060b1347d2SRichard Henderson         nullify_over(ctx);
27070b1347d2SRichard Henderson     }
27080b1347d2SRichard Henderson 
27090b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27100b1347d2SRichard Henderson     t2 = load_gpr(ctx, r2);
27110b1347d2SRichard Henderson     if (r1 == r2) {
27120b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
27130b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, t2);
27140b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
27150b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
27160b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
27170b1347d2SRichard Henderson     } else if (r1 == 0) {
27180b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
27190b1347d2SRichard Henderson     } else {
27200b1347d2SRichard Henderson         TCGv t0 = tcg_temp_new();
27210b1347d2SRichard Henderson         tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
27220b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
27230b1347d2SRichard Henderson         tcg_temp_free(t0);
27240b1347d2SRichard Henderson     }
27250b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27260b1347d2SRichard Henderson 
27270b1347d2SRichard Henderson     /* Install the new nullification.  */
27280b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27290b1347d2SRichard Henderson     if (c) {
27300b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27310b1347d2SRichard Henderson     }
2732869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
27330b1347d2SRichard Henderson }
27340b1347d2SRichard Henderson 
2735869051eaSRichard Henderson static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn,
27360b1347d2SRichard Henderson                                      const DisasInsn *di)
27370b1347d2SRichard Henderson {
27380b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27390b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27400b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27410b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27420b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27430b1347d2SRichard Henderson     unsigned len = 32 - clen;
27440b1347d2SRichard Henderson     TCGv dest, src, tmp;
27450b1347d2SRichard Henderson 
27460b1347d2SRichard Henderson     if (c) {
27470b1347d2SRichard Henderson         nullify_over(ctx);
27480b1347d2SRichard Henderson     }
27490b1347d2SRichard Henderson 
27500b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27510b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
27520b1347d2SRichard Henderson     tmp = tcg_temp_new();
27530b1347d2SRichard Henderson 
27540b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
27550b1347d2SRichard Henderson     tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
27560b1347d2SRichard Henderson     if (is_se) {
27570b1347d2SRichard Henderson         tcg_gen_sar_tl(dest, src, tmp);
27580b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, dest, 0, len);
27590b1347d2SRichard Henderson     } else {
27600b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, src, tmp);
27610b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, dest, 0, len);
27620b1347d2SRichard Henderson     }
27630b1347d2SRichard Henderson     tcg_temp_free(tmp);
27640b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27650b1347d2SRichard Henderson 
27660b1347d2SRichard Henderson     /* Install the new nullification.  */
27670b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27680b1347d2SRichard Henderson     if (c) {
27690b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27700b1347d2SRichard Henderson     }
2771869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
27720b1347d2SRichard Henderson }
27730b1347d2SRichard Henderson 
2774869051eaSRichard Henderson static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn,
27750b1347d2SRichard Henderson                                      const DisasInsn *di)
27760b1347d2SRichard Henderson {
27770b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27780b1347d2SRichard Henderson     unsigned pos = extract32(insn, 5, 5);
27790b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27800b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27810b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27820b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27830b1347d2SRichard Henderson     unsigned len = 32 - clen;
27840b1347d2SRichard Henderson     unsigned cpos = 31 - pos;
27850b1347d2SRichard Henderson     TCGv dest, src;
27860b1347d2SRichard Henderson 
27870b1347d2SRichard Henderson     if (c) {
27880b1347d2SRichard Henderson         nullify_over(ctx);
27890b1347d2SRichard Henderson     }
27900b1347d2SRichard Henderson 
27910b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27920b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
27930b1347d2SRichard Henderson     if (is_se) {
27940b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, src, cpos, len);
27950b1347d2SRichard Henderson     } else {
27960b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, src, cpos, len);
27970b1347d2SRichard Henderson     }
27980b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27990b1347d2SRichard Henderson 
28000b1347d2SRichard Henderson     /* Install the new nullification.  */
28010b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28020b1347d2SRichard Henderson     if (c) {
28030b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28040b1347d2SRichard Henderson     }
2805869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28060b1347d2SRichard Henderson }
28070b1347d2SRichard Henderson 
28080b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = {
28090b1347d2SRichard Henderson     { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
28100b1347d2SRichard Henderson     { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
28110b1347d2SRichard Henderson     { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
28120b1347d2SRichard Henderson     { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
28130b1347d2SRichard Henderson };
28140b1347d2SRichard Henderson 
2815869051eaSRichard Henderson static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
28160b1347d2SRichard Henderson                                       const DisasInsn *di)
28170b1347d2SRichard Henderson {
28180b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28190b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28200b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28210b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28220b1347d2SRichard Henderson     target_long val = low_sextract(insn, 16, 5);
28230b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28240b1347d2SRichard Henderson     unsigned len = 32 - clen;
28250b1347d2SRichard Henderson     target_long mask0, mask1;
28260b1347d2SRichard Henderson     TCGv dest;
28270b1347d2SRichard Henderson 
28280b1347d2SRichard Henderson     if (c) {
28290b1347d2SRichard Henderson         nullify_over(ctx);
28300b1347d2SRichard Henderson     }
28310b1347d2SRichard Henderson     if (cpos + len > 32) {
28320b1347d2SRichard Henderson         len = 32 - cpos;
28330b1347d2SRichard Henderson     }
28340b1347d2SRichard Henderson 
28350b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28360b1347d2SRichard Henderson     mask0 = deposit64(0, cpos, len, val);
28370b1347d2SRichard Henderson     mask1 = deposit64(-1, cpos, len, val);
28380b1347d2SRichard Henderson 
28390b1347d2SRichard Henderson     if (nz) {
28400b1347d2SRichard Henderson         TCGv src = load_gpr(ctx, rt);
28410b1347d2SRichard Henderson         if (mask1 != -1) {
28420b1347d2SRichard Henderson             tcg_gen_andi_tl(dest, src, mask1);
28430b1347d2SRichard Henderson             src = dest;
28440b1347d2SRichard Henderson         }
28450b1347d2SRichard Henderson         tcg_gen_ori_tl(dest, src, mask0);
28460b1347d2SRichard Henderson     } else {
28470b1347d2SRichard Henderson         tcg_gen_movi_tl(dest, mask0);
28480b1347d2SRichard Henderson     }
28490b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28500b1347d2SRichard Henderson 
28510b1347d2SRichard Henderson     /* Install the new nullification.  */
28520b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28530b1347d2SRichard Henderson     if (c) {
28540b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28550b1347d2SRichard Henderson     }
2856869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28570b1347d2SRichard Henderson }
28580b1347d2SRichard Henderson 
2859869051eaSRichard Henderson static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn,
28600b1347d2SRichard Henderson                                     const DisasInsn *di)
28610b1347d2SRichard Henderson {
28620b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28630b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28640b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28650b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28660b1347d2SRichard Henderson     unsigned rr = extract32(insn, 16, 5);
28670b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28680b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
28690b1347d2SRichard Henderson     unsigned len = 32 - clen;
28700b1347d2SRichard Henderson     TCGv dest, val;
28710b1347d2SRichard Henderson 
28720b1347d2SRichard Henderson     if (c) {
28730b1347d2SRichard Henderson         nullify_over(ctx);
28740b1347d2SRichard Henderson     }
28750b1347d2SRichard Henderson     if (cpos + len > 32) {
28760b1347d2SRichard Henderson         len = 32 - cpos;
28770b1347d2SRichard Henderson     }
28780b1347d2SRichard Henderson 
28790b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28800b1347d2SRichard Henderson     val = load_gpr(ctx, rr);
28810b1347d2SRichard Henderson     if (rs == 0) {
28820b1347d2SRichard Henderson         tcg_gen_deposit_z_tl(dest, val, cpos, len);
28830b1347d2SRichard Henderson     } else {
28840b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
28850b1347d2SRichard Henderson     }
28860b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28870b1347d2SRichard Henderson 
28880b1347d2SRichard Henderson     /* Install the new nullification.  */
28890b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28900b1347d2SRichard Henderson     if (c) {
28910b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28920b1347d2SRichard Henderson     }
2893869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
28940b1347d2SRichard Henderson }
28950b1347d2SRichard Henderson 
2896869051eaSRichard Henderson static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn,
28970b1347d2SRichard Henderson                                     const DisasInsn *di)
28980b1347d2SRichard Henderson {
28990b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
29000b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
29010b1347d2SRichard Henderson     unsigned i = extract32(insn, 12, 1);
29020b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
29030b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
29040b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
29050b1347d2SRichard Henderson     unsigned len = 32 - clen;
29060b1347d2SRichard Henderson     TCGv val, mask, tmp, shift, dest;
29070b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
29080b1347d2SRichard Henderson 
29090b1347d2SRichard Henderson     if (c) {
29100b1347d2SRichard Henderson         nullify_over(ctx);
29110b1347d2SRichard Henderson     }
29120b1347d2SRichard Henderson 
29130b1347d2SRichard Henderson     if (i) {
29140b1347d2SRichard Henderson         val = load_const(ctx, low_sextract(insn, 16, 5));
29150b1347d2SRichard Henderson     } else {
29160b1347d2SRichard Henderson         val = load_gpr(ctx, extract32(insn, 16, 5));
29170b1347d2SRichard Henderson     }
29180b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
29190b1347d2SRichard Henderson     shift = tcg_temp_new();
29200b1347d2SRichard Henderson     tmp = tcg_temp_new();
29210b1347d2SRichard Henderson 
29220b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
29230b1347d2SRichard Henderson     tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
29240b1347d2SRichard Henderson 
29250b1347d2SRichard Henderson     mask = tcg_const_tl(msb + (msb - 1));
29260b1347d2SRichard Henderson     tcg_gen_and_tl(tmp, val, mask);
29270b1347d2SRichard Henderson     if (rs) {
29280b1347d2SRichard Henderson         tcg_gen_shl_tl(mask, mask, shift);
29290b1347d2SRichard Henderson         tcg_gen_shl_tl(tmp, tmp, shift);
29300b1347d2SRichard Henderson         tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
29310b1347d2SRichard Henderson         tcg_gen_or_tl(dest, dest, tmp);
29320b1347d2SRichard Henderson     } else {
29330b1347d2SRichard Henderson         tcg_gen_shl_tl(dest, tmp, shift);
29340b1347d2SRichard Henderson     }
29350b1347d2SRichard Henderson     tcg_temp_free(shift);
29360b1347d2SRichard Henderson     tcg_temp_free(mask);
29370b1347d2SRichard Henderson     tcg_temp_free(tmp);
29380b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
29390b1347d2SRichard Henderson 
29400b1347d2SRichard Henderson     /* Install the new nullification.  */
29410b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
29420b1347d2SRichard Henderson     if (c) {
29430b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
29440b1347d2SRichard Henderson     }
2945869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
29460b1347d2SRichard Henderson }
29470b1347d2SRichard Henderson 
29480b1347d2SRichard Henderson static const DisasInsn table_depw[] = {
29490b1347d2SRichard Henderson     { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
29500b1347d2SRichard Henderson     { 0xd4000800u, 0xfc001800u, trans_depw_imm },
29510b1347d2SRichard Henderson     { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
29520b1347d2SRichard Henderson };
29530b1347d2SRichard Henderson 
2954869051eaSRichard Henderson static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
295598cd9ca7SRichard Henderson {
295698cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
295798cd9ca7SRichard Henderson     unsigned b = extract32(insn, 21, 5);
295898cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
295998cd9ca7SRichard Henderson 
296098cd9ca7SRichard Henderson     /* unsigned s = low_uextract(insn, 13, 3); */
296198cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
296298cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
296398cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
296498cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
296598cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
296698cd9ca7SRichard Henderson 
296798cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
296898cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
296998cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
297098cd9ca7SRichard Henderson     if (b == 0) {
297198cd9ca7SRichard Henderson         return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
297298cd9ca7SRichard Henderson     } else {
297398cd9ca7SRichard Henderson         TCGv tmp = get_temp(ctx);
297498cd9ca7SRichard Henderson         tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
297598cd9ca7SRichard Henderson         return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
297698cd9ca7SRichard Henderson     }
297798cd9ca7SRichard Henderson }
297898cd9ca7SRichard Henderson 
2979869051eaSRichard Henderson static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
298098cd9ca7SRichard Henderson                               const DisasInsn *di)
298198cd9ca7SRichard Henderson {
298298cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
298398cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
298498cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
298598cd9ca7SRichard Henderson 
298698cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
298798cd9ca7SRichard Henderson }
298898cd9ca7SRichard Henderson 
2989869051eaSRichard Henderson static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
299098cd9ca7SRichard Henderson                                    const DisasInsn *di)
299198cd9ca7SRichard Henderson {
299298cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
299398cd9ca7SRichard Henderson     target_long disp = assemble_22(insn);
299498cd9ca7SRichard Henderson 
299598cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
299698cd9ca7SRichard Henderson }
299798cd9ca7SRichard Henderson 
2998869051eaSRichard Henderson static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn,
299998cd9ca7SRichard Henderson                                const DisasInsn *di)
300098cd9ca7SRichard Henderson {
300198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
300298cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
300398cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
300498cd9ca7SRichard Henderson     TCGv tmp = get_temp(ctx);
300598cd9ca7SRichard Henderson 
300698cd9ca7SRichard Henderson     tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
300798cd9ca7SRichard Henderson     tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
300898cd9ca7SRichard Henderson     return do_ibranch(ctx, tmp, link, n);
300998cd9ca7SRichard Henderson }
301098cd9ca7SRichard Henderson 
3011869051eaSRichard Henderson static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn,
301298cd9ca7SRichard Henderson                               const DisasInsn *di)
301398cd9ca7SRichard Henderson {
301498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
301598cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
301698cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
301798cd9ca7SRichard Henderson     TCGv dest;
301898cd9ca7SRichard Henderson 
301998cd9ca7SRichard Henderson     if (rx == 0) {
302098cd9ca7SRichard Henderson         dest = load_gpr(ctx, rb);
302198cd9ca7SRichard Henderson     } else {
302298cd9ca7SRichard Henderson         dest = get_temp(ctx);
302398cd9ca7SRichard Henderson         tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
302498cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
302598cd9ca7SRichard Henderson     }
302698cd9ca7SRichard Henderson     return do_ibranch(ctx, dest, 0, n);
302798cd9ca7SRichard Henderson }
302898cd9ca7SRichard Henderson 
3029869051eaSRichard Henderson static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn,
303098cd9ca7SRichard Henderson                                const DisasInsn *di)
303198cd9ca7SRichard Henderson {
303298cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
303398cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
303498cd9ca7SRichard Henderson     unsigned link = extract32(insn, 13, 1) ? 2 : 0;
303598cd9ca7SRichard Henderson 
303698cd9ca7SRichard Henderson     return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
303798cd9ca7SRichard Henderson }
303898cd9ca7SRichard Henderson 
303998cd9ca7SRichard Henderson static const DisasInsn table_branch[] = {
304098cd9ca7SRichard Henderson     { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
304198cd9ca7SRichard Henderson     { 0xe800a000u, 0xfc00e000u, trans_bl_long },
304298cd9ca7SRichard Henderson     { 0xe8004000u, 0xfc00fffdu, trans_blr },
304398cd9ca7SRichard Henderson     { 0xe800c000u, 0xfc00fffdu, trans_bv },
304498cd9ca7SRichard Henderson     { 0xe800d000u, 0xfc00dffcu, trans_bve },
304598cd9ca7SRichard Henderson };
304698cd9ca7SRichard Henderson 
3047869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3048ebe9383cSRichard Henderson                                       const DisasInsn *di)
3049ebe9383cSRichard Henderson {
3050ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3051ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3052eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3053ebe9383cSRichard Henderson }
3054ebe9383cSRichard Henderson 
3055869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3056ebe9383cSRichard Henderson                                       const DisasInsn *di)
3057ebe9383cSRichard Henderson {
3058ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3059ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3060eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3061ebe9383cSRichard Henderson }
3062ebe9383cSRichard Henderson 
3063869051eaSRichard Henderson static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn,
3064ebe9383cSRichard Henderson                                    const DisasInsn *di)
3065ebe9383cSRichard Henderson {
3066ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3067ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3068eff235ebSPaolo Bonzini     return do_fop_ded(ctx, rt, ra, di->f.ded);
3069ebe9383cSRichard Henderson }
3070ebe9383cSRichard Henderson 
3071869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3072ebe9383cSRichard Henderson                                       const DisasInsn *di)
3073ebe9383cSRichard Henderson {
3074ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3075ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3076eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3077ebe9383cSRichard Henderson }
3078ebe9383cSRichard Henderson 
3079869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3080ebe9383cSRichard Henderson                                       const DisasInsn *di)
3081ebe9383cSRichard Henderson {
3082ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3083ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3084eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3085ebe9383cSRichard Henderson }
3086ebe9383cSRichard Henderson 
3087869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3088ebe9383cSRichard Henderson                                       const DisasInsn *di)
3089ebe9383cSRichard Henderson {
3090ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3091ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3092eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3093ebe9383cSRichard Henderson }
3094ebe9383cSRichard Henderson 
3095869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3096ebe9383cSRichard Henderson                                       const DisasInsn *di)
3097ebe9383cSRichard Henderson {
3098ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3099ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3100eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3101ebe9383cSRichard Henderson }
3102ebe9383cSRichard Henderson 
3103869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3104ebe9383cSRichard Henderson                                        const DisasInsn *di)
3105ebe9383cSRichard Henderson {
3106ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3107ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3108ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3109eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3110ebe9383cSRichard Henderson }
3111ebe9383cSRichard Henderson 
3112869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3113ebe9383cSRichard Henderson                                        const DisasInsn *di)
3114ebe9383cSRichard Henderson {
3115ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3116ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3117ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3118eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3119ebe9383cSRichard Henderson }
3120ebe9383cSRichard Henderson 
3121869051eaSRichard Henderson static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3122ebe9383cSRichard Henderson                                     const DisasInsn *di)
3123ebe9383cSRichard Henderson {
3124ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3125ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3126ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3127eff235ebSPaolo Bonzini     return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3128ebe9383cSRichard Henderson }
3129ebe9383cSRichard Henderson 
3130ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3131ebe9383cSRichard Henderson {
3132ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3133ebe9383cSRichard Henderson }
3134ebe9383cSRichard Henderson 
3135ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3136ebe9383cSRichard Henderson {
3137ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3138ebe9383cSRichard Henderson }
3139ebe9383cSRichard Henderson 
3140ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3141ebe9383cSRichard Henderson {
3142ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3143ebe9383cSRichard Henderson }
3144ebe9383cSRichard Henderson 
3145ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3146ebe9383cSRichard Henderson {
3147ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3148ebe9383cSRichard Henderson }
3149ebe9383cSRichard Henderson 
3150ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3151ebe9383cSRichard Henderson {
3152ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3153ebe9383cSRichard Henderson }
3154ebe9383cSRichard Henderson 
3155ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3156ebe9383cSRichard Henderson {
3157ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3158ebe9383cSRichard Henderson }
3159ebe9383cSRichard Henderson 
3160ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3161ebe9383cSRichard Henderson {
3162ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3163ebe9383cSRichard Henderson }
3164ebe9383cSRichard Henderson 
3165ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3166ebe9383cSRichard Henderson {
3167ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3168ebe9383cSRichard Henderson }
3169ebe9383cSRichard Henderson 
3170869051eaSRichard Henderson static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3171ebe9383cSRichard Henderson                                unsigned y, unsigned c)
3172ebe9383cSRichard Henderson {
3173ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3174ebe9383cSRichard Henderson 
3175ebe9383cSRichard Henderson     nullify_over(ctx);
3176ebe9383cSRichard Henderson 
3177ebe9383cSRichard Henderson     ta = load_frw0_i32(ra);
3178ebe9383cSRichard Henderson     tb = load_frw0_i32(rb);
3179ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3180ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3181ebe9383cSRichard Henderson 
3182ebe9383cSRichard Henderson     gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3183ebe9383cSRichard Henderson 
3184ebe9383cSRichard Henderson     tcg_temp_free_i32(ta);
3185ebe9383cSRichard Henderson     tcg_temp_free_i32(tb);
3186ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3187ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3188ebe9383cSRichard Henderson 
3189869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3190ebe9383cSRichard Henderson }
3191ebe9383cSRichard Henderson 
3192869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3193ebe9383cSRichard Henderson                                      const DisasInsn *di)
3194ebe9383cSRichard Henderson {
3195ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3196ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3197ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3198ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3199ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3200ebe9383cSRichard Henderson }
3201ebe9383cSRichard Henderson 
3202869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3203ebe9383cSRichard Henderson                                      const DisasInsn *di)
3204ebe9383cSRichard Henderson {
3205ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3206ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3207ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3208ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3209ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3210ebe9383cSRichard Henderson }
3211ebe9383cSRichard Henderson 
3212869051eaSRichard Henderson static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3213ebe9383cSRichard Henderson                                   const DisasInsn *di)
3214ebe9383cSRichard Henderson {
3215ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3216ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3217ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3218ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3219ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3220ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3221ebe9383cSRichard Henderson 
3222ebe9383cSRichard Henderson     nullify_over(ctx);
3223ebe9383cSRichard Henderson 
3224ebe9383cSRichard Henderson     ta = load_frd0(ra);
3225ebe9383cSRichard Henderson     tb = load_frd0(rb);
3226ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3227ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3228ebe9383cSRichard Henderson 
3229ebe9383cSRichard Henderson     gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3230ebe9383cSRichard Henderson 
3231ebe9383cSRichard Henderson     tcg_temp_free_i64(ta);
3232ebe9383cSRichard Henderson     tcg_temp_free_i64(tb);
3233ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3234ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3235ebe9383cSRichard Henderson 
3236869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3237ebe9383cSRichard Henderson }
3238ebe9383cSRichard Henderson 
3239869051eaSRichard Henderson static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn,
3240ebe9383cSRichard Henderson                                    const DisasInsn *di)
3241ebe9383cSRichard Henderson {
3242ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3243ebe9383cSRichard Henderson     unsigned cbit = (y ^ 1) - 1;
3244ebe9383cSRichard Henderson     TCGv t;
3245ebe9383cSRichard Henderson 
3246ebe9383cSRichard Henderson     nullify_over(ctx);
3247ebe9383cSRichard Henderson 
3248ebe9383cSRichard Henderson     t = tcg_temp_new();
3249ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3250ebe9383cSRichard Henderson     tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3251ebe9383cSRichard Henderson     ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3252ebe9383cSRichard Henderson     tcg_temp_free(t);
3253ebe9383cSRichard Henderson 
3254869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3255ebe9383cSRichard Henderson }
3256ebe9383cSRichard Henderson 
3257869051eaSRichard Henderson static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn,
3258ebe9383cSRichard Henderson                                    const DisasInsn *di)
3259ebe9383cSRichard Henderson {
3260ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3261ebe9383cSRichard Henderson     int mask;
3262ebe9383cSRichard Henderson     bool inv = false;
3263ebe9383cSRichard Henderson     TCGv t;
3264ebe9383cSRichard Henderson 
3265ebe9383cSRichard Henderson     nullify_over(ctx);
3266ebe9383cSRichard Henderson 
3267ebe9383cSRichard Henderson     t = tcg_temp_new();
3268ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3269ebe9383cSRichard Henderson 
3270ebe9383cSRichard Henderson     switch (c) {
3271ebe9383cSRichard Henderson     case 0: /* simple */
3272ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, 0x4000000);
3273ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3274ebe9383cSRichard Henderson         goto done;
3275ebe9383cSRichard Henderson     case 2: /* rej */
3276ebe9383cSRichard Henderson         inv = true;
3277ebe9383cSRichard Henderson         /* fallthru */
3278ebe9383cSRichard Henderson     case 1: /* acc */
3279ebe9383cSRichard Henderson         mask = 0x43ff800;
3280ebe9383cSRichard Henderson         break;
3281ebe9383cSRichard Henderson     case 6: /* rej8 */
3282ebe9383cSRichard Henderson         inv = true;
3283ebe9383cSRichard Henderson         /* fallthru */
3284ebe9383cSRichard Henderson     case 5: /* acc8 */
3285ebe9383cSRichard Henderson         mask = 0x43f8000;
3286ebe9383cSRichard Henderson         break;
3287ebe9383cSRichard Henderson     case 9: /* acc6 */
3288ebe9383cSRichard Henderson         mask = 0x43e0000;
3289ebe9383cSRichard Henderson         break;
3290ebe9383cSRichard Henderson     case 13: /* acc4 */
3291ebe9383cSRichard Henderson         mask = 0x4380000;
3292ebe9383cSRichard Henderson         break;
3293ebe9383cSRichard Henderson     case 17: /* acc2 */
3294ebe9383cSRichard Henderson         mask = 0x4200000;
3295ebe9383cSRichard Henderson         break;
3296ebe9383cSRichard Henderson     default:
3297ebe9383cSRichard Henderson         return gen_illegal(ctx);
3298ebe9383cSRichard Henderson     }
3299ebe9383cSRichard Henderson     if (inv) {
3300ebe9383cSRichard Henderson         TCGv c = load_const(ctx, mask);
3301ebe9383cSRichard Henderson         tcg_gen_or_tl(t, t, c);
3302ebe9383cSRichard Henderson         ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3303ebe9383cSRichard Henderson     } else {
3304ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, mask);
3305ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3306ebe9383cSRichard Henderson     }
3307ebe9383cSRichard Henderson  done:
3308869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3309ebe9383cSRichard Henderson }
3310ebe9383cSRichard Henderson 
3311869051eaSRichard Henderson static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn,
3312ebe9383cSRichard Henderson                                  const DisasInsn *di)
3313ebe9383cSRichard Henderson {
3314ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3315ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3316ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3317ebe9383cSRichard Henderson     TCGv_i64 a, b;
3318ebe9383cSRichard Henderson 
3319ebe9383cSRichard Henderson     nullify_over(ctx);
3320ebe9383cSRichard Henderson 
3321ebe9383cSRichard Henderson     a = load_frw0_i64(ra);
3322ebe9383cSRichard Henderson     b = load_frw0_i64(rb);
3323ebe9383cSRichard Henderson     tcg_gen_mul_i64(a, a, b);
3324ebe9383cSRichard Henderson     save_frd(rt, a);
3325ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3326ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3327ebe9383cSRichard Henderson 
3328869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3329ebe9383cSRichard Henderson }
3330ebe9383cSRichard Henderson 
3331eff235ebSPaolo Bonzini #define FOP_DED  trans_fop_ded, .f.ded
3332eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd
3333ebe9383cSRichard Henderson 
3334eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0c, .f.wew
3335eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0c, .f.dew
3336eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0c, .f.wed
3337eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww
3338ebe9383cSRichard Henderson 
3339ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = {
3340ebe9383cSRichard Henderson     /* floating point class zero */
3341ebe9383cSRichard Henderson     { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3342ebe9383cSRichard Henderson     { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3343ebe9383cSRichard Henderson     { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3344ebe9383cSRichard Henderson     { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3345ebe9383cSRichard Henderson     { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3346ebe9383cSRichard Henderson     { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3347ebe9383cSRichard Henderson 
3348ebe9383cSRichard Henderson     { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3349ebe9383cSRichard Henderson     { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3350ebe9383cSRichard Henderson     { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3351ebe9383cSRichard Henderson     { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3352ebe9383cSRichard Henderson     { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3353ebe9383cSRichard Henderson     { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3354ebe9383cSRichard Henderson 
3355ebe9383cSRichard Henderson     /* floating point class three */
3356ebe9383cSRichard Henderson     { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3357ebe9383cSRichard Henderson     { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3358ebe9383cSRichard Henderson     { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3359ebe9383cSRichard Henderson     { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3360ebe9383cSRichard Henderson 
3361ebe9383cSRichard Henderson     { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3362ebe9383cSRichard Henderson     { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3363ebe9383cSRichard Henderson     { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3364ebe9383cSRichard Henderson     { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3365ebe9383cSRichard Henderson 
3366ebe9383cSRichard Henderson     /* floating point class one */
3367ebe9383cSRichard Henderson     /* float/float */
3368ebe9383cSRichard Henderson     { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3369ebe9383cSRichard Henderson     { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3370ebe9383cSRichard Henderson     /* int/float */
3371ebe9383cSRichard Henderson     { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3372ebe9383cSRichard Henderson     { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3373ebe9383cSRichard Henderson     { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3374ebe9383cSRichard Henderson     { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3375ebe9383cSRichard Henderson     /* float/int */
3376ebe9383cSRichard Henderson     { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3377ebe9383cSRichard Henderson     { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3378ebe9383cSRichard Henderson     { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3379ebe9383cSRichard Henderson     { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3380ebe9383cSRichard Henderson     /* float/int truncate */
3381ebe9383cSRichard Henderson     { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3382ebe9383cSRichard Henderson     { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3383ebe9383cSRichard Henderson     { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3384ebe9383cSRichard Henderson     { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3385ebe9383cSRichard Henderson     /* uint/float */
3386ebe9383cSRichard Henderson     { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3387ebe9383cSRichard Henderson     { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3388ebe9383cSRichard Henderson     { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3389ebe9383cSRichard Henderson     { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3390ebe9383cSRichard Henderson     /* float/uint */
3391ebe9383cSRichard Henderson     { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3392ebe9383cSRichard Henderson     { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3393ebe9383cSRichard Henderson     { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3394ebe9383cSRichard Henderson     { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3395ebe9383cSRichard Henderson     /* float/uint truncate */
3396ebe9383cSRichard Henderson     { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3397ebe9383cSRichard Henderson     { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3398ebe9383cSRichard Henderson     { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3399ebe9383cSRichard Henderson     { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3400ebe9383cSRichard Henderson 
3401ebe9383cSRichard Henderson     /* floating point class two */
3402ebe9383cSRichard Henderson     { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3403ebe9383cSRichard Henderson     { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3404ebe9383cSRichard Henderson     { 0x30002420, 0xffffffe0, trans_ftest_q },
3405ebe9383cSRichard Henderson     { 0x30000420, 0xffff1fff, trans_ftest_t },
3406ebe9383cSRichard Henderson 
3407ebe9383cSRichard Henderson     /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3408ebe9383cSRichard Henderson        This is machine/revision == 0, which is reserved for simulator.  */
3409ebe9383cSRichard Henderson     { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3410ebe9383cSRichard Henderson };
3411ebe9383cSRichard Henderson 
3412ebe9383cSRichard Henderson #undef FOP_WEW
3413ebe9383cSRichard Henderson #undef FOP_DEW
3414ebe9383cSRichard Henderson #undef FOP_WED
3415ebe9383cSRichard Henderson #undef FOP_WEWW
3416eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0e, .f.wew
3417eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0e, .f.dew
3418eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0e, .f.wed
3419eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww
3420ebe9383cSRichard Henderson 
3421ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = {
3422ebe9383cSRichard Henderson     /* floating point class zero */
3423ebe9383cSRichard Henderson     { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3424ebe9383cSRichard Henderson     { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3425ebe9383cSRichard Henderson     { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3426ebe9383cSRichard Henderson     { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3427ebe9383cSRichard Henderson     { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3428ebe9383cSRichard Henderson     { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3429ebe9383cSRichard Henderson 
3430ebe9383cSRichard Henderson     { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3431ebe9383cSRichard Henderson     { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3432ebe9383cSRichard Henderson     { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3433ebe9383cSRichard Henderson     { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3434ebe9383cSRichard Henderson     { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3435ebe9383cSRichard Henderson     { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3436ebe9383cSRichard Henderson 
3437ebe9383cSRichard Henderson     /* floating point class three */
3438ebe9383cSRichard Henderson     { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3439ebe9383cSRichard Henderson     { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3440ebe9383cSRichard Henderson     { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3441ebe9383cSRichard Henderson     { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3442ebe9383cSRichard Henderson 
3443ebe9383cSRichard Henderson     { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3444ebe9383cSRichard Henderson     { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3445ebe9383cSRichard Henderson     { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3446ebe9383cSRichard Henderson     { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3447ebe9383cSRichard Henderson 
3448ebe9383cSRichard Henderson     { 0x38004700, 0xfc00ef60, trans_xmpyu },
3449ebe9383cSRichard Henderson 
3450ebe9383cSRichard Henderson     /* floating point class one */
3451ebe9383cSRichard Henderson     /* float/float */
3452ebe9383cSRichard Henderson     { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3453ebe9383cSRichard Henderson     { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3454ebe9383cSRichard Henderson     /* int/float */
3455ebe9383cSRichard Henderson     { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3456ebe9383cSRichard Henderson     { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3457ebe9383cSRichard Henderson     { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3458ebe9383cSRichard Henderson     { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3459ebe9383cSRichard Henderson     /* float/int */
3460ebe9383cSRichard Henderson     { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3461ebe9383cSRichard Henderson     { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3462ebe9383cSRichard Henderson     { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3463ebe9383cSRichard Henderson     { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3464ebe9383cSRichard Henderson     /* float/int truncate */
3465ebe9383cSRichard Henderson     { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3466ebe9383cSRichard Henderson     { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3467ebe9383cSRichard Henderson     { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3468ebe9383cSRichard Henderson     { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3469ebe9383cSRichard Henderson     /* uint/float */
3470ebe9383cSRichard Henderson     { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3471ebe9383cSRichard Henderson     { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3472ebe9383cSRichard Henderson     { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3473ebe9383cSRichard Henderson     { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3474ebe9383cSRichard Henderson     /* float/uint */
3475ebe9383cSRichard Henderson     { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3476ebe9383cSRichard Henderson     { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3477ebe9383cSRichard Henderson     { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3478ebe9383cSRichard Henderson     { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3479ebe9383cSRichard Henderson     /* float/uint truncate */
3480ebe9383cSRichard Henderson     { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3481ebe9383cSRichard Henderson     { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3482ebe9383cSRichard Henderson     { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3483ebe9383cSRichard Henderson     { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3484ebe9383cSRichard Henderson 
3485ebe9383cSRichard Henderson     /* floating point class two */
3486ebe9383cSRichard Henderson     { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3487ebe9383cSRichard Henderson     { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3488ebe9383cSRichard Henderson };
3489ebe9383cSRichard Henderson 
3490ebe9383cSRichard Henderson #undef FOP_WEW
3491ebe9383cSRichard Henderson #undef FOP_DEW
3492ebe9383cSRichard Henderson #undef FOP_WED
3493ebe9383cSRichard Henderson #undef FOP_WEWW
3494ebe9383cSRichard Henderson #undef FOP_DED
3495ebe9383cSRichard Henderson #undef FOP_DEDD
3496ebe9383cSRichard Henderson 
3497ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
3498ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
3499ebe9383cSRichard Henderson {
3500ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
3501ebe9383cSRichard Henderson }
3502ebe9383cSRichard Henderson 
3503869051eaSRichard Henderson static DisasJumpType trans_fmpyadd(DisasContext *ctx,
3504869051eaSRichard Henderson                                    uint32_t insn, bool is_sub)
3505ebe9383cSRichard Henderson {
3506ebe9383cSRichard Henderson     unsigned tm = extract32(insn, 0, 5);
3507ebe9383cSRichard Henderson     unsigned f = extract32(insn, 5, 1);
3508ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 6, 5);
3509ebe9383cSRichard Henderson     unsigned ta = extract32(insn, 11, 5);
3510ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3511ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3512ebe9383cSRichard Henderson 
3513ebe9383cSRichard Henderson     nullify_over(ctx);
3514ebe9383cSRichard Henderson 
3515ebe9383cSRichard Henderson     /* Independent multiply & add/sub, with undefined behaviour
3516ebe9383cSRichard Henderson        if outputs overlap inputs.  */
3517ebe9383cSRichard Henderson     if (f == 0) {
3518ebe9383cSRichard Henderson         tm = fmpyadd_s_reg(tm);
3519ebe9383cSRichard Henderson         ra = fmpyadd_s_reg(ra);
3520ebe9383cSRichard Henderson         ta = fmpyadd_s_reg(ta);
3521ebe9383cSRichard Henderson         rm2 = fmpyadd_s_reg(rm2);
3522ebe9383cSRichard Henderson         rm1 = fmpyadd_s_reg(rm1);
3523ebe9383cSRichard Henderson         do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3524ebe9383cSRichard Henderson         do_fop_weww(ctx, ta, ta, ra,
3525ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3526ebe9383cSRichard Henderson     } else {
3527ebe9383cSRichard Henderson         do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3528ebe9383cSRichard Henderson         do_fop_dedd(ctx, ta, ta, ra,
3529ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3530ebe9383cSRichard Henderson     }
3531ebe9383cSRichard Henderson 
3532869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3533ebe9383cSRichard Henderson }
3534ebe9383cSRichard Henderson 
3535869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3536ebe9383cSRichard Henderson                                       const DisasInsn *di)
3537ebe9383cSRichard Henderson {
3538ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3539ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3540ebe9383cSRichard Henderson     unsigned rm1 = assemble_ra64(insn);
3541ebe9383cSRichard Henderson     unsigned rm2 = assemble_rb64(insn);
3542ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3543ebe9383cSRichard Henderson     TCGv_i32 a, b, c;
3544ebe9383cSRichard Henderson 
3545ebe9383cSRichard Henderson     nullify_over(ctx);
3546ebe9383cSRichard Henderson     a = load_frw0_i32(rm1);
3547ebe9383cSRichard Henderson     b = load_frw0_i32(rm2);
3548ebe9383cSRichard Henderson     c = load_frw0_i32(ra3);
3549ebe9383cSRichard Henderson 
3550ebe9383cSRichard Henderson     if (neg) {
3551ebe9383cSRichard Henderson         gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3552ebe9383cSRichard Henderson     } else {
3553ebe9383cSRichard Henderson         gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3554ebe9383cSRichard Henderson     }
3555ebe9383cSRichard Henderson 
3556ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
3557ebe9383cSRichard Henderson     tcg_temp_free_i32(c);
3558ebe9383cSRichard Henderson     save_frw_i32(rt, a);
3559ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
3560869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3561ebe9383cSRichard Henderson }
3562ebe9383cSRichard Henderson 
3563869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3564ebe9383cSRichard Henderson                                       const DisasInsn *di)
3565ebe9383cSRichard Henderson {
3566ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3567ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3568ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3569ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3570ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3571ebe9383cSRichard Henderson     TCGv_i64 a, b, c;
3572ebe9383cSRichard Henderson 
3573ebe9383cSRichard Henderson     nullify_over(ctx);
3574ebe9383cSRichard Henderson     a = load_frd0(rm1);
3575ebe9383cSRichard Henderson     b = load_frd0(rm2);
3576ebe9383cSRichard Henderson     c = load_frd0(ra3);
3577ebe9383cSRichard Henderson 
3578ebe9383cSRichard Henderson     if (neg) {
3579ebe9383cSRichard Henderson         gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3580ebe9383cSRichard Henderson     } else {
3581ebe9383cSRichard Henderson         gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3582ebe9383cSRichard Henderson     }
3583ebe9383cSRichard Henderson 
3584ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3585ebe9383cSRichard Henderson     tcg_temp_free_i64(c);
3586ebe9383cSRichard Henderson     save_frd(rt, a);
3587ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3588869051eaSRichard Henderson     return nullify_end(ctx, DISAS_NEXT);
3589ebe9383cSRichard Henderson }
3590ebe9383cSRichard Henderson 
3591ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = {
3592ebe9383cSRichard Henderson     { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3593ebe9383cSRichard Henderson     { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3594ebe9383cSRichard Henderson };
3595ebe9383cSRichard Henderson 
3596869051eaSRichard Henderson static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn,
359761766fe9SRichard Henderson                                          const DisasInsn table[], size_t n)
359861766fe9SRichard Henderson {
359961766fe9SRichard Henderson     size_t i;
360061766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
360161766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
360261766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
360361766fe9SRichard Henderson         }
360461766fe9SRichard Henderson     }
360561766fe9SRichard Henderson     return gen_illegal(ctx);
360661766fe9SRichard Henderson }
360761766fe9SRichard Henderson 
360861766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
360961766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
361061766fe9SRichard Henderson 
3611869051eaSRichard Henderson static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
361261766fe9SRichard Henderson {
361361766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
361461766fe9SRichard Henderson 
361561766fe9SRichard Henderson     switch (opc) {
361698a9cb79SRichard Henderson     case 0x00: /* system op */
361798a9cb79SRichard Henderson         return translate_table(ctx, insn, table_system);
361898a9cb79SRichard Henderson     case 0x01:
361998a9cb79SRichard Henderson         return translate_table(ctx, insn, table_mem_mgmt);
3620b2167459SRichard Henderson     case 0x02:
3621b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
362296d6407fSRichard Henderson     case 0x03:
362396d6407fSRichard Henderson         return translate_table(ctx, insn, table_index_mem);
3624ebe9383cSRichard Henderson     case 0x06:
3625ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, false);
3626b2167459SRichard Henderson     case 0x08:
3627b2167459SRichard Henderson         return trans_ldil(ctx, insn);
362896d6407fSRichard Henderson     case 0x09:
362996d6407fSRichard Henderson         return trans_copr_w(ctx, insn);
3630b2167459SRichard Henderson     case 0x0A:
3631b2167459SRichard Henderson         return trans_addil(ctx, insn);
363296d6407fSRichard Henderson     case 0x0B:
363396d6407fSRichard Henderson         return trans_copr_dw(ctx, insn);
3634ebe9383cSRichard Henderson     case 0x0C:
3635ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0c);
3636b2167459SRichard Henderson     case 0x0D:
3637b2167459SRichard Henderson         return trans_ldo(ctx, insn);
3638ebe9383cSRichard Henderson     case 0x0E:
3639ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0e);
364096d6407fSRichard Henderson 
364196d6407fSRichard Henderson     case 0x10:
364296d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_UB);
364396d6407fSRichard Henderson     case 0x11:
364496d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUW);
364596d6407fSRichard Henderson     case 0x12:
364696d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUL);
364796d6407fSRichard Henderson     case 0x13:
364896d6407fSRichard Henderson         return trans_load(ctx, insn, true, MO_TEUL);
364996d6407fSRichard Henderson     case 0x16:
365096d6407fSRichard Henderson         return trans_fload_mod(ctx, insn);
365196d6407fSRichard Henderson     case 0x17:
365296d6407fSRichard Henderson         return trans_load_w(ctx, insn);
365396d6407fSRichard Henderson     case 0x18:
365496d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_UB);
365596d6407fSRichard Henderson     case 0x19:
365696d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUW);
365796d6407fSRichard Henderson     case 0x1A:
365896d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUL);
365996d6407fSRichard Henderson     case 0x1B:
366096d6407fSRichard Henderson         return trans_store(ctx, insn, true, MO_TEUL);
366196d6407fSRichard Henderson     case 0x1E:
366296d6407fSRichard Henderson         return trans_fstore_mod(ctx, insn);
366396d6407fSRichard Henderson     case 0x1F:
366496d6407fSRichard Henderson         return trans_store_w(ctx, insn);
366596d6407fSRichard Henderson 
366698cd9ca7SRichard Henderson     case 0x20:
366798cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, false);
366898cd9ca7SRichard Henderson     case 0x21:
366998cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, true, false);
367098cd9ca7SRichard Henderson     case 0x22:
367198cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, false);
367298cd9ca7SRichard Henderson     case 0x23:
367398cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, true, false);
3674b2167459SRichard Henderson     case 0x24:
3675b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
3676b2167459SRichard Henderson     case 0x25:
3677b2167459SRichard Henderson         return trans_subi(ctx, insn);
3678ebe9383cSRichard Henderson     case 0x26:
3679ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, true);
368098cd9ca7SRichard Henderson     case 0x27:
368198cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, true);
368298cd9ca7SRichard Henderson     case 0x28:
368398cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, false);
368498cd9ca7SRichard Henderson     case 0x29:
368598cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, true);
368698cd9ca7SRichard Henderson     case 0x2A:
368798cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, false);
368898cd9ca7SRichard Henderson     case 0x2B:
368998cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, true);
3690b2167459SRichard Henderson     case 0x2C:
3691b2167459SRichard Henderson     case 0x2D:
3692b2167459SRichard Henderson         return trans_addi(ctx, insn);
3693ebe9383cSRichard Henderson     case 0x2E:
3694ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_fp_fused);
369598cd9ca7SRichard Henderson     case 0x2F:
369698cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, true);
369796d6407fSRichard Henderson 
369898cd9ca7SRichard Henderson     case 0x30:
369998cd9ca7SRichard Henderson     case 0x31:
370098cd9ca7SRichard Henderson         return trans_bb(ctx, insn);
370198cd9ca7SRichard Henderson     case 0x32:
370298cd9ca7SRichard Henderson         return trans_movb(ctx, insn, false);
370398cd9ca7SRichard Henderson     case 0x33:
370498cd9ca7SRichard Henderson         return trans_movb(ctx, insn, true);
37050b1347d2SRichard Henderson     case 0x34:
37060b1347d2SRichard Henderson         return translate_table(ctx, insn, table_sh_ex);
37070b1347d2SRichard Henderson     case 0x35:
37080b1347d2SRichard Henderson         return translate_table(ctx, insn, table_depw);
370998cd9ca7SRichard Henderson     case 0x38:
371098cd9ca7SRichard Henderson         return trans_be(ctx, insn, false);
371198cd9ca7SRichard Henderson     case 0x39:
371298cd9ca7SRichard Henderson         return trans_be(ctx, insn, true);
371398cd9ca7SRichard Henderson     case 0x3A:
371498cd9ca7SRichard Henderson         return translate_table(ctx, insn, table_branch);
371596d6407fSRichard Henderson 
371696d6407fSRichard Henderson     case 0x04: /* spopn */
371796d6407fSRichard Henderson     case 0x05: /* diag */
371896d6407fSRichard Henderson     case 0x0F: /* product specific */
371996d6407fSRichard Henderson         break;
372096d6407fSRichard Henderson 
372196d6407fSRichard Henderson     case 0x07: /* unassigned */
372296d6407fSRichard Henderson     case 0x15: /* unassigned */
372396d6407fSRichard Henderson     case 0x1D: /* unassigned */
372496d6407fSRichard Henderson     case 0x37: /* unassigned */
372596d6407fSRichard Henderson     case 0x3F: /* unassigned */
372661766fe9SRichard Henderson     default:
372761766fe9SRichard Henderson         break;
372861766fe9SRichard Henderson     }
372961766fe9SRichard Henderson     return gen_illegal(ctx);
373061766fe9SRichard Henderson }
373161766fe9SRichard Henderson 
37329c489ea6SLluís Vilanova void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
373361766fe9SRichard Henderson {
37349c489ea6SLluís Vilanova     CPUHPPAState *env = cs->env_ptr;
373561766fe9SRichard Henderson     DisasContext ctx;
3736869051eaSRichard Henderson     DisasJumpType ret;
373761766fe9SRichard Henderson     int num_insns, max_insns, i;
373861766fe9SRichard Henderson 
3739*d01a3625SRichard Henderson     ctx.base.tb = tb;
3740*d01a3625SRichard Henderson     ctx.base.singlestep_enabled = cs->singlestep_enabled;
374161766fe9SRichard Henderson     ctx.cs = cs;
374261766fe9SRichard Henderson     ctx.iaoq_f = tb->pc;
374361766fe9SRichard Henderson     ctx.iaoq_b = tb->cs_base;
374461766fe9SRichard Henderson 
374561766fe9SRichard Henderson     ctx.ntemps = 0;
374661766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
374761766fe9SRichard Henderson         TCGV_UNUSED(ctx.temps[i]);
374861766fe9SRichard Henderson     }
374961766fe9SRichard Henderson 
375061766fe9SRichard Henderson     /* Compute the maximum number of insns to execute, as bounded by
375161766fe9SRichard Henderson        (1) icount, (2) single-stepping, (3) branch delay slots, or
375261766fe9SRichard Henderson        (4) the number of insns remaining on the current page.  */
375361766fe9SRichard Henderson     max_insns = tb->cflags & CF_COUNT_MASK;
375461766fe9SRichard Henderson     if (max_insns == 0) {
375561766fe9SRichard Henderson         max_insns = CF_COUNT_MASK;
375661766fe9SRichard Henderson     }
3757*d01a3625SRichard Henderson     if (ctx.base.singlestep_enabled || singlestep) {
375861766fe9SRichard Henderson         max_insns = 1;
375961766fe9SRichard Henderson     } else if (max_insns > TCG_MAX_INSNS) {
376061766fe9SRichard Henderson         max_insns = TCG_MAX_INSNS;
376161766fe9SRichard Henderson     }
376261766fe9SRichard Henderson 
376361766fe9SRichard Henderson     num_insns = 0;
376461766fe9SRichard Henderson     gen_tb_start(tb);
376561766fe9SRichard Henderson 
3766129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
3767129e9cc3SRichard Henderson     ctx.null_cond = cond_make_f();
3768129e9cc3SRichard Henderson     ctx.psw_n_nonzero = false;
3769129e9cc3SRichard Henderson     if (tb->flags & 1) {
3770129e9cc3SRichard Henderson         ctx.null_cond.c = TCG_COND_ALWAYS;
3771129e9cc3SRichard Henderson         ctx.psw_n_nonzero = true;
3772129e9cc3SRichard Henderson     }
3773129e9cc3SRichard Henderson     ctx.null_lab = NULL;
3774129e9cc3SRichard Henderson 
377561766fe9SRichard Henderson     do {
377661766fe9SRichard Henderson         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
377761766fe9SRichard Henderson         num_insns++;
377861766fe9SRichard Henderson 
377961766fe9SRichard Henderson         if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
378061766fe9SRichard Henderson             ret = gen_excp(&ctx, EXCP_DEBUG);
378161766fe9SRichard Henderson             break;
378261766fe9SRichard Henderson         }
378361766fe9SRichard Henderson         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
378461766fe9SRichard Henderson             gen_io_start();
378561766fe9SRichard Henderson         }
378661766fe9SRichard Henderson 
37877ad439dfSRichard Henderson         if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
37887ad439dfSRichard Henderson             ret = do_page_zero(&ctx);
3789869051eaSRichard Henderson             assert(ret != DISAS_NEXT);
37907ad439dfSRichard Henderson         } else {
379161766fe9SRichard Henderson             /* Always fetch the insn, even if nullified, so that we check
379261766fe9SRichard Henderson                the page permissions for execute.  */
379361766fe9SRichard Henderson             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
379461766fe9SRichard Henderson 
379561766fe9SRichard Henderson             /* Set up the IA queue for the next insn.
379661766fe9SRichard Henderson                This will be overwritten by a branch.  */
379761766fe9SRichard Henderson             if (ctx.iaoq_b == -1) {
379861766fe9SRichard Henderson                 ctx.iaoq_n = -1;
379961766fe9SRichard Henderson                 ctx.iaoq_n_var = get_temp(&ctx);
380061766fe9SRichard Henderson                 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
380161766fe9SRichard Henderson             } else {
380261766fe9SRichard Henderson                 ctx.iaoq_n = ctx.iaoq_b + 4;
380361766fe9SRichard Henderson                 TCGV_UNUSED(ctx.iaoq_n_var);
380461766fe9SRichard Henderson             }
380561766fe9SRichard Henderson 
3806129e9cc3SRichard Henderson             if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
3807129e9cc3SRichard Henderson                 ctx.null_cond.c = TCG_COND_NEVER;
3808869051eaSRichard Henderson                 ret = DISAS_NEXT;
3809129e9cc3SRichard Henderson             } else {
381061766fe9SRichard Henderson                 ret = translate_one(&ctx, insn);
3811129e9cc3SRichard Henderson                 assert(ctx.null_lab == NULL);
3812129e9cc3SRichard Henderson             }
381361766fe9SRichard Henderson         }
381461766fe9SRichard Henderson 
381561766fe9SRichard Henderson         for (i = 0; i < ctx.ntemps; ++i) {
381661766fe9SRichard Henderson             tcg_temp_free(ctx.temps[i]);
381761766fe9SRichard Henderson             TCGV_UNUSED(ctx.temps[i]);
381861766fe9SRichard Henderson         }
381961766fe9SRichard Henderson         ctx.ntemps = 0;
382061766fe9SRichard Henderson 
382161766fe9SRichard Henderson         /* If we see non-linear instructions, exhaust instruction count,
382261766fe9SRichard Henderson            or run out of buffer space, stop generation.  */
382361766fe9SRichard Henderson         /* ??? The non-linear instruction restriction is purely due to
382461766fe9SRichard Henderson            the debugging dump.  Otherwise we *could* follow unconditional
382561766fe9SRichard Henderson            branches within the same page.  */
3826869051eaSRichard Henderson         if (ret == DISAS_NEXT
382761766fe9SRichard Henderson             && (ctx.iaoq_b != ctx.iaoq_f + 4
382861766fe9SRichard Henderson                 || num_insns >= max_insns
382961766fe9SRichard Henderson                 || tcg_op_buf_full())) {
3830129e9cc3SRichard Henderson             if (ctx.null_cond.c == TCG_COND_NEVER
3831129e9cc3SRichard Henderson                 || ctx.null_cond.c == TCG_COND_ALWAYS) {
3832129e9cc3SRichard Henderson                 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
3833129e9cc3SRichard 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         }
383961766fe9SRichard Henderson 
384061766fe9SRichard Henderson         ctx.iaoq_f = ctx.iaoq_b;
384161766fe9SRichard Henderson         ctx.iaoq_b = ctx.iaoq_n;
3842869051eaSRichard Henderson         if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
384361766fe9SRichard Henderson             break;
384461766fe9SRichard Henderson         }
384561766fe9SRichard Henderson         if (ctx.iaoq_f == -1) {
384661766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
384761766fe9SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
3848129e9cc3SRichard Henderson             nullify_save(&ctx);
3849869051eaSRichard Henderson             ret = DISAS_IAQ_N_UPDATED;
385061766fe9SRichard Henderson             break;
385161766fe9SRichard Henderson         }
385261766fe9SRichard Henderson         if (ctx.iaoq_b == -1) {
385361766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
385461766fe9SRichard Henderson         }
3855869051eaSRichard Henderson     } while (ret == DISAS_NEXT);
385661766fe9SRichard Henderson 
385761766fe9SRichard Henderson     if (tb->cflags & CF_LAST_IO) {
385861766fe9SRichard Henderson         gen_io_end();
385961766fe9SRichard Henderson     }
386061766fe9SRichard Henderson 
386161766fe9SRichard Henderson     switch (ret) {
3862869051eaSRichard Henderson     case DISAS_NORETURN:
386361766fe9SRichard Henderson         break;
3864869051eaSRichard Henderson     case DISAS_IAQ_N_STALE:
386561766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
386661766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
3867129e9cc3SRichard Henderson         nullify_save(&ctx);
386861766fe9SRichard Henderson         /* FALLTHRU */
3869869051eaSRichard Henderson     case DISAS_IAQ_N_UPDATED:
3870*d01a3625SRichard Henderson         if (ctx.base.singlestep_enabled) {
387161766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
387261766fe9SRichard Henderson         } else {
38734137cb83SRichard Henderson             tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
387461766fe9SRichard Henderson         }
387561766fe9SRichard Henderson         break;
387661766fe9SRichard Henderson     default:
387761766fe9SRichard Henderson         abort();
387861766fe9SRichard Henderson     }
387961766fe9SRichard Henderson 
388061766fe9SRichard Henderson     gen_tb_end(tb, num_insns);
388161766fe9SRichard Henderson 
388261766fe9SRichard Henderson     tb->size = num_insns * 4;
388361766fe9SRichard Henderson     tb->icount = num_insns;
388461766fe9SRichard Henderson 
388561766fe9SRichard Henderson #ifdef DEBUG_DISAS
388661766fe9SRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
388761766fe9SRichard Henderson         && qemu_log_in_addr_range(tb->pc)) {
388861766fe9SRichard Henderson         qemu_log_lock();
38897ad439dfSRichard Henderson         switch (tb->pc) {
38907ad439dfSRichard Henderson         case 0x00:
38917ad439dfSRichard Henderson             qemu_log("IN:\n0x00000000:  (null)\n\n");
38927ad439dfSRichard Henderson             break;
38937ad439dfSRichard Henderson         case 0xb0:
38947ad439dfSRichard Henderson             qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
38957ad439dfSRichard Henderson             break;
38967ad439dfSRichard Henderson         case 0xe0:
38977ad439dfSRichard Henderson             qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
38987ad439dfSRichard Henderson             break;
38997ad439dfSRichard Henderson         case 0x100:
39007ad439dfSRichard Henderson             qemu_log("IN:\n0x00000100:  syscall\n\n");
39017ad439dfSRichard Henderson             break;
39027ad439dfSRichard Henderson         default:
390361766fe9SRichard Henderson             qemu_log("IN: %s\n", lookup_symbol(tb->pc));
390461766fe9SRichard Henderson             log_target_disas(cs, tb->pc, tb->size, 1);
390561766fe9SRichard Henderson             qemu_log("\n");
39067ad439dfSRichard Henderson             break;
39077ad439dfSRichard Henderson         }
390861766fe9SRichard Henderson         qemu_log_unlock();
390961766fe9SRichard Henderson     }
391061766fe9SRichard Henderson #endif
391161766fe9SRichard Henderson }
391261766fe9SRichard Henderson 
391361766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
391461766fe9SRichard Henderson                           target_ulong *data)
391561766fe9SRichard Henderson {
391661766fe9SRichard Henderson     env->iaoq_f = data[0];
391761766fe9SRichard Henderson     if (data[1] != -1) {
391861766fe9SRichard Henderson         env->iaoq_b = data[1];
391961766fe9SRichard Henderson     }
392061766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
392161766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
392261766fe9SRichard Henderson        that the instruction was not nullified.  */
392361766fe9SRichard Henderson     env->psw_n = 0;
392461766fe9SRichard Henderson }
3925