xref: /openbmc/qemu/target/hppa/translate.c (revision eff235eb2bcd7092901f4698a7907e742f3b7f2f)
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 
2861766fe9SRichard Henderson #include "exec/helper-proto.h"
2961766fe9SRichard Henderson #include "exec/helper-gen.h"
3061766fe9SRichard Henderson 
3161766fe9SRichard Henderson #include "trace-tcg.h"
3261766fe9SRichard Henderson #include "exec/log.h"
3361766fe9SRichard Henderson 
3461766fe9SRichard Henderson typedef struct DisasCond {
3561766fe9SRichard Henderson     TCGCond c;
3661766fe9SRichard Henderson     TCGv a0, a1;
3761766fe9SRichard Henderson     bool a0_is_n;
3861766fe9SRichard Henderson     bool a1_is_0;
3961766fe9SRichard Henderson } DisasCond;
4061766fe9SRichard Henderson 
4161766fe9SRichard Henderson typedef struct DisasContext {
4261766fe9SRichard Henderson     struct TranslationBlock *tb;
4361766fe9SRichard Henderson     CPUState *cs;
4461766fe9SRichard Henderson 
4561766fe9SRichard Henderson     target_ulong iaoq_f;
4661766fe9SRichard Henderson     target_ulong iaoq_b;
4761766fe9SRichard Henderson     target_ulong iaoq_n;
4861766fe9SRichard Henderson     TCGv iaoq_n_var;
4961766fe9SRichard Henderson 
5061766fe9SRichard Henderson     int ntemps;
5161766fe9SRichard Henderson     TCGv temps[8];
5261766fe9SRichard Henderson 
5361766fe9SRichard Henderson     DisasCond null_cond;
5461766fe9SRichard Henderson     TCGLabel *null_lab;
5561766fe9SRichard Henderson 
5661766fe9SRichard Henderson     bool singlestep_enabled;
5761766fe9SRichard Henderson     bool psw_n_nonzero;
5861766fe9SRichard Henderson } DisasContext;
5961766fe9SRichard Henderson 
6061766fe9SRichard Henderson /* Return values from translate_one, indicating the state of the TB.
6161766fe9SRichard Henderson    Note that zero indicates that we are not exiting the TB.  */
6261766fe9SRichard Henderson 
6361766fe9SRichard Henderson typedef enum {
6461766fe9SRichard Henderson     NO_EXIT,
6561766fe9SRichard Henderson 
6661766fe9SRichard Henderson     /* We have emitted one or more goto_tb.  No fixup required.  */
6761766fe9SRichard Henderson     EXIT_GOTO_TB,
6861766fe9SRichard Henderson 
6961766fe9SRichard Henderson     /* We are not using a goto_tb (for whatever reason), but have updated
7061766fe9SRichard Henderson        the iaq (for whatever reason), so don't do it again on exit.  */
7161766fe9SRichard Henderson     EXIT_IAQ_N_UPDATED,
7261766fe9SRichard Henderson 
7361766fe9SRichard Henderson     /* We are exiting the TB, but have neither emitted a goto_tb, nor
7461766fe9SRichard Henderson        updated the iaq for the next instruction to be executed.  */
7561766fe9SRichard Henderson     EXIT_IAQ_N_STALE,
7661766fe9SRichard Henderson 
7761766fe9SRichard Henderson     /* We are ending the TB with a noreturn function call, e.g. longjmp.
7861766fe9SRichard Henderson        No following code will be executed.  */
7961766fe9SRichard Henderson     EXIT_NORETURN,
8061766fe9SRichard Henderson } ExitStatus;
8161766fe9SRichard Henderson 
8261766fe9SRichard Henderson typedef struct DisasInsn {
8361766fe9SRichard Henderson     uint32_t insn, mask;
8461766fe9SRichard Henderson     ExitStatus (*trans)(DisasContext *ctx, uint32_t insn,
8561766fe9SRichard Henderson                         const struct DisasInsn *f);
86b2167459SRichard Henderson     union {
87*eff235ebSPaolo Bonzini         void (*ttt)(TCGv, TCGv, TCGv);
88*eff235ebSPaolo Bonzini         void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
89*eff235ebSPaolo Bonzini         void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
90*eff235ebSPaolo Bonzini         void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
91*eff235ebSPaolo Bonzini         void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
92*eff235ebSPaolo Bonzini         void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
93*eff235ebSPaolo Bonzini         void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
94*eff235ebSPaolo Bonzini     } f;
9561766fe9SRichard Henderson } DisasInsn;
9661766fe9SRichard Henderson 
9761766fe9SRichard Henderson /* global register indexes */
9861766fe9SRichard Henderson static TCGv_env cpu_env;
9961766fe9SRichard Henderson static TCGv cpu_gr[32];
10061766fe9SRichard Henderson static TCGv cpu_iaoq_f;
10161766fe9SRichard Henderson static TCGv cpu_iaoq_b;
10261766fe9SRichard Henderson static TCGv cpu_sar;
10361766fe9SRichard Henderson static TCGv cpu_psw_n;
10461766fe9SRichard Henderson static TCGv cpu_psw_v;
10561766fe9SRichard Henderson static TCGv cpu_psw_cb;
10661766fe9SRichard Henderson static TCGv cpu_psw_cb_msb;
10761766fe9SRichard Henderson static TCGv cpu_cr26;
10861766fe9SRichard Henderson static TCGv cpu_cr27;
10961766fe9SRichard Henderson 
11061766fe9SRichard Henderson #include "exec/gen-icount.h"
11161766fe9SRichard Henderson 
11261766fe9SRichard Henderson void hppa_translate_init(void)
11361766fe9SRichard Henderson {
11461766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
11561766fe9SRichard Henderson 
11661766fe9SRichard Henderson     typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
11761766fe9SRichard Henderson     static const GlobalVar vars[] = {
11861766fe9SRichard Henderson         DEF_VAR(sar),
11961766fe9SRichard Henderson         DEF_VAR(cr26),
12061766fe9SRichard Henderson         DEF_VAR(cr27),
12161766fe9SRichard Henderson         DEF_VAR(psw_n),
12261766fe9SRichard Henderson         DEF_VAR(psw_v),
12361766fe9SRichard Henderson         DEF_VAR(psw_cb),
12461766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
12561766fe9SRichard Henderson         DEF_VAR(iaoq_f),
12661766fe9SRichard Henderson         DEF_VAR(iaoq_b),
12761766fe9SRichard Henderson     };
12861766fe9SRichard Henderson 
12961766fe9SRichard Henderson #undef DEF_VAR
13061766fe9SRichard Henderson 
13161766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
13261766fe9SRichard Henderson     static const char gr_names[32][4] = {
13361766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
13461766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
13561766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
13661766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
13761766fe9SRichard Henderson     };
13861766fe9SRichard Henderson 
13961766fe9SRichard Henderson     static bool done_init = 0;
14061766fe9SRichard Henderson     int i;
14161766fe9SRichard Henderson 
14261766fe9SRichard Henderson     if (done_init) {
14361766fe9SRichard Henderson         return;
14461766fe9SRichard Henderson     }
14561766fe9SRichard Henderson     done_init = 1;
14661766fe9SRichard Henderson 
14761766fe9SRichard Henderson     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
14861766fe9SRichard Henderson     tcg_ctx.tcg_env = cpu_env;
14961766fe9SRichard Henderson 
15061766fe9SRichard Henderson     TCGV_UNUSED(cpu_gr[0]);
15161766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
15261766fe9SRichard Henderson         cpu_gr[i] = tcg_global_mem_new(cpu_env,
15361766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
15461766fe9SRichard Henderson                                        gr_names[i]);
15561766fe9SRichard Henderson     }
15661766fe9SRichard Henderson 
15761766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
15861766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
15961766fe9SRichard Henderson         *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
16061766fe9SRichard Henderson     }
16161766fe9SRichard Henderson }
16261766fe9SRichard Henderson 
163129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
164129e9cc3SRichard Henderson {
165129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NEVER };
166129e9cc3SRichard Henderson     TCGV_UNUSED(r.a0);
167129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
168129e9cc3SRichard Henderson     return r;
169129e9cc3SRichard Henderson }
170129e9cc3SRichard Henderson 
171129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
172129e9cc3SRichard Henderson {
173129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
174129e9cc3SRichard Henderson     r.a0 = cpu_psw_n;
175129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
176129e9cc3SRichard Henderson     return r;
177129e9cc3SRichard Henderson }
178129e9cc3SRichard Henderson 
179129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0)
180129e9cc3SRichard Henderson {
181129e9cc3SRichard Henderson     DisasCond r = { .c = c, .a1_is_0 = true };
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     TCGV_UNUSED(r.a1);
187129e9cc3SRichard Henderson 
188129e9cc3SRichard Henderson     return r;
189129e9cc3SRichard Henderson }
190129e9cc3SRichard Henderson 
191129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
192129e9cc3SRichard Henderson {
193129e9cc3SRichard Henderson     DisasCond r = { .c = c };
194129e9cc3SRichard Henderson 
195129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
196129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
197129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
198129e9cc3SRichard Henderson     r.a1 = tcg_temp_new();
199129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a1, a1);
200129e9cc3SRichard Henderson 
201129e9cc3SRichard Henderson     return r;
202129e9cc3SRichard Henderson }
203129e9cc3SRichard Henderson 
204129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond)
205129e9cc3SRichard Henderson {
206129e9cc3SRichard Henderson     if (cond->a1_is_0) {
207129e9cc3SRichard Henderson         cond->a1_is_0 = false;
208129e9cc3SRichard Henderson         cond->a1 = tcg_const_tl(0);
209129e9cc3SRichard Henderson     }
210129e9cc3SRichard Henderson }
211129e9cc3SRichard Henderson 
212129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
213129e9cc3SRichard Henderson {
214129e9cc3SRichard Henderson     switch (cond->c) {
215129e9cc3SRichard Henderson     default:
216129e9cc3SRichard Henderson         if (!cond->a0_is_n) {
217129e9cc3SRichard Henderson             tcg_temp_free(cond->a0);
218129e9cc3SRichard Henderson         }
219129e9cc3SRichard Henderson         if (!cond->a1_is_0) {
220129e9cc3SRichard Henderson             tcg_temp_free(cond->a1);
221129e9cc3SRichard Henderson         }
222129e9cc3SRichard Henderson         cond->a0_is_n = false;
223129e9cc3SRichard Henderson         cond->a1_is_0 = false;
224129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a0);
225129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a1);
226129e9cc3SRichard Henderson         /* fallthru */
227129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
228129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
229129e9cc3SRichard Henderson         break;
230129e9cc3SRichard Henderson     case TCG_COND_NEVER:
231129e9cc3SRichard Henderson         break;
232129e9cc3SRichard Henderson     }
233129e9cc3SRichard Henderson }
234129e9cc3SRichard Henderson 
23561766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx)
23661766fe9SRichard Henderson {
23761766fe9SRichard Henderson     unsigned i = ctx->ntemps++;
23861766fe9SRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->temps));
23961766fe9SRichard Henderson     return ctx->temps[i] = tcg_temp_new();
24061766fe9SRichard Henderson }
24161766fe9SRichard Henderson 
24261766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v)
24361766fe9SRichard Henderson {
24461766fe9SRichard Henderson     TCGv t = get_temp(ctx);
24561766fe9SRichard Henderson     tcg_gen_movi_tl(t, v);
24661766fe9SRichard Henderson     return t;
24761766fe9SRichard Henderson }
24861766fe9SRichard Henderson 
24961766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg)
25061766fe9SRichard Henderson {
25161766fe9SRichard Henderson     if (reg == 0) {
25261766fe9SRichard Henderson         TCGv t = get_temp(ctx);
25361766fe9SRichard Henderson         tcg_gen_movi_tl(t, 0);
25461766fe9SRichard Henderson         return t;
25561766fe9SRichard Henderson     } else {
25661766fe9SRichard Henderson         return cpu_gr[reg];
25761766fe9SRichard Henderson     }
25861766fe9SRichard Henderson }
25961766fe9SRichard Henderson 
26061766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
26161766fe9SRichard Henderson {
262129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
26361766fe9SRichard Henderson         return get_temp(ctx);
26461766fe9SRichard Henderson     } else {
26561766fe9SRichard Henderson         return cpu_gr[reg];
26661766fe9SRichard Henderson     }
26761766fe9SRichard Henderson }
26861766fe9SRichard Henderson 
269129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
270129e9cc3SRichard Henderson {
271129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
272129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
273129e9cc3SRichard Henderson         tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
274129e9cc3SRichard Henderson                            ctx->null_cond.a1, dest, t);
275129e9cc3SRichard Henderson     } else {
276129e9cc3SRichard Henderson         tcg_gen_mov_tl(dest, t);
277129e9cc3SRichard Henderson     }
278129e9cc3SRichard Henderson }
279129e9cc3SRichard Henderson 
280129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
281129e9cc3SRichard Henderson {
282129e9cc3SRichard Henderson     if (reg != 0) {
283129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
284129e9cc3SRichard Henderson     }
285129e9cc3SRichard Henderson }
286129e9cc3SRichard Henderson 
28796d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
28896d6407fSRichard Henderson # define HI_OFS  0
28996d6407fSRichard Henderson # define LO_OFS  4
29096d6407fSRichard Henderson #else
29196d6407fSRichard Henderson # define HI_OFS  4
29296d6407fSRichard Henderson # define LO_OFS  0
29396d6407fSRichard Henderson #endif
29496d6407fSRichard Henderson 
29596d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
29696d6407fSRichard Henderson {
29796d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
29896d6407fSRichard Henderson     tcg_gen_ld_i32(ret, cpu_env,
29996d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
30096d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
30196d6407fSRichard Henderson     return ret;
30296d6407fSRichard Henderson }
30396d6407fSRichard Henderson 
304ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt)
305ebe9383cSRichard Henderson {
306ebe9383cSRichard Henderson     if (rt == 0) {
307ebe9383cSRichard Henderson         return tcg_const_i32(0);
308ebe9383cSRichard Henderson     } else {
309ebe9383cSRichard Henderson         return load_frw_i32(rt);
310ebe9383cSRichard Henderson     }
311ebe9383cSRichard Henderson }
312ebe9383cSRichard Henderson 
313ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt)
314ebe9383cSRichard Henderson {
315ebe9383cSRichard Henderson     if (rt == 0) {
316ebe9383cSRichard Henderson         return tcg_const_i64(0);
317ebe9383cSRichard Henderson     } else {
318ebe9383cSRichard Henderson         TCGv_i64 ret = tcg_temp_new_i64();
319ebe9383cSRichard Henderson         tcg_gen_ld32u_i64(ret, cpu_env,
320ebe9383cSRichard Henderson                           offsetof(CPUHPPAState, fr[rt & 31])
321ebe9383cSRichard Henderson                           + (rt & 32 ? LO_OFS : HI_OFS));
322ebe9383cSRichard Henderson         return ret;
323ebe9383cSRichard Henderson     }
324ebe9383cSRichard Henderson }
325ebe9383cSRichard Henderson 
32696d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
32796d6407fSRichard Henderson {
32896d6407fSRichard Henderson     tcg_gen_st_i32(val, cpu_env,
32996d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
33096d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
33196d6407fSRichard Henderson }
33296d6407fSRichard Henderson 
33396d6407fSRichard Henderson #undef HI_OFS
33496d6407fSRichard Henderson #undef LO_OFS
33596d6407fSRichard Henderson 
33696d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
33796d6407fSRichard Henderson {
33896d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
33996d6407fSRichard Henderson     tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
34096d6407fSRichard Henderson     return ret;
34196d6407fSRichard Henderson }
34296d6407fSRichard Henderson 
343ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt)
344ebe9383cSRichard Henderson {
345ebe9383cSRichard Henderson     if (rt == 0) {
346ebe9383cSRichard Henderson         return tcg_const_i64(0);
347ebe9383cSRichard Henderson     } else {
348ebe9383cSRichard Henderson         return load_frd(rt);
349ebe9383cSRichard Henderson     }
350ebe9383cSRichard Henderson }
351ebe9383cSRichard Henderson 
35296d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
35396d6407fSRichard Henderson {
35496d6407fSRichard Henderson     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
35596d6407fSRichard Henderson }
35696d6407fSRichard Henderson 
357129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
358129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
359129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
360129e9cc3SRichard Henderson {
361129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
362129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
363129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
364129e9cc3SRichard Henderson 
365129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
366129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
367129e9cc3SRichard Henderson 
368129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
369129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
370129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
371129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
372129e9cc3SRichard Henderson             tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
373129e9cc3SRichard Henderson         }
374129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
375129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
376129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
377129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
378129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
379129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
380129e9cc3SRichard Henderson         }
381129e9cc3SRichard Henderson 
382129e9cc3SRichard Henderson         tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
383129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
384129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
385129e9cc3SRichard Henderson     }
386129e9cc3SRichard Henderson }
387129e9cc3SRichard Henderson 
388129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
389129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
390129e9cc3SRichard Henderson {
391129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
392129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
393129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
394129e9cc3SRichard Henderson         }
395129e9cc3SRichard Henderson         return;
396129e9cc3SRichard Henderson     }
397129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
398129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
399129e9cc3SRichard Henderson         tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
400129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
401129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
402129e9cc3SRichard Henderson     }
403129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
404129e9cc3SRichard Henderson }
405129e9cc3SRichard Henderson 
406129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
407129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
408129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
409129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
410129e9cc3SRichard Henderson {
411129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
412129e9cc3SRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, x);
413129e9cc3SRichard Henderson     }
414129e9cc3SRichard Henderson }
415129e9cc3SRichard Henderson 
416129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
417129e9cc3SRichard Henderson    This is the pair to nullify_over.  */
418129e9cc3SRichard Henderson static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
419129e9cc3SRichard Henderson {
420129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
421129e9cc3SRichard Henderson 
422129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
423129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
424129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
425129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
426129e9cc3SRichard Henderson         return status;
427129e9cc3SRichard Henderson     }
428129e9cc3SRichard Henderson     ctx->null_lab = NULL;
429129e9cc3SRichard Henderson 
430129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
431129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
432129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
433129e9cc3SRichard Henderson         gen_set_label(null_lab);
434129e9cc3SRichard Henderson     } else {
435129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
436129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
437129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
438129e9cc3SRichard Henderson            label we have the proper value in place.  */
439129e9cc3SRichard Henderson         nullify_save(ctx);
440129e9cc3SRichard Henderson         gen_set_label(null_lab);
441129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
442129e9cc3SRichard Henderson     }
443129e9cc3SRichard Henderson 
444129e9cc3SRichard Henderson     assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
445129e9cc3SRichard Henderson     if (status == EXIT_NORETURN) {
446129e9cc3SRichard Henderson         status = NO_EXIT;
447129e9cc3SRichard Henderson     }
448129e9cc3SRichard Henderson     return status;
449129e9cc3SRichard Henderson }
450129e9cc3SRichard Henderson 
45161766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
45261766fe9SRichard Henderson {
45361766fe9SRichard Henderson     if (unlikely(ival == -1)) {
45461766fe9SRichard Henderson         tcg_gen_mov_tl(dest, vval);
45561766fe9SRichard Henderson     } else {
45661766fe9SRichard Henderson         tcg_gen_movi_tl(dest, ival);
45761766fe9SRichard Henderson     }
45861766fe9SRichard Henderson }
45961766fe9SRichard Henderson 
46061766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
46161766fe9SRichard Henderson {
46261766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
46361766fe9SRichard Henderson }
46461766fe9SRichard Henderson 
46561766fe9SRichard Henderson static void gen_excp_1(int exception)
46661766fe9SRichard Henderson {
46761766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
46861766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
46961766fe9SRichard Henderson     tcg_temp_free_i32(t);
47061766fe9SRichard Henderson }
47161766fe9SRichard Henderson 
47261766fe9SRichard Henderson static ExitStatus gen_excp(DisasContext *ctx, int exception)
47361766fe9SRichard Henderson {
47461766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
47561766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
476129e9cc3SRichard Henderson     nullify_save(ctx);
47761766fe9SRichard Henderson     gen_excp_1(exception);
47861766fe9SRichard Henderson     return EXIT_NORETURN;
47961766fe9SRichard Henderson }
48061766fe9SRichard Henderson 
48161766fe9SRichard Henderson static ExitStatus gen_illegal(DisasContext *ctx)
48261766fe9SRichard Henderson {
483129e9cc3SRichard Henderson     nullify_over(ctx);
484129e9cc3SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
48561766fe9SRichard Henderson }
48661766fe9SRichard Henderson 
48761766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
48861766fe9SRichard Henderson {
48961766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
49061766fe9SRichard Henderson     if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
49161766fe9SRichard Henderson         return false;
49261766fe9SRichard Henderson     }
49361766fe9SRichard Henderson     return true;
49461766fe9SRichard Henderson }
49561766fe9SRichard Henderson 
496129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
497129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
498129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
499129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
500129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
501129e9cc3SRichard Henderson {
502129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
503129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
504129e9cc3SRichard Henderson }
505129e9cc3SRichard Henderson 
50661766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
50761766fe9SRichard Henderson                         target_ulong f, target_ulong b)
50861766fe9SRichard Henderson {
50961766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
51061766fe9SRichard Henderson         tcg_gen_goto_tb(which);
51161766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_f, f);
51261766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_b, b);
51361766fe9SRichard Henderson         tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
51461766fe9SRichard Henderson     } else {
51561766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
51661766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
51761766fe9SRichard Henderson         if (ctx->singlestep_enabled) {
51861766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
51961766fe9SRichard Henderson         } else {
52061766fe9SRichard Henderson             tcg_gen_exit_tb(0);
52161766fe9SRichard Henderson         }
52261766fe9SRichard Henderson     }
52361766fe9SRichard Henderson }
52461766fe9SRichard Henderson 
525b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
526b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
527b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
528b2167459SRichard Henderson {
529b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
530b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
531b2167459SRichard Henderson     return x;
532b2167459SRichard Henderson }
533b2167459SRichard Henderson 
534ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn)
535ebe9383cSRichard Henderson {
536ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 6, 1);
537ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 0, 5);
538ebe9383cSRichard Henderson     return r1 * 32 + r0;
539ebe9383cSRichard Henderson }
540ebe9383cSRichard Henderson 
541ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn)
542ebe9383cSRichard Henderson {
543ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 7, 1);
544ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 21, 5);
545ebe9383cSRichard Henderson     return r1 * 32 + r0;
546ebe9383cSRichard Henderson }
547ebe9383cSRichard Henderson 
548ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn)
549ebe9383cSRichard Henderson {
550ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 12, 1);
551ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 16, 5);
552ebe9383cSRichard Henderson     return r1 * 32 + r0;
553ebe9383cSRichard Henderson }
554ebe9383cSRichard Henderson 
555ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn)
556ebe9383cSRichard Henderson {
557ebe9383cSRichard Henderson     unsigned r2 = extract32(insn, 8, 1);
558ebe9383cSRichard Henderson     unsigned r1 = extract32(insn, 13, 3);
559ebe9383cSRichard Henderson     unsigned r0 = extract32(insn, 9, 2);
560ebe9383cSRichard Henderson     return r2 * 32 + r1 * 4 + r0;
561ebe9383cSRichard Henderson }
562ebe9383cSRichard Henderson 
56398cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn)
56498cd9ca7SRichard Henderson {
56598cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
56698cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
56798cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
56898cd9ca7SRichard Henderson     return x;
56998cd9ca7SRichard Henderson }
57098cd9ca7SRichard Henderson 
571b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
572b2167459SRichard Henderson {
573b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
574b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
575b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
576b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
577b2167459SRichard Henderson }
578b2167459SRichard Henderson 
57996d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn)
58096d6407fSRichard Henderson {
58196d6407fSRichard Henderson     /* Take the name from PA2.0, which produces a 14-bit shifted number
58296d6407fSRichard Henderson        only with wide mode; otherwise a 12-bit shifted number.  Since we
58396d6407fSRichard Henderson        don't implement wide mode, this is always the 12-bit number.  */
58496d6407fSRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
58596d6407fSRichard Henderson     x = (x << 11) | extract32(insn, 2, 11);
58696d6407fSRichard Henderson     return x << 2;
58796d6407fSRichard Henderson }
58896d6407fSRichard Henderson 
58998cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn)
59098cd9ca7SRichard Henderson {
59198cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
59298cd9ca7SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
59398cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
59498cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
59598cd9ca7SRichard Henderson     return x << 2;
59698cd9ca7SRichard Henderson }
59798cd9ca7SRichard Henderson 
598b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
599b2167459SRichard Henderson {
600b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
601b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
602b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
603b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
604b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
605b2167459SRichard Henderson     return x << 11;
606b2167459SRichard Henderson }
607b2167459SRichard Henderson 
60898cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn)
60998cd9ca7SRichard Henderson {
61098cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
61198cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 16, 10);
61298cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
61398cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
61498cd9ca7SRichard Henderson     return x << 2;
61598cd9ca7SRichard Henderson }
61698cd9ca7SRichard Henderson 
617b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
618b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
619b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
620b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
621b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
622b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
623b2167459SRichard Henderson 
624b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
625b2167459SRichard Henderson {
626b2167459SRichard Henderson     DisasCond cond;
627b2167459SRichard Henderson     TCGv tmp;
628b2167459SRichard Henderson 
629b2167459SRichard Henderson     switch (cf >> 1) {
630b2167459SRichard Henderson     case 0: /* Never / TR */
631b2167459SRichard Henderson         cond = cond_make_f();
632b2167459SRichard Henderson         break;
633b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
634b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
635b2167459SRichard Henderson         break;
636b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
637b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
638b2167459SRichard Henderson         break;
639b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
640b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
641b2167459SRichard Henderson         break;
642b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
643b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
644b2167459SRichard Henderson         break;
645b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
646b2167459SRichard Henderson         tmp = tcg_temp_new();
647b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
648b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
649b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
650b2167459SRichard Henderson         tcg_temp_free(tmp);
651b2167459SRichard Henderson         break;
652b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
653b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
654b2167459SRichard Henderson         break;
655b2167459SRichard Henderson     case 7: /* OD / EV */
656b2167459SRichard Henderson         tmp = tcg_temp_new();
657b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
658b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
659b2167459SRichard Henderson         tcg_temp_free(tmp);
660b2167459SRichard Henderson         break;
661b2167459SRichard Henderson     default:
662b2167459SRichard Henderson         g_assert_not_reached();
663b2167459SRichard Henderson     }
664b2167459SRichard Henderson     if (cf & 1) {
665b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
666b2167459SRichard Henderson     }
667b2167459SRichard Henderson 
668b2167459SRichard Henderson     return cond;
669b2167459SRichard Henderson }
670b2167459SRichard Henderson 
671b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
672b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
673b2167459SRichard Henderson    deleted as unused.  */
674b2167459SRichard Henderson 
675b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
676b2167459SRichard Henderson {
677b2167459SRichard Henderson     DisasCond cond;
678b2167459SRichard Henderson 
679b2167459SRichard Henderson     switch (cf >> 1) {
680b2167459SRichard Henderson     case 1: /* = / <> */
681b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
682b2167459SRichard Henderson         break;
683b2167459SRichard Henderson     case 2: /* < / >= */
684b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
685b2167459SRichard Henderson         break;
686b2167459SRichard Henderson     case 3: /* <= / > */
687b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
688b2167459SRichard Henderson         break;
689b2167459SRichard Henderson     case 4: /* << / >>= */
690b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
691b2167459SRichard Henderson         break;
692b2167459SRichard Henderson     case 5: /* <<= / >> */
693b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
694b2167459SRichard Henderson         break;
695b2167459SRichard Henderson     default:
696b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
697b2167459SRichard Henderson     }
698b2167459SRichard Henderson     if (cf & 1) {
699b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
700b2167459SRichard Henderson     }
701b2167459SRichard Henderson 
702b2167459SRichard Henderson     return cond;
703b2167459SRichard Henderson }
704b2167459SRichard Henderson 
705b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
706b2167459SRichard Henderson    computed, and use of them is undefined.  */
707b2167459SRichard Henderson 
708b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
709b2167459SRichard Henderson {
710b2167459SRichard Henderson     switch (cf >> 1) {
711b2167459SRichard Henderson     case 4: case 5: case 6:
712b2167459SRichard Henderson         cf &= 1;
713b2167459SRichard Henderson         break;
714b2167459SRichard Henderson     }
715b2167459SRichard Henderson     return do_cond(cf, res, res, res);
716b2167459SRichard Henderson }
717b2167459SRichard Henderson 
71898cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
71998cd9ca7SRichard Henderson 
72098cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res)
72198cd9ca7SRichard Henderson {
72298cd9ca7SRichard Henderson     unsigned c, f;
72398cd9ca7SRichard Henderson 
72498cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
72598cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
72698cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
72798cd9ca7SRichard Henderson     c = orig & 3;
72898cd9ca7SRichard Henderson     if (c == 3) {
72998cd9ca7SRichard Henderson         c = 7;
73098cd9ca7SRichard Henderson     }
73198cd9ca7SRichard Henderson     f = (orig & 4) / 4;
73298cd9ca7SRichard Henderson 
73398cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
73498cd9ca7SRichard Henderson }
73598cd9ca7SRichard Henderson 
736b2167459SRichard Henderson /* Similar, but for unit conditions.  */
737b2167459SRichard Henderson 
738b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
739b2167459SRichard Henderson {
740b2167459SRichard Henderson     DisasCond cond;
741b2167459SRichard Henderson     TCGv tmp, cb;
742b2167459SRichard Henderson 
743b2167459SRichard Henderson     TCGV_UNUSED(cb);
744b2167459SRichard Henderson     if (cf & 8) {
745b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
746b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
747b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
748b2167459SRichard Henderson          */
749b2167459SRichard Henderson         cb = tcg_temp_new();
750b2167459SRichard Henderson         tmp = tcg_temp_new();
751b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
752b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
753b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
754b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
755b2167459SRichard Henderson         tcg_temp_free(tmp);
756b2167459SRichard Henderson     }
757b2167459SRichard Henderson 
758b2167459SRichard Henderson     switch (cf >> 1) {
759b2167459SRichard Henderson     case 0: /* never / TR */
760b2167459SRichard Henderson     case 1: /* undefined */
761b2167459SRichard Henderson     case 5: /* undefined */
762b2167459SRichard Henderson         cond = cond_make_f();
763b2167459SRichard Henderson         break;
764b2167459SRichard Henderson 
765b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
766b2167459SRichard Henderson         /* See hasless(v,1) from
767b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
768b2167459SRichard Henderson          */
769b2167459SRichard Henderson         tmp = tcg_temp_new();
770b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
771b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
772b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
773b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
774b2167459SRichard Henderson         tcg_temp_free(tmp);
775b2167459SRichard Henderson         break;
776b2167459SRichard Henderson 
777b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
778b2167459SRichard Henderson         tmp = tcg_temp_new();
779b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
780b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
781b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
782b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
783b2167459SRichard Henderson         tcg_temp_free(tmp);
784b2167459SRichard Henderson         break;
785b2167459SRichard Henderson 
786b2167459SRichard Henderson     case 4: /* SDC / NDC */
787b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
788b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
789b2167459SRichard Henderson         break;
790b2167459SRichard Henderson 
791b2167459SRichard Henderson     case 6: /* SBC / NBC */
792b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
793b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
794b2167459SRichard Henderson         break;
795b2167459SRichard Henderson 
796b2167459SRichard Henderson     case 7: /* SHC / NHC */
797b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
798b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
799b2167459SRichard Henderson         break;
800b2167459SRichard Henderson 
801b2167459SRichard Henderson     default:
802b2167459SRichard Henderson         g_assert_not_reached();
803b2167459SRichard Henderson     }
804b2167459SRichard Henderson     if (cf & 8) {
805b2167459SRichard Henderson         tcg_temp_free(cb);
806b2167459SRichard Henderson     }
807b2167459SRichard Henderson     if (cf & 1) {
808b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
809b2167459SRichard Henderson     }
810b2167459SRichard Henderson 
811b2167459SRichard Henderson     return cond;
812b2167459SRichard Henderson }
813b2167459SRichard Henderson 
814b2167459SRichard Henderson /* Compute signed overflow for addition.  */
815b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
816b2167459SRichard Henderson {
817b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
818b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
819b2167459SRichard Henderson 
820b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
821b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
822b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
823b2167459SRichard Henderson     tcg_temp_free(tmp);
824b2167459SRichard Henderson 
825b2167459SRichard Henderson     return sv;
826b2167459SRichard Henderson }
827b2167459SRichard Henderson 
828b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
829b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
830b2167459SRichard Henderson {
831b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
832b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
833b2167459SRichard Henderson 
834b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
835b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
836b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
837b2167459SRichard Henderson     tcg_temp_free(tmp);
838b2167459SRichard Henderson 
839b2167459SRichard Henderson     return sv;
840b2167459SRichard Henderson }
841b2167459SRichard Henderson 
842b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
843b2167459SRichard Henderson                          unsigned shift, bool is_l, bool is_tsv, bool is_tc,
844b2167459SRichard Henderson                          bool is_c, unsigned cf)
845b2167459SRichard Henderson {
846b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
847b2167459SRichard Henderson     unsigned c = cf >> 1;
848b2167459SRichard Henderson     DisasCond cond;
849b2167459SRichard Henderson 
850b2167459SRichard Henderson     dest = tcg_temp_new();
851b2167459SRichard Henderson     TCGV_UNUSED(cb);
852b2167459SRichard Henderson     TCGV_UNUSED(cb_msb);
853b2167459SRichard Henderson 
854b2167459SRichard Henderson     if (shift) {
855b2167459SRichard Henderson         tmp = get_temp(ctx);
856b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
857b2167459SRichard Henderson         in1 = tmp;
858b2167459SRichard Henderson     }
859b2167459SRichard Henderson 
860b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
861b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
862b2167459SRichard Henderson         cb_msb = get_temp(ctx);
863b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
864b2167459SRichard Henderson         if (is_c) {
865b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
866b2167459SRichard Henderson         }
867b2167459SRichard Henderson         tcg_temp_free(zero);
868b2167459SRichard Henderson         if (!is_l) {
869b2167459SRichard Henderson             cb = get_temp(ctx);
870b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
871b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
872b2167459SRichard Henderson         }
873b2167459SRichard Henderson     } else {
874b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
875b2167459SRichard Henderson         if (is_c) {
876b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
877b2167459SRichard Henderson         }
878b2167459SRichard Henderson     }
879b2167459SRichard Henderson 
880b2167459SRichard Henderson     /* Compute signed overflow if required.  */
881b2167459SRichard Henderson     TCGV_UNUSED(sv);
882b2167459SRichard Henderson     if (is_tsv || c == 6) {
883b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
884b2167459SRichard Henderson         if (is_tsv) {
885b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
886b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
887b2167459SRichard Henderson         }
888b2167459SRichard Henderson     }
889b2167459SRichard Henderson 
890b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
891b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
892b2167459SRichard Henderson     if (is_tc) {
893b2167459SRichard Henderson         cond_prep(&cond);
894b2167459SRichard Henderson         tmp = tcg_temp_new();
895b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
896b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
897b2167459SRichard Henderson         tcg_temp_free(tmp);
898b2167459SRichard Henderson     }
899b2167459SRichard Henderson 
900b2167459SRichard Henderson     /* Write back the result.  */
901b2167459SRichard Henderson     if (!is_l) {
902b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
903b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
904b2167459SRichard Henderson     }
905b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
906b2167459SRichard Henderson     tcg_temp_free(dest);
907b2167459SRichard Henderson 
908b2167459SRichard Henderson     /* Install the new nullification.  */
909b2167459SRichard Henderson     cond_free(&ctx->null_cond);
910b2167459SRichard Henderson     ctx->null_cond = cond;
911b2167459SRichard Henderson     return NO_EXIT;
912b2167459SRichard Henderson }
913b2167459SRichard Henderson 
914b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
915b2167459SRichard Henderson                          bool is_tsv, bool is_b, bool is_tc, unsigned cf)
916b2167459SRichard Henderson {
917b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
918b2167459SRichard Henderson     unsigned c = cf >> 1;
919b2167459SRichard Henderson     DisasCond cond;
920b2167459SRichard Henderson 
921b2167459SRichard Henderson     dest = tcg_temp_new();
922b2167459SRichard Henderson     cb = tcg_temp_new();
923b2167459SRichard Henderson     cb_msb = tcg_temp_new();
924b2167459SRichard Henderson 
925b2167459SRichard Henderson     zero = tcg_const_tl(0);
926b2167459SRichard Henderson     if (is_b) {
927b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
928b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
929b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
930b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
931b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
932b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
933b2167459SRichard Henderson     } else {
934b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
935b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
936b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
937b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
938b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
939b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
940b2167459SRichard Henderson     }
941b2167459SRichard Henderson     tcg_temp_free(zero);
942b2167459SRichard Henderson 
943b2167459SRichard Henderson     /* Compute signed overflow if required.  */
944b2167459SRichard Henderson     TCGV_UNUSED(sv);
945b2167459SRichard Henderson     if (is_tsv || c == 6) {
946b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
947b2167459SRichard Henderson         if (is_tsv) {
948b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
949b2167459SRichard Henderson         }
950b2167459SRichard Henderson     }
951b2167459SRichard Henderson 
952b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
953b2167459SRichard Henderson     if (!is_b) {
954b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
955b2167459SRichard Henderson     } else {
956b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
957b2167459SRichard Henderson     }
958b2167459SRichard Henderson 
959b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
960b2167459SRichard Henderson     if (is_tc) {
961b2167459SRichard Henderson         cond_prep(&cond);
962b2167459SRichard Henderson         tmp = tcg_temp_new();
963b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
964b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
965b2167459SRichard Henderson         tcg_temp_free(tmp);
966b2167459SRichard Henderson     }
967b2167459SRichard Henderson 
968b2167459SRichard Henderson     /* Write back the result.  */
969b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
970b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
971b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
972b2167459SRichard Henderson     tcg_temp_free(dest);
973b2167459SRichard Henderson 
974b2167459SRichard Henderson     /* Install the new nullification.  */
975b2167459SRichard Henderson     cond_free(&ctx->null_cond);
976b2167459SRichard Henderson     ctx->null_cond = cond;
977b2167459SRichard Henderson     return NO_EXIT;
978b2167459SRichard Henderson }
979b2167459SRichard Henderson 
980b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
981b2167459SRichard Henderson                             TCGv in2, unsigned cf)
982b2167459SRichard Henderson {
983b2167459SRichard Henderson     TCGv dest, sv;
984b2167459SRichard Henderson     DisasCond cond;
985b2167459SRichard Henderson 
986b2167459SRichard Henderson     dest = tcg_temp_new();
987b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
988b2167459SRichard Henderson 
989b2167459SRichard Henderson     /* Compute signed overflow if required.  */
990b2167459SRichard Henderson     TCGV_UNUSED(sv);
991b2167459SRichard Henderson     if ((cf >> 1) == 6) {
992b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
993b2167459SRichard Henderson     }
994b2167459SRichard Henderson 
995b2167459SRichard Henderson     /* Form the condition for the compare.  */
996b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
997b2167459SRichard Henderson 
998b2167459SRichard Henderson     /* Clear.  */
999b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
1000b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1001b2167459SRichard Henderson     tcg_temp_free(dest);
1002b2167459SRichard Henderson 
1003b2167459SRichard Henderson     /* Install the new nullification.  */
1004b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1005b2167459SRichard Henderson     ctx->null_cond = cond;
1006b2167459SRichard Henderson     return NO_EXIT;
1007b2167459SRichard Henderson }
1008b2167459SRichard Henderson 
1009b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
1010b2167459SRichard Henderson                          unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
1011b2167459SRichard Henderson {
1012b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
1013b2167459SRichard Henderson 
1014b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
1015b2167459SRichard Henderson     fn(dest, in1, in2);
1016b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1017b2167459SRichard Henderson 
1018b2167459SRichard Henderson     /* Install the new nullification.  */
1019b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1020b2167459SRichard Henderson     if (cf) {
1021b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
1022b2167459SRichard Henderson     }
1023b2167459SRichard Henderson     return NO_EXIT;
1024b2167459SRichard Henderson }
1025b2167459SRichard Henderson 
1026b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1027b2167459SRichard Henderson                           TCGv in2, unsigned cf, bool is_tc,
1028b2167459SRichard Henderson                           void (*fn)(TCGv, TCGv, TCGv))
1029b2167459SRichard Henderson {
1030b2167459SRichard Henderson     TCGv dest;
1031b2167459SRichard Henderson     DisasCond cond;
1032b2167459SRichard Henderson 
1033b2167459SRichard Henderson     if (cf == 0) {
1034b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
1035b2167459SRichard Henderson         fn(dest, in1, in2);
1036b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1037b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1038b2167459SRichard Henderson     } else {
1039b2167459SRichard Henderson         dest = tcg_temp_new();
1040b2167459SRichard Henderson         fn(dest, in1, in2);
1041b2167459SRichard Henderson 
1042b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
1043b2167459SRichard Henderson 
1044b2167459SRichard Henderson         if (is_tc) {
1045b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
1046b2167459SRichard Henderson             cond_prep(&cond);
1047b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1048b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
1049b2167459SRichard Henderson             tcg_temp_free(tmp);
1050b2167459SRichard Henderson         }
1051b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1052b2167459SRichard Henderson 
1053b2167459SRichard Henderson         cond_free(&ctx->null_cond);
1054b2167459SRichard Henderson         ctx->null_cond = cond;
1055b2167459SRichard Henderson     }
1056b2167459SRichard Henderson     return NO_EXIT;
1057b2167459SRichard Henderson }
1058b2167459SRichard Henderson 
105996d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
106096d6407fSRichard Henderson  * < 0 for pre-modify,
106196d6407fSRichard Henderson  * > 0 for post-modify,
106296d6407fSRichard Henderson  * = 0 for no base register update.
106396d6407fSRichard Henderson  */
106496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
106596d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
106696d6407fSRichard Henderson                        int modify, TCGMemOp mop)
106796d6407fSRichard Henderson {
106896d6407fSRichard Henderson     TCGv addr, base;
106996d6407fSRichard Henderson 
107096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
107196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
107296d6407fSRichard Henderson 
107396d6407fSRichard Henderson     addr = tcg_temp_new();
107496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
107596d6407fSRichard Henderson 
107696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
107796d6407fSRichard Henderson     if (rx) {
107896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
107996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
108096d6407fSRichard Henderson     } else {
108196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
108296d6407fSRichard Henderson     }
108396d6407fSRichard Henderson 
108496d6407fSRichard Henderson     if (modify == 0) {
108596d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
108696d6407fSRichard Henderson     } else {
108796d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
108896d6407fSRichard Henderson                             MMU_USER_IDX, mop);
108996d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
109096d6407fSRichard Henderson     }
109196d6407fSRichard Henderson     tcg_temp_free(addr);
109296d6407fSRichard Henderson }
109396d6407fSRichard Henderson 
109496d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
109596d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
109696d6407fSRichard Henderson                        int modify, TCGMemOp mop)
109796d6407fSRichard Henderson {
109896d6407fSRichard Henderson     TCGv addr, base;
109996d6407fSRichard Henderson 
110096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
110196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
110296d6407fSRichard Henderson 
110396d6407fSRichard Henderson     addr = tcg_temp_new();
110496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
110596d6407fSRichard Henderson 
110696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
110796d6407fSRichard Henderson     if (rx) {
110896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
110996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
111096d6407fSRichard Henderson     } else {
111196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
111296d6407fSRichard Henderson     }
111396d6407fSRichard Henderson 
111496d6407fSRichard Henderson     if (modify == 0) {
111596d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
111696d6407fSRichard Henderson     } else {
111796d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
111896d6407fSRichard Henderson                             MMU_USER_IDX, mop);
111996d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
112096d6407fSRichard Henderson     }
112196d6407fSRichard Henderson     tcg_temp_free(addr);
112296d6407fSRichard Henderson }
112396d6407fSRichard Henderson 
112496d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
112596d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
112696d6407fSRichard Henderson                         int modify, TCGMemOp mop)
112796d6407fSRichard Henderson {
112896d6407fSRichard Henderson     TCGv addr, base;
112996d6407fSRichard Henderson 
113096d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
113196d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
113296d6407fSRichard Henderson 
113396d6407fSRichard Henderson     addr = tcg_temp_new();
113496d6407fSRichard Henderson     base = load_gpr(ctx, rb);
113596d6407fSRichard Henderson 
113696d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
113796d6407fSRichard Henderson     if (rx) {
113896d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
113996d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
114096d6407fSRichard Henderson     } else {
114196d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
114296d6407fSRichard Henderson     }
114396d6407fSRichard Henderson 
114496d6407fSRichard Henderson     tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
114596d6407fSRichard Henderson 
114696d6407fSRichard Henderson     if (modify != 0) {
114796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
114896d6407fSRichard Henderson     }
114996d6407fSRichard Henderson     tcg_temp_free(addr);
115096d6407fSRichard Henderson }
115196d6407fSRichard Henderson 
115296d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
115396d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
115496d6407fSRichard Henderson                         int modify, TCGMemOp mop)
115596d6407fSRichard Henderson {
115696d6407fSRichard Henderson     TCGv addr, base;
115796d6407fSRichard Henderson 
115896d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
115996d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
116096d6407fSRichard Henderson 
116196d6407fSRichard Henderson     addr = tcg_temp_new();
116296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
116396d6407fSRichard Henderson 
116496d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
116596d6407fSRichard Henderson     if (rx) {
116696d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
116796d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
116896d6407fSRichard Henderson     } else {
116996d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
117096d6407fSRichard Henderson     }
117196d6407fSRichard Henderson 
117296d6407fSRichard Henderson     tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
117396d6407fSRichard Henderson 
117496d6407fSRichard Henderson     if (modify != 0) {
117596d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
117696d6407fSRichard Henderson     }
117796d6407fSRichard Henderson     tcg_temp_free(addr);
117896d6407fSRichard Henderson }
117996d6407fSRichard Henderson 
118096d6407fSRichard Henderson #if TARGET_LONG_BITS == 64
118196d6407fSRichard Henderson #define do_load_tl  do_load_64
118296d6407fSRichard Henderson #define do_store_tl do_store_64
118396d6407fSRichard Henderson #else
118496d6407fSRichard Henderson #define do_load_tl  do_load_32
118596d6407fSRichard Henderson #define do_store_tl do_store_32
118696d6407fSRichard Henderson #endif
118796d6407fSRichard Henderson 
118896d6407fSRichard Henderson static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb,
118996d6407fSRichard Henderson                           unsigned rx, int scale, target_long disp,
119096d6407fSRichard Henderson                           int modify, TCGMemOp mop)
119196d6407fSRichard Henderson {
119296d6407fSRichard Henderson     TCGv dest;
119396d6407fSRichard Henderson 
119496d6407fSRichard Henderson     nullify_over(ctx);
119596d6407fSRichard Henderson 
119696d6407fSRichard Henderson     if (modify == 0) {
119796d6407fSRichard Henderson         /* No base register update.  */
119896d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
119996d6407fSRichard Henderson     } else {
120096d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
120196d6407fSRichard Henderson         dest = get_temp(ctx);
120296d6407fSRichard Henderson     }
120396d6407fSRichard Henderson     do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
120496d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
120596d6407fSRichard Henderson 
120696d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
120796d6407fSRichard Henderson }
120896d6407fSRichard Henderson 
120996d6407fSRichard Henderson static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
121096d6407fSRichard Henderson                             unsigned rx, int scale, target_long disp,
121196d6407fSRichard Henderson                             int modify)
121296d6407fSRichard Henderson {
121396d6407fSRichard Henderson     TCGv_i32 tmp;
121496d6407fSRichard Henderson 
121596d6407fSRichard Henderson     nullify_over(ctx);
121696d6407fSRichard Henderson 
121796d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
121896d6407fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
121996d6407fSRichard Henderson     save_frw_i32(rt, tmp);
122096d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
122196d6407fSRichard Henderson 
122296d6407fSRichard Henderson     if (rt == 0) {
122396d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
122496d6407fSRichard Henderson     }
122596d6407fSRichard Henderson 
122696d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
122796d6407fSRichard Henderson }
122896d6407fSRichard Henderson 
122996d6407fSRichard Henderson static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
123096d6407fSRichard Henderson                             unsigned rx, int scale, target_long disp,
123196d6407fSRichard Henderson                             int modify)
123296d6407fSRichard Henderson {
123396d6407fSRichard Henderson     TCGv_i64 tmp;
123496d6407fSRichard Henderson 
123596d6407fSRichard Henderson     nullify_over(ctx);
123696d6407fSRichard Henderson 
123796d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
123896d6407fSRichard Henderson     do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
123996d6407fSRichard Henderson     save_frd(rt, tmp);
124096d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
124196d6407fSRichard Henderson 
124296d6407fSRichard Henderson     if (rt == 0) {
124396d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
124496d6407fSRichard Henderson     }
124596d6407fSRichard Henderson 
124696d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
124796d6407fSRichard Henderson }
124896d6407fSRichard Henderson 
124996d6407fSRichard Henderson static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb,
125096d6407fSRichard Henderson                            target_long disp, int modify, TCGMemOp mop)
125196d6407fSRichard Henderson {
125296d6407fSRichard Henderson     nullify_over(ctx);
125396d6407fSRichard Henderson     do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
125496d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
125596d6407fSRichard Henderson }
125696d6407fSRichard Henderson 
125796d6407fSRichard Henderson static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
125896d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
125996d6407fSRichard Henderson                              int modify)
126096d6407fSRichard Henderson {
126196d6407fSRichard Henderson     TCGv_i32 tmp;
126296d6407fSRichard Henderson 
126396d6407fSRichard Henderson     nullify_over(ctx);
126496d6407fSRichard Henderson 
126596d6407fSRichard Henderson     tmp = load_frw_i32(rt);
126696d6407fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
126796d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
126896d6407fSRichard Henderson 
126996d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
127096d6407fSRichard Henderson }
127196d6407fSRichard Henderson 
127296d6407fSRichard Henderson static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
127396d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
127496d6407fSRichard Henderson                              int modify)
127596d6407fSRichard Henderson {
127696d6407fSRichard Henderson     TCGv_i64 tmp;
127796d6407fSRichard Henderson 
127896d6407fSRichard Henderson     nullify_over(ctx);
127996d6407fSRichard Henderson 
128096d6407fSRichard Henderson     tmp = load_frd(rt);
128196d6407fSRichard Henderson     do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
128296d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
128396d6407fSRichard Henderson 
128496d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
128596d6407fSRichard Henderson }
128696d6407fSRichard Henderson 
1287ebe9383cSRichard Henderson static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1288ebe9383cSRichard Henderson                              void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1289ebe9383cSRichard Henderson {
1290ebe9383cSRichard Henderson     TCGv_i32 tmp;
1291ebe9383cSRichard Henderson 
1292ebe9383cSRichard Henderson     nullify_over(ctx);
1293ebe9383cSRichard Henderson     tmp = load_frw0_i32(ra);
1294ebe9383cSRichard Henderson 
1295ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1296ebe9383cSRichard Henderson 
1297ebe9383cSRichard Henderson     save_frw_i32(rt, tmp);
1298ebe9383cSRichard Henderson     tcg_temp_free_i32(tmp);
1299ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1300ebe9383cSRichard Henderson }
1301ebe9383cSRichard Henderson 
1302ebe9383cSRichard Henderson static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1303ebe9383cSRichard Henderson                              void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1304ebe9383cSRichard Henderson {
1305ebe9383cSRichard Henderson     TCGv_i32 dst;
1306ebe9383cSRichard Henderson     TCGv_i64 src;
1307ebe9383cSRichard Henderson 
1308ebe9383cSRichard Henderson     nullify_over(ctx);
1309ebe9383cSRichard Henderson     src = load_frd(ra);
1310ebe9383cSRichard Henderson     dst = tcg_temp_new_i32();
1311ebe9383cSRichard Henderson 
1312ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1313ebe9383cSRichard Henderson 
1314ebe9383cSRichard Henderson     tcg_temp_free_i64(src);
1315ebe9383cSRichard Henderson     save_frw_i32(rt, dst);
1316ebe9383cSRichard Henderson     tcg_temp_free_i32(dst);
1317ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1318ebe9383cSRichard Henderson }
1319ebe9383cSRichard Henderson 
1320ebe9383cSRichard Henderson static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1321ebe9383cSRichard Henderson                              void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1322ebe9383cSRichard Henderson {
1323ebe9383cSRichard Henderson     TCGv_i64 tmp;
1324ebe9383cSRichard Henderson 
1325ebe9383cSRichard Henderson     nullify_over(ctx);
1326ebe9383cSRichard Henderson     tmp = load_frd0(ra);
1327ebe9383cSRichard Henderson 
1328ebe9383cSRichard Henderson     func(tmp, cpu_env, tmp);
1329ebe9383cSRichard Henderson 
1330ebe9383cSRichard Henderson     save_frd(rt, tmp);
1331ebe9383cSRichard Henderson     tcg_temp_free_i64(tmp);
1332ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1333ebe9383cSRichard Henderson }
1334ebe9383cSRichard Henderson 
1335ebe9383cSRichard Henderson static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1336ebe9383cSRichard Henderson                              void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1337ebe9383cSRichard Henderson {
1338ebe9383cSRichard Henderson     TCGv_i32 src;
1339ebe9383cSRichard Henderson     TCGv_i64 dst;
1340ebe9383cSRichard Henderson 
1341ebe9383cSRichard Henderson     nullify_over(ctx);
1342ebe9383cSRichard Henderson     src = load_frw0_i32(ra);
1343ebe9383cSRichard Henderson     dst = tcg_temp_new_i64();
1344ebe9383cSRichard Henderson 
1345ebe9383cSRichard Henderson     func(dst, cpu_env, src);
1346ebe9383cSRichard Henderson 
1347ebe9383cSRichard Henderson     tcg_temp_free_i32(src);
1348ebe9383cSRichard Henderson     save_frd(rt, dst);
1349ebe9383cSRichard Henderson     tcg_temp_free_i64(dst);
1350ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1351ebe9383cSRichard Henderson }
1352ebe9383cSRichard Henderson 
1353ebe9383cSRichard Henderson static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt,
1354ebe9383cSRichard Henderson                               unsigned ra, unsigned rb,
1355ebe9383cSRichard Henderson                               void (*func)(TCGv_i32, TCGv_env,
1356ebe9383cSRichard Henderson                                            TCGv_i32, TCGv_i32))
1357ebe9383cSRichard Henderson {
1358ebe9383cSRichard Henderson     TCGv_i32 a, b;
1359ebe9383cSRichard Henderson 
1360ebe9383cSRichard Henderson     nullify_over(ctx);
1361ebe9383cSRichard Henderson     a = load_frw0_i32(ra);
1362ebe9383cSRichard Henderson     b = load_frw0_i32(rb);
1363ebe9383cSRichard Henderson 
1364ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1365ebe9383cSRichard Henderson 
1366ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
1367ebe9383cSRichard Henderson     save_frw_i32(rt, a);
1368ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
1369ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1370ebe9383cSRichard Henderson }
1371ebe9383cSRichard Henderson 
1372ebe9383cSRichard Henderson static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt,
1373ebe9383cSRichard Henderson                               unsigned ra, unsigned rb,
1374ebe9383cSRichard Henderson                               void (*func)(TCGv_i64, TCGv_env,
1375ebe9383cSRichard Henderson                                            TCGv_i64, TCGv_i64))
1376ebe9383cSRichard Henderson {
1377ebe9383cSRichard Henderson     TCGv_i64 a, b;
1378ebe9383cSRichard Henderson 
1379ebe9383cSRichard Henderson     nullify_over(ctx);
1380ebe9383cSRichard Henderson     a = load_frd0(ra);
1381ebe9383cSRichard Henderson     b = load_frd0(rb);
1382ebe9383cSRichard Henderson 
1383ebe9383cSRichard Henderson     func(a, cpu_env, a, b);
1384ebe9383cSRichard Henderson 
1385ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
1386ebe9383cSRichard Henderson     save_frd(rt, a);
1387ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
1388ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
1389ebe9383cSRichard Henderson }
1390ebe9383cSRichard Henderson 
139198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
139298cd9ca7SRichard Henderson    have already had nullification handled.  */
139398cd9ca7SRichard Henderson static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
139498cd9ca7SRichard Henderson                              unsigned link, bool is_n)
139598cd9ca7SRichard Henderson {
139698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
139798cd9ca7SRichard Henderson         if (link != 0) {
139898cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
139998cd9ca7SRichard Henderson         }
140098cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
140198cd9ca7SRichard Henderson         if (is_n) {
140298cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
140398cd9ca7SRichard Henderson         }
140498cd9ca7SRichard Henderson         return NO_EXIT;
140598cd9ca7SRichard Henderson     } else {
140698cd9ca7SRichard Henderson         nullify_over(ctx);
140798cd9ca7SRichard Henderson 
140898cd9ca7SRichard Henderson         if (link != 0) {
140998cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
141098cd9ca7SRichard Henderson         }
141198cd9ca7SRichard Henderson 
141298cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
141398cd9ca7SRichard Henderson             nullify_set(ctx, 0);
141498cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
141598cd9ca7SRichard Henderson         } else {
141698cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
141798cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
141898cd9ca7SRichard Henderson         }
141998cd9ca7SRichard Henderson 
142098cd9ca7SRichard Henderson         nullify_end(ctx, NO_EXIT);
142198cd9ca7SRichard Henderson 
142298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
142398cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
142498cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
142598cd9ca7SRichard Henderson     }
142698cd9ca7SRichard Henderson }
142798cd9ca7SRichard Henderson 
142898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
142998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
143098cd9ca7SRichard Henderson static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
143198cd9ca7SRichard Henderson                              DisasCond *cond)
143298cd9ca7SRichard Henderson {
143398cd9ca7SRichard Henderson     target_ulong dest = iaoq_dest(ctx, disp);
143498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
143598cd9ca7SRichard Henderson     TCGCond c = cond->c;
143698cd9ca7SRichard Henderson     bool n;
143798cd9ca7SRichard Henderson 
143898cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
143998cd9ca7SRichard Henderson 
144098cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
144198cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
144298cd9ca7SRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
144398cd9ca7SRichard Henderson     }
144498cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
144598cd9ca7SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
144698cd9ca7SRichard Henderson     }
144798cd9ca7SRichard Henderson 
144898cd9ca7SRichard Henderson     taken = gen_new_label();
144998cd9ca7SRichard Henderson     cond_prep(cond);
145098cd9ca7SRichard Henderson     tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
145198cd9ca7SRichard Henderson     cond_free(cond);
145298cd9ca7SRichard Henderson 
145398cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
145498cd9ca7SRichard Henderson     n = is_n && disp < 0;
145598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
145698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1457a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
145898cd9ca7SRichard Henderson     } else {
145998cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
146098cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
146198cd9ca7SRichard Henderson             ctx->null_lab = NULL;
146298cd9ca7SRichard Henderson         }
146398cd9ca7SRichard Henderson         nullify_set(ctx, n);
1464a881c8e7SRichard Henderson         gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
146598cd9ca7SRichard Henderson     }
146698cd9ca7SRichard Henderson 
146798cd9ca7SRichard Henderson     gen_set_label(taken);
146898cd9ca7SRichard Henderson 
146998cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
147098cd9ca7SRichard Henderson     n = is_n && disp >= 0;
147198cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
147298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
1473a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, dest, dest + 4);
147498cd9ca7SRichard Henderson     } else {
147598cd9ca7SRichard Henderson         nullify_set(ctx, n);
1476a881c8e7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
147798cd9ca7SRichard Henderson     }
147898cd9ca7SRichard Henderson 
147998cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
148098cd9ca7SRichard Henderson     if (ctx->null_lab) {
148198cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
148298cd9ca7SRichard Henderson         ctx->null_lab = NULL;
148398cd9ca7SRichard Henderson         return EXIT_IAQ_N_STALE;
148498cd9ca7SRichard Henderson     } else {
148598cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
148698cd9ca7SRichard Henderson     }
148798cd9ca7SRichard Henderson }
148898cd9ca7SRichard Henderson 
148998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
149098cd9ca7SRichard Henderson    nullification of the branch itself.  */
149198cd9ca7SRichard Henderson static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
149298cd9ca7SRichard Henderson                              unsigned link, bool is_n)
149398cd9ca7SRichard Henderson {
149498cd9ca7SRichard Henderson     TCGv a0, a1, next, tmp;
149598cd9ca7SRichard Henderson     TCGCond c;
149698cd9ca7SRichard Henderson 
149798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
149898cd9ca7SRichard Henderson 
149998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
150098cd9ca7SRichard Henderson         if (link != 0) {
150198cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
150298cd9ca7SRichard Henderson         }
150398cd9ca7SRichard Henderson         next = get_temp(ctx);
150498cd9ca7SRichard Henderson         tcg_gen_mov_tl(next, dest);
150598cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
150698cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
150798cd9ca7SRichard Henderson         if (is_n) {
150898cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
150998cd9ca7SRichard Henderson         }
151098cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
151198cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
151298cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
151398cd9ca7SRichard Henderson            tracepoint in effect).  Since the exit_tb that we must use
151498cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
151598cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
151698cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
151798cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
151898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
151998cd9ca7SRichard Henderson 
152098cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
152198cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
152298cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
152398cd9ca7SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, dest);
152498cd9ca7SRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
152598cd9ca7SRichard Henderson 
152698cd9ca7SRichard Henderson         nullify_over(ctx);
152798cd9ca7SRichard Henderson         if (link != 0) {
152898cd9ca7SRichard Henderson             tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
152998cd9ca7SRichard Henderson         }
153098cd9ca7SRichard Henderson         tcg_gen_exit_tb(0);
153198cd9ca7SRichard Henderson         return nullify_end(ctx, NO_EXIT);
153298cd9ca7SRichard Henderson     } else {
153398cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
153498cd9ca7SRichard Henderson         c = ctx->null_cond.c;
153598cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
153698cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
153798cd9ca7SRichard Henderson 
153898cd9ca7SRichard Henderson         tmp = tcg_temp_new();
153998cd9ca7SRichard Henderson         next = get_temp(ctx);
154098cd9ca7SRichard Henderson 
154198cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
154298cd9ca7SRichard Henderson         tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
154398cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
154498cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
154598cd9ca7SRichard Henderson 
154698cd9ca7SRichard Henderson         if (link != 0) {
154798cd9ca7SRichard Henderson             tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
154898cd9ca7SRichard Henderson         }
154998cd9ca7SRichard Henderson 
155098cd9ca7SRichard Henderson         if (is_n) {
155198cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
155298cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
155398cd9ca7SRichard Henderson                to the branch.  */
155498cd9ca7SRichard Henderson             tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
155598cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
155698cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
155798cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
155898cd9ca7SRichard Henderson         } else {
155998cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
156098cd9ca7SRichard Henderson         }
156198cd9ca7SRichard Henderson     }
156298cd9ca7SRichard Henderson 
156398cd9ca7SRichard Henderson     return NO_EXIT;
156498cd9ca7SRichard Henderson }
156598cd9ca7SRichard Henderson 
15667ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
15677ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
15687ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
15697ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
15707ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
15717ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
15727ad439dfSRichard Henderson    aforementioned BE.  */
15737ad439dfSRichard Henderson static ExitStatus do_page_zero(DisasContext *ctx)
15747ad439dfSRichard Henderson {
15757ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
15767ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
15777ad439dfSRichard Henderson        next insn within the privilaged page.  */
15787ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
15797ad439dfSRichard Henderson     case TCG_COND_NEVER:
15807ad439dfSRichard Henderson         break;
15817ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
15827ad439dfSRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, 0);
15837ad439dfSRichard Henderson         goto do_sigill;
15847ad439dfSRichard Henderson     default:
15857ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
15867ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
15877ad439dfSRichard Henderson         g_assert_not_reached();
15887ad439dfSRichard Henderson     }
15897ad439dfSRichard Henderson 
15907ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
15917ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
15927ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
15937ad439dfSRichard Henderson        under such conditions.  */
15947ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
15957ad439dfSRichard Henderson         goto do_sigill;
15967ad439dfSRichard Henderson     }
15977ad439dfSRichard Henderson 
15987ad439dfSRichard Henderson     switch (ctx->iaoq_f) {
15997ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
16007ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGSEGV);
16017ad439dfSRichard Henderson         return EXIT_NORETURN;
16027ad439dfSRichard Henderson 
16037ad439dfSRichard Henderson     case 0xb0: /* LWS */
16047ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
16057ad439dfSRichard Henderson         return EXIT_NORETURN;
16067ad439dfSRichard Henderson 
16077ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
16087ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
16097ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
16107ad439dfSRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
16117ad439dfSRichard Henderson         return EXIT_IAQ_N_UPDATED;
16127ad439dfSRichard Henderson 
16137ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
16147ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
16157ad439dfSRichard Henderson         return EXIT_NORETURN;
16167ad439dfSRichard Henderson 
16177ad439dfSRichard Henderson     default:
16187ad439dfSRichard Henderson     do_sigill:
16197ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGILL);
16207ad439dfSRichard Henderson         return EXIT_NORETURN;
16217ad439dfSRichard Henderson     }
16227ad439dfSRichard Henderson }
16237ad439dfSRichard Henderson 
1624b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
1625b2167459SRichard Henderson                             const DisasInsn *di)
1626b2167459SRichard Henderson {
1627b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1628b2167459SRichard Henderson     return NO_EXIT;
1629b2167459SRichard Henderson }
1630b2167459SRichard Henderson 
163198a9cb79SRichard Henderson static ExitStatus trans_break(DisasContext *ctx, uint32_t insn,
163298a9cb79SRichard Henderson                               const DisasInsn *di)
163398a9cb79SRichard Henderson {
163498a9cb79SRichard Henderson     nullify_over(ctx);
163598a9cb79SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
163698a9cb79SRichard Henderson }
163798a9cb79SRichard Henderson 
163898a9cb79SRichard Henderson static ExitStatus trans_sync(DisasContext *ctx, uint32_t insn,
163998a9cb79SRichard Henderson                              const DisasInsn *di)
164098a9cb79SRichard Henderson {
164198a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
164298a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
164398a9cb79SRichard Henderson 
164498a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
164598a9cb79SRichard Henderson     return NO_EXIT;
164698a9cb79SRichard Henderson }
164798a9cb79SRichard Henderson 
164898a9cb79SRichard Henderson static ExitStatus trans_mfia(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     tcg_gen_movi_tl(tmp, ctx->iaoq_f);
165498a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
165598a9cb79SRichard Henderson 
165698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
165798a9cb79SRichard Henderson     return NO_EXIT;
165898a9cb79SRichard Henderson }
165998a9cb79SRichard Henderson 
166098a9cb79SRichard Henderson static ExitStatus trans_mfsp(DisasContext *ctx, uint32_t insn,
166198a9cb79SRichard Henderson                              const DisasInsn *di)
166298a9cb79SRichard Henderson {
166398a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
166498a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
166598a9cb79SRichard Henderson 
166698a9cb79SRichard Henderson     /* ??? We don't implement space registers.  */
166798a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, 0);
166898a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
166998a9cb79SRichard Henderson 
167098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
167198a9cb79SRichard Henderson     return NO_EXIT;
167298a9cb79SRichard Henderson }
167398a9cb79SRichard Henderson 
167498a9cb79SRichard Henderson static ExitStatus trans_mfctl(DisasContext *ctx, uint32_t insn,
167598a9cb79SRichard Henderson                               const DisasInsn *di)
167698a9cb79SRichard Henderson {
167798a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
167898a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
167998a9cb79SRichard Henderson     TCGv tmp;
168098a9cb79SRichard Henderson 
168198a9cb79SRichard Henderson     switch (ctl) {
168298a9cb79SRichard Henderson     case 11: /* SAR */
168398a9cb79SRichard Henderson #ifdef TARGET_HPPA64
168498a9cb79SRichard Henderson         if (extract32(insn, 14, 1) == 0) {
168598a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
168698a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
168798a9cb79SRichard Henderson             tcg_gen_andi_tl(tmp, cpu_sar, 31);
168898a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
168998a9cb79SRichard Henderson             break;
169098a9cb79SRichard Henderson         }
169198a9cb79SRichard Henderson #endif
169298a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
169398a9cb79SRichard Henderson         break;
169498a9cb79SRichard Henderson     case 16: /* Interval Timer */
169598a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
169698a9cb79SRichard Henderson         tcg_gen_movi_tl(tmp, 0); /* FIXME */
169798a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
169898a9cb79SRichard Henderson         break;
169998a9cb79SRichard Henderson     case 26:
170098a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr26);
170198a9cb79SRichard Henderson         break;
170298a9cb79SRichard Henderson     case 27:
170398a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr27);
170498a9cb79SRichard Henderson         break;
170598a9cb79SRichard Henderson     default:
170698a9cb79SRichard Henderson         /* All other control registers are privileged.  */
170798a9cb79SRichard Henderson         return gen_illegal(ctx);
170898a9cb79SRichard Henderson     }
170998a9cb79SRichard Henderson 
171098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
171198a9cb79SRichard Henderson     return NO_EXIT;
171298a9cb79SRichard Henderson }
171398a9cb79SRichard Henderson 
171498a9cb79SRichard Henderson static ExitStatus trans_mtctl(DisasContext *ctx, uint32_t insn,
171598a9cb79SRichard Henderson                               const DisasInsn *di)
171698a9cb79SRichard Henderson {
171798a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
171898a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
171998a9cb79SRichard Henderson     TCGv tmp;
172098a9cb79SRichard Henderson 
172198a9cb79SRichard Henderson     if (ctl == 11) { /* SAR */
172298a9cb79SRichard Henderson         tmp = tcg_temp_new();
172398a9cb79SRichard Henderson         tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
172498a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
172598a9cb79SRichard Henderson         tcg_temp_free(tmp);
172698a9cb79SRichard Henderson     } else {
172798a9cb79SRichard Henderson         /* All other control registers are privileged or read-only.  */
172898a9cb79SRichard Henderson         return gen_illegal(ctx);
172998a9cb79SRichard Henderson     }
173098a9cb79SRichard Henderson 
173198a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
173298a9cb79SRichard Henderson     return NO_EXIT;
173398a9cb79SRichard Henderson }
173498a9cb79SRichard Henderson 
173598a9cb79SRichard Henderson static ExitStatus trans_mtsarcm(DisasContext *ctx, uint32_t insn,
173698a9cb79SRichard Henderson                                 const DisasInsn *di)
173798a9cb79SRichard Henderson {
173898a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
173998a9cb79SRichard Henderson     TCGv tmp = tcg_temp_new();
174098a9cb79SRichard Henderson 
174198a9cb79SRichard Henderson     tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
174298a9cb79SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
174398a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
174498a9cb79SRichard Henderson     tcg_temp_free(tmp);
174598a9cb79SRichard Henderson 
174698a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
174798a9cb79SRichard Henderson     return NO_EXIT;
174898a9cb79SRichard Henderson }
174998a9cb79SRichard Henderson 
175098a9cb79SRichard Henderson static ExitStatus trans_ldsid(DisasContext *ctx, uint32_t insn,
175198a9cb79SRichard Henderson                               const DisasInsn *di)
175298a9cb79SRichard Henderson {
175398a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
175498a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
175598a9cb79SRichard Henderson 
175698a9cb79SRichard Henderson     /* Since we don't implement space registers, this returns zero.  */
175798a9cb79SRichard Henderson     tcg_gen_movi_tl(dest, 0);
175898a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
175998a9cb79SRichard Henderson 
176098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
176198a9cb79SRichard Henderson     return NO_EXIT;
176298a9cb79SRichard Henderson }
176398a9cb79SRichard Henderson 
176498a9cb79SRichard Henderson static const DisasInsn table_system[] = {
176598a9cb79SRichard Henderson     { 0x00000000u, 0xfc001fe0u, trans_break },
176698a9cb79SRichard Henderson     /* We don't implement space register, so MTSP is a nop.  */
176798a9cb79SRichard Henderson     { 0x00001820u, 0xffe01fffu, trans_nop },
176898a9cb79SRichard Henderson     { 0x00001840u, 0xfc00ffffu, trans_mtctl },
176998a9cb79SRichard Henderson     { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
177098a9cb79SRichard Henderson     { 0x000014a0u, 0xffffffe0u, trans_mfia },
177198a9cb79SRichard Henderson     { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
177298a9cb79SRichard Henderson     { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
177398a9cb79SRichard Henderson     { 0x00000400u, 0xffffffffu, trans_sync },
177498a9cb79SRichard Henderson     { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
177598a9cb79SRichard Henderson };
177698a9cb79SRichard Henderson 
177798a9cb79SRichard Henderson static ExitStatus trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
177898a9cb79SRichard Henderson                                      const DisasInsn *di)
177998a9cb79SRichard Henderson {
178098a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
178198a9cb79SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
178298a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rb);
178398a9cb79SRichard Henderson     TCGv src1 = load_gpr(ctx, rb);
178498a9cb79SRichard Henderson     TCGv src2 = load_gpr(ctx, rx);
178598a9cb79SRichard Henderson 
178698a9cb79SRichard Henderson     /* The only thing we need to do is the base register modification.  */
178798a9cb79SRichard Henderson     tcg_gen_add_tl(dest, src1, src2);
178898a9cb79SRichard Henderson     save_gpr(ctx, rb, dest);
178998a9cb79SRichard Henderson 
179098a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
179198a9cb79SRichard Henderson     return NO_EXIT;
179298a9cb79SRichard Henderson }
179398a9cb79SRichard Henderson 
179498a9cb79SRichard Henderson static ExitStatus trans_probe(DisasContext *ctx, uint32_t insn,
179598a9cb79SRichard Henderson                               const DisasInsn *di)
179698a9cb79SRichard Henderson {
179798a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
179898a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
179998a9cb79SRichard Henderson     unsigned is_write = extract32(insn, 6, 1);
180098a9cb79SRichard Henderson     TCGv dest;
180198a9cb79SRichard Henderson 
180298a9cb79SRichard Henderson     nullify_over(ctx);
180398a9cb79SRichard Henderson 
180498a9cb79SRichard Henderson     /* ??? Do something with priv level operand.  */
180598a9cb79SRichard Henderson     dest = dest_gpr(ctx, rt);
180698a9cb79SRichard Henderson     if (is_write) {
180798a9cb79SRichard Henderson         gen_helper_probe_w(dest, load_gpr(ctx, rb));
180898a9cb79SRichard Henderson     } else {
180998a9cb79SRichard Henderson         gen_helper_probe_r(dest, load_gpr(ctx, rb));
181098a9cb79SRichard Henderson     }
181198a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
181298a9cb79SRichard Henderson     return nullify_end(ctx, NO_EXIT);
181398a9cb79SRichard Henderson }
181498a9cb79SRichard Henderson 
181598a9cb79SRichard Henderson static const DisasInsn table_mem_mgmt[] = {
181698a9cb79SRichard Henderson     { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
181798a9cb79SRichard Henderson     { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
181898a9cb79SRichard Henderson     { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
181998a9cb79SRichard Henderson     { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
182098a9cb79SRichard Henderson     { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
182198a9cb79SRichard Henderson     { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
182298a9cb79SRichard Henderson     { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
182398a9cb79SRichard Henderson     { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
182498a9cb79SRichard Henderson     { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
182598a9cb79SRichard Henderson     { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
182698a9cb79SRichard Henderson     { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
182798a9cb79SRichard Henderson     { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
182898a9cb79SRichard Henderson     { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
182998a9cb79SRichard Henderson     { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
183098a9cb79SRichard Henderson     { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
183198a9cb79SRichard Henderson };
183298a9cb79SRichard Henderson 
1833b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
1834b2167459SRichard Henderson                             const DisasInsn *di)
1835b2167459SRichard Henderson {
1836b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1837b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1838b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1839b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
1840b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
1841b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1842b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1843b2167459SRichard Henderson     bool is_c = false;
1844b2167459SRichard Henderson     bool is_l = false;
1845b2167459SRichard Henderson     bool is_tc = false;
1846b2167459SRichard Henderson     bool is_tsv = false;
1847b2167459SRichard Henderson     ExitStatus ret;
1848b2167459SRichard Henderson 
1849b2167459SRichard Henderson     switch (ext) {
1850b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
1851b2167459SRichard Henderson         break;
1852b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
1853b2167459SRichard Henderson         is_l = true;
1854b2167459SRichard Henderson         break;
1855b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1856b2167459SRichard Henderson         is_tsv = true;
1857b2167459SRichard Henderson         break;
1858b2167459SRichard Henderson     case 0x7: /* ADD,C */
1859b2167459SRichard Henderson         is_c = true;
1860b2167459SRichard Henderson         break;
1861b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
1862b2167459SRichard Henderson         is_c = is_tsv = true;
1863b2167459SRichard Henderson         break;
1864b2167459SRichard Henderson     default:
1865b2167459SRichard Henderson         return gen_illegal(ctx);
1866b2167459SRichard Henderson     }
1867b2167459SRichard Henderson 
1868b2167459SRichard Henderson     if (cf) {
1869b2167459SRichard Henderson         nullify_over(ctx);
1870b2167459SRichard Henderson     }
1871b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1872b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1873b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1874b2167459SRichard Henderson     return nullify_end(ctx, ret);
1875b2167459SRichard Henderson }
1876b2167459SRichard Henderson 
1877b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
1878b2167459SRichard Henderson                             const DisasInsn *di)
1879b2167459SRichard Henderson {
1880b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1881b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1882b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1883b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
1884b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1885b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1886b2167459SRichard Henderson     bool is_b = false;
1887b2167459SRichard Henderson     bool is_tc = false;
1888b2167459SRichard Henderson     bool is_tsv = false;
1889b2167459SRichard Henderson     ExitStatus ret;
1890b2167459SRichard Henderson 
1891b2167459SRichard Henderson     switch (ext) {
1892b2167459SRichard Henderson     case 0x10: /* SUB */
1893b2167459SRichard Henderson         break;
1894b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
1895b2167459SRichard Henderson         is_tsv = true;
1896b2167459SRichard Henderson         break;
1897b2167459SRichard Henderson     case 0x14: /* SUB,B */
1898b2167459SRichard Henderson         is_b = true;
1899b2167459SRichard Henderson         break;
1900b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
1901b2167459SRichard Henderson         is_b = is_tsv = true;
1902b2167459SRichard Henderson         break;
1903b2167459SRichard Henderson     case 0x13: /* SUB,TC */
1904b2167459SRichard Henderson         is_tc = true;
1905b2167459SRichard Henderson         break;
1906b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
1907b2167459SRichard Henderson         is_tc = is_tsv = true;
1908b2167459SRichard Henderson         break;
1909b2167459SRichard Henderson     default:
1910b2167459SRichard Henderson         return gen_illegal(ctx);
1911b2167459SRichard Henderson     }
1912b2167459SRichard Henderson 
1913b2167459SRichard Henderson     if (cf) {
1914b2167459SRichard Henderson         nullify_over(ctx);
1915b2167459SRichard Henderson     }
1916b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1917b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1918b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1919b2167459SRichard Henderson     return nullify_end(ctx, ret);
1920b2167459SRichard Henderson }
1921b2167459SRichard Henderson 
1922b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
1923b2167459SRichard Henderson                             const DisasInsn *di)
1924b2167459SRichard Henderson {
1925b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1926b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1927b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1928b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1929b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1930b2167459SRichard Henderson     ExitStatus ret;
1931b2167459SRichard Henderson 
1932b2167459SRichard Henderson     if (cf) {
1933b2167459SRichard Henderson         nullify_over(ctx);
1934b2167459SRichard Henderson     }
1935b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1936b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1937*eff235ebSPaolo Bonzini     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1938b2167459SRichard Henderson     return nullify_end(ctx, ret);
1939b2167459SRichard Henderson }
1940b2167459SRichard Henderson 
1941b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1942b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1943b2167459SRichard Henderson                              const DisasInsn *di)
1944b2167459SRichard Henderson {
1945b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1946b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1947b2167459SRichard Henderson 
1948b2167459SRichard Henderson     if (r1 == 0) {
1949b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1950b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1951b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1952b2167459SRichard Henderson     } else {
1953b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1954b2167459SRichard Henderson     }
1955b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1956b2167459SRichard Henderson     return NO_EXIT;
1957b2167459SRichard Henderson }
1958b2167459SRichard Henderson 
1959b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1960b2167459SRichard Henderson                                const DisasInsn *di)
1961b2167459SRichard Henderson {
1962b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1963b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1964b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1965b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1966b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1967b2167459SRichard Henderson     ExitStatus ret;
1968b2167459SRichard Henderson 
1969b2167459SRichard Henderson     if (cf) {
1970b2167459SRichard Henderson         nullify_over(ctx);
1971b2167459SRichard Henderson     }
1972b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1973b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1974b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1975b2167459SRichard Henderson     return nullify_end(ctx, ret);
1976b2167459SRichard Henderson }
1977b2167459SRichard Henderson 
1978b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1979b2167459SRichard Henderson                              const DisasInsn *di)
1980b2167459SRichard Henderson {
1981b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1982b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1983b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1984b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1985b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1986b2167459SRichard Henderson     ExitStatus ret;
1987b2167459SRichard Henderson 
1988b2167459SRichard Henderson     if (cf) {
1989b2167459SRichard Henderson         nullify_over(ctx);
1990b2167459SRichard Henderson     }
1991b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1992b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1993b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1994b2167459SRichard Henderson     return nullify_end(ctx, ret);
1995b2167459SRichard Henderson }
1996b2167459SRichard Henderson 
1997b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1998b2167459SRichard Henderson                                const DisasInsn *di)
1999b2167459SRichard Henderson {
2000b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2001b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
2002b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2003b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
2004b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2005b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
2006b2167459SRichard Henderson     ExitStatus ret;
2007b2167459SRichard Henderson 
2008b2167459SRichard Henderson     if (cf) {
2009b2167459SRichard Henderson         nullify_over(ctx);
2010b2167459SRichard Henderson     }
2011b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
2012b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2013b2167459SRichard Henderson     tmp = get_temp(ctx);
2014b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
2015b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
2016b2167459SRichard Henderson     return nullify_end(ctx, ret);
2017b2167459SRichard Henderson }
2018b2167459SRichard Henderson 
2019b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
2020b2167459SRichard Henderson                              const DisasInsn *di)
2021b2167459SRichard Henderson {
2022b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2023b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2024b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
2025b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2026b2167459SRichard Henderson     TCGv tmp;
2027b2167459SRichard Henderson     ExitStatus ret;
2028b2167459SRichard Henderson 
2029b2167459SRichard Henderson     nullify_over(ctx);
2030b2167459SRichard Henderson 
2031b2167459SRichard Henderson     tmp = get_temp(ctx);
2032b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2033b2167459SRichard Henderson     if (!is_i) {
2034b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
2035b2167459SRichard Henderson     }
2036b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2037b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
2038b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2039b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2040b2167459SRichard Henderson 
2041b2167459SRichard Henderson     return nullify_end(ctx, ret);
2042b2167459SRichard Henderson }
2043b2167459SRichard Henderson 
2044b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
2045b2167459SRichard Henderson                            const DisasInsn *di)
2046b2167459SRichard Henderson {
2047b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2048b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
2049b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2050b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
2051b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
2052b2167459SRichard Henderson 
2053b2167459SRichard Henderson     nullify_over(ctx);
2054b2167459SRichard Henderson 
2055b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
2056b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
2057b2167459SRichard Henderson 
2058b2167459SRichard Henderson     add1 = tcg_temp_new();
2059b2167459SRichard Henderson     add2 = tcg_temp_new();
2060b2167459SRichard Henderson     addc = tcg_temp_new();
2061b2167459SRichard Henderson     dest = tcg_temp_new();
2062b2167459SRichard Henderson     zero = tcg_const_tl(0);
2063b2167459SRichard Henderson 
2064b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
2065b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
2066b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2067b2167459SRichard Henderson 
2068b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
2069b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
2070b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
2071b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
2072b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2073b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
2074b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
2075b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
2076b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2077b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2078b2167459SRichard Henderson 
2079b2167459SRichard Henderson     tcg_temp_free(addc);
2080b2167459SRichard Henderson     tcg_temp_free(zero);
2081b2167459SRichard Henderson 
2082b2167459SRichard Henderson     /* Write back the result register.  */
2083b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
2084b2167459SRichard Henderson 
2085b2167459SRichard Henderson     /* Write back PSW[CB].  */
2086b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2087b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2088b2167459SRichard Henderson 
2089b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
2090b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2091b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2092b2167459SRichard Henderson 
2093b2167459SRichard Henderson     /* Install the new nullification.  */
2094b2167459SRichard Henderson     if (cf) {
2095b2167459SRichard Henderson         TCGv sv;
2096b2167459SRichard Henderson         TCGV_UNUSED(sv);
2097b2167459SRichard Henderson         if (cf >> 1 == 6) {
2098b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
2099b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
2100b2167459SRichard Henderson         }
2101b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2102b2167459SRichard Henderson     }
2103b2167459SRichard Henderson 
2104b2167459SRichard Henderson     tcg_temp_free(add1);
2105b2167459SRichard Henderson     tcg_temp_free(add2);
2106b2167459SRichard Henderson     tcg_temp_free(dest);
2107b2167459SRichard Henderson 
2108b2167459SRichard Henderson     return nullify_end(ctx, NO_EXIT);
2109b2167459SRichard Henderson }
2110b2167459SRichard Henderson 
2111b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
2112b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
2113b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2114*eff235ebSPaolo Bonzini     { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2115*eff235ebSPaolo Bonzini     { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2116*eff235ebSPaolo Bonzini     { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2117*eff235ebSPaolo Bonzini     { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2118b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2119b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
2120b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2121b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2122b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
2123b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2124b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2125b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2126b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2127b2167459SRichard Henderson };
2128b2167459SRichard Henderson 
2129b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
2130b2167459SRichard Henderson {
2131b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2132b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2133b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2134b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2135b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2136b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
2137b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2138b2167459SRichard Henderson     ExitStatus ret;
2139b2167459SRichard Henderson 
2140b2167459SRichard Henderson     if (cf) {
2141b2167459SRichard Henderson         nullify_over(ctx);
2142b2167459SRichard Henderson     }
2143b2167459SRichard Henderson 
2144b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2145b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2146b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2147b2167459SRichard Henderson 
2148b2167459SRichard Henderson     return nullify_end(ctx, ret);
2149b2167459SRichard Henderson }
2150b2167459SRichard Henderson 
2151b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
2152b2167459SRichard Henderson {
2153b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2154b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
2155b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2156b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2157b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2158b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2159b2167459SRichard Henderson     ExitStatus ret;
2160b2167459SRichard Henderson 
2161b2167459SRichard Henderson     if (cf) {
2162b2167459SRichard Henderson         nullify_over(ctx);
2163b2167459SRichard Henderson     }
2164b2167459SRichard Henderson 
2165b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2166b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2167b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2168b2167459SRichard Henderson 
2169b2167459SRichard Henderson     return nullify_end(ctx, ret);
2170b2167459SRichard Henderson }
2171b2167459SRichard Henderson 
2172b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2173b2167459SRichard Henderson {
2174b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2175b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2176b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2177b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2178b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2179b2167459SRichard Henderson     ExitStatus ret;
2180b2167459SRichard Henderson 
2181b2167459SRichard Henderson     if (cf) {
2182b2167459SRichard Henderson         nullify_over(ctx);
2183b2167459SRichard Henderson     }
2184b2167459SRichard Henderson 
2185b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2186b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2187b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2188b2167459SRichard Henderson 
2189b2167459SRichard Henderson     return nullify_end(ctx, ret);
2190b2167459SRichard Henderson }
2191b2167459SRichard Henderson 
219296d6407fSRichard Henderson static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
219396d6407fSRichard Henderson                                  const DisasInsn *di)
219496d6407fSRichard Henderson {
219596d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
219696d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
219796d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
219896d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
219996d6407fSRichard Henderson     int disp = low_sextract(insn, 16, 5);
220096d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
220196d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
220296d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
220396d6407fSRichard Henderson 
220496d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
220596d6407fSRichard Henderson }
220696d6407fSRichard Henderson 
220796d6407fSRichard Henderson static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
220896d6407fSRichard Henderson                                  const DisasInsn *di)
220996d6407fSRichard Henderson {
221096d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
221196d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
221296d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
221396d6407fSRichard Henderson     unsigned u = extract32(insn, 13, 1);
221496d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
221596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
221696d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
221796d6407fSRichard Henderson 
221896d6407fSRichard Henderson     return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
221996d6407fSRichard Henderson }
222096d6407fSRichard Henderson 
222196d6407fSRichard Henderson static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn,
222296d6407fSRichard Henderson                                  const DisasInsn *di)
222396d6407fSRichard Henderson {
222496d6407fSRichard Henderson     int disp = low_sextract(insn, 0, 5);
222596d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
222696d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
222796d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
222896d6407fSRichard Henderson     unsigned rr = extract32(insn, 16, 5);
222996d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
223096d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
223196d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
223296d6407fSRichard Henderson 
223396d6407fSRichard Henderson     return do_store(ctx, rr, rb, disp, modify, mop);
223496d6407fSRichard Henderson }
223596d6407fSRichard Henderson 
223696d6407fSRichard Henderson static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn,
223796d6407fSRichard Henderson                              const DisasInsn *di)
223896d6407fSRichard Henderson {
223996d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
224096d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
224196d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
224296d6407fSRichard Henderson     unsigned au = extract32(insn, 13, 1);
224396d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
224496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
224596d6407fSRichard Henderson     TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
224696d6407fSRichard Henderson     TCGv zero, addr, base, dest;
224796d6407fSRichard Henderson     int modify, disp = 0, scale = 0;
224896d6407fSRichard Henderson 
224996d6407fSRichard Henderson     nullify_over(ctx);
225096d6407fSRichard Henderson 
225196d6407fSRichard Henderson     /* ??? Share more code with do_load and do_load_{32,64}.  */
225296d6407fSRichard Henderson 
225396d6407fSRichard Henderson     if (i) {
225496d6407fSRichard Henderson         modify = (m ? (au ? -1 : 1) : 0);
225596d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
225696d6407fSRichard Henderson         rx = 0;
225796d6407fSRichard Henderson     } else {
225896d6407fSRichard Henderson         modify = m;
225996d6407fSRichard Henderson         if (au) {
226096d6407fSRichard Henderson             scale = mop & MO_SIZE;
226196d6407fSRichard Henderson         }
226296d6407fSRichard Henderson     }
226396d6407fSRichard Henderson     if (modify) {
226496d6407fSRichard Henderson         /* Base register modification.  Make sure if RT == RB, we see
226596d6407fSRichard Henderson            the result of the load.  */
226696d6407fSRichard Henderson         dest = get_temp(ctx);
226796d6407fSRichard Henderson     } else {
226896d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
226996d6407fSRichard Henderson     }
227096d6407fSRichard Henderson 
227196d6407fSRichard Henderson     addr = tcg_temp_new();
227296d6407fSRichard Henderson     base = load_gpr(ctx, rb);
227396d6407fSRichard Henderson     if (rx) {
227496d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
227596d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
227696d6407fSRichard Henderson     } else {
227796d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
227896d6407fSRichard Henderson     }
227996d6407fSRichard Henderson 
228096d6407fSRichard Henderson     zero = tcg_const_tl(0);
228196d6407fSRichard Henderson     tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
228296d6407fSRichard Henderson                            zero, MMU_USER_IDX, mop);
228396d6407fSRichard Henderson     if (modify) {
228496d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
228596d6407fSRichard Henderson     }
228696d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
228796d6407fSRichard Henderson 
228896d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
228996d6407fSRichard Henderson }
229096d6407fSRichard Henderson 
229196d6407fSRichard Henderson static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn,
229296d6407fSRichard Henderson                              const DisasInsn *di)
229396d6407fSRichard Henderson {
229496d6407fSRichard Henderson     target_long disp = low_sextract(insn, 0, 5);
229596d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
229696d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
229796d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
229896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
229996d6407fSRichard Henderson     TCGv addr, val;
230096d6407fSRichard Henderson 
230196d6407fSRichard Henderson     nullify_over(ctx);
230296d6407fSRichard Henderson 
230396d6407fSRichard Henderson     addr = tcg_temp_new();
230496d6407fSRichard Henderson     if (m || disp == 0) {
230596d6407fSRichard Henderson         tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
230696d6407fSRichard Henderson     } else {
230796d6407fSRichard Henderson         tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
230896d6407fSRichard Henderson     }
230996d6407fSRichard Henderson     val = load_gpr(ctx, rt);
231096d6407fSRichard Henderson 
231196d6407fSRichard Henderson     if (a) {
231296d6407fSRichard Henderson         gen_helper_stby_e(cpu_env, addr, val);
231396d6407fSRichard Henderson     } else {
231496d6407fSRichard Henderson         gen_helper_stby_b(cpu_env, addr, val);
231596d6407fSRichard Henderson     }
231696d6407fSRichard Henderson 
231796d6407fSRichard Henderson     if (m) {
231896d6407fSRichard Henderson         tcg_gen_addi_tl(addr, addr, disp);
231996d6407fSRichard Henderson         tcg_gen_andi_tl(addr, addr, ~3);
232096d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
232196d6407fSRichard Henderson     }
232296d6407fSRichard Henderson     tcg_temp_free(addr);
232396d6407fSRichard Henderson 
232496d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
232596d6407fSRichard Henderson }
232696d6407fSRichard Henderson 
232796d6407fSRichard Henderson static const DisasInsn table_index_mem[] = {
232896d6407fSRichard Henderson     { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
232996d6407fSRichard Henderson     { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
233096d6407fSRichard Henderson     { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
233196d6407fSRichard Henderson     { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
233296d6407fSRichard Henderson     { 0x0c001300u, 0xfc0013c0, trans_stby },
233396d6407fSRichard Henderson };
233496d6407fSRichard Henderson 
2335b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
2336b2167459SRichard Henderson {
2337b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2338b2167459SRichard Henderson     target_long i = assemble_21(insn);
2339b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2340b2167459SRichard Henderson 
2341b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
2342b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2343b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2344b2167459SRichard Henderson 
2345b2167459SRichard Henderson     return NO_EXIT;
2346b2167459SRichard Henderson }
2347b2167459SRichard Henderson 
2348b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
2349b2167459SRichard Henderson {
2350b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2351b2167459SRichard Henderson     target_long i = assemble_21(insn);
2352b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
2353b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
2354b2167459SRichard Henderson 
2355b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2356b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2357b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2358b2167459SRichard Henderson 
2359b2167459SRichard Henderson     return NO_EXIT;
2360b2167459SRichard Henderson }
2361b2167459SRichard Henderson 
2362b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
2363b2167459SRichard Henderson {
2364b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
2365b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2366b2167459SRichard Henderson     target_long i = assemble_16(insn);
2367b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2368b2167459SRichard Henderson 
2369b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2370b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2371b2167459SRichard Henderson     if (rb == 0) {
2372b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
2373b2167459SRichard Henderson     } else {
2374b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2375b2167459SRichard Henderson     }
2376b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2377b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2378b2167459SRichard Henderson 
2379b2167459SRichard Henderson     return NO_EXIT;
2380b2167459SRichard Henderson }
2381b2167459SRichard Henderson 
238296d6407fSRichard Henderson static ExitStatus trans_load(DisasContext *ctx, uint32_t insn,
238396d6407fSRichard Henderson                              bool is_mod, TCGMemOp mop)
238496d6407fSRichard Henderson {
238596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
238696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
238796d6407fSRichard Henderson     target_long i = assemble_16(insn);
238896d6407fSRichard Henderson 
238996d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
239096d6407fSRichard Henderson }
239196d6407fSRichard Henderson 
239296d6407fSRichard Henderson static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn)
239396d6407fSRichard Henderson {
239496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
239596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
239696d6407fSRichard Henderson     target_long i = assemble_16a(insn);
239796d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
239896d6407fSRichard Henderson 
239996d6407fSRichard Henderson     switch (ext2) {
240096d6407fSRichard Henderson     case 0:
240196d6407fSRichard Henderson     case 1:
240296d6407fSRichard Henderson         /* FLDW without modification.  */
240396d6407fSRichard Henderson         return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
240496d6407fSRichard Henderson     case 2:
240596d6407fSRichard Henderson         /* LDW with modification.  Note that the sign of I selects
240696d6407fSRichard Henderson            post-dec vs pre-inc.  */
240796d6407fSRichard Henderson         return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
240896d6407fSRichard Henderson     default:
240996d6407fSRichard Henderson         return gen_illegal(ctx);
241096d6407fSRichard Henderson     }
241196d6407fSRichard Henderson }
241296d6407fSRichard Henderson 
241396d6407fSRichard Henderson static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn)
241496d6407fSRichard Henderson {
241596d6407fSRichard Henderson     target_long i = assemble_16a(insn);
241696d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
241796d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
241896d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
241996d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
242096d6407fSRichard Henderson 
242196d6407fSRichard Henderson     /* FLDW with modification.  */
242296d6407fSRichard Henderson     return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
242396d6407fSRichard Henderson }
242496d6407fSRichard Henderson 
242596d6407fSRichard Henderson static ExitStatus trans_store(DisasContext *ctx, uint32_t insn,
242696d6407fSRichard Henderson                               bool is_mod, TCGMemOp mop)
242796d6407fSRichard Henderson {
242896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
242996d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
243096d6407fSRichard Henderson     target_long i = assemble_16(insn);
243196d6407fSRichard Henderson 
243296d6407fSRichard Henderson     return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
243396d6407fSRichard Henderson }
243496d6407fSRichard Henderson 
243596d6407fSRichard Henderson static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn)
243696d6407fSRichard Henderson {
243796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
243896d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
243996d6407fSRichard Henderson     target_long i = assemble_16a(insn);
244096d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
244196d6407fSRichard Henderson 
244296d6407fSRichard Henderson     switch (ext2) {
244396d6407fSRichard Henderson     case 0:
244496d6407fSRichard Henderson     case 1:
244596d6407fSRichard Henderson         /* FSTW without modification.  */
244696d6407fSRichard Henderson         return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
244796d6407fSRichard Henderson     case 2:
244896d6407fSRichard Henderson         /* LDW with modification.  */
244996d6407fSRichard Henderson         return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
245096d6407fSRichard Henderson     default:
245196d6407fSRichard Henderson         return gen_illegal(ctx);
245296d6407fSRichard Henderson     }
245396d6407fSRichard Henderson }
245496d6407fSRichard Henderson 
245596d6407fSRichard Henderson static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn)
245696d6407fSRichard Henderson {
245796d6407fSRichard Henderson     target_long i = assemble_16a(insn);
245896d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
245996d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
246096d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
246196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
246296d6407fSRichard Henderson 
246396d6407fSRichard Henderson     /* FSTW with modification.  */
246496d6407fSRichard Henderson     return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
246596d6407fSRichard Henderson }
246696d6407fSRichard Henderson 
246796d6407fSRichard Henderson static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn)
246896d6407fSRichard Henderson {
246996d6407fSRichard Henderson     unsigned t0 = extract32(insn, 0, 5);
247096d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
247196d6407fSRichard Henderson     unsigned t1 = extract32(insn, 6, 1);
247296d6407fSRichard Henderson     unsigned ext3 = extract32(insn, 7, 3);
247396d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
247496d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
247596d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
247696d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
247796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
247896d6407fSRichard Henderson     unsigned rt = t1 * 32 + t0;
247996d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
248096d6407fSRichard Henderson     int disp, scale;
248196d6407fSRichard Henderson 
248296d6407fSRichard Henderson     if (i == 0) {
248396d6407fSRichard Henderson         scale = (ua ? 2 : 0);
248496d6407fSRichard Henderson         disp = 0;
248596d6407fSRichard Henderson         modify = m;
248696d6407fSRichard Henderson     } else {
248796d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
248896d6407fSRichard Henderson         scale = 0;
248996d6407fSRichard Henderson         rx = 0;
249096d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
249196d6407fSRichard Henderson     }
249296d6407fSRichard Henderson 
249396d6407fSRichard Henderson     switch (ext3) {
249496d6407fSRichard Henderson     case 0: /* FLDW */
249596d6407fSRichard Henderson         return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
249696d6407fSRichard Henderson     case 4: /* FSTW */
249796d6407fSRichard Henderson         return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
249896d6407fSRichard Henderson     }
249996d6407fSRichard Henderson     return gen_illegal(ctx);
250096d6407fSRichard Henderson }
250196d6407fSRichard Henderson 
250296d6407fSRichard Henderson static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn)
250396d6407fSRichard Henderson {
250496d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
250596d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
250696d6407fSRichard Henderson     unsigned ext4 = extract32(insn, 6, 4);
250796d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
250896d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
250996d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
251096d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
251196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
251296d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
251396d6407fSRichard Henderson     int disp, scale;
251496d6407fSRichard Henderson 
251596d6407fSRichard Henderson     if (i == 0) {
251696d6407fSRichard Henderson         scale = (ua ? 3 : 0);
251796d6407fSRichard Henderson         disp = 0;
251896d6407fSRichard Henderson         modify = m;
251996d6407fSRichard Henderson     } else {
252096d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
252196d6407fSRichard Henderson         scale = 0;
252296d6407fSRichard Henderson         rx = 0;
252396d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
252496d6407fSRichard Henderson     }
252596d6407fSRichard Henderson 
252696d6407fSRichard Henderson     switch (ext4) {
252796d6407fSRichard Henderson     case 0: /* FLDD */
252896d6407fSRichard Henderson         return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
252996d6407fSRichard Henderson     case 8: /* FSTD */
253096d6407fSRichard Henderson         return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
253196d6407fSRichard Henderson     default:
253296d6407fSRichard Henderson         return gen_illegal(ctx);
253396d6407fSRichard Henderson     }
253496d6407fSRichard Henderson }
253596d6407fSRichard Henderson 
253698cd9ca7SRichard Henderson static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
253798cd9ca7SRichard Henderson                              bool is_true, bool is_imm, bool is_dw)
253898cd9ca7SRichard Henderson {
253998cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
254098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
254198cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
254298cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
254398cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
254498cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv;
254598cd9ca7SRichard Henderson     DisasCond cond;
254698cd9ca7SRichard Henderson 
254798cd9ca7SRichard Henderson     nullify_over(ctx);
254898cd9ca7SRichard Henderson 
254998cd9ca7SRichard Henderson     if (is_imm) {
255098cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
255198cd9ca7SRichard Henderson     } else {
255298cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
255398cd9ca7SRichard Henderson     }
255498cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
255598cd9ca7SRichard Henderson     dest = get_temp(ctx);
255698cd9ca7SRichard Henderson 
255798cd9ca7SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
255898cd9ca7SRichard Henderson 
255998cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
256098cd9ca7SRichard Henderson     if (c == 6) {
256198cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
256298cd9ca7SRichard Henderson     }
256398cd9ca7SRichard Henderson 
256498cd9ca7SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
256598cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
256698cd9ca7SRichard Henderson }
256798cd9ca7SRichard Henderson 
256898cd9ca7SRichard Henderson static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
256998cd9ca7SRichard Henderson                              bool is_true, bool is_imm)
257098cd9ca7SRichard Henderson {
257198cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
257298cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
257398cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
257498cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
257598cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
257698cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv, cb_msb;
257798cd9ca7SRichard Henderson     DisasCond cond;
257898cd9ca7SRichard Henderson 
257998cd9ca7SRichard Henderson     nullify_over(ctx);
258098cd9ca7SRichard Henderson 
258198cd9ca7SRichard Henderson     if (is_imm) {
258298cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
258398cd9ca7SRichard Henderson     } else {
258498cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
258598cd9ca7SRichard Henderson     }
258698cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
258798cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
258898cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
258998cd9ca7SRichard Henderson     TCGV_UNUSED(cb_msb);
259098cd9ca7SRichard Henderson 
259198cd9ca7SRichard Henderson     switch (c) {
259298cd9ca7SRichard Henderson     default:
259398cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
259498cd9ca7SRichard Henderson         break;
259598cd9ca7SRichard Henderson     case 4: case 5:
259698cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
259798cd9ca7SRichard Henderson         tcg_gen_movi_tl(cb_msb, 0);
259898cd9ca7SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
259998cd9ca7SRichard Henderson         break;
260098cd9ca7SRichard Henderson     case 6:
260198cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
260298cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
260398cd9ca7SRichard Henderson         break;
260498cd9ca7SRichard Henderson     }
260598cd9ca7SRichard Henderson 
260698cd9ca7SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
260798cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
260898cd9ca7SRichard Henderson }
260998cd9ca7SRichard Henderson 
261098cd9ca7SRichard Henderson static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
261198cd9ca7SRichard Henderson {
261298cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
261398cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
261498cd9ca7SRichard Henderson     unsigned c = extract32(insn, 15, 1);
261598cd9ca7SRichard Henderson     unsigned r = extract32(insn, 16, 5);
261698cd9ca7SRichard Henderson     unsigned p = extract32(insn, 21, 5);
261798cd9ca7SRichard Henderson     unsigned i = extract32(insn, 26, 1);
261898cd9ca7SRichard Henderson     TCGv tmp, tcg_r;
261998cd9ca7SRichard Henderson     DisasCond cond;
262098cd9ca7SRichard Henderson 
262198cd9ca7SRichard Henderson     nullify_over(ctx);
262298cd9ca7SRichard Henderson 
262398cd9ca7SRichard Henderson     tmp = tcg_temp_new();
262498cd9ca7SRichard Henderson     tcg_r = load_gpr(ctx, r);
262598cd9ca7SRichard Henderson     if (i) {
262698cd9ca7SRichard Henderson         tcg_gen_shli_tl(tmp, tcg_r, p);
262798cd9ca7SRichard Henderson     } else {
262898cd9ca7SRichard Henderson         tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
262998cd9ca7SRichard Henderson     }
263098cd9ca7SRichard Henderson 
263198cd9ca7SRichard Henderson     cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
263298cd9ca7SRichard Henderson     tcg_temp_free(tmp);
263398cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
263498cd9ca7SRichard Henderson }
263598cd9ca7SRichard Henderson 
263698cd9ca7SRichard Henderson static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
263798cd9ca7SRichard Henderson {
263898cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
263998cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
264098cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
264198cd9ca7SRichard Henderson     unsigned t = extract32(insn, 16, 5);
264298cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
264398cd9ca7SRichard Henderson     TCGv dest;
264498cd9ca7SRichard Henderson     DisasCond cond;
264598cd9ca7SRichard Henderson 
264698cd9ca7SRichard Henderson     nullify_over(ctx);
264798cd9ca7SRichard Henderson 
264898cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
264998cd9ca7SRichard Henderson     if (is_imm) {
265098cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
265198cd9ca7SRichard Henderson     } else if (t == 0) {
265298cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, 0);
265398cd9ca7SRichard Henderson     } else {
265498cd9ca7SRichard Henderson         tcg_gen_mov_tl(dest, cpu_gr[t]);
265598cd9ca7SRichard Henderson     }
265698cd9ca7SRichard Henderson 
265798cd9ca7SRichard Henderson     cond = do_sed_cond(c, dest);
265898cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
265998cd9ca7SRichard Henderson }
266098cd9ca7SRichard Henderson 
26610b1347d2SRichard Henderson static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
26620b1347d2SRichard Henderson                                  const DisasInsn *di)
26630b1347d2SRichard Henderson {
26640b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
26650b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26660b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
26670b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
26680b1347d2SRichard Henderson     TCGv dest;
26690b1347d2SRichard Henderson 
26700b1347d2SRichard Henderson     if (c) {
26710b1347d2SRichard Henderson         nullify_over(ctx);
26720b1347d2SRichard Henderson     }
26730b1347d2SRichard Henderson 
26740b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26750b1347d2SRichard Henderson     if (r1 == 0) {
26760b1347d2SRichard Henderson         tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
26770b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, dest, cpu_sar);
26780b1347d2SRichard Henderson     } else if (r1 == r2) {
26790b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
26800b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
26810b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
26820b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
26830b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
26840b1347d2SRichard Henderson     } else {
26850b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
26860b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
26870b1347d2SRichard Henderson 
26880b1347d2SRichard Henderson         tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
26890b1347d2SRichard Henderson         tcg_gen_extu_tl_i64(s, cpu_sar);
26900b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
26910b1347d2SRichard Henderson         tcg_gen_trunc_i64_tl(dest, t);
26920b1347d2SRichard Henderson 
26930b1347d2SRichard Henderson         tcg_temp_free_i64(t);
26940b1347d2SRichard Henderson         tcg_temp_free_i64(s);
26950b1347d2SRichard Henderson     }
26960b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26970b1347d2SRichard Henderson 
26980b1347d2SRichard Henderson     /* Install the new nullification.  */
26990b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27000b1347d2SRichard Henderson     if (c) {
27010b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27020b1347d2SRichard Henderson     }
27030b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27040b1347d2SRichard Henderson }
27050b1347d2SRichard Henderson 
27060b1347d2SRichard Henderson static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
27070b1347d2SRichard Henderson                                   const DisasInsn *di)
27080b1347d2SRichard Henderson {
27090b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
27100b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
27110b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27120b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
27130b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
27140b1347d2SRichard Henderson     unsigned sa = 31 - cpos;
27150b1347d2SRichard Henderson     TCGv dest, t2;
27160b1347d2SRichard Henderson 
27170b1347d2SRichard Henderson     if (c) {
27180b1347d2SRichard Henderson         nullify_over(ctx);
27190b1347d2SRichard Henderson     }
27200b1347d2SRichard Henderson 
27210b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27220b1347d2SRichard Henderson     t2 = load_gpr(ctx, r2);
27230b1347d2SRichard Henderson     if (r1 == r2) {
27240b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
27250b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, t2);
27260b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
27270b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
27280b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
27290b1347d2SRichard Henderson     } else if (r1 == 0) {
27300b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
27310b1347d2SRichard Henderson     } else {
27320b1347d2SRichard Henderson         TCGv t0 = tcg_temp_new();
27330b1347d2SRichard Henderson         tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
27340b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
27350b1347d2SRichard Henderson         tcg_temp_free(t0);
27360b1347d2SRichard Henderson     }
27370b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27380b1347d2SRichard Henderson 
27390b1347d2SRichard Henderson     /* Install the new nullification.  */
27400b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27410b1347d2SRichard Henderson     if (c) {
27420b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27430b1347d2SRichard Henderson     }
27440b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27450b1347d2SRichard Henderson }
27460b1347d2SRichard Henderson 
27470b1347d2SRichard Henderson static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
27480b1347d2SRichard Henderson                                   const DisasInsn *di)
27490b1347d2SRichard Henderson {
27500b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27510b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27520b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27530b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27540b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27550b1347d2SRichard Henderson     unsigned len = 32 - clen;
27560b1347d2SRichard Henderson     TCGv dest, src, tmp;
27570b1347d2SRichard Henderson 
27580b1347d2SRichard Henderson     if (c) {
27590b1347d2SRichard Henderson         nullify_over(ctx);
27600b1347d2SRichard Henderson     }
27610b1347d2SRichard Henderson 
27620b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27630b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
27640b1347d2SRichard Henderson     tmp = tcg_temp_new();
27650b1347d2SRichard Henderson 
27660b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
27670b1347d2SRichard Henderson     tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
27680b1347d2SRichard Henderson     if (is_se) {
27690b1347d2SRichard Henderson         tcg_gen_sar_tl(dest, src, tmp);
27700b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, dest, 0, len);
27710b1347d2SRichard Henderson     } else {
27720b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, src, tmp);
27730b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, dest, 0, len);
27740b1347d2SRichard Henderson     }
27750b1347d2SRichard Henderson     tcg_temp_free(tmp);
27760b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27770b1347d2SRichard Henderson 
27780b1347d2SRichard Henderson     /* Install the new nullification.  */
27790b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27800b1347d2SRichard Henderson     if (c) {
27810b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27820b1347d2SRichard Henderson     }
27830b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27840b1347d2SRichard Henderson }
27850b1347d2SRichard Henderson 
27860b1347d2SRichard Henderson static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
27870b1347d2SRichard Henderson                                   const DisasInsn *di)
27880b1347d2SRichard Henderson {
27890b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27900b1347d2SRichard Henderson     unsigned pos = extract32(insn, 5, 5);
27910b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
27920b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27930b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
27940b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
27950b1347d2SRichard Henderson     unsigned len = 32 - clen;
27960b1347d2SRichard Henderson     unsigned cpos = 31 - pos;
27970b1347d2SRichard Henderson     TCGv dest, src;
27980b1347d2SRichard Henderson 
27990b1347d2SRichard Henderson     if (c) {
28000b1347d2SRichard Henderson         nullify_over(ctx);
28010b1347d2SRichard Henderson     }
28020b1347d2SRichard Henderson 
28030b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28040b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
28050b1347d2SRichard Henderson     if (is_se) {
28060b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, src, cpos, len);
28070b1347d2SRichard Henderson     } else {
28080b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, src, cpos, len);
28090b1347d2SRichard Henderson     }
28100b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28110b1347d2SRichard Henderson 
28120b1347d2SRichard Henderson     /* Install the new nullification.  */
28130b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28140b1347d2SRichard Henderson     if (c) {
28150b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28160b1347d2SRichard Henderson     }
28170b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
28180b1347d2SRichard Henderson }
28190b1347d2SRichard Henderson 
28200b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = {
28210b1347d2SRichard Henderson     { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
28220b1347d2SRichard Henderson     { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
28230b1347d2SRichard Henderson     { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
28240b1347d2SRichard Henderson     { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
28250b1347d2SRichard Henderson };
28260b1347d2SRichard Henderson 
28270b1347d2SRichard Henderson static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
28280b1347d2SRichard Henderson                                    const DisasInsn *di)
28290b1347d2SRichard Henderson {
28300b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28310b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28320b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28330b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28340b1347d2SRichard Henderson     target_long val = low_sextract(insn, 16, 5);
28350b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28360b1347d2SRichard Henderson     unsigned len = 32 - clen;
28370b1347d2SRichard Henderson     target_long mask0, mask1;
28380b1347d2SRichard Henderson     TCGv dest;
28390b1347d2SRichard Henderson 
28400b1347d2SRichard Henderson     if (c) {
28410b1347d2SRichard Henderson         nullify_over(ctx);
28420b1347d2SRichard Henderson     }
28430b1347d2SRichard Henderson     if (cpos + len > 32) {
28440b1347d2SRichard Henderson         len = 32 - cpos;
28450b1347d2SRichard Henderson     }
28460b1347d2SRichard Henderson 
28470b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28480b1347d2SRichard Henderson     mask0 = deposit64(0, cpos, len, val);
28490b1347d2SRichard Henderson     mask1 = deposit64(-1, cpos, len, val);
28500b1347d2SRichard Henderson 
28510b1347d2SRichard Henderson     if (nz) {
28520b1347d2SRichard Henderson         TCGv src = load_gpr(ctx, rt);
28530b1347d2SRichard Henderson         if (mask1 != -1) {
28540b1347d2SRichard Henderson             tcg_gen_andi_tl(dest, src, mask1);
28550b1347d2SRichard Henderson             src = dest;
28560b1347d2SRichard Henderson         }
28570b1347d2SRichard Henderson         tcg_gen_ori_tl(dest, src, mask0);
28580b1347d2SRichard Henderson     } else {
28590b1347d2SRichard Henderson         tcg_gen_movi_tl(dest, mask0);
28600b1347d2SRichard Henderson     }
28610b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28620b1347d2SRichard Henderson 
28630b1347d2SRichard Henderson     /* Install the new nullification.  */
28640b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
28650b1347d2SRichard Henderson     if (c) {
28660b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
28670b1347d2SRichard Henderson     }
28680b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
28690b1347d2SRichard Henderson }
28700b1347d2SRichard Henderson 
28710b1347d2SRichard Henderson static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
28720b1347d2SRichard Henderson                                  const DisasInsn *di)
28730b1347d2SRichard Henderson {
28740b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
28750b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
28760b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
28770b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
28780b1347d2SRichard Henderson     unsigned rr = extract32(insn, 16, 5);
28790b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
28800b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
28810b1347d2SRichard Henderson     unsigned len = 32 - clen;
28820b1347d2SRichard Henderson     TCGv dest, val;
28830b1347d2SRichard Henderson 
28840b1347d2SRichard Henderson     if (c) {
28850b1347d2SRichard Henderson         nullify_over(ctx);
28860b1347d2SRichard Henderson     }
28870b1347d2SRichard Henderson     if (cpos + len > 32) {
28880b1347d2SRichard Henderson         len = 32 - cpos;
28890b1347d2SRichard Henderson     }
28900b1347d2SRichard Henderson 
28910b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
28920b1347d2SRichard Henderson     val = load_gpr(ctx, rr);
28930b1347d2SRichard Henderson     if (rs == 0) {
28940b1347d2SRichard Henderson         tcg_gen_deposit_z_tl(dest, val, cpos, len);
28950b1347d2SRichard Henderson     } else {
28960b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
28970b1347d2SRichard Henderson     }
28980b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
28990b1347d2SRichard Henderson 
29000b1347d2SRichard Henderson     /* Install the new nullification.  */
29010b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
29020b1347d2SRichard Henderson     if (c) {
29030b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
29040b1347d2SRichard Henderson     }
29050b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
29060b1347d2SRichard Henderson }
29070b1347d2SRichard Henderson 
29080b1347d2SRichard Henderson static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
29090b1347d2SRichard Henderson                                  const DisasInsn *di)
29100b1347d2SRichard Henderson {
29110b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
29120b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
29130b1347d2SRichard Henderson     unsigned i = extract32(insn, 12, 1);
29140b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
29150b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
29160b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
29170b1347d2SRichard Henderson     unsigned len = 32 - clen;
29180b1347d2SRichard Henderson     TCGv val, mask, tmp, shift, dest;
29190b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
29200b1347d2SRichard Henderson 
29210b1347d2SRichard Henderson     if (c) {
29220b1347d2SRichard Henderson         nullify_over(ctx);
29230b1347d2SRichard Henderson     }
29240b1347d2SRichard Henderson 
29250b1347d2SRichard Henderson     if (i) {
29260b1347d2SRichard Henderson         val = load_const(ctx, low_sextract(insn, 16, 5));
29270b1347d2SRichard Henderson     } else {
29280b1347d2SRichard Henderson         val = load_gpr(ctx, extract32(insn, 16, 5));
29290b1347d2SRichard Henderson     }
29300b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
29310b1347d2SRichard Henderson     shift = tcg_temp_new();
29320b1347d2SRichard Henderson     tmp = tcg_temp_new();
29330b1347d2SRichard Henderson 
29340b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
29350b1347d2SRichard Henderson     tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
29360b1347d2SRichard Henderson 
29370b1347d2SRichard Henderson     mask = tcg_const_tl(msb + (msb - 1));
29380b1347d2SRichard Henderson     tcg_gen_and_tl(tmp, val, mask);
29390b1347d2SRichard Henderson     if (rs) {
29400b1347d2SRichard Henderson         tcg_gen_shl_tl(mask, mask, shift);
29410b1347d2SRichard Henderson         tcg_gen_shl_tl(tmp, tmp, shift);
29420b1347d2SRichard Henderson         tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
29430b1347d2SRichard Henderson         tcg_gen_or_tl(dest, dest, tmp);
29440b1347d2SRichard Henderson     } else {
29450b1347d2SRichard Henderson         tcg_gen_shl_tl(dest, tmp, shift);
29460b1347d2SRichard Henderson     }
29470b1347d2SRichard Henderson     tcg_temp_free(shift);
29480b1347d2SRichard Henderson     tcg_temp_free(mask);
29490b1347d2SRichard Henderson     tcg_temp_free(tmp);
29500b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
29510b1347d2SRichard Henderson 
29520b1347d2SRichard Henderson     /* Install the new nullification.  */
29530b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
29540b1347d2SRichard Henderson     if (c) {
29550b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
29560b1347d2SRichard Henderson     }
29570b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
29580b1347d2SRichard Henderson }
29590b1347d2SRichard Henderson 
29600b1347d2SRichard Henderson static const DisasInsn table_depw[] = {
29610b1347d2SRichard Henderson     { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
29620b1347d2SRichard Henderson     { 0xd4000800u, 0xfc001800u, trans_depw_imm },
29630b1347d2SRichard Henderson     { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
29640b1347d2SRichard Henderson };
29650b1347d2SRichard Henderson 
296698cd9ca7SRichard Henderson static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
296798cd9ca7SRichard Henderson {
296898cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
296998cd9ca7SRichard Henderson     unsigned b = extract32(insn, 21, 5);
297098cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
297198cd9ca7SRichard Henderson 
297298cd9ca7SRichard Henderson     /* unsigned s = low_uextract(insn, 13, 3); */
297398cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
297498cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
297598cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
297698cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
297798cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
297898cd9ca7SRichard Henderson 
297998cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
298098cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
298198cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
298298cd9ca7SRichard Henderson     if (b == 0) {
298398cd9ca7SRichard Henderson         return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
298498cd9ca7SRichard Henderson     } else {
298598cd9ca7SRichard Henderson         TCGv tmp = get_temp(ctx);
298698cd9ca7SRichard Henderson         tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
298798cd9ca7SRichard Henderson         return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
298898cd9ca7SRichard Henderson     }
298998cd9ca7SRichard Henderson }
299098cd9ca7SRichard Henderson 
299198cd9ca7SRichard Henderson static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
299298cd9ca7SRichard Henderson                            const DisasInsn *di)
299398cd9ca7SRichard Henderson {
299498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
299598cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
299698cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
299798cd9ca7SRichard Henderson 
299898cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
299998cd9ca7SRichard Henderson }
300098cd9ca7SRichard Henderson 
300198cd9ca7SRichard Henderson static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
300298cd9ca7SRichard Henderson                                 const DisasInsn *di)
300398cd9ca7SRichard Henderson {
300498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
300598cd9ca7SRichard Henderson     target_long disp = assemble_22(insn);
300698cd9ca7SRichard Henderson 
300798cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
300898cd9ca7SRichard Henderson }
300998cd9ca7SRichard Henderson 
301098cd9ca7SRichard Henderson static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
301198cd9ca7SRichard Henderson                             const DisasInsn *di)
301298cd9ca7SRichard Henderson {
301398cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
301498cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
301598cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
301698cd9ca7SRichard Henderson     TCGv tmp = get_temp(ctx);
301798cd9ca7SRichard Henderson 
301898cd9ca7SRichard Henderson     tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
301998cd9ca7SRichard Henderson     tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
302098cd9ca7SRichard Henderson     return do_ibranch(ctx, tmp, link, n);
302198cd9ca7SRichard Henderson }
302298cd9ca7SRichard Henderson 
302398cd9ca7SRichard Henderson static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
302498cd9ca7SRichard Henderson                            const DisasInsn *di)
302598cd9ca7SRichard Henderson {
302698cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
302798cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
302898cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
302998cd9ca7SRichard Henderson     TCGv dest;
303098cd9ca7SRichard Henderson 
303198cd9ca7SRichard Henderson     if (rx == 0) {
303298cd9ca7SRichard Henderson         dest = load_gpr(ctx, rb);
303398cd9ca7SRichard Henderson     } else {
303498cd9ca7SRichard Henderson         dest = get_temp(ctx);
303598cd9ca7SRichard Henderson         tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
303698cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
303798cd9ca7SRichard Henderson     }
303898cd9ca7SRichard Henderson     return do_ibranch(ctx, dest, 0, n);
303998cd9ca7SRichard Henderson }
304098cd9ca7SRichard Henderson 
304198cd9ca7SRichard Henderson static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
304298cd9ca7SRichard Henderson                             const DisasInsn *di)
304398cd9ca7SRichard Henderson {
304498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
304598cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
304698cd9ca7SRichard Henderson     unsigned link = extract32(insn, 13, 1) ? 2 : 0;
304798cd9ca7SRichard Henderson 
304898cd9ca7SRichard Henderson     return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
304998cd9ca7SRichard Henderson }
305098cd9ca7SRichard Henderson 
305198cd9ca7SRichard Henderson static const DisasInsn table_branch[] = {
305298cd9ca7SRichard Henderson     { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
305398cd9ca7SRichard Henderson     { 0xe800a000u, 0xfc00e000u, trans_bl_long },
305498cd9ca7SRichard Henderson     { 0xe8004000u, 0xfc00fffdu, trans_blr },
305598cd9ca7SRichard Henderson     { 0xe800c000u, 0xfc00fffdu, trans_bv },
305698cd9ca7SRichard Henderson     { 0xe800d000u, 0xfc00dffcu, trans_bve },
305798cd9ca7SRichard Henderson };
305898cd9ca7SRichard Henderson 
3059ebe9383cSRichard Henderson static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3060ebe9383cSRichard Henderson                                    const DisasInsn *di)
3061ebe9383cSRichard Henderson {
3062ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3063ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3064*eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3065ebe9383cSRichard Henderson }
3066ebe9383cSRichard Henderson 
3067ebe9383cSRichard Henderson static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3068ebe9383cSRichard Henderson                                    const DisasInsn *di)
3069ebe9383cSRichard Henderson {
3070ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3071ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3072*eff235ebSPaolo Bonzini     return do_fop_wew(ctx, rt, ra, di->f.wew);
3073ebe9383cSRichard Henderson }
3074ebe9383cSRichard Henderson 
3075ebe9383cSRichard Henderson static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn,
3076ebe9383cSRichard Henderson                                 const DisasInsn *di)
3077ebe9383cSRichard Henderson {
3078ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3079ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3080*eff235ebSPaolo Bonzini     return do_fop_ded(ctx, rt, ra, di->f.ded);
3081ebe9383cSRichard Henderson }
3082ebe9383cSRichard Henderson 
3083ebe9383cSRichard Henderson static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3084ebe9383cSRichard Henderson                                    const DisasInsn *di)
3085ebe9383cSRichard Henderson {
3086ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3087ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3088*eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3089ebe9383cSRichard Henderson }
3090ebe9383cSRichard Henderson 
3091ebe9383cSRichard Henderson static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3092ebe9383cSRichard Henderson                                    const DisasInsn *di)
3093ebe9383cSRichard Henderson {
3094ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3095ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3096*eff235ebSPaolo Bonzini     return do_fop_wed(ctx, rt, ra, di->f.wed);
3097ebe9383cSRichard Henderson }
3098ebe9383cSRichard Henderson 
3099ebe9383cSRichard Henderson static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3100ebe9383cSRichard Henderson                                    const DisasInsn *di)
3101ebe9383cSRichard Henderson {
3102ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3103ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3104*eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3105ebe9383cSRichard Henderson }
3106ebe9383cSRichard Henderson 
3107ebe9383cSRichard Henderson static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3108ebe9383cSRichard Henderson                                    const DisasInsn *di)
3109ebe9383cSRichard Henderson {
3110ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3111ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3112*eff235ebSPaolo Bonzini     return do_fop_dew(ctx, rt, ra, di->f.dew);
3113ebe9383cSRichard Henderson }
3114ebe9383cSRichard Henderson 
3115ebe9383cSRichard Henderson static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3116ebe9383cSRichard Henderson                                     const DisasInsn *di)
3117ebe9383cSRichard Henderson {
3118ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3119ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3120ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3121*eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3122ebe9383cSRichard Henderson }
3123ebe9383cSRichard Henderson 
3124ebe9383cSRichard Henderson static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3125ebe9383cSRichard Henderson                                     const DisasInsn *di)
3126ebe9383cSRichard Henderson {
3127ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3128ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3129ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3130*eff235ebSPaolo Bonzini     return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3131ebe9383cSRichard Henderson }
3132ebe9383cSRichard Henderson 
3133ebe9383cSRichard Henderson static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3134ebe9383cSRichard Henderson                                  const DisasInsn *di)
3135ebe9383cSRichard Henderson {
3136ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3137ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3138ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3139*eff235ebSPaolo Bonzini     return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3140ebe9383cSRichard Henderson }
3141ebe9383cSRichard Henderson 
3142ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3143ebe9383cSRichard Henderson {
3144ebe9383cSRichard Henderson     tcg_gen_mov_i32(dst, src);
3145ebe9383cSRichard Henderson }
3146ebe9383cSRichard Henderson 
3147ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3148ebe9383cSRichard Henderson {
3149ebe9383cSRichard Henderson     tcg_gen_mov_i64(dst, src);
3150ebe9383cSRichard Henderson }
3151ebe9383cSRichard Henderson 
3152ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3153ebe9383cSRichard Henderson {
3154ebe9383cSRichard Henderson     tcg_gen_andi_i32(dst, src, INT32_MAX);
3155ebe9383cSRichard Henderson }
3156ebe9383cSRichard Henderson 
3157ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3158ebe9383cSRichard Henderson {
3159ebe9383cSRichard Henderson     tcg_gen_andi_i64(dst, src, INT64_MAX);
3160ebe9383cSRichard Henderson }
3161ebe9383cSRichard Henderson 
3162ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3163ebe9383cSRichard Henderson {
3164ebe9383cSRichard Henderson     tcg_gen_xori_i32(dst, src, INT32_MIN);
3165ebe9383cSRichard Henderson }
3166ebe9383cSRichard Henderson 
3167ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3168ebe9383cSRichard Henderson {
3169ebe9383cSRichard Henderson     tcg_gen_xori_i64(dst, src, INT64_MIN);
3170ebe9383cSRichard Henderson }
3171ebe9383cSRichard Henderson 
3172ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3173ebe9383cSRichard Henderson {
3174ebe9383cSRichard Henderson     tcg_gen_ori_i32(dst, src, INT32_MIN);
3175ebe9383cSRichard Henderson }
3176ebe9383cSRichard Henderson 
3177ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3178ebe9383cSRichard Henderson {
3179ebe9383cSRichard Henderson     tcg_gen_ori_i64(dst, src, INT64_MIN);
3180ebe9383cSRichard Henderson }
3181ebe9383cSRichard Henderson 
3182ebe9383cSRichard Henderson static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3183ebe9383cSRichard Henderson                             unsigned y, unsigned c)
3184ebe9383cSRichard Henderson {
3185ebe9383cSRichard Henderson     TCGv_i32 ta, tb, tc, ty;
3186ebe9383cSRichard Henderson 
3187ebe9383cSRichard Henderson     nullify_over(ctx);
3188ebe9383cSRichard Henderson 
3189ebe9383cSRichard Henderson     ta = load_frw0_i32(ra);
3190ebe9383cSRichard Henderson     tb = load_frw0_i32(rb);
3191ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3192ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3193ebe9383cSRichard Henderson 
3194ebe9383cSRichard Henderson     gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3195ebe9383cSRichard Henderson 
3196ebe9383cSRichard Henderson     tcg_temp_free_i32(ta);
3197ebe9383cSRichard Henderson     tcg_temp_free_i32(tb);
3198ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3199ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3200ebe9383cSRichard Henderson 
3201ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3202ebe9383cSRichard Henderson }
3203ebe9383cSRichard Henderson 
3204ebe9383cSRichard Henderson static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3205ebe9383cSRichard Henderson                                   const DisasInsn *di)
3206ebe9383cSRichard Henderson {
3207ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3208ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3209ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3210ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3211ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3212ebe9383cSRichard Henderson }
3213ebe9383cSRichard Henderson 
3214ebe9383cSRichard Henderson static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3215ebe9383cSRichard Henderson                                   const DisasInsn *di)
3216ebe9383cSRichard Henderson {
3217ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3218ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3219ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3220ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3221ebe9383cSRichard Henderson     return do_fcmp_s(ctx, ra, rb, y, c);
3222ebe9383cSRichard Henderson }
3223ebe9383cSRichard Henderson 
3224ebe9383cSRichard Henderson static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3225ebe9383cSRichard Henderson                                const DisasInsn *di)
3226ebe9383cSRichard Henderson {
3227ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3228ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3229ebe9383cSRichard Henderson     unsigned rb = extract32(insn, 16, 5);
3230ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 21, 5);
3231ebe9383cSRichard Henderson     TCGv_i64 ta, tb;
3232ebe9383cSRichard Henderson     TCGv_i32 tc, ty;
3233ebe9383cSRichard Henderson 
3234ebe9383cSRichard Henderson     nullify_over(ctx);
3235ebe9383cSRichard Henderson 
3236ebe9383cSRichard Henderson     ta = load_frd0(ra);
3237ebe9383cSRichard Henderson     tb = load_frd0(rb);
3238ebe9383cSRichard Henderson     ty = tcg_const_i32(y);
3239ebe9383cSRichard Henderson     tc = tcg_const_i32(c);
3240ebe9383cSRichard Henderson 
3241ebe9383cSRichard Henderson     gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3242ebe9383cSRichard Henderson 
3243ebe9383cSRichard Henderson     tcg_temp_free_i64(ta);
3244ebe9383cSRichard Henderson     tcg_temp_free_i64(tb);
3245ebe9383cSRichard Henderson     tcg_temp_free_i32(ty);
3246ebe9383cSRichard Henderson     tcg_temp_free_i32(tc);
3247ebe9383cSRichard Henderson 
3248ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3249ebe9383cSRichard Henderson }
3250ebe9383cSRichard Henderson 
3251ebe9383cSRichard Henderson static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn,
3252ebe9383cSRichard Henderson                                 const DisasInsn *di)
3253ebe9383cSRichard Henderson {
3254ebe9383cSRichard Henderson     unsigned y = extract32(insn, 13, 3);
3255ebe9383cSRichard Henderson     unsigned cbit = (y ^ 1) - 1;
3256ebe9383cSRichard Henderson     TCGv t;
3257ebe9383cSRichard Henderson 
3258ebe9383cSRichard Henderson     nullify_over(ctx);
3259ebe9383cSRichard Henderson 
3260ebe9383cSRichard Henderson     t = tcg_temp_new();
3261ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3262ebe9383cSRichard Henderson     tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3263ebe9383cSRichard Henderson     ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3264ebe9383cSRichard Henderson     tcg_temp_free(t);
3265ebe9383cSRichard Henderson 
3266ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3267ebe9383cSRichard Henderson }
3268ebe9383cSRichard Henderson 
3269ebe9383cSRichard Henderson static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn,
3270ebe9383cSRichard Henderson                                 const DisasInsn *di)
3271ebe9383cSRichard Henderson {
3272ebe9383cSRichard Henderson     unsigned c = extract32(insn, 0, 5);
3273ebe9383cSRichard Henderson     int mask;
3274ebe9383cSRichard Henderson     bool inv = false;
3275ebe9383cSRichard Henderson     TCGv t;
3276ebe9383cSRichard Henderson 
3277ebe9383cSRichard Henderson     nullify_over(ctx);
3278ebe9383cSRichard Henderson 
3279ebe9383cSRichard Henderson     t = tcg_temp_new();
3280ebe9383cSRichard Henderson     tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3281ebe9383cSRichard Henderson 
3282ebe9383cSRichard Henderson     switch (c) {
3283ebe9383cSRichard Henderson     case 0: /* simple */
3284ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, 0x4000000);
3285ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3286ebe9383cSRichard Henderson         goto done;
3287ebe9383cSRichard Henderson     case 2: /* rej */
3288ebe9383cSRichard Henderson         inv = true;
3289ebe9383cSRichard Henderson         /* fallthru */
3290ebe9383cSRichard Henderson     case 1: /* acc */
3291ebe9383cSRichard Henderson         mask = 0x43ff800;
3292ebe9383cSRichard Henderson         break;
3293ebe9383cSRichard Henderson     case 6: /* rej8 */
3294ebe9383cSRichard Henderson         inv = true;
3295ebe9383cSRichard Henderson         /* fallthru */
3296ebe9383cSRichard Henderson     case 5: /* acc8 */
3297ebe9383cSRichard Henderson         mask = 0x43f8000;
3298ebe9383cSRichard Henderson         break;
3299ebe9383cSRichard Henderson     case 9: /* acc6 */
3300ebe9383cSRichard Henderson         mask = 0x43e0000;
3301ebe9383cSRichard Henderson         break;
3302ebe9383cSRichard Henderson     case 13: /* acc4 */
3303ebe9383cSRichard Henderson         mask = 0x4380000;
3304ebe9383cSRichard Henderson         break;
3305ebe9383cSRichard Henderson     case 17: /* acc2 */
3306ebe9383cSRichard Henderson         mask = 0x4200000;
3307ebe9383cSRichard Henderson         break;
3308ebe9383cSRichard Henderson     default:
3309ebe9383cSRichard Henderson         return gen_illegal(ctx);
3310ebe9383cSRichard Henderson     }
3311ebe9383cSRichard Henderson     if (inv) {
3312ebe9383cSRichard Henderson         TCGv c = load_const(ctx, mask);
3313ebe9383cSRichard Henderson         tcg_gen_or_tl(t, t, c);
3314ebe9383cSRichard Henderson         ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3315ebe9383cSRichard Henderson     } else {
3316ebe9383cSRichard Henderson         tcg_gen_andi_tl(t, t, mask);
3317ebe9383cSRichard Henderson         ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3318ebe9383cSRichard Henderson     }
3319ebe9383cSRichard Henderson  done:
3320ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3321ebe9383cSRichard Henderson }
3322ebe9383cSRichard Henderson 
3323ebe9383cSRichard Henderson static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn,
3324ebe9383cSRichard Henderson                               const DisasInsn *di)
3325ebe9383cSRichard Henderson {
3326ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3327ebe9383cSRichard Henderson     unsigned rb = assemble_rb64(insn);
3328ebe9383cSRichard Henderson     unsigned ra = assemble_ra64(insn);
3329ebe9383cSRichard Henderson     TCGv_i64 a, b;
3330ebe9383cSRichard Henderson 
3331ebe9383cSRichard Henderson     nullify_over(ctx);
3332ebe9383cSRichard Henderson 
3333ebe9383cSRichard Henderson     a = load_frw0_i64(ra);
3334ebe9383cSRichard Henderson     b = load_frw0_i64(rb);
3335ebe9383cSRichard Henderson     tcg_gen_mul_i64(a, a, b);
3336ebe9383cSRichard Henderson     save_frd(rt, a);
3337ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3338ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3339ebe9383cSRichard Henderson 
3340ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3341ebe9383cSRichard Henderson }
3342ebe9383cSRichard Henderson 
3343*eff235ebSPaolo Bonzini #define FOP_DED  trans_fop_ded, .f.ded
3344*eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd
3345ebe9383cSRichard Henderson 
3346*eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0c, .f.wew
3347*eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0c, .f.dew
3348*eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0c, .f.wed
3349*eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww
3350ebe9383cSRichard Henderson 
3351ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = {
3352ebe9383cSRichard Henderson     /* floating point class zero */
3353ebe9383cSRichard Henderson     { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3354ebe9383cSRichard Henderson     { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3355ebe9383cSRichard Henderson     { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3356ebe9383cSRichard Henderson     { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3357ebe9383cSRichard Henderson     { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3358ebe9383cSRichard Henderson     { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3359ebe9383cSRichard Henderson 
3360ebe9383cSRichard Henderson     { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3361ebe9383cSRichard Henderson     { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3362ebe9383cSRichard Henderson     { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3363ebe9383cSRichard Henderson     { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3364ebe9383cSRichard Henderson     { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3365ebe9383cSRichard Henderson     { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3366ebe9383cSRichard Henderson 
3367ebe9383cSRichard Henderson     /* floating point class three */
3368ebe9383cSRichard Henderson     { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3369ebe9383cSRichard Henderson     { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3370ebe9383cSRichard Henderson     { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3371ebe9383cSRichard Henderson     { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3372ebe9383cSRichard Henderson 
3373ebe9383cSRichard Henderson     { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3374ebe9383cSRichard Henderson     { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3375ebe9383cSRichard Henderson     { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3376ebe9383cSRichard Henderson     { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3377ebe9383cSRichard Henderson 
3378ebe9383cSRichard Henderson     /* floating point class one */
3379ebe9383cSRichard Henderson     /* float/float */
3380ebe9383cSRichard Henderson     { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3381ebe9383cSRichard Henderson     { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3382ebe9383cSRichard Henderson     /* int/float */
3383ebe9383cSRichard Henderson     { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3384ebe9383cSRichard Henderson     { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3385ebe9383cSRichard Henderson     { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3386ebe9383cSRichard Henderson     { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3387ebe9383cSRichard Henderson     /* float/int */
3388ebe9383cSRichard Henderson     { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3389ebe9383cSRichard Henderson     { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3390ebe9383cSRichard Henderson     { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3391ebe9383cSRichard Henderson     { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3392ebe9383cSRichard Henderson     /* float/int truncate */
3393ebe9383cSRichard Henderson     { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3394ebe9383cSRichard Henderson     { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3395ebe9383cSRichard Henderson     { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3396ebe9383cSRichard Henderson     { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3397ebe9383cSRichard Henderson     /* uint/float */
3398ebe9383cSRichard Henderson     { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3399ebe9383cSRichard Henderson     { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3400ebe9383cSRichard Henderson     { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3401ebe9383cSRichard Henderson     { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3402ebe9383cSRichard Henderson     /* float/uint */
3403ebe9383cSRichard Henderson     { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3404ebe9383cSRichard Henderson     { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3405ebe9383cSRichard Henderson     { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3406ebe9383cSRichard Henderson     { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3407ebe9383cSRichard Henderson     /* float/uint truncate */
3408ebe9383cSRichard Henderson     { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3409ebe9383cSRichard Henderson     { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3410ebe9383cSRichard Henderson     { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3411ebe9383cSRichard Henderson     { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3412ebe9383cSRichard Henderson 
3413ebe9383cSRichard Henderson     /* floating point class two */
3414ebe9383cSRichard Henderson     { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3415ebe9383cSRichard Henderson     { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3416ebe9383cSRichard Henderson     { 0x30002420, 0xffffffe0, trans_ftest_q },
3417ebe9383cSRichard Henderson     { 0x30000420, 0xffff1fff, trans_ftest_t },
3418ebe9383cSRichard Henderson 
3419ebe9383cSRichard Henderson     /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3420ebe9383cSRichard Henderson        This is machine/revision == 0, which is reserved for simulator.  */
3421ebe9383cSRichard Henderson     { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3422ebe9383cSRichard Henderson };
3423ebe9383cSRichard Henderson 
3424ebe9383cSRichard Henderson #undef FOP_WEW
3425ebe9383cSRichard Henderson #undef FOP_DEW
3426ebe9383cSRichard Henderson #undef FOP_WED
3427ebe9383cSRichard Henderson #undef FOP_WEWW
3428*eff235ebSPaolo Bonzini #define FOP_WEW  trans_fop_wew_0e, .f.wew
3429*eff235ebSPaolo Bonzini #define FOP_DEW  trans_fop_dew_0e, .f.dew
3430*eff235ebSPaolo Bonzini #define FOP_WED  trans_fop_wed_0e, .f.wed
3431*eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww
3432ebe9383cSRichard Henderson 
3433ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = {
3434ebe9383cSRichard Henderson     /* floating point class zero */
3435ebe9383cSRichard Henderson     { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3436ebe9383cSRichard Henderson     { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3437ebe9383cSRichard Henderson     { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3438ebe9383cSRichard Henderson     { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3439ebe9383cSRichard Henderson     { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3440ebe9383cSRichard Henderson     { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3441ebe9383cSRichard Henderson 
3442ebe9383cSRichard Henderson     { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3443ebe9383cSRichard Henderson     { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3444ebe9383cSRichard Henderson     { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3445ebe9383cSRichard Henderson     { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3446ebe9383cSRichard Henderson     { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3447ebe9383cSRichard Henderson     { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3448ebe9383cSRichard Henderson 
3449ebe9383cSRichard Henderson     /* floating point class three */
3450ebe9383cSRichard Henderson     { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3451ebe9383cSRichard Henderson     { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3452ebe9383cSRichard Henderson     { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3453ebe9383cSRichard Henderson     { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3454ebe9383cSRichard Henderson 
3455ebe9383cSRichard Henderson     { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3456ebe9383cSRichard Henderson     { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3457ebe9383cSRichard Henderson     { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3458ebe9383cSRichard Henderson     { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3459ebe9383cSRichard Henderson 
3460ebe9383cSRichard Henderson     { 0x38004700, 0xfc00ef60, trans_xmpyu },
3461ebe9383cSRichard Henderson 
3462ebe9383cSRichard Henderson     /* floating point class one */
3463ebe9383cSRichard Henderson     /* float/float */
3464ebe9383cSRichard Henderson     { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3465ebe9383cSRichard Henderson     { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3466ebe9383cSRichard Henderson     /* int/float */
3467ebe9383cSRichard Henderson     { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3468ebe9383cSRichard Henderson     { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3469ebe9383cSRichard Henderson     { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3470ebe9383cSRichard Henderson     { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3471ebe9383cSRichard Henderson     /* float/int */
3472ebe9383cSRichard Henderson     { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3473ebe9383cSRichard Henderson     { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3474ebe9383cSRichard Henderson     { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3475ebe9383cSRichard Henderson     { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3476ebe9383cSRichard Henderson     /* float/int truncate */
3477ebe9383cSRichard Henderson     { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3478ebe9383cSRichard Henderson     { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3479ebe9383cSRichard Henderson     { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3480ebe9383cSRichard Henderson     { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3481ebe9383cSRichard Henderson     /* uint/float */
3482ebe9383cSRichard Henderson     { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3483ebe9383cSRichard Henderson     { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3484ebe9383cSRichard Henderson     { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3485ebe9383cSRichard Henderson     { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3486ebe9383cSRichard Henderson     /* float/uint */
3487ebe9383cSRichard Henderson     { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3488ebe9383cSRichard Henderson     { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3489ebe9383cSRichard Henderson     { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3490ebe9383cSRichard Henderson     { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3491ebe9383cSRichard Henderson     /* float/uint truncate */
3492ebe9383cSRichard Henderson     { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3493ebe9383cSRichard Henderson     { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3494ebe9383cSRichard Henderson     { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3495ebe9383cSRichard Henderson     { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3496ebe9383cSRichard Henderson 
3497ebe9383cSRichard Henderson     /* floating point class two */
3498ebe9383cSRichard Henderson     { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3499ebe9383cSRichard Henderson     { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3500ebe9383cSRichard Henderson };
3501ebe9383cSRichard Henderson 
3502ebe9383cSRichard Henderson #undef FOP_WEW
3503ebe9383cSRichard Henderson #undef FOP_DEW
3504ebe9383cSRichard Henderson #undef FOP_WED
3505ebe9383cSRichard Henderson #undef FOP_WEWW
3506ebe9383cSRichard Henderson #undef FOP_DED
3507ebe9383cSRichard Henderson #undef FOP_DEDD
3508ebe9383cSRichard Henderson 
3509ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard.  */
3510ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r)
3511ebe9383cSRichard Henderson {
3512ebe9383cSRichard Henderson     return (r & 16) * 2 + 16 + (r & 15);
3513ebe9383cSRichard Henderson }
3514ebe9383cSRichard Henderson 
3515ebe9383cSRichard Henderson static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub)
3516ebe9383cSRichard Henderson {
3517ebe9383cSRichard Henderson     unsigned tm = extract32(insn, 0, 5);
3518ebe9383cSRichard Henderson     unsigned f = extract32(insn, 5, 1);
3519ebe9383cSRichard Henderson     unsigned ra = extract32(insn, 6, 5);
3520ebe9383cSRichard Henderson     unsigned ta = extract32(insn, 11, 5);
3521ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3522ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3523ebe9383cSRichard Henderson 
3524ebe9383cSRichard Henderson     nullify_over(ctx);
3525ebe9383cSRichard Henderson 
3526ebe9383cSRichard Henderson     /* Independent multiply & add/sub, with undefined behaviour
3527ebe9383cSRichard Henderson        if outputs overlap inputs.  */
3528ebe9383cSRichard Henderson     if (f == 0) {
3529ebe9383cSRichard Henderson         tm = fmpyadd_s_reg(tm);
3530ebe9383cSRichard Henderson         ra = fmpyadd_s_reg(ra);
3531ebe9383cSRichard Henderson         ta = fmpyadd_s_reg(ta);
3532ebe9383cSRichard Henderson         rm2 = fmpyadd_s_reg(rm2);
3533ebe9383cSRichard Henderson         rm1 = fmpyadd_s_reg(rm1);
3534ebe9383cSRichard Henderson         do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3535ebe9383cSRichard Henderson         do_fop_weww(ctx, ta, ta, ra,
3536ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3537ebe9383cSRichard Henderson     } else {
3538ebe9383cSRichard Henderson         do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3539ebe9383cSRichard Henderson         do_fop_dedd(ctx, ta, ta, ra,
3540ebe9383cSRichard Henderson                     is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3541ebe9383cSRichard Henderson     }
3542ebe9383cSRichard Henderson 
3543ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3544ebe9383cSRichard Henderson }
3545ebe9383cSRichard Henderson 
3546ebe9383cSRichard Henderson static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3547ebe9383cSRichard Henderson                                    const DisasInsn *di)
3548ebe9383cSRichard Henderson {
3549ebe9383cSRichard Henderson     unsigned rt = assemble_rt64(insn);
3550ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3551ebe9383cSRichard Henderson     unsigned rm1 = assemble_ra64(insn);
3552ebe9383cSRichard Henderson     unsigned rm2 = assemble_rb64(insn);
3553ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3554ebe9383cSRichard Henderson     TCGv_i32 a, b, c;
3555ebe9383cSRichard Henderson 
3556ebe9383cSRichard Henderson     nullify_over(ctx);
3557ebe9383cSRichard Henderson     a = load_frw0_i32(rm1);
3558ebe9383cSRichard Henderson     b = load_frw0_i32(rm2);
3559ebe9383cSRichard Henderson     c = load_frw0_i32(ra3);
3560ebe9383cSRichard Henderson 
3561ebe9383cSRichard Henderson     if (neg) {
3562ebe9383cSRichard Henderson         gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3563ebe9383cSRichard Henderson     } else {
3564ebe9383cSRichard Henderson         gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3565ebe9383cSRichard Henderson     }
3566ebe9383cSRichard Henderson 
3567ebe9383cSRichard Henderson     tcg_temp_free_i32(b);
3568ebe9383cSRichard Henderson     tcg_temp_free_i32(c);
3569ebe9383cSRichard Henderson     save_frw_i32(rt, a);
3570ebe9383cSRichard Henderson     tcg_temp_free_i32(a);
3571ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3572ebe9383cSRichard Henderson }
3573ebe9383cSRichard Henderson 
3574ebe9383cSRichard Henderson static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3575ebe9383cSRichard Henderson                                    const DisasInsn *di)
3576ebe9383cSRichard Henderson {
3577ebe9383cSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
3578ebe9383cSRichard Henderson     unsigned neg = extract32(insn, 5, 1);
3579ebe9383cSRichard Henderson     unsigned rm1 = extract32(insn, 21, 5);
3580ebe9383cSRichard Henderson     unsigned rm2 = extract32(insn, 16, 5);
3581ebe9383cSRichard Henderson     unsigned ra3 = assemble_rc64(insn);
3582ebe9383cSRichard Henderson     TCGv_i64 a, b, c;
3583ebe9383cSRichard Henderson 
3584ebe9383cSRichard Henderson     nullify_over(ctx);
3585ebe9383cSRichard Henderson     a = load_frd0(rm1);
3586ebe9383cSRichard Henderson     b = load_frd0(rm2);
3587ebe9383cSRichard Henderson     c = load_frd0(ra3);
3588ebe9383cSRichard Henderson 
3589ebe9383cSRichard Henderson     if (neg) {
3590ebe9383cSRichard Henderson         gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3591ebe9383cSRichard Henderson     } else {
3592ebe9383cSRichard Henderson         gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3593ebe9383cSRichard Henderson     }
3594ebe9383cSRichard Henderson 
3595ebe9383cSRichard Henderson     tcg_temp_free_i64(b);
3596ebe9383cSRichard Henderson     tcg_temp_free_i64(c);
3597ebe9383cSRichard Henderson     save_frd(rt, a);
3598ebe9383cSRichard Henderson     tcg_temp_free_i64(a);
3599ebe9383cSRichard Henderson     return nullify_end(ctx, NO_EXIT);
3600ebe9383cSRichard Henderson }
3601ebe9383cSRichard Henderson 
3602ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = {
3603ebe9383cSRichard Henderson     { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3604ebe9383cSRichard Henderson     { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3605ebe9383cSRichard Henderson };
3606ebe9383cSRichard Henderson 
360761766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
360861766fe9SRichard Henderson                                       const DisasInsn table[], size_t n)
360961766fe9SRichard Henderson {
361061766fe9SRichard Henderson     size_t i;
361161766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
361261766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
361361766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
361461766fe9SRichard Henderson         }
361561766fe9SRichard Henderson     }
361661766fe9SRichard Henderson     return gen_illegal(ctx);
361761766fe9SRichard Henderson }
361861766fe9SRichard Henderson 
361961766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
362061766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
362161766fe9SRichard Henderson 
362261766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
362361766fe9SRichard Henderson {
362461766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
362561766fe9SRichard Henderson 
362661766fe9SRichard Henderson     switch (opc) {
362798a9cb79SRichard Henderson     case 0x00: /* system op */
362898a9cb79SRichard Henderson         return translate_table(ctx, insn, table_system);
362998a9cb79SRichard Henderson     case 0x01:
363098a9cb79SRichard Henderson         return translate_table(ctx, insn, table_mem_mgmt);
3631b2167459SRichard Henderson     case 0x02:
3632b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
363396d6407fSRichard Henderson     case 0x03:
363496d6407fSRichard Henderson         return translate_table(ctx, insn, table_index_mem);
3635ebe9383cSRichard Henderson     case 0x06:
3636ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, false);
3637b2167459SRichard Henderson     case 0x08:
3638b2167459SRichard Henderson         return trans_ldil(ctx, insn);
363996d6407fSRichard Henderson     case 0x09:
364096d6407fSRichard Henderson         return trans_copr_w(ctx, insn);
3641b2167459SRichard Henderson     case 0x0A:
3642b2167459SRichard Henderson         return trans_addil(ctx, insn);
364396d6407fSRichard Henderson     case 0x0B:
364496d6407fSRichard Henderson         return trans_copr_dw(ctx, insn);
3645ebe9383cSRichard Henderson     case 0x0C:
3646ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0c);
3647b2167459SRichard Henderson     case 0x0D:
3648b2167459SRichard Henderson         return trans_ldo(ctx, insn);
3649ebe9383cSRichard Henderson     case 0x0E:
3650ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_float_0e);
365196d6407fSRichard Henderson 
365296d6407fSRichard Henderson     case 0x10:
365396d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_UB);
365496d6407fSRichard Henderson     case 0x11:
365596d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUW);
365696d6407fSRichard Henderson     case 0x12:
365796d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUL);
365896d6407fSRichard Henderson     case 0x13:
365996d6407fSRichard Henderson         return trans_load(ctx, insn, true, MO_TEUL);
366096d6407fSRichard Henderson     case 0x16:
366196d6407fSRichard Henderson         return trans_fload_mod(ctx, insn);
366296d6407fSRichard Henderson     case 0x17:
366396d6407fSRichard Henderson         return trans_load_w(ctx, insn);
366496d6407fSRichard Henderson     case 0x18:
366596d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_UB);
366696d6407fSRichard Henderson     case 0x19:
366796d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUW);
366896d6407fSRichard Henderson     case 0x1A:
366996d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUL);
367096d6407fSRichard Henderson     case 0x1B:
367196d6407fSRichard Henderson         return trans_store(ctx, insn, true, MO_TEUL);
367296d6407fSRichard Henderson     case 0x1E:
367396d6407fSRichard Henderson         return trans_fstore_mod(ctx, insn);
367496d6407fSRichard Henderson     case 0x1F:
367596d6407fSRichard Henderson         return trans_store_w(ctx, insn);
367696d6407fSRichard Henderson 
367798cd9ca7SRichard Henderson     case 0x20:
367898cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, false);
367998cd9ca7SRichard Henderson     case 0x21:
368098cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, true, false);
368198cd9ca7SRichard Henderson     case 0x22:
368298cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, false);
368398cd9ca7SRichard Henderson     case 0x23:
368498cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, true, false);
3685b2167459SRichard Henderson     case 0x24:
3686b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
3687b2167459SRichard Henderson     case 0x25:
3688b2167459SRichard Henderson         return trans_subi(ctx, insn);
3689ebe9383cSRichard Henderson     case 0x26:
3690ebe9383cSRichard Henderson         return trans_fmpyadd(ctx, insn, true);
369198cd9ca7SRichard Henderson     case 0x27:
369298cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, true);
369398cd9ca7SRichard Henderson     case 0x28:
369498cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, false);
369598cd9ca7SRichard Henderson     case 0x29:
369698cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, true);
369798cd9ca7SRichard Henderson     case 0x2A:
369898cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, false);
369998cd9ca7SRichard Henderson     case 0x2B:
370098cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, true);
3701b2167459SRichard Henderson     case 0x2C:
3702b2167459SRichard Henderson     case 0x2D:
3703b2167459SRichard Henderson         return trans_addi(ctx, insn);
3704ebe9383cSRichard Henderson     case 0x2E:
3705ebe9383cSRichard Henderson         return translate_table(ctx, insn, table_fp_fused);
370698cd9ca7SRichard Henderson     case 0x2F:
370798cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, true);
370896d6407fSRichard Henderson 
370998cd9ca7SRichard Henderson     case 0x30:
371098cd9ca7SRichard Henderson     case 0x31:
371198cd9ca7SRichard Henderson         return trans_bb(ctx, insn);
371298cd9ca7SRichard Henderson     case 0x32:
371398cd9ca7SRichard Henderson         return trans_movb(ctx, insn, false);
371498cd9ca7SRichard Henderson     case 0x33:
371598cd9ca7SRichard Henderson         return trans_movb(ctx, insn, true);
37160b1347d2SRichard Henderson     case 0x34:
37170b1347d2SRichard Henderson         return translate_table(ctx, insn, table_sh_ex);
37180b1347d2SRichard Henderson     case 0x35:
37190b1347d2SRichard Henderson         return translate_table(ctx, insn, table_depw);
372098cd9ca7SRichard Henderson     case 0x38:
372198cd9ca7SRichard Henderson         return trans_be(ctx, insn, false);
372298cd9ca7SRichard Henderson     case 0x39:
372398cd9ca7SRichard Henderson         return trans_be(ctx, insn, true);
372498cd9ca7SRichard Henderson     case 0x3A:
372598cd9ca7SRichard Henderson         return translate_table(ctx, insn, table_branch);
372696d6407fSRichard Henderson 
372796d6407fSRichard Henderson     case 0x04: /* spopn */
372896d6407fSRichard Henderson     case 0x05: /* diag */
372996d6407fSRichard Henderson     case 0x0F: /* product specific */
373096d6407fSRichard Henderson         break;
373196d6407fSRichard Henderson 
373296d6407fSRichard Henderson     case 0x07: /* unassigned */
373396d6407fSRichard Henderson     case 0x15: /* unassigned */
373496d6407fSRichard Henderson     case 0x1D: /* unassigned */
373596d6407fSRichard Henderson     case 0x37: /* unassigned */
373696d6407fSRichard Henderson     case 0x3F: /* unassigned */
373761766fe9SRichard Henderson     default:
373861766fe9SRichard Henderson         break;
373961766fe9SRichard Henderson     }
374061766fe9SRichard Henderson     return gen_illegal(ctx);
374161766fe9SRichard Henderson }
374261766fe9SRichard Henderson 
374361766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
374461766fe9SRichard Henderson {
374561766fe9SRichard Henderson     HPPACPU *cpu = hppa_env_get_cpu(env);
374661766fe9SRichard Henderson     CPUState *cs = CPU(cpu);
374761766fe9SRichard Henderson     DisasContext ctx;
374861766fe9SRichard Henderson     ExitStatus ret;
374961766fe9SRichard Henderson     int num_insns, max_insns, i;
375061766fe9SRichard Henderson 
375161766fe9SRichard Henderson     ctx.tb = tb;
375261766fe9SRichard Henderson     ctx.cs = cs;
375361766fe9SRichard Henderson     ctx.iaoq_f = tb->pc;
375461766fe9SRichard Henderson     ctx.iaoq_b = tb->cs_base;
375561766fe9SRichard Henderson     ctx.singlestep_enabled = cs->singlestep_enabled;
375661766fe9SRichard Henderson 
375761766fe9SRichard Henderson     ctx.ntemps = 0;
375861766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
375961766fe9SRichard Henderson         TCGV_UNUSED(ctx.temps[i]);
376061766fe9SRichard Henderson     }
376161766fe9SRichard Henderson 
376261766fe9SRichard Henderson     /* Compute the maximum number of insns to execute, as bounded by
376361766fe9SRichard Henderson        (1) icount, (2) single-stepping, (3) branch delay slots, or
376461766fe9SRichard Henderson        (4) the number of insns remaining on the current page.  */
376561766fe9SRichard Henderson     max_insns = tb->cflags & CF_COUNT_MASK;
376661766fe9SRichard Henderson     if (max_insns == 0) {
376761766fe9SRichard Henderson         max_insns = CF_COUNT_MASK;
376861766fe9SRichard Henderson     }
376961766fe9SRichard Henderson     if (ctx.singlestep_enabled || singlestep) {
377061766fe9SRichard Henderson         max_insns = 1;
377161766fe9SRichard Henderson     } else if (max_insns > TCG_MAX_INSNS) {
377261766fe9SRichard Henderson         max_insns = TCG_MAX_INSNS;
377361766fe9SRichard Henderson     }
377461766fe9SRichard Henderson 
377561766fe9SRichard Henderson     num_insns = 0;
377661766fe9SRichard Henderson     gen_tb_start(tb);
377761766fe9SRichard Henderson 
3778129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
3779129e9cc3SRichard Henderson     ctx.null_cond = cond_make_f();
3780129e9cc3SRichard Henderson     ctx.psw_n_nonzero = false;
3781129e9cc3SRichard Henderson     if (tb->flags & 1) {
3782129e9cc3SRichard Henderson         ctx.null_cond.c = TCG_COND_ALWAYS;
3783129e9cc3SRichard Henderson         ctx.psw_n_nonzero = true;
3784129e9cc3SRichard Henderson     }
3785129e9cc3SRichard Henderson     ctx.null_lab = NULL;
3786129e9cc3SRichard Henderson 
378761766fe9SRichard Henderson     do {
378861766fe9SRichard Henderson         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
378961766fe9SRichard Henderson         num_insns++;
379061766fe9SRichard Henderson 
379161766fe9SRichard Henderson         if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
379261766fe9SRichard Henderson             ret = gen_excp(&ctx, EXCP_DEBUG);
379361766fe9SRichard Henderson             break;
379461766fe9SRichard Henderson         }
379561766fe9SRichard Henderson         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
379661766fe9SRichard Henderson             gen_io_start();
379761766fe9SRichard Henderson         }
379861766fe9SRichard Henderson 
37997ad439dfSRichard Henderson         if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
38007ad439dfSRichard Henderson             ret = do_page_zero(&ctx);
38017ad439dfSRichard Henderson             assert(ret != NO_EXIT);
38027ad439dfSRichard Henderson         } else {
380361766fe9SRichard Henderson             /* Always fetch the insn, even if nullified, so that we check
380461766fe9SRichard Henderson                the page permissions for execute.  */
380561766fe9SRichard Henderson             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
380661766fe9SRichard Henderson 
380761766fe9SRichard Henderson             /* Set up the IA queue for the next insn.
380861766fe9SRichard Henderson                This will be overwritten by a branch.  */
380961766fe9SRichard Henderson             if (ctx.iaoq_b == -1) {
381061766fe9SRichard Henderson                 ctx.iaoq_n = -1;
381161766fe9SRichard Henderson                 ctx.iaoq_n_var = get_temp(&ctx);
381261766fe9SRichard Henderson                 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
381361766fe9SRichard Henderson             } else {
381461766fe9SRichard Henderson                 ctx.iaoq_n = ctx.iaoq_b + 4;
381561766fe9SRichard Henderson                 TCGV_UNUSED(ctx.iaoq_n_var);
381661766fe9SRichard Henderson             }
381761766fe9SRichard Henderson 
3818129e9cc3SRichard Henderson             if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
3819129e9cc3SRichard Henderson                 ctx.null_cond.c = TCG_COND_NEVER;
3820129e9cc3SRichard Henderson                 ret = NO_EXIT;
3821129e9cc3SRichard Henderson             } else {
382261766fe9SRichard Henderson                 ret = translate_one(&ctx, insn);
3823129e9cc3SRichard Henderson                 assert(ctx.null_lab == NULL);
3824129e9cc3SRichard Henderson             }
382561766fe9SRichard Henderson         }
382661766fe9SRichard Henderson 
382761766fe9SRichard Henderson         for (i = 0; i < ctx.ntemps; ++i) {
382861766fe9SRichard Henderson             tcg_temp_free(ctx.temps[i]);
382961766fe9SRichard Henderson             TCGV_UNUSED(ctx.temps[i]);
383061766fe9SRichard Henderson         }
383161766fe9SRichard Henderson         ctx.ntemps = 0;
383261766fe9SRichard Henderson 
383361766fe9SRichard Henderson         /* If we see non-linear instructions, exhaust instruction count,
383461766fe9SRichard Henderson            or run out of buffer space, stop generation.  */
383561766fe9SRichard Henderson         /* ??? The non-linear instruction restriction is purely due to
383661766fe9SRichard Henderson            the debugging dump.  Otherwise we *could* follow unconditional
383761766fe9SRichard Henderson            branches within the same page.  */
383861766fe9SRichard Henderson         if (ret == NO_EXIT
383961766fe9SRichard Henderson             && (ctx.iaoq_b != ctx.iaoq_f + 4
384061766fe9SRichard Henderson                 || num_insns >= max_insns
384161766fe9SRichard Henderson                 || tcg_op_buf_full())) {
3842129e9cc3SRichard Henderson             if (ctx.null_cond.c == TCG_COND_NEVER
3843129e9cc3SRichard Henderson                 || ctx.null_cond.c == TCG_COND_ALWAYS) {
3844129e9cc3SRichard Henderson                 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
3845129e9cc3SRichard Henderson                 gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
3846129e9cc3SRichard Henderson                 ret = EXIT_GOTO_TB;
3847129e9cc3SRichard Henderson             } else {
384861766fe9SRichard Henderson                 ret = EXIT_IAQ_N_STALE;
384961766fe9SRichard Henderson             }
3850129e9cc3SRichard Henderson         }
385161766fe9SRichard Henderson 
385261766fe9SRichard Henderson         ctx.iaoq_f = ctx.iaoq_b;
385361766fe9SRichard Henderson         ctx.iaoq_b = ctx.iaoq_n;
385461766fe9SRichard Henderson         if (ret == EXIT_NORETURN
385561766fe9SRichard Henderson             || ret == EXIT_GOTO_TB
385661766fe9SRichard Henderson             || ret == EXIT_IAQ_N_UPDATED) {
385761766fe9SRichard Henderson             break;
385861766fe9SRichard Henderson         }
385961766fe9SRichard Henderson         if (ctx.iaoq_f == -1) {
386061766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
386161766fe9SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
3862129e9cc3SRichard Henderson             nullify_save(&ctx);
386361766fe9SRichard Henderson             ret = EXIT_IAQ_N_UPDATED;
386461766fe9SRichard Henderson             break;
386561766fe9SRichard Henderson         }
386661766fe9SRichard Henderson         if (ctx.iaoq_b == -1) {
386761766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
386861766fe9SRichard Henderson         }
386961766fe9SRichard Henderson     } while (ret == NO_EXIT);
387061766fe9SRichard Henderson 
387161766fe9SRichard Henderson     if (tb->cflags & CF_LAST_IO) {
387261766fe9SRichard Henderson         gen_io_end();
387361766fe9SRichard Henderson     }
387461766fe9SRichard Henderson 
387561766fe9SRichard Henderson     switch (ret) {
387661766fe9SRichard Henderson     case EXIT_GOTO_TB:
387761766fe9SRichard Henderson     case EXIT_NORETURN:
387861766fe9SRichard Henderson         break;
387961766fe9SRichard Henderson     case EXIT_IAQ_N_STALE:
388061766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
388161766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
3882129e9cc3SRichard Henderson         nullify_save(&ctx);
388361766fe9SRichard Henderson         /* FALLTHRU */
388461766fe9SRichard Henderson     case EXIT_IAQ_N_UPDATED:
388561766fe9SRichard Henderson         if (ctx.singlestep_enabled) {
388661766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
388761766fe9SRichard Henderson         } else {
388861766fe9SRichard Henderson             tcg_gen_exit_tb(0);
388961766fe9SRichard Henderson         }
389061766fe9SRichard Henderson         break;
389161766fe9SRichard Henderson     default:
389261766fe9SRichard Henderson         abort();
389361766fe9SRichard Henderson     }
389461766fe9SRichard Henderson 
389561766fe9SRichard Henderson     gen_tb_end(tb, num_insns);
389661766fe9SRichard Henderson 
389761766fe9SRichard Henderson     tb->size = num_insns * 4;
389861766fe9SRichard Henderson     tb->icount = num_insns;
389961766fe9SRichard Henderson 
390061766fe9SRichard Henderson #ifdef DEBUG_DISAS
390161766fe9SRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
390261766fe9SRichard Henderson         && qemu_log_in_addr_range(tb->pc)) {
390361766fe9SRichard Henderson         qemu_log_lock();
39047ad439dfSRichard Henderson         switch (tb->pc) {
39057ad439dfSRichard Henderson         case 0x00:
39067ad439dfSRichard Henderson             qemu_log("IN:\n0x00000000:  (null)\n\n");
39077ad439dfSRichard Henderson             break;
39087ad439dfSRichard Henderson         case 0xb0:
39097ad439dfSRichard Henderson             qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
39107ad439dfSRichard Henderson             break;
39117ad439dfSRichard Henderson         case 0xe0:
39127ad439dfSRichard Henderson             qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
39137ad439dfSRichard Henderson             break;
39147ad439dfSRichard Henderson         case 0x100:
39157ad439dfSRichard Henderson             qemu_log("IN:\n0x00000100:  syscall\n\n");
39167ad439dfSRichard Henderson             break;
39177ad439dfSRichard Henderson         default:
391861766fe9SRichard Henderson             qemu_log("IN: %s\n", lookup_symbol(tb->pc));
391961766fe9SRichard Henderson             log_target_disas(cs, tb->pc, tb->size, 1);
392061766fe9SRichard Henderson             qemu_log("\n");
39217ad439dfSRichard Henderson             break;
39227ad439dfSRichard Henderson         }
392361766fe9SRichard Henderson         qemu_log_unlock();
392461766fe9SRichard Henderson     }
392561766fe9SRichard Henderson #endif
392661766fe9SRichard Henderson }
392761766fe9SRichard Henderson 
392861766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
392961766fe9SRichard Henderson                           target_ulong *data)
393061766fe9SRichard Henderson {
393161766fe9SRichard Henderson     env->iaoq_f = data[0];
393261766fe9SRichard Henderson     if (data[1] != -1) {
393361766fe9SRichard Henderson         env->iaoq_b = data[1];
393461766fe9SRichard Henderson     }
393561766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
393661766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
393761766fe9SRichard Henderson        that the instruction was not nullified.  */
393861766fe9SRichard Henderson     env->psw_n = 0;
393961766fe9SRichard Henderson }
3940