xref: /openbmc/qemu/target/hppa/translate.c (revision 98a9cb792c8c177d5d81c2c4a08e740deeb207fd)
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 {
87b2167459SRichard Henderson         void (*f_ttt)(TCGv, TCGv, TCGv);
88b2167459SRichard Henderson     };
8961766fe9SRichard Henderson } DisasInsn;
9061766fe9SRichard Henderson 
9161766fe9SRichard Henderson /* global register indexes */
9261766fe9SRichard Henderson static TCGv_env cpu_env;
9361766fe9SRichard Henderson static TCGv cpu_gr[32];
9461766fe9SRichard Henderson static TCGv cpu_iaoq_f;
9561766fe9SRichard Henderson static TCGv cpu_iaoq_b;
9661766fe9SRichard Henderson static TCGv cpu_sar;
9761766fe9SRichard Henderson static TCGv cpu_psw_n;
9861766fe9SRichard Henderson static TCGv cpu_psw_v;
9961766fe9SRichard Henderson static TCGv cpu_psw_cb;
10061766fe9SRichard Henderson static TCGv cpu_psw_cb_msb;
10161766fe9SRichard Henderson static TCGv cpu_cr26;
10261766fe9SRichard Henderson static TCGv cpu_cr27;
10361766fe9SRichard Henderson 
10461766fe9SRichard Henderson #include "exec/gen-icount.h"
10561766fe9SRichard Henderson 
10661766fe9SRichard Henderson void hppa_translate_init(void)
10761766fe9SRichard Henderson {
10861766fe9SRichard Henderson #define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
10961766fe9SRichard Henderson 
11061766fe9SRichard Henderson     typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
11161766fe9SRichard Henderson     static const GlobalVar vars[] = {
11261766fe9SRichard Henderson         DEF_VAR(sar),
11361766fe9SRichard Henderson         DEF_VAR(cr26),
11461766fe9SRichard Henderson         DEF_VAR(cr27),
11561766fe9SRichard Henderson         DEF_VAR(psw_n),
11661766fe9SRichard Henderson         DEF_VAR(psw_v),
11761766fe9SRichard Henderson         DEF_VAR(psw_cb),
11861766fe9SRichard Henderson         DEF_VAR(psw_cb_msb),
11961766fe9SRichard Henderson         DEF_VAR(iaoq_f),
12061766fe9SRichard Henderson         DEF_VAR(iaoq_b),
12161766fe9SRichard Henderson     };
12261766fe9SRichard Henderson 
12361766fe9SRichard Henderson #undef DEF_VAR
12461766fe9SRichard Henderson 
12561766fe9SRichard Henderson     /* Use the symbolic register names that match the disassembler.  */
12661766fe9SRichard Henderson     static const char gr_names[32][4] = {
12761766fe9SRichard Henderson         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
12861766fe9SRichard Henderson         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
12961766fe9SRichard Henderson         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
13061766fe9SRichard Henderson         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
13161766fe9SRichard Henderson     };
13261766fe9SRichard Henderson 
13361766fe9SRichard Henderson     static bool done_init = 0;
13461766fe9SRichard Henderson     int i;
13561766fe9SRichard Henderson 
13661766fe9SRichard Henderson     if (done_init) {
13761766fe9SRichard Henderson         return;
13861766fe9SRichard Henderson     }
13961766fe9SRichard Henderson     done_init = 1;
14061766fe9SRichard Henderson 
14161766fe9SRichard Henderson     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
14261766fe9SRichard Henderson     tcg_ctx.tcg_env = cpu_env;
14361766fe9SRichard Henderson 
14461766fe9SRichard Henderson     TCGV_UNUSED(cpu_gr[0]);
14561766fe9SRichard Henderson     for (i = 1; i < 32; i++) {
14661766fe9SRichard Henderson         cpu_gr[i] = tcg_global_mem_new(cpu_env,
14761766fe9SRichard Henderson                                        offsetof(CPUHPPAState, gr[i]),
14861766fe9SRichard Henderson                                        gr_names[i]);
14961766fe9SRichard Henderson     }
15061766fe9SRichard Henderson 
15161766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(vars); ++i) {
15261766fe9SRichard Henderson         const GlobalVar *v = &vars[i];
15361766fe9SRichard Henderson         *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
15461766fe9SRichard Henderson     }
15561766fe9SRichard Henderson }
15661766fe9SRichard Henderson 
157129e9cc3SRichard Henderson static DisasCond cond_make_f(void)
158129e9cc3SRichard Henderson {
159129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NEVER };
160129e9cc3SRichard Henderson     TCGV_UNUSED(r.a0);
161129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
162129e9cc3SRichard Henderson     return r;
163129e9cc3SRichard Henderson }
164129e9cc3SRichard Henderson 
165129e9cc3SRichard Henderson static DisasCond cond_make_n(void)
166129e9cc3SRichard Henderson {
167129e9cc3SRichard Henderson     DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
168129e9cc3SRichard Henderson     r.a0 = cpu_psw_n;
169129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
170129e9cc3SRichard Henderson     return r;
171129e9cc3SRichard Henderson }
172129e9cc3SRichard Henderson 
173129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0)
174129e9cc3SRichard Henderson {
175129e9cc3SRichard Henderson     DisasCond r = { .c = c, .a1_is_0 = true };
176129e9cc3SRichard Henderson 
177129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
178129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
179129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
180129e9cc3SRichard Henderson     TCGV_UNUSED(r.a1);
181129e9cc3SRichard Henderson 
182129e9cc3SRichard Henderson     return r;
183129e9cc3SRichard Henderson }
184129e9cc3SRichard Henderson 
185129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
186129e9cc3SRichard Henderson {
187129e9cc3SRichard Henderson     DisasCond r = { .c = c };
188129e9cc3SRichard Henderson 
189129e9cc3SRichard Henderson     assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
190129e9cc3SRichard Henderson     r.a0 = tcg_temp_new();
191129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a0, a0);
192129e9cc3SRichard Henderson     r.a1 = tcg_temp_new();
193129e9cc3SRichard Henderson     tcg_gen_mov_tl(r.a1, a1);
194129e9cc3SRichard Henderson 
195129e9cc3SRichard Henderson     return r;
196129e9cc3SRichard Henderson }
197129e9cc3SRichard Henderson 
198129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond)
199129e9cc3SRichard Henderson {
200129e9cc3SRichard Henderson     if (cond->a1_is_0) {
201129e9cc3SRichard Henderson         cond->a1_is_0 = false;
202129e9cc3SRichard Henderson         cond->a1 = tcg_const_tl(0);
203129e9cc3SRichard Henderson     }
204129e9cc3SRichard Henderson }
205129e9cc3SRichard Henderson 
206129e9cc3SRichard Henderson static void cond_free(DisasCond *cond)
207129e9cc3SRichard Henderson {
208129e9cc3SRichard Henderson     switch (cond->c) {
209129e9cc3SRichard Henderson     default:
210129e9cc3SRichard Henderson         if (!cond->a0_is_n) {
211129e9cc3SRichard Henderson             tcg_temp_free(cond->a0);
212129e9cc3SRichard Henderson         }
213129e9cc3SRichard Henderson         if (!cond->a1_is_0) {
214129e9cc3SRichard Henderson             tcg_temp_free(cond->a1);
215129e9cc3SRichard Henderson         }
216129e9cc3SRichard Henderson         cond->a0_is_n = false;
217129e9cc3SRichard Henderson         cond->a1_is_0 = false;
218129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a0);
219129e9cc3SRichard Henderson         TCGV_UNUSED(cond->a1);
220129e9cc3SRichard Henderson         /* fallthru */
221129e9cc3SRichard Henderson     case TCG_COND_ALWAYS:
222129e9cc3SRichard Henderson         cond->c = TCG_COND_NEVER;
223129e9cc3SRichard Henderson         break;
224129e9cc3SRichard Henderson     case TCG_COND_NEVER:
225129e9cc3SRichard Henderson         break;
226129e9cc3SRichard Henderson     }
227129e9cc3SRichard Henderson }
228129e9cc3SRichard Henderson 
22961766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx)
23061766fe9SRichard Henderson {
23161766fe9SRichard Henderson     unsigned i = ctx->ntemps++;
23261766fe9SRichard Henderson     g_assert(i < ARRAY_SIZE(ctx->temps));
23361766fe9SRichard Henderson     return ctx->temps[i] = tcg_temp_new();
23461766fe9SRichard Henderson }
23561766fe9SRichard Henderson 
23661766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v)
23761766fe9SRichard Henderson {
23861766fe9SRichard Henderson     TCGv t = get_temp(ctx);
23961766fe9SRichard Henderson     tcg_gen_movi_tl(t, v);
24061766fe9SRichard Henderson     return t;
24161766fe9SRichard Henderson }
24261766fe9SRichard Henderson 
24361766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg)
24461766fe9SRichard Henderson {
24561766fe9SRichard Henderson     if (reg == 0) {
24661766fe9SRichard Henderson         TCGv t = get_temp(ctx);
24761766fe9SRichard Henderson         tcg_gen_movi_tl(t, 0);
24861766fe9SRichard Henderson         return t;
24961766fe9SRichard Henderson     } else {
25061766fe9SRichard Henderson         return cpu_gr[reg];
25161766fe9SRichard Henderson     }
25261766fe9SRichard Henderson }
25361766fe9SRichard Henderson 
25461766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
25561766fe9SRichard Henderson {
256129e9cc3SRichard Henderson     if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
25761766fe9SRichard Henderson         return get_temp(ctx);
25861766fe9SRichard Henderson     } else {
25961766fe9SRichard Henderson         return cpu_gr[reg];
26061766fe9SRichard Henderson     }
26161766fe9SRichard Henderson }
26261766fe9SRichard Henderson 
263129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
264129e9cc3SRichard Henderson {
265129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
266129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
267129e9cc3SRichard Henderson         tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
268129e9cc3SRichard Henderson                            ctx->null_cond.a1, dest, t);
269129e9cc3SRichard Henderson     } else {
270129e9cc3SRichard Henderson         tcg_gen_mov_tl(dest, t);
271129e9cc3SRichard Henderson     }
272129e9cc3SRichard Henderson }
273129e9cc3SRichard Henderson 
274129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
275129e9cc3SRichard Henderson {
276129e9cc3SRichard Henderson     if (reg != 0) {
277129e9cc3SRichard Henderson         save_or_nullify(ctx, cpu_gr[reg], t);
278129e9cc3SRichard Henderson     }
279129e9cc3SRichard Henderson }
280129e9cc3SRichard Henderson 
28196d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
28296d6407fSRichard Henderson # define HI_OFS  0
28396d6407fSRichard Henderson # define LO_OFS  4
28496d6407fSRichard Henderson #else
28596d6407fSRichard Henderson # define HI_OFS  4
28696d6407fSRichard Henderson # define LO_OFS  0
28796d6407fSRichard Henderson #endif
28896d6407fSRichard Henderson 
28996d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt)
29096d6407fSRichard Henderson {
29196d6407fSRichard Henderson     TCGv_i32 ret = tcg_temp_new_i32();
29296d6407fSRichard Henderson     tcg_gen_ld_i32(ret, cpu_env,
29396d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
29496d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
29596d6407fSRichard Henderson     return ret;
29696d6407fSRichard Henderson }
29796d6407fSRichard Henderson 
29896d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val)
29996d6407fSRichard Henderson {
30096d6407fSRichard Henderson     tcg_gen_st_i32(val, cpu_env,
30196d6407fSRichard Henderson                    offsetof(CPUHPPAState, fr[rt & 31])
30296d6407fSRichard Henderson                    + (rt & 32 ? LO_OFS : HI_OFS));
30396d6407fSRichard Henderson }
30496d6407fSRichard Henderson 
30596d6407fSRichard Henderson #undef HI_OFS
30696d6407fSRichard Henderson #undef LO_OFS
30796d6407fSRichard Henderson 
30896d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt)
30996d6407fSRichard Henderson {
31096d6407fSRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
31196d6407fSRichard Henderson     tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
31296d6407fSRichard Henderson     return ret;
31396d6407fSRichard Henderson }
31496d6407fSRichard Henderson 
31596d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val)
31696d6407fSRichard Henderson {
31796d6407fSRichard Henderson     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
31896d6407fSRichard Henderson }
31996d6407fSRichard Henderson 
320129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
321129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
322129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
323129e9cc3SRichard Henderson {
324129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
325129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
326129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
327129e9cc3SRichard Henderson 
328129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
329129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
330129e9cc3SRichard Henderson 
331129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
332129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
333129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
334129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
335129e9cc3SRichard Henderson             tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
336129e9cc3SRichard Henderson         }
337129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
338129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
339129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
340129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
341129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
342129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
343129e9cc3SRichard Henderson         }
344129e9cc3SRichard Henderson 
345129e9cc3SRichard Henderson         tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
346129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
347129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
348129e9cc3SRichard Henderson     }
349129e9cc3SRichard Henderson }
350129e9cc3SRichard Henderson 
351129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
352129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
353129e9cc3SRichard Henderson {
354129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
355129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
356129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
357129e9cc3SRichard Henderson         }
358129e9cc3SRichard Henderson         return;
359129e9cc3SRichard Henderson     }
360129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
361129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
362129e9cc3SRichard Henderson         tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
363129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
364129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
365129e9cc3SRichard Henderson     }
366129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
367129e9cc3SRichard Henderson }
368129e9cc3SRichard Henderson 
369129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
370129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
371129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
372129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
373129e9cc3SRichard Henderson {
374129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
375129e9cc3SRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, x);
376129e9cc3SRichard Henderson     }
377129e9cc3SRichard Henderson }
378129e9cc3SRichard Henderson 
379129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
380129e9cc3SRichard Henderson    This is the pair to nullify_over.  */
381129e9cc3SRichard Henderson static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
382129e9cc3SRichard Henderson {
383129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
384129e9cc3SRichard Henderson 
385129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
386129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
387129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
388129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
389129e9cc3SRichard Henderson         return status;
390129e9cc3SRichard Henderson     }
391129e9cc3SRichard Henderson     ctx->null_lab = NULL;
392129e9cc3SRichard Henderson 
393129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
394129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
395129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
396129e9cc3SRichard Henderson         gen_set_label(null_lab);
397129e9cc3SRichard Henderson     } else {
398129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
399129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
400129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
401129e9cc3SRichard Henderson            label we have the proper value in place.  */
402129e9cc3SRichard Henderson         nullify_save(ctx);
403129e9cc3SRichard Henderson         gen_set_label(null_lab);
404129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
405129e9cc3SRichard Henderson     }
406129e9cc3SRichard Henderson 
407129e9cc3SRichard Henderson     assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
408129e9cc3SRichard Henderson     if (status == EXIT_NORETURN) {
409129e9cc3SRichard Henderson         status = NO_EXIT;
410129e9cc3SRichard Henderson     }
411129e9cc3SRichard Henderson     return status;
412129e9cc3SRichard Henderson }
413129e9cc3SRichard Henderson 
41461766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
41561766fe9SRichard Henderson {
41661766fe9SRichard Henderson     if (unlikely(ival == -1)) {
41761766fe9SRichard Henderson         tcg_gen_mov_tl(dest, vval);
41861766fe9SRichard Henderson     } else {
41961766fe9SRichard Henderson         tcg_gen_movi_tl(dest, ival);
42061766fe9SRichard Henderson     }
42161766fe9SRichard Henderson }
42261766fe9SRichard Henderson 
42361766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
42461766fe9SRichard Henderson {
42561766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
42661766fe9SRichard Henderson }
42761766fe9SRichard Henderson 
42861766fe9SRichard Henderson static void gen_excp_1(int exception)
42961766fe9SRichard Henderson {
43061766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
43161766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
43261766fe9SRichard Henderson     tcg_temp_free_i32(t);
43361766fe9SRichard Henderson }
43461766fe9SRichard Henderson 
43561766fe9SRichard Henderson static ExitStatus gen_excp(DisasContext *ctx, int exception)
43661766fe9SRichard Henderson {
43761766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
43861766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
439129e9cc3SRichard Henderson     nullify_save(ctx);
44061766fe9SRichard Henderson     gen_excp_1(exception);
44161766fe9SRichard Henderson     return EXIT_NORETURN;
44261766fe9SRichard Henderson }
44361766fe9SRichard Henderson 
44461766fe9SRichard Henderson static ExitStatus gen_illegal(DisasContext *ctx)
44561766fe9SRichard Henderson {
446129e9cc3SRichard Henderson     nullify_over(ctx);
447129e9cc3SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
44861766fe9SRichard Henderson }
44961766fe9SRichard Henderson 
45061766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
45161766fe9SRichard Henderson {
45261766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
45361766fe9SRichard Henderson     if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
45461766fe9SRichard Henderson         return false;
45561766fe9SRichard Henderson     }
45661766fe9SRichard Henderson     return true;
45761766fe9SRichard Henderson }
45861766fe9SRichard Henderson 
459129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
460129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
461129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
462129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
463129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
464129e9cc3SRichard Henderson {
465129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
466129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
467129e9cc3SRichard Henderson }
468129e9cc3SRichard Henderson 
46961766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
47061766fe9SRichard Henderson                         target_ulong f, target_ulong b)
47161766fe9SRichard Henderson {
47261766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
47361766fe9SRichard Henderson         tcg_gen_goto_tb(which);
47461766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_f, f);
47561766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_b, b);
47661766fe9SRichard Henderson         tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
47761766fe9SRichard Henderson     } else {
47861766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
47961766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
48061766fe9SRichard Henderson         if (ctx->singlestep_enabled) {
48161766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
48261766fe9SRichard Henderson         } else {
48361766fe9SRichard Henderson             tcg_gen_exit_tb(0);
48461766fe9SRichard Henderson         }
48561766fe9SRichard Henderson     }
48661766fe9SRichard Henderson }
48761766fe9SRichard Henderson 
488b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
489b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
490b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
491b2167459SRichard Henderson {
492b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
493b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
494b2167459SRichard Henderson     return x;
495b2167459SRichard Henderson }
496b2167459SRichard Henderson 
49798cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn)
49898cd9ca7SRichard Henderson {
49998cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
50098cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
50198cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
50298cd9ca7SRichard Henderson     return x;
50398cd9ca7SRichard Henderson }
50498cd9ca7SRichard Henderson 
505b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
506b2167459SRichard Henderson {
507b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
508b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
509b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
510b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
511b2167459SRichard Henderson }
512b2167459SRichard Henderson 
51396d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn)
51496d6407fSRichard Henderson {
51596d6407fSRichard Henderson     /* Take the name from PA2.0, which produces a 14-bit shifted number
51696d6407fSRichard Henderson        only with wide mode; otherwise a 12-bit shifted number.  Since we
51796d6407fSRichard Henderson        don't implement wide mode, this is always the 12-bit number.  */
51896d6407fSRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
51996d6407fSRichard Henderson     x = (x << 11) | extract32(insn, 2, 11);
52096d6407fSRichard Henderson     return x << 2;
52196d6407fSRichard Henderson }
52296d6407fSRichard Henderson 
52398cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn)
52498cd9ca7SRichard Henderson {
52598cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
52698cd9ca7SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
52798cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
52898cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
52998cd9ca7SRichard Henderson     return x << 2;
53098cd9ca7SRichard Henderson }
53198cd9ca7SRichard Henderson 
532b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
533b2167459SRichard Henderson {
534b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
535b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
536b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
537b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
538b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
539b2167459SRichard Henderson     return x << 11;
540b2167459SRichard Henderson }
541b2167459SRichard Henderson 
54298cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn)
54398cd9ca7SRichard Henderson {
54498cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
54598cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 16, 10);
54698cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
54798cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
54898cd9ca7SRichard Henderson     return x << 2;
54998cd9ca7SRichard Henderson }
55098cd9ca7SRichard Henderson 
551b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
552b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
553b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
554b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
555b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
556b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
557b2167459SRichard Henderson 
558b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
559b2167459SRichard Henderson {
560b2167459SRichard Henderson     DisasCond cond;
561b2167459SRichard Henderson     TCGv tmp;
562b2167459SRichard Henderson 
563b2167459SRichard Henderson     switch (cf >> 1) {
564b2167459SRichard Henderson     case 0: /* Never / TR */
565b2167459SRichard Henderson         cond = cond_make_f();
566b2167459SRichard Henderson         break;
567b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
568b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
569b2167459SRichard Henderson         break;
570b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
571b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
572b2167459SRichard Henderson         break;
573b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
574b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
575b2167459SRichard Henderson         break;
576b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
577b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
578b2167459SRichard Henderson         break;
579b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
580b2167459SRichard Henderson         tmp = tcg_temp_new();
581b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
582b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
583b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
584b2167459SRichard Henderson         tcg_temp_free(tmp);
585b2167459SRichard Henderson         break;
586b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
587b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
588b2167459SRichard Henderson         break;
589b2167459SRichard Henderson     case 7: /* OD / EV */
590b2167459SRichard Henderson         tmp = tcg_temp_new();
591b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
592b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
593b2167459SRichard Henderson         tcg_temp_free(tmp);
594b2167459SRichard Henderson         break;
595b2167459SRichard Henderson     default:
596b2167459SRichard Henderson         g_assert_not_reached();
597b2167459SRichard Henderson     }
598b2167459SRichard Henderson     if (cf & 1) {
599b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
600b2167459SRichard Henderson     }
601b2167459SRichard Henderson 
602b2167459SRichard Henderson     return cond;
603b2167459SRichard Henderson }
604b2167459SRichard Henderson 
605b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
606b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
607b2167459SRichard Henderson    deleted as unused.  */
608b2167459SRichard Henderson 
609b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
610b2167459SRichard Henderson {
611b2167459SRichard Henderson     DisasCond cond;
612b2167459SRichard Henderson 
613b2167459SRichard Henderson     switch (cf >> 1) {
614b2167459SRichard Henderson     case 1: /* = / <> */
615b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
616b2167459SRichard Henderson         break;
617b2167459SRichard Henderson     case 2: /* < / >= */
618b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
619b2167459SRichard Henderson         break;
620b2167459SRichard Henderson     case 3: /* <= / > */
621b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
622b2167459SRichard Henderson         break;
623b2167459SRichard Henderson     case 4: /* << / >>= */
624b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
625b2167459SRichard Henderson         break;
626b2167459SRichard Henderson     case 5: /* <<= / >> */
627b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
628b2167459SRichard Henderson         break;
629b2167459SRichard Henderson     default:
630b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
631b2167459SRichard Henderson     }
632b2167459SRichard Henderson     if (cf & 1) {
633b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
634b2167459SRichard Henderson     }
635b2167459SRichard Henderson 
636b2167459SRichard Henderson     return cond;
637b2167459SRichard Henderson }
638b2167459SRichard Henderson 
639b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
640b2167459SRichard Henderson    computed, and use of them is undefined.  */
641b2167459SRichard Henderson 
642b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
643b2167459SRichard Henderson {
644b2167459SRichard Henderson     switch (cf >> 1) {
645b2167459SRichard Henderson     case 4: case 5: case 6:
646b2167459SRichard Henderson         cf &= 1;
647b2167459SRichard Henderson         break;
648b2167459SRichard Henderson     }
649b2167459SRichard Henderson     return do_cond(cf, res, res, res);
650b2167459SRichard Henderson }
651b2167459SRichard Henderson 
65298cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
65398cd9ca7SRichard Henderson 
65498cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res)
65598cd9ca7SRichard Henderson {
65698cd9ca7SRichard Henderson     unsigned c, f;
65798cd9ca7SRichard Henderson 
65898cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
65998cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
66098cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
66198cd9ca7SRichard Henderson     c = orig & 3;
66298cd9ca7SRichard Henderson     if (c == 3) {
66398cd9ca7SRichard Henderson         c = 7;
66498cd9ca7SRichard Henderson     }
66598cd9ca7SRichard Henderson     f = (orig & 4) / 4;
66698cd9ca7SRichard Henderson 
66798cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
66898cd9ca7SRichard Henderson }
66998cd9ca7SRichard Henderson 
670b2167459SRichard Henderson /* Similar, but for unit conditions.  */
671b2167459SRichard Henderson 
672b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
673b2167459SRichard Henderson {
674b2167459SRichard Henderson     DisasCond cond;
675b2167459SRichard Henderson     TCGv tmp, cb;
676b2167459SRichard Henderson 
677b2167459SRichard Henderson     TCGV_UNUSED(cb);
678b2167459SRichard Henderson     if (cf & 8) {
679b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
680b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
681b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
682b2167459SRichard Henderson          */
683b2167459SRichard Henderson         cb = tcg_temp_new();
684b2167459SRichard Henderson         tmp = tcg_temp_new();
685b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
686b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
687b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
688b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
689b2167459SRichard Henderson         tcg_temp_free(tmp);
690b2167459SRichard Henderson     }
691b2167459SRichard Henderson 
692b2167459SRichard Henderson     switch (cf >> 1) {
693b2167459SRichard Henderson     case 0: /* never / TR */
694b2167459SRichard Henderson     case 1: /* undefined */
695b2167459SRichard Henderson     case 5: /* undefined */
696b2167459SRichard Henderson         cond = cond_make_f();
697b2167459SRichard Henderson         break;
698b2167459SRichard Henderson 
699b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
700b2167459SRichard Henderson         /* See hasless(v,1) from
701b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
702b2167459SRichard Henderson          */
703b2167459SRichard Henderson         tmp = tcg_temp_new();
704b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
705b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
706b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
707b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
708b2167459SRichard Henderson         tcg_temp_free(tmp);
709b2167459SRichard Henderson         break;
710b2167459SRichard Henderson 
711b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
712b2167459SRichard Henderson         tmp = tcg_temp_new();
713b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
714b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
715b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
716b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
717b2167459SRichard Henderson         tcg_temp_free(tmp);
718b2167459SRichard Henderson         break;
719b2167459SRichard Henderson 
720b2167459SRichard Henderson     case 4: /* SDC / NDC */
721b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
722b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
723b2167459SRichard Henderson         break;
724b2167459SRichard Henderson 
725b2167459SRichard Henderson     case 6: /* SBC / NBC */
726b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
727b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
728b2167459SRichard Henderson         break;
729b2167459SRichard Henderson 
730b2167459SRichard Henderson     case 7: /* SHC / NHC */
731b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
732b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
733b2167459SRichard Henderson         break;
734b2167459SRichard Henderson 
735b2167459SRichard Henderson     default:
736b2167459SRichard Henderson         g_assert_not_reached();
737b2167459SRichard Henderson     }
738b2167459SRichard Henderson     if (cf & 8) {
739b2167459SRichard Henderson         tcg_temp_free(cb);
740b2167459SRichard Henderson     }
741b2167459SRichard Henderson     if (cf & 1) {
742b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
743b2167459SRichard Henderson     }
744b2167459SRichard Henderson 
745b2167459SRichard Henderson     return cond;
746b2167459SRichard Henderson }
747b2167459SRichard Henderson 
748b2167459SRichard Henderson /* Compute signed overflow for addition.  */
749b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
750b2167459SRichard Henderson {
751b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
752b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
753b2167459SRichard Henderson 
754b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
755b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
756b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
757b2167459SRichard Henderson     tcg_temp_free(tmp);
758b2167459SRichard Henderson 
759b2167459SRichard Henderson     return sv;
760b2167459SRichard Henderson }
761b2167459SRichard Henderson 
762b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
763b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
764b2167459SRichard Henderson {
765b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
766b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
767b2167459SRichard Henderson 
768b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
769b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
770b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
771b2167459SRichard Henderson     tcg_temp_free(tmp);
772b2167459SRichard Henderson 
773b2167459SRichard Henderson     return sv;
774b2167459SRichard Henderson }
775b2167459SRichard Henderson 
776b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
777b2167459SRichard Henderson                          unsigned shift, bool is_l, bool is_tsv, bool is_tc,
778b2167459SRichard Henderson                          bool is_c, unsigned cf)
779b2167459SRichard Henderson {
780b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
781b2167459SRichard Henderson     unsigned c = cf >> 1;
782b2167459SRichard Henderson     DisasCond cond;
783b2167459SRichard Henderson 
784b2167459SRichard Henderson     dest = tcg_temp_new();
785b2167459SRichard Henderson     TCGV_UNUSED(cb);
786b2167459SRichard Henderson     TCGV_UNUSED(cb_msb);
787b2167459SRichard Henderson 
788b2167459SRichard Henderson     if (shift) {
789b2167459SRichard Henderson         tmp = get_temp(ctx);
790b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
791b2167459SRichard Henderson         in1 = tmp;
792b2167459SRichard Henderson     }
793b2167459SRichard Henderson 
794b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
795b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
796b2167459SRichard Henderson         cb_msb = get_temp(ctx);
797b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
798b2167459SRichard Henderson         if (is_c) {
799b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
800b2167459SRichard Henderson         }
801b2167459SRichard Henderson         tcg_temp_free(zero);
802b2167459SRichard Henderson         if (!is_l) {
803b2167459SRichard Henderson             cb = get_temp(ctx);
804b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
805b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
806b2167459SRichard Henderson         }
807b2167459SRichard Henderson     } else {
808b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
809b2167459SRichard Henderson         if (is_c) {
810b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
811b2167459SRichard Henderson         }
812b2167459SRichard Henderson     }
813b2167459SRichard Henderson 
814b2167459SRichard Henderson     /* Compute signed overflow if required.  */
815b2167459SRichard Henderson     TCGV_UNUSED(sv);
816b2167459SRichard Henderson     if (is_tsv || c == 6) {
817b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
818b2167459SRichard Henderson         if (is_tsv) {
819b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
820b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
821b2167459SRichard Henderson         }
822b2167459SRichard Henderson     }
823b2167459SRichard Henderson 
824b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
825b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
826b2167459SRichard Henderson     if (is_tc) {
827b2167459SRichard Henderson         cond_prep(&cond);
828b2167459SRichard Henderson         tmp = tcg_temp_new();
829b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
830b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
831b2167459SRichard Henderson         tcg_temp_free(tmp);
832b2167459SRichard Henderson     }
833b2167459SRichard Henderson 
834b2167459SRichard Henderson     /* Write back the result.  */
835b2167459SRichard Henderson     if (!is_l) {
836b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
837b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
838b2167459SRichard Henderson     }
839b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
840b2167459SRichard Henderson     tcg_temp_free(dest);
841b2167459SRichard Henderson 
842b2167459SRichard Henderson     /* Install the new nullification.  */
843b2167459SRichard Henderson     cond_free(&ctx->null_cond);
844b2167459SRichard Henderson     ctx->null_cond = cond;
845b2167459SRichard Henderson     return NO_EXIT;
846b2167459SRichard Henderson }
847b2167459SRichard Henderson 
848b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
849b2167459SRichard Henderson                          bool is_tsv, bool is_b, bool is_tc, unsigned cf)
850b2167459SRichard Henderson {
851b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
852b2167459SRichard Henderson     unsigned c = cf >> 1;
853b2167459SRichard Henderson     DisasCond cond;
854b2167459SRichard Henderson 
855b2167459SRichard Henderson     dest = tcg_temp_new();
856b2167459SRichard Henderson     cb = tcg_temp_new();
857b2167459SRichard Henderson     cb_msb = tcg_temp_new();
858b2167459SRichard Henderson 
859b2167459SRichard Henderson     zero = tcg_const_tl(0);
860b2167459SRichard Henderson     if (is_b) {
861b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
862b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
863b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
864b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
865b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
866b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
867b2167459SRichard Henderson     } else {
868b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
869b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
870b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
871b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
872b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
873b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
874b2167459SRichard Henderson     }
875b2167459SRichard Henderson     tcg_temp_free(zero);
876b2167459SRichard Henderson 
877b2167459SRichard Henderson     /* Compute signed overflow if required.  */
878b2167459SRichard Henderson     TCGV_UNUSED(sv);
879b2167459SRichard Henderson     if (is_tsv || c == 6) {
880b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
881b2167459SRichard Henderson         if (is_tsv) {
882b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
883b2167459SRichard Henderson         }
884b2167459SRichard Henderson     }
885b2167459SRichard Henderson 
886b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
887b2167459SRichard Henderson     if (!is_b) {
888b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
889b2167459SRichard Henderson     } else {
890b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
891b2167459SRichard Henderson     }
892b2167459SRichard Henderson 
893b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
894b2167459SRichard Henderson     if (is_tc) {
895b2167459SRichard Henderson         cond_prep(&cond);
896b2167459SRichard Henderson         tmp = tcg_temp_new();
897b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
898b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
899b2167459SRichard Henderson         tcg_temp_free(tmp);
900b2167459SRichard Henderson     }
901b2167459SRichard Henderson 
902b2167459SRichard Henderson     /* Write back the result.  */
903b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
904b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
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_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
915b2167459SRichard Henderson                             TCGv in2, unsigned cf)
916b2167459SRichard Henderson {
917b2167459SRichard Henderson     TCGv dest, sv;
918b2167459SRichard Henderson     DisasCond cond;
919b2167459SRichard Henderson 
920b2167459SRichard Henderson     dest = tcg_temp_new();
921b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
922b2167459SRichard Henderson 
923b2167459SRichard Henderson     /* Compute signed overflow if required.  */
924b2167459SRichard Henderson     TCGV_UNUSED(sv);
925b2167459SRichard Henderson     if ((cf >> 1) == 6) {
926b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
927b2167459SRichard Henderson     }
928b2167459SRichard Henderson 
929b2167459SRichard Henderson     /* Form the condition for the compare.  */
930b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
931b2167459SRichard Henderson 
932b2167459SRichard Henderson     /* Clear.  */
933b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
934b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
935b2167459SRichard Henderson     tcg_temp_free(dest);
936b2167459SRichard Henderson 
937b2167459SRichard Henderson     /* Install the new nullification.  */
938b2167459SRichard Henderson     cond_free(&ctx->null_cond);
939b2167459SRichard Henderson     ctx->null_cond = cond;
940b2167459SRichard Henderson     return NO_EXIT;
941b2167459SRichard Henderson }
942b2167459SRichard Henderson 
943b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
944b2167459SRichard Henderson                          unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
945b2167459SRichard Henderson {
946b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
947b2167459SRichard Henderson 
948b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
949b2167459SRichard Henderson     fn(dest, in1, in2);
950b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
951b2167459SRichard Henderson 
952b2167459SRichard Henderson     /* Install the new nullification.  */
953b2167459SRichard Henderson     cond_free(&ctx->null_cond);
954b2167459SRichard Henderson     if (cf) {
955b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
956b2167459SRichard Henderson     }
957b2167459SRichard Henderson     return NO_EXIT;
958b2167459SRichard Henderson }
959b2167459SRichard Henderson 
960b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
961b2167459SRichard Henderson                           TCGv in2, unsigned cf, bool is_tc,
962b2167459SRichard Henderson                           void (*fn)(TCGv, TCGv, TCGv))
963b2167459SRichard Henderson {
964b2167459SRichard Henderson     TCGv dest;
965b2167459SRichard Henderson     DisasCond cond;
966b2167459SRichard Henderson 
967b2167459SRichard Henderson     if (cf == 0) {
968b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
969b2167459SRichard Henderson         fn(dest, in1, in2);
970b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
971b2167459SRichard Henderson         cond_free(&ctx->null_cond);
972b2167459SRichard Henderson     } else {
973b2167459SRichard Henderson         dest = tcg_temp_new();
974b2167459SRichard Henderson         fn(dest, in1, in2);
975b2167459SRichard Henderson 
976b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
977b2167459SRichard Henderson 
978b2167459SRichard Henderson         if (is_tc) {
979b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
980b2167459SRichard Henderson             cond_prep(&cond);
981b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
982b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
983b2167459SRichard Henderson             tcg_temp_free(tmp);
984b2167459SRichard Henderson         }
985b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
986b2167459SRichard Henderson 
987b2167459SRichard Henderson         cond_free(&ctx->null_cond);
988b2167459SRichard Henderson         ctx->null_cond = cond;
989b2167459SRichard Henderson     }
990b2167459SRichard Henderson     return NO_EXIT;
991b2167459SRichard Henderson }
992b2167459SRichard Henderson 
99396d6407fSRichard Henderson /* Emit a memory load.  The modify parameter should be
99496d6407fSRichard Henderson  * < 0 for pre-modify,
99596d6407fSRichard Henderson  * > 0 for post-modify,
99696d6407fSRichard Henderson  * = 0 for no base register update.
99796d6407fSRichard Henderson  */
99896d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
99996d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
100096d6407fSRichard Henderson                        int modify, TCGMemOp mop)
100196d6407fSRichard Henderson {
100296d6407fSRichard Henderson     TCGv addr, base;
100396d6407fSRichard Henderson 
100496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
100596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
100696d6407fSRichard Henderson 
100796d6407fSRichard Henderson     addr = tcg_temp_new();
100896d6407fSRichard Henderson     base = load_gpr(ctx, rb);
100996d6407fSRichard Henderson 
101096d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
101196d6407fSRichard Henderson     if (rx) {
101296d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
101396d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
101496d6407fSRichard Henderson     } else {
101596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
101696d6407fSRichard Henderson     }
101796d6407fSRichard Henderson 
101896d6407fSRichard Henderson     if (modify == 0) {
101996d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
102096d6407fSRichard Henderson     } else {
102196d6407fSRichard Henderson         tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
102296d6407fSRichard Henderson                             MMU_USER_IDX, mop);
102396d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
102496d6407fSRichard Henderson     }
102596d6407fSRichard Henderson     tcg_temp_free(addr);
102696d6407fSRichard Henderson }
102796d6407fSRichard Henderson 
102896d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
102996d6407fSRichard Henderson                        unsigned rx, int scale, target_long disp,
103096d6407fSRichard Henderson                        int modify, TCGMemOp mop)
103196d6407fSRichard Henderson {
103296d6407fSRichard Henderson     TCGv addr, base;
103396d6407fSRichard Henderson 
103496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
103596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
103696d6407fSRichard Henderson 
103796d6407fSRichard Henderson     addr = tcg_temp_new();
103896d6407fSRichard Henderson     base = load_gpr(ctx, rb);
103996d6407fSRichard Henderson 
104096d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
104196d6407fSRichard Henderson     if (rx) {
104296d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
104396d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
104496d6407fSRichard Henderson     } else {
104596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
104696d6407fSRichard Henderson     }
104796d6407fSRichard Henderson 
104896d6407fSRichard Henderson     if (modify == 0) {
104996d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
105096d6407fSRichard Henderson     } else {
105196d6407fSRichard Henderson         tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
105296d6407fSRichard Henderson                             MMU_USER_IDX, mop);
105396d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
105496d6407fSRichard Henderson     }
105596d6407fSRichard Henderson     tcg_temp_free(addr);
105696d6407fSRichard Henderson }
105796d6407fSRichard Henderson 
105896d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
105996d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
106096d6407fSRichard Henderson                         int modify, TCGMemOp mop)
106196d6407fSRichard Henderson {
106296d6407fSRichard Henderson     TCGv addr, base;
106396d6407fSRichard Henderson 
106496d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
106596d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
106696d6407fSRichard Henderson 
106796d6407fSRichard Henderson     addr = tcg_temp_new();
106896d6407fSRichard Henderson     base = load_gpr(ctx, rb);
106996d6407fSRichard Henderson 
107096d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
107196d6407fSRichard Henderson     if (rx) {
107296d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
107396d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
107496d6407fSRichard Henderson     } else {
107596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
107696d6407fSRichard Henderson     }
107796d6407fSRichard Henderson 
107896d6407fSRichard Henderson     tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
107996d6407fSRichard Henderson 
108096d6407fSRichard Henderson     if (modify != 0) {
108196d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
108296d6407fSRichard Henderson     }
108396d6407fSRichard Henderson     tcg_temp_free(addr);
108496d6407fSRichard Henderson }
108596d6407fSRichard Henderson 
108696d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
108796d6407fSRichard Henderson                         unsigned rx, int scale, target_long disp,
108896d6407fSRichard Henderson                         int modify, TCGMemOp mop)
108996d6407fSRichard Henderson {
109096d6407fSRichard Henderson     TCGv addr, base;
109196d6407fSRichard Henderson 
109296d6407fSRichard Henderson     /* Caller uses nullify_over/nullify_end.  */
109396d6407fSRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
109496d6407fSRichard Henderson 
109596d6407fSRichard Henderson     addr = tcg_temp_new();
109696d6407fSRichard Henderson     base = load_gpr(ctx, rb);
109796d6407fSRichard Henderson 
109896d6407fSRichard Henderson     /* Note that RX is mutually exclusive with DISP.  */
109996d6407fSRichard Henderson     if (rx) {
110096d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
110196d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
110296d6407fSRichard Henderson     } else {
110396d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
110496d6407fSRichard Henderson     }
110596d6407fSRichard Henderson 
110696d6407fSRichard Henderson     tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
110796d6407fSRichard Henderson 
110896d6407fSRichard Henderson     if (modify != 0) {
110996d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
111096d6407fSRichard Henderson     }
111196d6407fSRichard Henderson     tcg_temp_free(addr);
111296d6407fSRichard Henderson }
111396d6407fSRichard Henderson 
111496d6407fSRichard Henderson #if TARGET_LONG_BITS == 64
111596d6407fSRichard Henderson #define do_load_tl  do_load_64
111696d6407fSRichard Henderson #define do_store_tl do_store_64
111796d6407fSRichard Henderson #else
111896d6407fSRichard Henderson #define do_load_tl  do_load_32
111996d6407fSRichard Henderson #define do_store_tl do_store_32
112096d6407fSRichard Henderson #endif
112196d6407fSRichard Henderson 
112296d6407fSRichard Henderson static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb,
112396d6407fSRichard Henderson                           unsigned rx, int scale, target_long disp,
112496d6407fSRichard Henderson                           int modify, TCGMemOp mop)
112596d6407fSRichard Henderson {
112696d6407fSRichard Henderson     TCGv dest;
112796d6407fSRichard Henderson 
112896d6407fSRichard Henderson     nullify_over(ctx);
112996d6407fSRichard Henderson 
113096d6407fSRichard Henderson     if (modify == 0) {
113196d6407fSRichard Henderson         /* No base register update.  */
113296d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
113396d6407fSRichard Henderson     } else {
113496d6407fSRichard Henderson         /* Make sure if RT == RB, we see the result of the load.  */
113596d6407fSRichard Henderson         dest = get_temp(ctx);
113696d6407fSRichard Henderson     }
113796d6407fSRichard Henderson     do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
113896d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
113996d6407fSRichard Henderson 
114096d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
114196d6407fSRichard Henderson }
114296d6407fSRichard Henderson 
114396d6407fSRichard Henderson static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
114496d6407fSRichard Henderson                             unsigned rx, int scale, target_long disp,
114596d6407fSRichard Henderson                             int modify)
114696d6407fSRichard Henderson {
114796d6407fSRichard Henderson     TCGv_i32 tmp;
114896d6407fSRichard Henderson 
114996d6407fSRichard Henderson     nullify_over(ctx);
115096d6407fSRichard Henderson 
115196d6407fSRichard Henderson     tmp = tcg_temp_new_i32();
115296d6407fSRichard Henderson     do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
115396d6407fSRichard Henderson     save_frw_i32(rt, tmp);
115496d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
115596d6407fSRichard Henderson 
115696d6407fSRichard Henderson     if (rt == 0) {
115796d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
115896d6407fSRichard Henderson     }
115996d6407fSRichard Henderson 
116096d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
116196d6407fSRichard Henderson }
116296d6407fSRichard Henderson 
116396d6407fSRichard Henderson static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
116496d6407fSRichard Henderson                             unsigned rx, int scale, target_long disp,
116596d6407fSRichard Henderson                             int modify)
116696d6407fSRichard Henderson {
116796d6407fSRichard Henderson     TCGv_i64 tmp;
116896d6407fSRichard Henderson 
116996d6407fSRichard Henderson     nullify_over(ctx);
117096d6407fSRichard Henderson 
117196d6407fSRichard Henderson     tmp = tcg_temp_new_i64();
117296d6407fSRichard Henderson     do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
117396d6407fSRichard Henderson     save_frd(rt, tmp);
117496d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
117596d6407fSRichard Henderson 
117696d6407fSRichard Henderson     if (rt == 0) {
117796d6407fSRichard Henderson         gen_helper_loaded_fr0(cpu_env);
117896d6407fSRichard Henderson     }
117996d6407fSRichard Henderson 
118096d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
118196d6407fSRichard Henderson }
118296d6407fSRichard Henderson 
118396d6407fSRichard Henderson static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb,
118496d6407fSRichard Henderson                            target_long disp, int modify, TCGMemOp mop)
118596d6407fSRichard Henderson {
118696d6407fSRichard Henderson     nullify_over(ctx);
118796d6407fSRichard Henderson     do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
118896d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
118996d6407fSRichard Henderson }
119096d6407fSRichard Henderson 
119196d6407fSRichard Henderson static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
119296d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
119396d6407fSRichard Henderson                              int modify)
119496d6407fSRichard Henderson {
119596d6407fSRichard Henderson     TCGv_i32 tmp;
119696d6407fSRichard Henderson 
119796d6407fSRichard Henderson     nullify_over(ctx);
119896d6407fSRichard Henderson 
119996d6407fSRichard Henderson     tmp = load_frw_i32(rt);
120096d6407fSRichard Henderson     do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
120196d6407fSRichard Henderson     tcg_temp_free_i32(tmp);
120296d6407fSRichard Henderson 
120396d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
120496d6407fSRichard Henderson }
120596d6407fSRichard Henderson 
120696d6407fSRichard Henderson static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
120796d6407fSRichard Henderson                              unsigned rx, int scale, target_long disp,
120896d6407fSRichard Henderson                              int modify)
120996d6407fSRichard Henderson {
121096d6407fSRichard Henderson     TCGv_i64 tmp;
121196d6407fSRichard Henderson 
121296d6407fSRichard Henderson     nullify_over(ctx);
121396d6407fSRichard Henderson 
121496d6407fSRichard Henderson     tmp = load_frd(rt);
121596d6407fSRichard Henderson     do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
121696d6407fSRichard Henderson     tcg_temp_free_i64(tmp);
121796d6407fSRichard Henderson 
121896d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
121996d6407fSRichard Henderson }
122096d6407fSRichard Henderson 
122198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
122298cd9ca7SRichard Henderson    have already had nullification handled.  */
122398cd9ca7SRichard Henderson static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
122498cd9ca7SRichard Henderson                              unsigned link, bool is_n)
122598cd9ca7SRichard Henderson {
122698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
122798cd9ca7SRichard Henderson         if (link != 0) {
122898cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
122998cd9ca7SRichard Henderson         }
123098cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
123198cd9ca7SRichard Henderson         if (is_n) {
123298cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
123398cd9ca7SRichard Henderson         }
123498cd9ca7SRichard Henderson         return NO_EXIT;
123598cd9ca7SRichard Henderson     } else {
123698cd9ca7SRichard Henderson         nullify_over(ctx);
123798cd9ca7SRichard Henderson 
123898cd9ca7SRichard Henderson         if (link != 0) {
123998cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
124098cd9ca7SRichard Henderson         }
124198cd9ca7SRichard Henderson 
124298cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
124398cd9ca7SRichard Henderson             nullify_set(ctx, 0);
124498cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
124598cd9ca7SRichard Henderson         } else {
124698cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
124798cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
124898cd9ca7SRichard Henderson         }
124998cd9ca7SRichard Henderson 
125098cd9ca7SRichard Henderson         nullify_end(ctx, NO_EXIT);
125198cd9ca7SRichard Henderson 
125298cd9ca7SRichard Henderson         nullify_set(ctx, 0);
125398cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
125498cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
125598cd9ca7SRichard Henderson     }
125698cd9ca7SRichard Henderson }
125798cd9ca7SRichard Henderson 
125898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
125998cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
126098cd9ca7SRichard Henderson static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
126198cd9ca7SRichard Henderson                              DisasCond *cond)
126298cd9ca7SRichard Henderson {
126398cd9ca7SRichard Henderson     target_ulong dest = iaoq_dest(ctx, disp);
126498cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
126598cd9ca7SRichard Henderson     TCGCond c = cond->c;
126698cd9ca7SRichard Henderson     int which = 0;
126798cd9ca7SRichard Henderson     bool n;
126898cd9ca7SRichard Henderson 
126998cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
127098cd9ca7SRichard Henderson 
127198cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
127298cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
127398cd9ca7SRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
127498cd9ca7SRichard Henderson     }
127598cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
127698cd9ca7SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
127798cd9ca7SRichard Henderson     }
127898cd9ca7SRichard Henderson 
127998cd9ca7SRichard Henderson     taken = gen_new_label();
128098cd9ca7SRichard Henderson     cond_prep(cond);
128198cd9ca7SRichard Henderson     tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
128298cd9ca7SRichard Henderson     cond_free(cond);
128398cd9ca7SRichard Henderson 
128498cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
128598cd9ca7SRichard Henderson     n = is_n && disp < 0;
128698cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
128798cd9ca7SRichard Henderson         nullify_set(ctx, 0);
128898cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4);
128998cd9ca7SRichard Henderson     } else {
129098cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
129198cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
129298cd9ca7SRichard Henderson             ctx->null_lab = NULL;
129398cd9ca7SRichard Henderson         }
129498cd9ca7SRichard Henderson         nullify_set(ctx, n);
129598cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n);
129698cd9ca7SRichard Henderson     }
129798cd9ca7SRichard Henderson 
129898cd9ca7SRichard Henderson     gen_set_label(taken);
129998cd9ca7SRichard Henderson 
130098cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
130198cd9ca7SRichard Henderson     n = is_n && disp >= 0;
130298cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
130398cd9ca7SRichard Henderson         nullify_set(ctx, 0);
130498cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, dest, dest + 4);
130598cd9ca7SRichard Henderson     } else {
130698cd9ca7SRichard Henderson         nullify_set(ctx, n);
130798cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_b, dest);
130898cd9ca7SRichard Henderson     }
130998cd9ca7SRichard Henderson 
131098cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
131198cd9ca7SRichard Henderson     if (ctx->null_lab) {
131298cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
131398cd9ca7SRichard Henderson         ctx->null_lab = NULL;
131498cd9ca7SRichard Henderson         if (which < 2) {
131598cd9ca7SRichard Henderson             nullify_set(ctx, 0);
131698cd9ca7SRichard Henderson             gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n);
131798cd9ca7SRichard Henderson             return EXIT_GOTO_TB;
131898cd9ca7SRichard Henderson         } else {
131998cd9ca7SRichard Henderson             return EXIT_IAQ_N_STALE;
132098cd9ca7SRichard Henderson         }
132198cd9ca7SRichard Henderson     } else {
132298cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
132398cd9ca7SRichard Henderson     }
132498cd9ca7SRichard Henderson }
132598cd9ca7SRichard Henderson 
132698cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
132798cd9ca7SRichard Henderson    nullification of the branch itself.  */
132898cd9ca7SRichard Henderson static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
132998cd9ca7SRichard Henderson                              unsigned link, bool is_n)
133098cd9ca7SRichard Henderson {
133198cd9ca7SRichard Henderson     TCGv a0, a1, next, tmp;
133298cd9ca7SRichard Henderson     TCGCond c;
133398cd9ca7SRichard Henderson 
133498cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
133598cd9ca7SRichard Henderson 
133698cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
133798cd9ca7SRichard Henderson         if (link != 0) {
133898cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
133998cd9ca7SRichard Henderson         }
134098cd9ca7SRichard Henderson         next = get_temp(ctx);
134198cd9ca7SRichard Henderson         tcg_gen_mov_tl(next, dest);
134298cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
134398cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
134498cd9ca7SRichard Henderson         if (is_n) {
134598cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
134698cd9ca7SRichard Henderson         }
134798cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
134898cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
134998cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
135098cd9ca7SRichard Henderson            tracepoint in effect).  Since the exit_tb that we must use
135198cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
135298cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
135398cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
135498cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
135598cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
135698cd9ca7SRichard Henderson 
135798cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
135898cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
135998cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
136098cd9ca7SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, dest);
136198cd9ca7SRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
136298cd9ca7SRichard Henderson 
136398cd9ca7SRichard Henderson         nullify_over(ctx);
136498cd9ca7SRichard Henderson         if (link != 0) {
136598cd9ca7SRichard Henderson             tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
136698cd9ca7SRichard Henderson         }
136798cd9ca7SRichard Henderson         tcg_gen_exit_tb(0);
136898cd9ca7SRichard Henderson         return nullify_end(ctx, NO_EXIT);
136998cd9ca7SRichard Henderson     } else {
137098cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
137198cd9ca7SRichard Henderson         c = ctx->null_cond.c;
137298cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
137398cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
137498cd9ca7SRichard Henderson 
137598cd9ca7SRichard Henderson         tmp = tcg_temp_new();
137698cd9ca7SRichard Henderson         next = get_temp(ctx);
137798cd9ca7SRichard Henderson 
137898cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
137998cd9ca7SRichard Henderson         tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
138098cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
138198cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
138298cd9ca7SRichard Henderson 
138398cd9ca7SRichard Henderson         if (link != 0) {
138498cd9ca7SRichard Henderson             tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
138598cd9ca7SRichard Henderson         }
138698cd9ca7SRichard Henderson 
138798cd9ca7SRichard Henderson         if (is_n) {
138898cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
138998cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
139098cd9ca7SRichard Henderson                to the branch.  */
139198cd9ca7SRichard Henderson             tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
139298cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
139398cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
139498cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
139598cd9ca7SRichard Henderson         } else {
139698cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
139798cd9ca7SRichard Henderson         }
139898cd9ca7SRichard Henderson     }
139998cd9ca7SRichard Henderson 
140098cd9ca7SRichard Henderson     return NO_EXIT;
140198cd9ca7SRichard Henderson }
140298cd9ca7SRichard Henderson 
14037ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
14047ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
14057ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
14067ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
14077ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
14087ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
14097ad439dfSRichard Henderson    aforementioned BE.  */
14107ad439dfSRichard Henderson static ExitStatus do_page_zero(DisasContext *ctx)
14117ad439dfSRichard Henderson {
14127ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
14137ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
14147ad439dfSRichard Henderson        next insn within the privilaged page.  */
14157ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
14167ad439dfSRichard Henderson     case TCG_COND_NEVER:
14177ad439dfSRichard Henderson         break;
14187ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
14197ad439dfSRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, 0);
14207ad439dfSRichard Henderson         goto do_sigill;
14217ad439dfSRichard Henderson     default:
14227ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
14237ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
14247ad439dfSRichard Henderson         g_assert_not_reached();
14257ad439dfSRichard Henderson     }
14267ad439dfSRichard Henderson 
14277ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
14287ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
14297ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
14307ad439dfSRichard Henderson        under such conditions.  */
14317ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
14327ad439dfSRichard Henderson         goto do_sigill;
14337ad439dfSRichard Henderson     }
14347ad439dfSRichard Henderson 
14357ad439dfSRichard Henderson     switch (ctx->iaoq_f) {
14367ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
14377ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGSEGV);
14387ad439dfSRichard Henderson         return EXIT_NORETURN;
14397ad439dfSRichard Henderson 
14407ad439dfSRichard Henderson     case 0xb0: /* LWS */
14417ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
14427ad439dfSRichard Henderson         return EXIT_NORETURN;
14437ad439dfSRichard Henderson 
14447ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
14457ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
14467ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
14477ad439dfSRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
14487ad439dfSRichard Henderson         return EXIT_IAQ_N_UPDATED;
14497ad439dfSRichard Henderson 
14507ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
14517ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
14527ad439dfSRichard Henderson         return EXIT_NORETURN;
14537ad439dfSRichard Henderson 
14547ad439dfSRichard Henderson     default:
14557ad439dfSRichard Henderson     do_sigill:
14567ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGILL);
14577ad439dfSRichard Henderson         return EXIT_NORETURN;
14587ad439dfSRichard Henderson     }
14597ad439dfSRichard Henderson }
14607ad439dfSRichard Henderson 
1461b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
1462b2167459SRichard Henderson                             const DisasInsn *di)
1463b2167459SRichard Henderson {
1464b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1465b2167459SRichard Henderson     return NO_EXIT;
1466b2167459SRichard Henderson }
1467b2167459SRichard Henderson 
1468*98a9cb79SRichard Henderson static ExitStatus trans_break(DisasContext *ctx, uint32_t insn,
1469*98a9cb79SRichard Henderson                               const DisasInsn *di)
1470*98a9cb79SRichard Henderson {
1471*98a9cb79SRichard Henderson     nullify_over(ctx);
1472*98a9cb79SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
1473*98a9cb79SRichard Henderson }
1474*98a9cb79SRichard Henderson 
1475*98a9cb79SRichard Henderson static ExitStatus trans_sync(DisasContext *ctx, uint32_t insn,
1476*98a9cb79SRichard Henderson                              const DisasInsn *di)
1477*98a9cb79SRichard Henderson {
1478*98a9cb79SRichard Henderson     /* No point in nullifying the memory barrier.  */
1479*98a9cb79SRichard Henderson     tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1480*98a9cb79SRichard Henderson 
1481*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1482*98a9cb79SRichard Henderson     return NO_EXIT;
1483*98a9cb79SRichard Henderson }
1484*98a9cb79SRichard Henderson 
1485*98a9cb79SRichard Henderson static ExitStatus trans_mfia(DisasContext *ctx, uint32_t insn,
1486*98a9cb79SRichard Henderson                              const DisasInsn *di)
1487*98a9cb79SRichard Henderson {
1488*98a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1489*98a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
1490*98a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, ctx->iaoq_f);
1491*98a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
1492*98a9cb79SRichard Henderson 
1493*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1494*98a9cb79SRichard Henderson     return NO_EXIT;
1495*98a9cb79SRichard Henderson }
1496*98a9cb79SRichard Henderson 
1497*98a9cb79SRichard Henderson static ExitStatus trans_mfsp(DisasContext *ctx, uint32_t insn,
1498*98a9cb79SRichard Henderson                              const DisasInsn *di)
1499*98a9cb79SRichard Henderson {
1500*98a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1501*98a9cb79SRichard Henderson     TCGv tmp = dest_gpr(ctx, rt);
1502*98a9cb79SRichard Henderson 
1503*98a9cb79SRichard Henderson     /* ??? We don't implement space registers.  */
1504*98a9cb79SRichard Henderson     tcg_gen_movi_tl(tmp, 0);
1505*98a9cb79SRichard Henderson     save_gpr(ctx, rt, tmp);
1506*98a9cb79SRichard Henderson 
1507*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1508*98a9cb79SRichard Henderson     return NO_EXIT;
1509*98a9cb79SRichard Henderson }
1510*98a9cb79SRichard Henderson 
1511*98a9cb79SRichard Henderson static ExitStatus trans_mfctl(DisasContext *ctx, uint32_t insn,
1512*98a9cb79SRichard Henderson                               const DisasInsn *di)
1513*98a9cb79SRichard Henderson {
1514*98a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1515*98a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
1516*98a9cb79SRichard Henderson     TCGv tmp;
1517*98a9cb79SRichard Henderson 
1518*98a9cb79SRichard Henderson     switch (ctl) {
1519*98a9cb79SRichard Henderson     case 11: /* SAR */
1520*98a9cb79SRichard Henderson #ifdef TARGET_HPPA64
1521*98a9cb79SRichard Henderson         if (extract32(insn, 14, 1) == 0) {
1522*98a9cb79SRichard Henderson             /* MFSAR without ,W masks low 5 bits.  */
1523*98a9cb79SRichard Henderson             tmp = dest_gpr(ctx, rt);
1524*98a9cb79SRichard Henderson             tcg_gen_andi_tl(tmp, cpu_sar, 31);
1525*98a9cb79SRichard Henderson             save_gpr(ctx, rt, tmp);
1526*98a9cb79SRichard Henderson             break;
1527*98a9cb79SRichard Henderson         }
1528*98a9cb79SRichard Henderson #endif
1529*98a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_sar);
1530*98a9cb79SRichard Henderson         break;
1531*98a9cb79SRichard Henderson     case 16: /* Interval Timer */
1532*98a9cb79SRichard Henderson         tmp = dest_gpr(ctx, rt);
1533*98a9cb79SRichard Henderson         tcg_gen_movi_tl(tmp, 0); /* FIXME */
1534*98a9cb79SRichard Henderson         save_gpr(ctx, rt, tmp);
1535*98a9cb79SRichard Henderson         break;
1536*98a9cb79SRichard Henderson     case 26:
1537*98a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr26);
1538*98a9cb79SRichard Henderson         break;
1539*98a9cb79SRichard Henderson     case 27:
1540*98a9cb79SRichard Henderson         save_gpr(ctx, rt, cpu_cr27);
1541*98a9cb79SRichard Henderson         break;
1542*98a9cb79SRichard Henderson     default:
1543*98a9cb79SRichard Henderson         /* All other control registers are privileged.  */
1544*98a9cb79SRichard Henderson         return gen_illegal(ctx);
1545*98a9cb79SRichard Henderson     }
1546*98a9cb79SRichard Henderson 
1547*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1548*98a9cb79SRichard Henderson     return NO_EXIT;
1549*98a9cb79SRichard Henderson }
1550*98a9cb79SRichard Henderson 
1551*98a9cb79SRichard Henderson static ExitStatus trans_mtctl(DisasContext *ctx, uint32_t insn,
1552*98a9cb79SRichard Henderson                               const DisasInsn *di)
1553*98a9cb79SRichard Henderson {
1554*98a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
1555*98a9cb79SRichard Henderson     unsigned ctl = extract32(insn, 21, 5);
1556*98a9cb79SRichard Henderson     TCGv tmp;
1557*98a9cb79SRichard Henderson 
1558*98a9cb79SRichard Henderson     if (ctl == 11) { /* SAR */
1559*98a9cb79SRichard Henderson         tmp = tcg_temp_new();
1560*98a9cb79SRichard Henderson         tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
1561*98a9cb79SRichard Henderson         save_or_nullify(ctx, cpu_sar, tmp);
1562*98a9cb79SRichard Henderson         tcg_temp_free(tmp);
1563*98a9cb79SRichard Henderson     } else {
1564*98a9cb79SRichard Henderson         /* All other control registers are privileged or read-only.  */
1565*98a9cb79SRichard Henderson         return gen_illegal(ctx);
1566*98a9cb79SRichard Henderson     }
1567*98a9cb79SRichard Henderson 
1568*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1569*98a9cb79SRichard Henderson     return NO_EXIT;
1570*98a9cb79SRichard Henderson }
1571*98a9cb79SRichard Henderson 
1572*98a9cb79SRichard Henderson static ExitStatus trans_mtsarcm(DisasContext *ctx, uint32_t insn,
1573*98a9cb79SRichard Henderson                                 const DisasInsn *di)
1574*98a9cb79SRichard Henderson {
1575*98a9cb79SRichard Henderson     unsigned rin = extract32(insn, 16, 5);
1576*98a9cb79SRichard Henderson     TCGv tmp = tcg_temp_new();
1577*98a9cb79SRichard Henderson 
1578*98a9cb79SRichard Henderson     tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
1579*98a9cb79SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
1580*98a9cb79SRichard Henderson     save_or_nullify(ctx, cpu_sar, tmp);
1581*98a9cb79SRichard Henderson     tcg_temp_free(tmp);
1582*98a9cb79SRichard Henderson 
1583*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1584*98a9cb79SRichard Henderson     return NO_EXIT;
1585*98a9cb79SRichard Henderson }
1586*98a9cb79SRichard Henderson 
1587*98a9cb79SRichard Henderson static ExitStatus trans_ldsid(DisasContext *ctx, uint32_t insn,
1588*98a9cb79SRichard Henderson                               const DisasInsn *di)
1589*98a9cb79SRichard Henderson {
1590*98a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1591*98a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
1592*98a9cb79SRichard Henderson 
1593*98a9cb79SRichard Henderson     /* Since we don't implement space registers, this returns zero.  */
1594*98a9cb79SRichard Henderson     tcg_gen_movi_tl(dest, 0);
1595*98a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
1596*98a9cb79SRichard Henderson 
1597*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1598*98a9cb79SRichard Henderson     return NO_EXIT;
1599*98a9cb79SRichard Henderson }
1600*98a9cb79SRichard Henderson 
1601*98a9cb79SRichard Henderson static const DisasInsn table_system[] = {
1602*98a9cb79SRichard Henderson     { 0x00000000u, 0xfc001fe0u, trans_break },
1603*98a9cb79SRichard Henderson     /* We don't implement space register, so MTSP is a nop.  */
1604*98a9cb79SRichard Henderson     { 0x00001820u, 0xffe01fffu, trans_nop },
1605*98a9cb79SRichard Henderson     { 0x00001840u, 0xfc00ffffu, trans_mtctl },
1606*98a9cb79SRichard Henderson     { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
1607*98a9cb79SRichard Henderson     { 0x000014a0u, 0xffffffe0u, trans_mfia },
1608*98a9cb79SRichard Henderson     { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
1609*98a9cb79SRichard Henderson     { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
1610*98a9cb79SRichard Henderson     { 0x00000400u, 0xffffffffu, trans_sync },
1611*98a9cb79SRichard Henderson     { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
1612*98a9cb79SRichard Henderson };
1613*98a9cb79SRichard Henderson 
1614*98a9cb79SRichard Henderson static ExitStatus trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
1615*98a9cb79SRichard Henderson                                      const DisasInsn *di)
1616*98a9cb79SRichard Henderson {
1617*98a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
1618*98a9cb79SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
1619*98a9cb79SRichard Henderson     TCGv dest = dest_gpr(ctx, rb);
1620*98a9cb79SRichard Henderson     TCGv src1 = load_gpr(ctx, rb);
1621*98a9cb79SRichard Henderson     TCGv src2 = load_gpr(ctx, rx);
1622*98a9cb79SRichard Henderson 
1623*98a9cb79SRichard Henderson     /* The only thing we need to do is the base register modification.  */
1624*98a9cb79SRichard Henderson     tcg_gen_add_tl(dest, src1, src2);
1625*98a9cb79SRichard Henderson     save_gpr(ctx, rb, dest);
1626*98a9cb79SRichard Henderson 
1627*98a9cb79SRichard Henderson     cond_free(&ctx->null_cond);
1628*98a9cb79SRichard Henderson     return NO_EXIT;
1629*98a9cb79SRichard Henderson }
1630*98a9cb79SRichard Henderson 
1631*98a9cb79SRichard Henderson static ExitStatus trans_probe(DisasContext *ctx, uint32_t insn,
1632*98a9cb79SRichard Henderson                               const DisasInsn *di)
1633*98a9cb79SRichard Henderson {
1634*98a9cb79SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1635*98a9cb79SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
1636*98a9cb79SRichard Henderson     unsigned is_write = extract32(insn, 6, 1);
1637*98a9cb79SRichard Henderson     TCGv dest;
1638*98a9cb79SRichard Henderson 
1639*98a9cb79SRichard Henderson     nullify_over(ctx);
1640*98a9cb79SRichard Henderson 
1641*98a9cb79SRichard Henderson     /* ??? Do something with priv level operand.  */
1642*98a9cb79SRichard Henderson     dest = dest_gpr(ctx, rt);
1643*98a9cb79SRichard Henderson     if (is_write) {
1644*98a9cb79SRichard Henderson         gen_helper_probe_w(dest, load_gpr(ctx, rb));
1645*98a9cb79SRichard Henderson     } else {
1646*98a9cb79SRichard Henderson         gen_helper_probe_r(dest, load_gpr(ctx, rb));
1647*98a9cb79SRichard Henderson     }
1648*98a9cb79SRichard Henderson     save_gpr(ctx, rt, dest);
1649*98a9cb79SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1650*98a9cb79SRichard Henderson }
1651*98a9cb79SRichard Henderson 
1652*98a9cb79SRichard Henderson static const DisasInsn table_mem_mgmt[] = {
1653*98a9cb79SRichard Henderson     { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
1654*98a9cb79SRichard Henderson     { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
1655*98a9cb79SRichard Henderson     { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
1656*98a9cb79SRichard Henderson     { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
1657*98a9cb79SRichard Henderson     { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
1658*98a9cb79SRichard Henderson     { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
1659*98a9cb79SRichard Henderson     { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
1660*98a9cb79SRichard Henderson     { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
1661*98a9cb79SRichard Henderson     { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
1662*98a9cb79SRichard Henderson     { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
1663*98a9cb79SRichard Henderson     { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
1664*98a9cb79SRichard Henderson     { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
1665*98a9cb79SRichard Henderson     { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
1666*98a9cb79SRichard Henderson     { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
1667*98a9cb79SRichard Henderson     { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
1668*98a9cb79SRichard Henderson };
1669*98a9cb79SRichard Henderson 
1670b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
1671b2167459SRichard Henderson                             const DisasInsn *di)
1672b2167459SRichard Henderson {
1673b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1674b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1675b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1676b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
1677b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
1678b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1679b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1680b2167459SRichard Henderson     bool is_c = false;
1681b2167459SRichard Henderson     bool is_l = false;
1682b2167459SRichard Henderson     bool is_tc = false;
1683b2167459SRichard Henderson     bool is_tsv = false;
1684b2167459SRichard Henderson     ExitStatus ret;
1685b2167459SRichard Henderson 
1686b2167459SRichard Henderson     switch (ext) {
1687b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
1688b2167459SRichard Henderson         break;
1689b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
1690b2167459SRichard Henderson         is_l = true;
1691b2167459SRichard Henderson         break;
1692b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1693b2167459SRichard Henderson         is_tsv = true;
1694b2167459SRichard Henderson         break;
1695b2167459SRichard Henderson     case 0x7: /* ADD,C */
1696b2167459SRichard Henderson         is_c = true;
1697b2167459SRichard Henderson         break;
1698b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
1699b2167459SRichard Henderson         is_c = is_tsv = true;
1700b2167459SRichard Henderson         break;
1701b2167459SRichard Henderson     default:
1702b2167459SRichard Henderson         return gen_illegal(ctx);
1703b2167459SRichard Henderson     }
1704b2167459SRichard Henderson 
1705b2167459SRichard Henderson     if (cf) {
1706b2167459SRichard Henderson         nullify_over(ctx);
1707b2167459SRichard Henderson     }
1708b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1709b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1710b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1711b2167459SRichard Henderson     return nullify_end(ctx, ret);
1712b2167459SRichard Henderson }
1713b2167459SRichard Henderson 
1714b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
1715b2167459SRichard Henderson                             const DisasInsn *di)
1716b2167459SRichard Henderson {
1717b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1718b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1719b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1720b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
1721b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1722b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1723b2167459SRichard Henderson     bool is_b = false;
1724b2167459SRichard Henderson     bool is_tc = false;
1725b2167459SRichard Henderson     bool is_tsv = false;
1726b2167459SRichard Henderson     ExitStatus ret;
1727b2167459SRichard Henderson 
1728b2167459SRichard Henderson     switch (ext) {
1729b2167459SRichard Henderson     case 0x10: /* SUB */
1730b2167459SRichard Henderson         break;
1731b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
1732b2167459SRichard Henderson         is_tsv = true;
1733b2167459SRichard Henderson         break;
1734b2167459SRichard Henderson     case 0x14: /* SUB,B */
1735b2167459SRichard Henderson         is_b = true;
1736b2167459SRichard Henderson         break;
1737b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
1738b2167459SRichard Henderson         is_b = is_tsv = true;
1739b2167459SRichard Henderson         break;
1740b2167459SRichard Henderson     case 0x13: /* SUB,TC */
1741b2167459SRichard Henderson         is_tc = true;
1742b2167459SRichard Henderson         break;
1743b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
1744b2167459SRichard Henderson         is_tc = is_tsv = true;
1745b2167459SRichard Henderson         break;
1746b2167459SRichard Henderson     default:
1747b2167459SRichard Henderson         return gen_illegal(ctx);
1748b2167459SRichard Henderson     }
1749b2167459SRichard Henderson 
1750b2167459SRichard Henderson     if (cf) {
1751b2167459SRichard Henderson         nullify_over(ctx);
1752b2167459SRichard Henderson     }
1753b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1754b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1755b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1756b2167459SRichard Henderson     return nullify_end(ctx, ret);
1757b2167459SRichard Henderson }
1758b2167459SRichard Henderson 
1759b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
1760b2167459SRichard Henderson                             const DisasInsn *di)
1761b2167459SRichard Henderson {
1762b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1763b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1764b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1765b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1766b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1767b2167459SRichard Henderson     ExitStatus ret;
1768b2167459SRichard Henderson 
1769b2167459SRichard Henderson     if (cf) {
1770b2167459SRichard Henderson         nullify_over(ctx);
1771b2167459SRichard Henderson     }
1772b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1773b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1774b2167459SRichard Henderson     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt);
1775b2167459SRichard Henderson     return nullify_end(ctx, ret);
1776b2167459SRichard Henderson }
1777b2167459SRichard Henderson 
1778b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1779b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1780b2167459SRichard Henderson                              const DisasInsn *di)
1781b2167459SRichard Henderson {
1782b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1783b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1784b2167459SRichard Henderson 
1785b2167459SRichard Henderson     if (r1 == 0) {
1786b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1787b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1788b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1789b2167459SRichard Henderson     } else {
1790b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1791b2167459SRichard Henderson     }
1792b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1793b2167459SRichard Henderson     return NO_EXIT;
1794b2167459SRichard Henderson }
1795b2167459SRichard Henderson 
1796b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1797b2167459SRichard Henderson                                const DisasInsn *di)
1798b2167459SRichard Henderson {
1799b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1800b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1801b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1802b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1803b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1804b2167459SRichard Henderson     ExitStatus ret;
1805b2167459SRichard Henderson 
1806b2167459SRichard Henderson     if (cf) {
1807b2167459SRichard Henderson         nullify_over(ctx);
1808b2167459SRichard Henderson     }
1809b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1810b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1811b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1812b2167459SRichard Henderson     return nullify_end(ctx, ret);
1813b2167459SRichard Henderson }
1814b2167459SRichard Henderson 
1815b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1816b2167459SRichard Henderson                              const DisasInsn *di)
1817b2167459SRichard Henderson {
1818b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1819b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1820b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1821b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1822b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1823b2167459SRichard Henderson     ExitStatus ret;
1824b2167459SRichard Henderson 
1825b2167459SRichard Henderson     if (cf) {
1826b2167459SRichard Henderson         nullify_over(ctx);
1827b2167459SRichard Henderson     }
1828b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1829b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1830b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1831b2167459SRichard Henderson     return nullify_end(ctx, ret);
1832b2167459SRichard Henderson }
1833b2167459SRichard Henderson 
1834b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1835b2167459SRichard Henderson                                const DisasInsn *di)
1836b2167459SRichard Henderson {
1837b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1838b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1839b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1840b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
1841b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1842b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
1843b2167459SRichard Henderson     ExitStatus ret;
1844b2167459SRichard Henderson 
1845b2167459SRichard Henderson     if (cf) {
1846b2167459SRichard Henderson         nullify_over(ctx);
1847b2167459SRichard Henderson     }
1848b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1849b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1850b2167459SRichard Henderson     tmp = get_temp(ctx);
1851b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
1852b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
1853b2167459SRichard Henderson     return nullify_end(ctx, ret);
1854b2167459SRichard Henderson }
1855b2167459SRichard Henderson 
1856b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
1857b2167459SRichard Henderson                              const DisasInsn *di)
1858b2167459SRichard Henderson {
1859b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1860b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1861b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
1862b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1863b2167459SRichard Henderson     TCGv tmp;
1864b2167459SRichard Henderson     ExitStatus ret;
1865b2167459SRichard Henderson 
1866b2167459SRichard Henderson     nullify_over(ctx);
1867b2167459SRichard Henderson 
1868b2167459SRichard Henderson     tmp = get_temp(ctx);
1869b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
1870b2167459SRichard Henderson     if (!is_i) {
1871b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
1872b2167459SRichard Henderson     }
1873b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
1874b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
1875b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
1876b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
1877b2167459SRichard Henderson 
1878b2167459SRichard Henderson     return nullify_end(ctx, ret);
1879b2167459SRichard Henderson }
1880b2167459SRichard Henderson 
1881b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
1882b2167459SRichard Henderson                            const DisasInsn *di)
1883b2167459SRichard Henderson {
1884b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1885b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1886b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1887b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1888b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
1889b2167459SRichard Henderson 
1890b2167459SRichard Henderson     nullify_over(ctx);
1891b2167459SRichard Henderson 
1892b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
1893b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
1894b2167459SRichard Henderson 
1895b2167459SRichard Henderson     add1 = tcg_temp_new();
1896b2167459SRichard Henderson     add2 = tcg_temp_new();
1897b2167459SRichard Henderson     addc = tcg_temp_new();
1898b2167459SRichard Henderson     dest = tcg_temp_new();
1899b2167459SRichard Henderson     zero = tcg_const_tl(0);
1900b2167459SRichard Henderson 
1901b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
1902b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
1903b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
1904b2167459SRichard Henderson 
1905b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
1906b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
1907b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
1908b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
1909b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
1910b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
1911b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
1912b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
1913b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
1914b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
1915b2167459SRichard Henderson 
1916b2167459SRichard Henderson     tcg_temp_free(addc);
1917b2167459SRichard Henderson     tcg_temp_free(zero);
1918b2167459SRichard Henderson 
1919b2167459SRichard Henderson     /* Write back the result register.  */
1920b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1921b2167459SRichard Henderson 
1922b2167459SRichard Henderson     /* Write back PSW[CB].  */
1923b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
1924b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
1925b2167459SRichard Henderson 
1926b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
1927b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
1928b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
1929b2167459SRichard Henderson 
1930b2167459SRichard Henderson     /* Install the new nullification.  */
1931b2167459SRichard Henderson     if (cf) {
1932b2167459SRichard Henderson         TCGv sv;
1933b2167459SRichard Henderson         TCGV_UNUSED(sv);
1934b2167459SRichard Henderson         if (cf >> 1 == 6) {
1935b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
1936b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
1937b2167459SRichard Henderson         }
1938b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
1939b2167459SRichard Henderson     }
1940b2167459SRichard Henderson 
1941b2167459SRichard Henderson     tcg_temp_free(add1);
1942b2167459SRichard Henderson     tcg_temp_free(add2);
1943b2167459SRichard Henderson     tcg_temp_free(dest);
1944b2167459SRichard Henderson 
1945b2167459SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1946b2167459SRichard Henderson }
1947b2167459SRichard Henderson 
1948b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
1949b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
1950b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
1951b2167459SRichard Henderson     { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl },
1952b2167459SRichard Henderson     { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl },
1953b2167459SRichard Henderson     { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl },
1954b2167459SRichard Henderson     { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl },
1955b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
1956b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
1957b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
1958b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
1959b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
1960b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
1961b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
1962b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
1963b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
1964b2167459SRichard Henderson };
1965b2167459SRichard Henderson 
1966b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
1967b2167459SRichard Henderson {
1968b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1969b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1970b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1971b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1972b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1973b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
1974b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1975b2167459SRichard Henderson     ExitStatus ret;
1976b2167459SRichard Henderson 
1977b2167459SRichard Henderson     if (cf) {
1978b2167459SRichard Henderson         nullify_over(ctx);
1979b2167459SRichard Henderson     }
1980b2167459SRichard Henderson 
1981b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1982b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1983b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
1984b2167459SRichard Henderson 
1985b2167459SRichard Henderson     return nullify_end(ctx, ret);
1986b2167459SRichard Henderson }
1987b2167459SRichard Henderson 
1988b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
1989b2167459SRichard Henderson {
1990b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1991b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1992b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1993b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1994b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1995b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1996b2167459SRichard Henderson     ExitStatus ret;
1997b2167459SRichard Henderson 
1998b2167459SRichard Henderson     if (cf) {
1999b2167459SRichard Henderson         nullify_over(ctx);
2000b2167459SRichard Henderson     }
2001b2167459SRichard Henderson 
2002b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2003b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2004b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2005b2167459SRichard Henderson 
2006b2167459SRichard Henderson     return nullify_end(ctx, ret);
2007b2167459SRichard Henderson }
2008b2167459SRichard Henderson 
2009b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2010b2167459SRichard Henderson {
2011b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
2012b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
2013b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2014b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
2015b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
2016b2167459SRichard Henderson     ExitStatus ret;
2017b2167459SRichard Henderson 
2018b2167459SRichard Henderson     if (cf) {
2019b2167459SRichard Henderson         nullify_over(ctx);
2020b2167459SRichard Henderson     }
2021b2167459SRichard Henderson 
2022b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
2023b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
2024b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2025b2167459SRichard Henderson 
2026b2167459SRichard Henderson     return nullify_end(ctx, ret);
2027b2167459SRichard Henderson }
2028b2167459SRichard Henderson 
202996d6407fSRichard Henderson static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
203096d6407fSRichard Henderson                                  const DisasInsn *di)
203196d6407fSRichard Henderson {
203296d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
203396d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
203496d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
203596d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
203696d6407fSRichard Henderson     int disp = low_sextract(insn, 16, 5);
203796d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
203896d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
203996d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
204096d6407fSRichard Henderson 
204196d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
204296d6407fSRichard Henderson }
204396d6407fSRichard Henderson 
204496d6407fSRichard Henderson static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
204596d6407fSRichard Henderson                                  const DisasInsn *di)
204696d6407fSRichard Henderson {
204796d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
204896d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
204996d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
205096d6407fSRichard Henderson     unsigned u = extract32(insn, 13, 1);
205196d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
205296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
205396d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
205496d6407fSRichard Henderson 
205596d6407fSRichard Henderson     return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
205696d6407fSRichard Henderson }
205796d6407fSRichard Henderson 
205896d6407fSRichard Henderson static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn,
205996d6407fSRichard Henderson                                  const DisasInsn *di)
206096d6407fSRichard Henderson {
206196d6407fSRichard Henderson     int disp = low_sextract(insn, 0, 5);
206296d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
206396d6407fSRichard Henderson     unsigned sz = extract32(insn, 6, 2);
206496d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
206596d6407fSRichard Henderson     unsigned rr = extract32(insn, 16, 5);
206696d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
206796d6407fSRichard Henderson     int modify = (m ? (a ? -1 : 1) : 0);
206896d6407fSRichard Henderson     TCGMemOp mop = MO_TE | sz;
206996d6407fSRichard Henderson 
207096d6407fSRichard Henderson     return do_store(ctx, rr, rb, disp, modify, mop);
207196d6407fSRichard Henderson }
207296d6407fSRichard Henderson 
207396d6407fSRichard Henderson static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn,
207496d6407fSRichard Henderson                              const DisasInsn *di)
207596d6407fSRichard Henderson {
207696d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
207796d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
207896d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
207996d6407fSRichard Henderson     unsigned au = extract32(insn, 13, 1);
208096d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
208196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
208296d6407fSRichard Henderson     TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
208396d6407fSRichard Henderson     TCGv zero, addr, base, dest;
208496d6407fSRichard Henderson     int modify, disp = 0, scale = 0;
208596d6407fSRichard Henderson 
208696d6407fSRichard Henderson     nullify_over(ctx);
208796d6407fSRichard Henderson 
208896d6407fSRichard Henderson     /* ??? Share more code with do_load and do_load_{32,64}.  */
208996d6407fSRichard Henderson 
209096d6407fSRichard Henderson     if (i) {
209196d6407fSRichard Henderson         modify = (m ? (au ? -1 : 1) : 0);
209296d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
209396d6407fSRichard Henderson         rx = 0;
209496d6407fSRichard Henderson     } else {
209596d6407fSRichard Henderson         modify = m;
209696d6407fSRichard Henderson         if (au) {
209796d6407fSRichard Henderson             scale = mop & MO_SIZE;
209896d6407fSRichard Henderson         }
209996d6407fSRichard Henderson     }
210096d6407fSRichard Henderson     if (modify) {
210196d6407fSRichard Henderson         /* Base register modification.  Make sure if RT == RB, we see
210296d6407fSRichard Henderson            the result of the load.  */
210396d6407fSRichard Henderson         dest = get_temp(ctx);
210496d6407fSRichard Henderson     } else {
210596d6407fSRichard Henderson         dest = dest_gpr(ctx, rt);
210696d6407fSRichard Henderson     }
210796d6407fSRichard Henderson 
210896d6407fSRichard Henderson     addr = tcg_temp_new();
210996d6407fSRichard Henderson     base = load_gpr(ctx, rb);
211096d6407fSRichard Henderson     if (rx) {
211196d6407fSRichard Henderson         tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
211296d6407fSRichard Henderson         tcg_gen_add_tl(addr, addr, base);
211396d6407fSRichard Henderson     } else {
211496d6407fSRichard Henderson         tcg_gen_addi_tl(addr, base, disp);
211596d6407fSRichard Henderson     }
211696d6407fSRichard Henderson 
211796d6407fSRichard Henderson     zero = tcg_const_tl(0);
211896d6407fSRichard Henderson     tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
211996d6407fSRichard Henderson                            zero, MMU_USER_IDX, mop);
212096d6407fSRichard Henderson     if (modify) {
212196d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
212296d6407fSRichard Henderson     }
212396d6407fSRichard Henderson     save_gpr(ctx, rt, dest);
212496d6407fSRichard Henderson 
212596d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
212696d6407fSRichard Henderson }
212796d6407fSRichard Henderson 
212896d6407fSRichard Henderson static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn,
212996d6407fSRichard Henderson                              const DisasInsn *di)
213096d6407fSRichard Henderson {
213196d6407fSRichard Henderson     target_long disp = low_sextract(insn, 0, 5);
213296d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
213396d6407fSRichard Henderson     unsigned a = extract32(insn, 13, 1);
213496d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
213596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
213696d6407fSRichard Henderson     TCGv addr, val;
213796d6407fSRichard Henderson 
213896d6407fSRichard Henderson     nullify_over(ctx);
213996d6407fSRichard Henderson 
214096d6407fSRichard Henderson     addr = tcg_temp_new();
214196d6407fSRichard Henderson     if (m || disp == 0) {
214296d6407fSRichard Henderson         tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
214396d6407fSRichard Henderson     } else {
214496d6407fSRichard Henderson         tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
214596d6407fSRichard Henderson     }
214696d6407fSRichard Henderson     val = load_gpr(ctx, rt);
214796d6407fSRichard Henderson 
214896d6407fSRichard Henderson     if (a) {
214996d6407fSRichard Henderson         gen_helper_stby_e(cpu_env, addr, val);
215096d6407fSRichard Henderson     } else {
215196d6407fSRichard Henderson         gen_helper_stby_b(cpu_env, addr, val);
215296d6407fSRichard Henderson     }
215396d6407fSRichard Henderson 
215496d6407fSRichard Henderson     if (m) {
215596d6407fSRichard Henderson         tcg_gen_addi_tl(addr, addr, disp);
215696d6407fSRichard Henderson         tcg_gen_andi_tl(addr, addr, ~3);
215796d6407fSRichard Henderson         save_gpr(ctx, rb, addr);
215896d6407fSRichard Henderson     }
215996d6407fSRichard Henderson     tcg_temp_free(addr);
216096d6407fSRichard Henderson 
216196d6407fSRichard Henderson     return nullify_end(ctx, NO_EXIT);
216296d6407fSRichard Henderson }
216396d6407fSRichard Henderson 
216496d6407fSRichard Henderson static const DisasInsn table_index_mem[] = {
216596d6407fSRichard Henderson     { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
216696d6407fSRichard Henderson     { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
216796d6407fSRichard Henderson     { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
216896d6407fSRichard Henderson     { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
216996d6407fSRichard Henderson     { 0x0c001300u, 0xfc0013c0, trans_stby },
217096d6407fSRichard Henderson };
217196d6407fSRichard Henderson 
2172b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
2173b2167459SRichard Henderson {
2174b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2175b2167459SRichard Henderson     target_long i = assemble_21(insn);
2176b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2177b2167459SRichard Henderson 
2178b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
2179b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2180b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2181b2167459SRichard Henderson 
2182b2167459SRichard Henderson     return NO_EXIT;
2183b2167459SRichard Henderson }
2184b2167459SRichard Henderson 
2185b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
2186b2167459SRichard Henderson {
2187b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
2188b2167459SRichard Henderson     target_long i = assemble_21(insn);
2189b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
2190b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
2191b2167459SRichard Henderson 
2192b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2193b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
2194b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2195b2167459SRichard Henderson 
2196b2167459SRichard Henderson     return NO_EXIT;
2197b2167459SRichard Henderson }
2198b2167459SRichard Henderson 
2199b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
2200b2167459SRichard Henderson {
2201b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
2202b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
2203b2167459SRichard Henderson     target_long i = assemble_16(insn);
2204b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
2205b2167459SRichard Henderson 
2206b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
2207b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2208b2167459SRichard Henderson     if (rb == 0) {
2209b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
2210b2167459SRichard Henderson     } else {
2211b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2212b2167459SRichard Henderson     }
2213b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
2214b2167459SRichard Henderson     cond_free(&ctx->null_cond);
2215b2167459SRichard Henderson 
2216b2167459SRichard Henderson     return NO_EXIT;
2217b2167459SRichard Henderson }
2218b2167459SRichard Henderson 
221996d6407fSRichard Henderson static ExitStatus trans_load(DisasContext *ctx, uint32_t insn,
222096d6407fSRichard Henderson                              bool is_mod, TCGMemOp mop)
222196d6407fSRichard Henderson {
222296d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
222396d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
222496d6407fSRichard Henderson     target_long i = assemble_16(insn);
222596d6407fSRichard Henderson 
222696d6407fSRichard Henderson     return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
222796d6407fSRichard Henderson }
222896d6407fSRichard Henderson 
222996d6407fSRichard Henderson static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn)
223096d6407fSRichard Henderson {
223196d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
223296d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
223396d6407fSRichard Henderson     target_long i = assemble_16a(insn);
223496d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
223596d6407fSRichard Henderson 
223696d6407fSRichard Henderson     switch (ext2) {
223796d6407fSRichard Henderson     case 0:
223896d6407fSRichard Henderson     case 1:
223996d6407fSRichard Henderson         /* FLDW without modification.  */
224096d6407fSRichard Henderson         return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
224196d6407fSRichard Henderson     case 2:
224296d6407fSRichard Henderson         /* LDW with modification.  Note that the sign of I selects
224396d6407fSRichard Henderson            post-dec vs pre-inc.  */
224496d6407fSRichard Henderson         return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
224596d6407fSRichard Henderson     default:
224696d6407fSRichard Henderson         return gen_illegal(ctx);
224796d6407fSRichard Henderson     }
224896d6407fSRichard Henderson }
224996d6407fSRichard Henderson 
225096d6407fSRichard Henderson static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn)
225196d6407fSRichard Henderson {
225296d6407fSRichard Henderson     target_long i = assemble_16a(insn);
225396d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
225496d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
225596d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
225696d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
225796d6407fSRichard Henderson 
225896d6407fSRichard Henderson     /* FLDW with modification.  */
225996d6407fSRichard Henderson     return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
226096d6407fSRichard Henderson }
226196d6407fSRichard Henderson 
226296d6407fSRichard Henderson static ExitStatus trans_store(DisasContext *ctx, uint32_t insn,
226396d6407fSRichard Henderson                               bool is_mod, TCGMemOp mop)
226496d6407fSRichard Henderson {
226596d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
226696d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
226796d6407fSRichard Henderson     target_long i = assemble_16(insn);
226896d6407fSRichard Henderson 
226996d6407fSRichard Henderson     return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
227096d6407fSRichard Henderson }
227196d6407fSRichard Henderson 
227296d6407fSRichard Henderson static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn)
227396d6407fSRichard Henderson {
227496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
227596d6407fSRichard Henderson     unsigned rt = extract32(insn, 16, 5);
227696d6407fSRichard Henderson     target_long i = assemble_16a(insn);
227796d6407fSRichard Henderson     unsigned ext2 = extract32(insn, 1, 2);
227896d6407fSRichard Henderson 
227996d6407fSRichard Henderson     switch (ext2) {
228096d6407fSRichard Henderson     case 0:
228196d6407fSRichard Henderson     case 1:
228296d6407fSRichard Henderson         /* FSTW without modification.  */
228396d6407fSRichard Henderson         return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
228496d6407fSRichard Henderson     case 2:
228596d6407fSRichard Henderson         /* LDW with modification.  */
228696d6407fSRichard Henderson         return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
228796d6407fSRichard Henderson     default:
228896d6407fSRichard Henderson         return gen_illegal(ctx);
228996d6407fSRichard Henderson     }
229096d6407fSRichard Henderson }
229196d6407fSRichard Henderson 
229296d6407fSRichard Henderson static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn)
229396d6407fSRichard Henderson {
229496d6407fSRichard Henderson     target_long i = assemble_16a(insn);
229596d6407fSRichard Henderson     unsigned t1 = extract32(insn, 1, 1);
229696d6407fSRichard Henderson     unsigned a = extract32(insn, 2, 1);
229796d6407fSRichard Henderson     unsigned t0 = extract32(insn, 16, 5);
229896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
229996d6407fSRichard Henderson 
230096d6407fSRichard Henderson     /* FSTW with modification.  */
230196d6407fSRichard Henderson     return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
230296d6407fSRichard Henderson }
230396d6407fSRichard Henderson 
230496d6407fSRichard Henderson static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn)
230596d6407fSRichard Henderson {
230696d6407fSRichard Henderson     unsigned t0 = extract32(insn, 0, 5);
230796d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
230896d6407fSRichard Henderson     unsigned t1 = extract32(insn, 6, 1);
230996d6407fSRichard Henderson     unsigned ext3 = extract32(insn, 7, 3);
231096d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
231196d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
231296d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
231396d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
231496d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
231596d6407fSRichard Henderson     unsigned rt = t1 * 32 + t0;
231696d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
231796d6407fSRichard Henderson     int disp, scale;
231896d6407fSRichard Henderson 
231996d6407fSRichard Henderson     if (i == 0) {
232096d6407fSRichard Henderson         scale = (ua ? 2 : 0);
232196d6407fSRichard Henderson         disp = 0;
232296d6407fSRichard Henderson         modify = m;
232396d6407fSRichard Henderson     } else {
232496d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
232596d6407fSRichard Henderson         scale = 0;
232696d6407fSRichard Henderson         rx = 0;
232796d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
232896d6407fSRichard Henderson     }
232996d6407fSRichard Henderson 
233096d6407fSRichard Henderson     switch (ext3) {
233196d6407fSRichard Henderson     case 0: /* FLDW */
233296d6407fSRichard Henderson         return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
233396d6407fSRichard Henderson     case 4: /* FSTW */
233496d6407fSRichard Henderson         return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
233596d6407fSRichard Henderson     }
233696d6407fSRichard Henderson     return gen_illegal(ctx);
233796d6407fSRichard Henderson }
233896d6407fSRichard Henderson 
233996d6407fSRichard Henderson static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn)
234096d6407fSRichard Henderson {
234196d6407fSRichard Henderson     unsigned rt = extract32(insn, 0, 5);
234296d6407fSRichard Henderson     unsigned m = extract32(insn, 5, 1);
234396d6407fSRichard Henderson     unsigned ext4 = extract32(insn, 6, 4);
234496d6407fSRichard Henderson     /* unsigned cc = extract32(insn, 10, 2); */
234596d6407fSRichard Henderson     unsigned i = extract32(insn, 12, 1);
234696d6407fSRichard Henderson     unsigned ua = extract32(insn, 13, 1);
234796d6407fSRichard Henderson     unsigned rx = extract32(insn, 16, 5);
234896d6407fSRichard Henderson     unsigned rb = extract32(insn, 21, 5);
234996d6407fSRichard Henderson     int modify = (m ? (ua ? -1 : 1) : 0);
235096d6407fSRichard Henderson     int disp, scale;
235196d6407fSRichard Henderson 
235296d6407fSRichard Henderson     if (i == 0) {
235396d6407fSRichard Henderson         scale = (ua ? 3 : 0);
235496d6407fSRichard Henderson         disp = 0;
235596d6407fSRichard Henderson         modify = m;
235696d6407fSRichard Henderson     } else {
235796d6407fSRichard Henderson         disp = low_sextract(rx, 0, 5);
235896d6407fSRichard Henderson         scale = 0;
235996d6407fSRichard Henderson         rx = 0;
236096d6407fSRichard Henderson         modify = (m ? (ua ? -1 : 1) : 0);
236196d6407fSRichard Henderson     }
236296d6407fSRichard Henderson 
236396d6407fSRichard Henderson     switch (ext4) {
236496d6407fSRichard Henderson     case 0: /* FLDD */
236596d6407fSRichard Henderson         return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
236696d6407fSRichard Henderson     case 8: /* FSTD */
236796d6407fSRichard Henderson         return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
236896d6407fSRichard Henderson     default:
236996d6407fSRichard Henderson         return gen_illegal(ctx);
237096d6407fSRichard Henderson     }
237196d6407fSRichard Henderson }
237296d6407fSRichard Henderson 
237398cd9ca7SRichard Henderson static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
237498cd9ca7SRichard Henderson                              bool is_true, bool is_imm, bool is_dw)
237598cd9ca7SRichard Henderson {
237698cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
237798cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
237898cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
237998cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
238098cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
238198cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv;
238298cd9ca7SRichard Henderson     DisasCond cond;
238398cd9ca7SRichard Henderson 
238498cd9ca7SRichard Henderson     nullify_over(ctx);
238598cd9ca7SRichard Henderson 
238698cd9ca7SRichard Henderson     if (is_imm) {
238798cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
238898cd9ca7SRichard Henderson     } else {
238998cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
239098cd9ca7SRichard Henderson     }
239198cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
239298cd9ca7SRichard Henderson     dest = get_temp(ctx);
239398cd9ca7SRichard Henderson 
239498cd9ca7SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
239598cd9ca7SRichard Henderson 
239698cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
239798cd9ca7SRichard Henderson     if (c == 6) {
239898cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
239998cd9ca7SRichard Henderson     }
240098cd9ca7SRichard Henderson 
240198cd9ca7SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
240298cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
240398cd9ca7SRichard Henderson }
240498cd9ca7SRichard Henderson 
240598cd9ca7SRichard Henderson static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
240698cd9ca7SRichard Henderson                              bool is_true, bool is_imm)
240798cd9ca7SRichard Henderson {
240898cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
240998cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
241098cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
241198cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
241298cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
241398cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv, cb_msb;
241498cd9ca7SRichard Henderson     DisasCond cond;
241598cd9ca7SRichard Henderson 
241698cd9ca7SRichard Henderson     nullify_over(ctx);
241798cd9ca7SRichard Henderson 
241898cd9ca7SRichard Henderson     if (is_imm) {
241998cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
242098cd9ca7SRichard Henderson     } else {
242198cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
242298cd9ca7SRichard Henderson     }
242398cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
242498cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
242598cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
242698cd9ca7SRichard Henderson     TCGV_UNUSED(cb_msb);
242798cd9ca7SRichard Henderson 
242898cd9ca7SRichard Henderson     switch (c) {
242998cd9ca7SRichard Henderson     default:
243098cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
243198cd9ca7SRichard Henderson         break;
243298cd9ca7SRichard Henderson     case 4: case 5:
243398cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
243498cd9ca7SRichard Henderson         tcg_gen_movi_tl(cb_msb, 0);
243598cd9ca7SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
243698cd9ca7SRichard Henderson         break;
243798cd9ca7SRichard Henderson     case 6:
243898cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
243998cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
244098cd9ca7SRichard Henderson         break;
244198cd9ca7SRichard Henderson     }
244298cd9ca7SRichard Henderson 
244398cd9ca7SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
244498cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
244598cd9ca7SRichard Henderson }
244698cd9ca7SRichard Henderson 
244798cd9ca7SRichard Henderson static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
244898cd9ca7SRichard Henderson {
244998cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
245098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
245198cd9ca7SRichard Henderson     unsigned c = extract32(insn, 15, 1);
245298cd9ca7SRichard Henderson     unsigned r = extract32(insn, 16, 5);
245398cd9ca7SRichard Henderson     unsigned p = extract32(insn, 21, 5);
245498cd9ca7SRichard Henderson     unsigned i = extract32(insn, 26, 1);
245598cd9ca7SRichard Henderson     TCGv tmp, tcg_r;
245698cd9ca7SRichard Henderson     DisasCond cond;
245798cd9ca7SRichard Henderson 
245898cd9ca7SRichard Henderson     nullify_over(ctx);
245998cd9ca7SRichard Henderson 
246098cd9ca7SRichard Henderson     tmp = tcg_temp_new();
246198cd9ca7SRichard Henderson     tcg_r = load_gpr(ctx, r);
246298cd9ca7SRichard Henderson     if (i) {
246398cd9ca7SRichard Henderson         tcg_gen_shli_tl(tmp, tcg_r, p);
246498cd9ca7SRichard Henderson     } else {
246598cd9ca7SRichard Henderson         tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
246698cd9ca7SRichard Henderson     }
246798cd9ca7SRichard Henderson 
246898cd9ca7SRichard Henderson     cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
246998cd9ca7SRichard Henderson     tcg_temp_free(tmp);
247098cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
247198cd9ca7SRichard Henderson }
247298cd9ca7SRichard Henderson 
247398cd9ca7SRichard Henderson static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
247498cd9ca7SRichard Henderson {
247598cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
247698cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
247798cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
247898cd9ca7SRichard Henderson     unsigned t = extract32(insn, 16, 5);
247998cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
248098cd9ca7SRichard Henderson     TCGv dest;
248198cd9ca7SRichard Henderson     DisasCond cond;
248298cd9ca7SRichard Henderson 
248398cd9ca7SRichard Henderson     nullify_over(ctx);
248498cd9ca7SRichard Henderson 
248598cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
248698cd9ca7SRichard Henderson     if (is_imm) {
248798cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
248898cd9ca7SRichard Henderson     } else if (t == 0) {
248998cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, 0);
249098cd9ca7SRichard Henderson     } else {
249198cd9ca7SRichard Henderson         tcg_gen_mov_tl(dest, cpu_gr[t]);
249298cd9ca7SRichard Henderson     }
249398cd9ca7SRichard Henderson 
249498cd9ca7SRichard Henderson     cond = do_sed_cond(c, dest);
249598cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
249698cd9ca7SRichard Henderson }
249798cd9ca7SRichard Henderson 
24980b1347d2SRichard Henderson static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
24990b1347d2SRichard Henderson                                  const DisasInsn *di)
25000b1347d2SRichard Henderson {
25010b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
25020b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
25030b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
25040b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
25050b1347d2SRichard Henderson     TCGv dest;
25060b1347d2SRichard Henderson 
25070b1347d2SRichard Henderson     if (c) {
25080b1347d2SRichard Henderson         nullify_over(ctx);
25090b1347d2SRichard Henderson     }
25100b1347d2SRichard Henderson 
25110b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
25120b1347d2SRichard Henderson     if (r1 == 0) {
25130b1347d2SRichard Henderson         tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
25140b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, dest, cpu_sar);
25150b1347d2SRichard Henderson     } else if (r1 == r2) {
25160b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
25170b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
25180b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
25190b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
25200b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
25210b1347d2SRichard Henderson     } else {
25220b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
25230b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
25240b1347d2SRichard Henderson 
25250b1347d2SRichard Henderson         tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
25260b1347d2SRichard Henderson         tcg_gen_extu_tl_i64(s, cpu_sar);
25270b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
25280b1347d2SRichard Henderson         tcg_gen_trunc_i64_tl(dest, t);
25290b1347d2SRichard Henderson 
25300b1347d2SRichard Henderson         tcg_temp_free_i64(t);
25310b1347d2SRichard Henderson         tcg_temp_free_i64(s);
25320b1347d2SRichard Henderson     }
25330b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
25340b1347d2SRichard Henderson 
25350b1347d2SRichard Henderson     /* Install the new nullification.  */
25360b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
25370b1347d2SRichard Henderson     if (c) {
25380b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
25390b1347d2SRichard Henderson     }
25400b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
25410b1347d2SRichard Henderson }
25420b1347d2SRichard Henderson 
25430b1347d2SRichard Henderson static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
25440b1347d2SRichard Henderson                                   const DisasInsn *di)
25450b1347d2SRichard Henderson {
25460b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
25470b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
25480b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
25490b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
25500b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
25510b1347d2SRichard Henderson     unsigned sa = 31 - cpos;
25520b1347d2SRichard Henderson     TCGv dest, t2;
25530b1347d2SRichard Henderson 
25540b1347d2SRichard Henderson     if (c) {
25550b1347d2SRichard Henderson         nullify_over(ctx);
25560b1347d2SRichard Henderson     }
25570b1347d2SRichard Henderson 
25580b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
25590b1347d2SRichard Henderson     t2 = load_gpr(ctx, r2);
25600b1347d2SRichard Henderson     if (r1 == r2) {
25610b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
25620b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, t2);
25630b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
25640b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
25650b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
25660b1347d2SRichard Henderson     } else if (r1 == 0) {
25670b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
25680b1347d2SRichard Henderson     } else {
25690b1347d2SRichard Henderson         TCGv t0 = tcg_temp_new();
25700b1347d2SRichard Henderson         tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
25710b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
25720b1347d2SRichard Henderson         tcg_temp_free(t0);
25730b1347d2SRichard Henderson     }
25740b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
25750b1347d2SRichard Henderson 
25760b1347d2SRichard Henderson     /* Install the new nullification.  */
25770b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
25780b1347d2SRichard Henderson     if (c) {
25790b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
25800b1347d2SRichard Henderson     }
25810b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
25820b1347d2SRichard Henderson }
25830b1347d2SRichard Henderson 
25840b1347d2SRichard Henderson static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
25850b1347d2SRichard Henderson                                   const DisasInsn *di)
25860b1347d2SRichard Henderson {
25870b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
25880b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
25890b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
25900b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
25910b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
25920b1347d2SRichard Henderson     unsigned len = 32 - clen;
25930b1347d2SRichard Henderson     TCGv dest, src, tmp;
25940b1347d2SRichard Henderson 
25950b1347d2SRichard Henderson     if (c) {
25960b1347d2SRichard Henderson         nullify_over(ctx);
25970b1347d2SRichard Henderson     }
25980b1347d2SRichard Henderson 
25990b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26000b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
26010b1347d2SRichard Henderson     tmp = tcg_temp_new();
26020b1347d2SRichard Henderson 
26030b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
26040b1347d2SRichard Henderson     tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
26050b1347d2SRichard Henderson     if (is_se) {
26060b1347d2SRichard Henderson         tcg_gen_sar_tl(dest, src, tmp);
26070b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, dest, 0, len);
26080b1347d2SRichard Henderson     } else {
26090b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, src, tmp);
26100b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, dest, 0, len);
26110b1347d2SRichard Henderson     }
26120b1347d2SRichard Henderson     tcg_temp_free(tmp);
26130b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26140b1347d2SRichard Henderson 
26150b1347d2SRichard Henderson     /* Install the new nullification.  */
26160b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
26170b1347d2SRichard Henderson     if (c) {
26180b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
26190b1347d2SRichard Henderson     }
26200b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
26210b1347d2SRichard Henderson }
26220b1347d2SRichard Henderson 
26230b1347d2SRichard Henderson static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
26240b1347d2SRichard Henderson                                   const DisasInsn *di)
26250b1347d2SRichard Henderson {
26260b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
26270b1347d2SRichard Henderson     unsigned pos = extract32(insn, 5, 5);
26280b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
26290b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26300b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
26310b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
26320b1347d2SRichard Henderson     unsigned len = 32 - clen;
26330b1347d2SRichard Henderson     unsigned cpos = 31 - pos;
26340b1347d2SRichard Henderson     TCGv dest, src;
26350b1347d2SRichard Henderson 
26360b1347d2SRichard Henderson     if (c) {
26370b1347d2SRichard Henderson         nullify_over(ctx);
26380b1347d2SRichard Henderson     }
26390b1347d2SRichard Henderson 
26400b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26410b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
26420b1347d2SRichard Henderson     if (is_se) {
26430b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, src, cpos, len);
26440b1347d2SRichard Henderson     } else {
26450b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, src, cpos, len);
26460b1347d2SRichard Henderson     }
26470b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26480b1347d2SRichard Henderson 
26490b1347d2SRichard Henderson     /* Install the new nullification.  */
26500b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
26510b1347d2SRichard Henderson     if (c) {
26520b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
26530b1347d2SRichard Henderson     }
26540b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
26550b1347d2SRichard Henderson }
26560b1347d2SRichard Henderson 
26570b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = {
26580b1347d2SRichard Henderson     { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
26590b1347d2SRichard Henderson     { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
26600b1347d2SRichard Henderson     { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
26610b1347d2SRichard Henderson     { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
26620b1347d2SRichard Henderson };
26630b1347d2SRichard Henderson 
26640b1347d2SRichard Henderson static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
26650b1347d2SRichard Henderson                                    const DisasInsn *di)
26660b1347d2SRichard Henderson {
26670b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
26680b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
26690b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
26700b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
26710b1347d2SRichard Henderson     target_long val = low_sextract(insn, 16, 5);
26720b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
26730b1347d2SRichard Henderson     unsigned len = 32 - clen;
26740b1347d2SRichard Henderson     target_long mask0, mask1;
26750b1347d2SRichard Henderson     TCGv dest;
26760b1347d2SRichard Henderson 
26770b1347d2SRichard Henderson     if (c) {
26780b1347d2SRichard Henderson         nullify_over(ctx);
26790b1347d2SRichard Henderson     }
26800b1347d2SRichard Henderson     if (cpos + len > 32) {
26810b1347d2SRichard Henderson         len = 32 - cpos;
26820b1347d2SRichard Henderson     }
26830b1347d2SRichard Henderson 
26840b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
26850b1347d2SRichard Henderson     mask0 = deposit64(0, cpos, len, val);
26860b1347d2SRichard Henderson     mask1 = deposit64(-1, cpos, len, val);
26870b1347d2SRichard Henderson 
26880b1347d2SRichard Henderson     if (nz) {
26890b1347d2SRichard Henderson         TCGv src = load_gpr(ctx, rt);
26900b1347d2SRichard Henderson         if (mask1 != -1) {
26910b1347d2SRichard Henderson             tcg_gen_andi_tl(dest, src, mask1);
26920b1347d2SRichard Henderson             src = dest;
26930b1347d2SRichard Henderson         }
26940b1347d2SRichard Henderson         tcg_gen_ori_tl(dest, src, mask0);
26950b1347d2SRichard Henderson     } else {
26960b1347d2SRichard Henderson         tcg_gen_movi_tl(dest, mask0);
26970b1347d2SRichard Henderson     }
26980b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
26990b1347d2SRichard Henderson 
27000b1347d2SRichard Henderson     /* Install the new nullification.  */
27010b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27020b1347d2SRichard Henderson     if (c) {
27030b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27040b1347d2SRichard Henderson     }
27050b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27060b1347d2SRichard Henderson }
27070b1347d2SRichard Henderson 
27080b1347d2SRichard Henderson static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
27090b1347d2SRichard Henderson                                  const DisasInsn *di)
27100b1347d2SRichard Henderson {
27110b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27120b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
27130b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
27140b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27150b1347d2SRichard Henderson     unsigned rr = extract32(insn, 16, 5);
27160b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
27170b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
27180b1347d2SRichard Henderson     unsigned len = 32 - clen;
27190b1347d2SRichard Henderson     TCGv dest, val;
27200b1347d2SRichard Henderson 
27210b1347d2SRichard Henderson     if (c) {
27220b1347d2SRichard Henderson         nullify_over(ctx);
27230b1347d2SRichard Henderson     }
27240b1347d2SRichard Henderson     if (cpos + len > 32) {
27250b1347d2SRichard Henderson         len = 32 - cpos;
27260b1347d2SRichard Henderson     }
27270b1347d2SRichard Henderson 
27280b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27290b1347d2SRichard Henderson     val = load_gpr(ctx, rr);
27300b1347d2SRichard Henderson     if (rs == 0) {
27310b1347d2SRichard Henderson         tcg_gen_deposit_z_tl(dest, val, cpos, len);
27320b1347d2SRichard Henderson     } else {
27330b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
27340b1347d2SRichard Henderson     }
27350b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27360b1347d2SRichard Henderson 
27370b1347d2SRichard Henderson     /* Install the new nullification.  */
27380b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27390b1347d2SRichard Henderson     if (c) {
27400b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27410b1347d2SRichard Henderson     }
27420b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27430b1347d2SRichard Henderson }
27440b1347d2SRichard Henderson 
27450b1347d2SRichard Henderson static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
27460b1347d2SRichard Henderson                                  const DisasInsn *di)
27470b1347d2SRichard Henderson {
27480b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
27490b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
27500b1347d2SRichard Henderson     unsigned i = extract32(insn, 12, 1);
27510b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
27520b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
27530b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
27540b1347d2SRichard Henderson     unsigned len = 32 - clen;
27550b1347d2SRichard Henderson     TCGv val, mask, tmp, shift, dest;
27560b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
27570b1347d2SRichard Henderson 
27580b1347d2SRichard Henderson     if (c) {
27590b1347d2SRichard Henderson         nullify_over(ctx);
27600b1347d2SRichard Henderson     }
27610b1347d2SRichard Henderson 
27620b1347d2SRichard Henderson     if (i) {
27630b1347d2SRichard Henderson         val = load_const(ctx, low_sextract(insn, 16, 5));
27640b1347d2SRichard Henderson     } else {
27650b1347d2SRichard Henderson         val = load_gpr(ctx, extract32(insn, 16, 5));
27660b1347d2SRichard Henderson     }
27670b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
27680b1347d2SRichard Henderson     shift = tcg_temp_new();
27690b1347d2SRichard Henderson     tmp = tcg_temp_new();
27700b1347d2SRichard Henderson 
27710b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
27720b1347d2SRichard Henderson     tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
27730b1347d2SRichard Henderson 
27740b1347d2SRichard Henderson     mask = tcg_const_tl(msb + (msb - 1));
27750b1347d2SRichard Henderson     tcg_gen_and_tl(tmp, val, mask);
27760b1347d2SRichard Henderson     if (rs) {
27770b1347d2SRichard Henderson         tcg_gen_shl_tl(mask, mask, shift);
27780b1347d2SRichard Henderson         tcg_gen_shl_tl(tmp, tmp, shift);
27790b1347d2SRichard Henderson         tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
27800b1347d2SRichard Henderson         tcg_gen_or_tl(dest, dest, tmp);
27810b1347d2SRichard Henderson     } else {
27820b1347d2SRichard Henderson         tcg_gen_shl_tl(dest, tmp, shift);
27830b1347d2SRichard Henderson     }
27840b1347d2SRichard Henderson     tcg_temp_free(shift);
27850b1347d2SRichard Henderson     tcg_temp_free(mask);
27860b1347d2SRichard Henderson     tcg_temp_free(tmp);
27870b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
27880b1347d2SRichard Henderson 
27890b1347d2SRichard Henderson     /* Install the new nullification.  */
27900b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
27910b1347d2SRichard Henderson     if (c) {
27920b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
27930b1347d2SRichard Henderson     }
27940b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
27950b1347d2SRichard Henderson }
27960b1347d2SRichard Henderson 
27970b1347d2SRichard Henderson static const DisasInsn table_depw[] = {
27980b1347d2SRichard Henderson     { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
27990b1347d2SRichard Henderson     { 0xd4000800u, 0xfc001800u, trans_depw_imm },
28000b1347d2SRichard Henderson     { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
28010b1347d2SRichard Henderson };
28020b1347d2SRichard Henderson 
280398cd9ca7SRichard Henderson static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
280498cd9ca7SRichard Henderson {
280598cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
280698cd9ca7SRichard Henderson     unsigned b = extract32(insn, 21, 5);
280798cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
280898cd9ca7SRichard Henderson 
280998cd9ca7SRichard Henderson     /* unsigned s = low_uextract(insn, 13, 3); */
281098cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
281198cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
281298cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
281398cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
281498cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
281598cd9ca7SRichard Henderson 
281698cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
281798cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
281898cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
281998cd9ca7SRichard Henderson     if (b == 0) {
282098cd9ca7SRichard Henderson         return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
282198cd9ca7SRichard Henderson     } else {
282298cd9ca7SRichard Henderson         TCGv tmp = get_temp(ctx);
282398cd9ca7SRichard Henderson         tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
282498cd9ca7SRichard Henderson         return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
282598cd9ca7SRichard Henderson     }
282698cd9ca7SRichard Henderson }
282798cd9ca7SRichard Henderson 
282898cd9ca7SRichard Henderson static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
282998cd9ca7SRichard Henderson                            const DisasInsn *di)
283098cd9ca7SRichard Henderson {
283198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
283298cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
283398cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
283498cd9ca7SRichard Henderson 
283598cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
283698cd9ca7SRichard Henderson }
283798cd9ca7SRichard Henderson 
283898cd9ca7SRichard Henderson static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
283998cd9ca7SRichard Henderson                                 const DisasInsn *di)
284098cd9ca7SRichard Henderson {
284198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
284298cd9ca7SRichard Henderson     target_long disp = assemble_22(insn);
284398cd9ca7SRichard Henderson 
284498cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
284598cd9ca7SRichard Henderson }
284698cd9ca7SRichard Henderson 
284798cd9ca7SRichard Henderson static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
284898cd9ca7SRichard Henderson                             const DisasInsn *di)
284998cd9ca7SRichard Henderson {
285098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
285198cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
285298cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
285398cd9ca7SRichard Henderson     TCGv tmp = get_temp(ctx);
285498cd9ca7SRichard Henderson 
285598cd9ca7SRichard Henderson     tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
285698cd9ca7SRichard Henderson     tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
285798cd9ca7SRichard Henderson     return do_ibranch(ctx, tmp, link, n);
285898cd9ca7SRichard Henderson }
285998cd9ca7SRichard Henderson 
286098cd9ca7SRichard Henderson static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
286198cd9ca7SRichard Henderson                            const DisasInsn *di)
286298cd9ca7SRichard Henderson {
286398cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
286498cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
286598cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
286698cd9ca7SRichard Henderson     TCGv dest;
286798cd9ca7SRichard Henderson 
286898cd9ca7SRichard Henderson     if (rx == 0) {
286998cd9ca7SRichard Henderson         dest = load_gpr(ctx, rb);
287098cd9ca7SRichard Henderson     } else {
287198cd9ca7SRichard Henderson         dest = get_temp(ctx);
287298cd9ca7SRichard Henderson         tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
287398cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
287498cd9ca7SRichard Henderson     }
287598cd9ca7SRichard Henderson     return do_ibranch(ctx, dest, 0, n);
287698cd9ca7SRichard Henderson }
287798cd9ca7SRichard Henderson 
287898cd9ca7SRichard Henderson static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
287998cd9ca7SRichard Henderson                             const DisasInsn *di)
288098cd9ca7SRichard Henderson {
288198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
288298cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
288398cd9ca7SRichard Henderson     unsigned link = extract32(insn, 13, 1) ? 2 : 0;
288498cd9ca7SRichard Henderson 
288598cd9ca7SRichard Henderson     return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
288698cd9ca7SRichard Henderson }
288798cd9ca7SRichard Henderson 
288898cd9ca7SRichard Henderson static const DisasInsn table_branch[] = {
288998cd9ca7SRichard Henderson     { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
289098cd9ca7SRichard Henderson     { 0xe800a000u, 0xfc00e000u, trans_bl_long },
289198cd9ca7SRichard Henderson     { 0xe8004000u, 0xfc00fffdu, trans_blr },
289298cd9ca7SRichard Henderson     { 0xe800c000u, 0xfc00fffdu, trans_bv },
289398cd9ca7SRichard Henderson     { 0xe800d000u, 0xfc00dffcu, trans_bve },
289498cd9ca7SRichard Henderson };
289598cd9ca7SRichard Henderson 
289661766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
289761766fe9SRichard Henderson                                       const DisasInsn table[], size_t n)
289861766fe9SRichard Henderson {
289961766fe9SRichard Henderson     size_t i;
290061766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
290161766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
290261766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
290361766fe9SRichard Henderson         }
290461766fe9SRichard Henderson     }
290561766fe9SRichard Henderson     return gen_illegal(ctx);
290661766fe9SRichard Henderson }
290761766fe9SRichard Henderson 
290861766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
290961766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
291061766fe9SRichard Henderson 
291161766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
291261766fe9SRichard Henderson {
291361766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
291461766fe9SRichard Henderson 
291561766fe9SRichard Henderson     switch (opc) {
2916*98a9cb79SRichard Henderson     case 0x00: /* system op */
2917*98a9cb79SRichard Henderson         return translate_table(ctx, insn, table_system);
2918*98a9cb79SRichard Henderson     case 0x01:
2919*98a9cb79SRichard Henderson         return translate_table(ctx, insn, table_mem_mgmt);
2920b2167459SRichard Henderson     case 0x02:
2921b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
292296d6407fSRichard Henderson     case 0x03:
292396d6407fSRichard Henderson         return translate_table(ctx, insn, table_index_mem);
2924b2167459SRichard Henderson     case 0x08:
2925b2167459SRichard Henderson         return trans_ldil(ctx, insn);
292696d6407fSRichard Henderson     case 0x09:
292796d6407fSRichard Henderson         return trans_copr_w(ctx, insn);
2928b2167459SRichard Henderson     case 0x0A:
2929b2167459SRichard Henderson         return trans_addil(ctx, insn);
293096d6407fSRichard Henderson     case 0x0B:
293196d6407fSRichard Henderson         return trans_copr_dw(ctx, insn);
2932b2167459SRichard Henderson     case 0x0D:
2933b2167459SRichard Henderson         return trans_ldo(ctx, insn);
293496d6407fSRichard Henderson 
293596d6407fSRichard Henderson     case 0x10:
293696d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_UB);
293796d6407fSRichard Henderson     case 0x11:
293896d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUW);
293996d6407fSRichard Henderson     case 0x12:
294096d6407fSRichard Henderson         return trans_load(ctx, insn, false, MO_TEUL);
294196d6407fSRichard Henderson     case 0x13:
294296d6407fSRichard Henderson         return trans_load(ctx, insn, true, MO_TEUL);
294396d6407fSRichard Henderson     case 0x16:
294496d6407fSRichard Henderson         return trans_fload_mod(ctx, insn);
294596d6407fSRichard Henderson     case 0x17:
294696d6407fSRichard Henderson         return trans_load_w(ctx, insn);
294796d6407fSRichard Henderson     case 0x18:
294896d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_UB);
294996d6407fSRichard Henderson     case 0x19:
295096d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUW);
295196d6407fSRichard Henderson     case 0x1A:
295296d6407fSRichard Henderson         return trans_store(ctx, insn, false, MO_TEUL);
295396d6407fSRichard Henderson     case 0x1B:
295496d6407fSRichard Henderson         return trans_store(ctx, insn, true, MO_TEUL);
295596d6407fSRichard Henderson     case 0x1E:
295696d6407fSRichard Henderson         return trans_fstore_mod(ctx, insn);
295796d6407fSRichard Henderson     case 0x1F:
295896d6407fSRichard Henderson         return trans_store_w(ctx, insn);
295996d6407fSRichard Henderson 
296098cd9ca7SRichard Henderson     case 0x20:
296198cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, false);
296298cd9ca7SRichard Henderson     case 0x21:
296398cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, true, false);
296498cd9ca7SRichard Henderson     case 0x22:
296598cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, false);
296698cd9ca7SRichard Henderson     case 0x23:
296798cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, true, false);
2968b2167459SRichard Henderson     case 0x24:
2969b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
2970b2167459SRichard Henderson     case 0x25:
2971b2167459SRichard Henderson         return trans_subi(ctx, insn);
297298cd9ca7SRichard Henderson     case 0x27:
297398cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, true);
297498cd9ca7SRichard Henderson     case 0x28:
297598cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, false);
297698cd9ca7SRichard Henderson     case 0x29:
297798cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, true);
297898cd9ca7SRichard Henderson     case 0x2A:
297998cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, false);
298098cd9ca7SRichard Henderson     case 0x2B:
298198cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, true);
2982b2167459SRichard Henderson     case 0x2C:
2983b2167459SRichard Henderson     case 0x2D:
2984b2167459SRichard Henderson         return trans_addi(ctx, insn);
298598cd9ca7SRichard Henderson     case 0x2F:
298698cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, true);
298796d6407fSRichard Henderson 
298898cd9ca7SRichard Henderson     case 0x30:
298998cd9ca7SRichard Henderson     case 0x31:
299098cd9ca7SRichard Henderson         return trans_bb(ctx, insn);
299198cd9ca7SRichard Henderson     case 0x32:
299298cd9ca7SRichard Henderson         return trans_movb(ctx, insn, false);
299398cd9ca7SRichard Henderson     case 0x33:
299498cd9ca7SRichard Henderson         return trans_movb(ctx, insn, true);
29950b1347d2SRichard Henderson     case 0x34:
29960b1347d2SRichard Henderson         return translate_table(ctx, insn, table_sh_ex);
29970b1347d2SRichard Henderson     case 0x35:
29980b1347d2SRichard Henderson         return translate_table(ctx, insn, table_depw);
299998cd9ca7SRichard Henderson     case 0x38:
300098cd9ca7SRichard Henderson         return trans_be(ctx, insn, false);
300198cd9ca7SRichard Henderson     case 0x39:
300298cd9ca7SRichard Henderson         return trans_be(ctx, insn, true);
300398cd9ca7SRichard Henderson     case 0x3A:
300498cd9ca7SRichard Henderson         return translate_table(ctx, insn, table_branch);
300596d6407fSRichard Henderson 
300696d6407fSRichard Henderson     case 0x04: /* spopn */
300796d6407fSRichard Henderson     case 0x05: /* diag */
300896d6407fSRichard Henderson     case 0x0F: /* product specific */
300996d6407fSRichard Henderson         break;
301096d6407fSRichard Henderson 
301196d6407fSRichard Henderson     case 0x07: /* unassigned */
301296d6407fSRichard Henderson     case 0x15: /* unassigned */
301396d6407fSRichard Henderson     case 0x1D: /* unassigned */
301496d6407fSRichard Henderson     case 0x37: /* unassigned */
301596d6407fSRichard Henderson     case 0x3F: /* unassigned */
301661766fe9SRichard Henderson     default:
301761766fe9SRichard Henderson         break;
301861766fe9SRichard Henderson     }
301961766fe9SRichard Henderson     return gen_illegal(ctx);
302061766fe9SRichard Henderson }
302161766fe9SRichard Henderson 
302261766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
302361766fe9SRichard Henderson {
302461766fe9SRichard Henderson     HPPACPU *cpu = hppa_env_get_cpu(env);
302561766fe9SRichard Henderson     CPUState *cs = CPU(cpu);
302661766fe9SRichard Henderson     DisasContext ctx;
302761766fe9SRichard Henderson     ExitStatus ret;
302861766fe9SRichard Henderson     int num_insns, max_insns, i;
302961766fe9SRichard Henderson 
303061766fe9SRichard Henderson     ctx.tb = tb;
303161766fe9SRichard Henderson     ctx.cs = cs;
303261766fe9SRichard Henderson     ctx.iaoq_f = tb->pc;
303361766fe9SRichard Henderson     ctx.iaoq_b = tb->cs_base;
303461766fe9SRichard Henderson     ctx.singlestep_enabled = cs->singlestep_enabled;
303561766fe9SRichard Henderson 
303661766fe9SRichard Henderson     ctx.ntemps = 0;
303761766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
303861766fe9SRichard Henderson         TCGV_UNUSED(ctx.temps[i]);
303961766fe9SRichard Henderson     }
304061766fe9SRichard Henderson 
304161766fe9SRichard Henderson     /* Compute the maximum number of insns to execute, as bounded by
304261766fe9SRichard Henderson        (1) icount, (2) single-stepping, (3) branch delay slots, or
304361766fe9SRichard Henderson        (4) the number of insns remaining on the current page.  */
304461766fe9SRichard Henderson     max_insns = tb->cflags & CF_COUNT_MASK;
304561766fe9SRichard Henderson     if (max_insns == 0) {
304661766fe9SRichard Henderson         max_insns = CF_COUNT_MASK;
304761766fe9SRichard Henderson     }
304861766fe9SRichard Henderson     if (ctx.singlestep_enabled || singlestep) {
304961766fe9SRichard Henderson         max_insns = 1;
305061766fe9SRichard Henderson     } else if (max_insns > TCG_MAX_INSNS) {
305161766fe9SRichard Henderson         max_insns = TCG_MAX_INSNS;
305261766fe9SRichard Henderson     }
305361766fe9SRichard Henderson 
305461766fe9SRichard Henderson     num_insns = 0;
305561766fe9SRichard Henderson     gen_tb_start(tb);
305661766fe9SRichard Henderson 
3057129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
3058129e9cc3SRichard Henderson     ctx.null_cond = cond_make_f();
3059129e9cc3SRichard Henderson     ctx.psw_n_nonzero = false;
3060129e9cc3SRichard Henderson     if (tb->flags & 1) {
3061129e9cc3SRichard Henderson         ctx.null_cond.c = TCG_COND_ALWAYS;
3062129e9cc3SRichard Henderson         ctx.psw_n_nonzero = true;
3063129e9cc3SRichard Henderson     }
3064129e9cc3SRichard Henderson     ctx.null_lab = NULL;
3065129e9cc3SRichard Henderson 
306661766fe9SRichard Henderson     do {
306761766fe9SRichard Henderson         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
306861766fe9SRichard Henderson         num_insns++;
306961766fe9SRichard Henderson 
307061766fe9SRichard Henderson         if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
307161766fe9SRichard Henderson             ret = gen_excp(&ctx, EXCP_DEBUG);
307261766fe9SRichard Henderson             break;
307361766fe9SRichard Henderson         }
307461766fe9SRichard Henderson         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
307561766fe9SRichard Henderson             gen_io_start();
307661766fe9SRichard Henderson         }
307761766fe9SRichard Henderson 
30787ad439dfSRichard Henderson         if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
30797ad439dfSRichard Henderson             ret = do_page_zero(&ctx);
30807ad439dfSRichard Henderson             assert(ret != NO_EXIT);
30817ad439dfSRichard Henderson         } else {
308261766fe9SRichard Henderson             /* Always fetch the insn, even if nullified, so that we check
308361766fe9SRichard Henderson                the page permissions for execute.  */
308461766fe9SRichard Henderson             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
308561766fe9SRichard Henderson 
308661766fe9SRichard Henderson             /* Set up the IA queue for the next insn.
308761766fe9SRichard Henderson                This will be overwritten by a branch.  */
308861766fe9SRichard Henderson             if (ctx.iaoq_b == -1) {
308961766fe9SRichard Henderson                 ctx.iaoq_n = -1;
309061766fe9SRichard Henderson                 ctx.iaoq_n_var = get_temp(&ctx);
309161766fe9SRichard Henderson                 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
309261766fe9SRichard Henderson             } else {
309361766fe9SRichard Henderson                 ctx.iaoq_n = ctx.iaoq_b + 4;
309461766fe9SRichard Henderson                 TCGV_UNUSED(ctx.iaoq_n_var);
309561766fe9SRichard Henderson             }
309661766fe9SRichard Henderson 
3097129e9cc3SRichard Henderson             if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
3098129e9cc3SRichard Henderson                 ctx.null_cond.c = TCG_COND_NEVER;
3099129e9cc3SRichard Henderson                 ret = NO_EXIT;
3100129e9cc3SRichard Henderson             } else {
310161766fe9SRichard Henderson                 ret = translate_one(&ctx, insn);
3102129e9cc3SRichard Henderson                 assert(ctx.null_lab == NULL);
3103129e9cc3SRichard Henderson             }
310461766fe9SRichard Henderson         }
310561766fe9SRichard Henderson 
310661766fe9SRichard Henderson         for (i = 0; i < ctx.ntemps; ++i) {
310761766fe9SRichard Henderson             tcg_temp_free(ctx.temps[i]);
310861766fe9SRichard Henderson             TCGV_UNUSED(ctx.temps[i]);
310961766fe9SRichard Henderson         }
311061766fe9SRichard Henderson         ctx.ntemps = 0;
311161766fe9SRichard Henderson 
311261766fe9SRichard Henderson         /* If we see non-linear instructions, exhaust instruction count,
311361766fe9SRichard Henderson            or run out of buffer space, stop generation.  */
311461766fe9SRichard Henderson         /* ??? The non-linear instruction restriction is purely due to
311561766fe9SRichard Henderson            the debugging dump.  Otherwise we *could* follow unconditional
311661766fe9SRichard Henderson            branches within the same page.  */
311761766fe9SRichard Henderson         if (ret == NO_EXIT
311861766fe9SRichard Henderson             && (ctx.iaoq_b != ctx.iaoq_f + 4
311961766fe9SRichard Henderson                 || num_insns >= max_insns
312061766fe9SRichard Henderson                 || tcg_op_buf_full())) {
3121129e9cc3SRichard Henderson             if (ctx.null_cond.c == TCG_COND_NEVER
3122129e9cc3SRichard Henderson                 || ctx.null_cond.c == TCG_COND_ALWAYS) {
3123129e9cc3SRichard Henderson                 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
3124129e9cc3SRichard Henderson                 gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
3125129e9cc3SRichard Henderson                 ret = EXIT_GOTO_TB;
3126129e9cc3SRichard Henderson             } else {
312761766fe9SRichard Henderson                 ret = EXIT_IAQ_N_STALE;
312861766fe9SRichard Henderson             }
3129129e9cc3SRichard Henderson         }
313061766fe9SRichard Henderson 
313161766fe9SRichard Henderson         ctx.iaoq_f = ctx.iaoq_b;
313261766fe9SRichard Henderson         ctx.iaoq_b = ctx.iaoq_n;
313361766fe9SRichard Henderson         if (ret == EXIT_NORETURN
313461766fe9SRichard Henderson             || ret == EXIT_GOTO_TB
313561766fe9SRichard Henderson             || ret == EXIT_IAQ_N_UPDATED) {
313661766fe9SRichard Henderson             break;
313761766fe9SRichard Henderson         }
313861766fe9SRichard Henderson         if (ctx.iaoq_f == -1) {
313961766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
314061766fe9SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
3141129e9cc3SRichard Henderson             nullify_save(&ctx);
314261766fe9SRichard Henderson             ret = EXIT_IAQ_N_UPDATED;
314361766fe9SRichard Henderson             break;
314461766fe9SRichard Henderson         }
314561766fe9SRichard Henderson         if (ctx.iaoq_b == -1) {
314661766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
314761766fe9SRichard Henderson         }
314861766fe9SRichard Henderson     } while (ret == NO_EXIT);
314961766fe9SRichard Henderson 
315061766fe9SRichard Henderson     if (tb->cflags & CF_LAST_IO) {
315161766fe9SRichard Henderson         gen_io_end();
315261766fe9SRichard Henderson     }
315361766fe9SRichard Henderson 
315461766fe9SRichard Henderson     switch (ret) {
315561766fe9SRichard Henderson     case EXIT_GOTO_TB:
315661766fe9SRichard Henderson     case EXIT_NORETURN:
315761766fe9SRichard Henderson         break;
315861766fe9SRichard Henderson     case EXIT_IAQ_N_STALE:
315961766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
316061766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
3161129e9cc3SRichard Henderson         nullify_save(&ctx);
316261766fe9SRichard Henderson         /* FALLTHRU */
316361766fe9SRichard Henderson     case EXIT_IAQ_N_UPDATED:
316461766fe9SRichard Henderson         if (ctx.singlestep_enabled) {
316561766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
316661766fe9SRichard Henderson         } else {
316761766fe9SRichard Henderson             tcg_gen_exit_tb(0);
316861766fe9SRichard Henderson         }
316961766fe9SRichard Henderson         break;
317061766fe9SRichard Henderson     default:
317161766fe9SRichard Henderson         abort();
317261766fe9SRichard Henderson     }
317361766fe9SRichard Henderson 
317461766fe9SRichard Henderson     gen_tb_end(tb, num_insns);
317561766fe9SRichard Henderson 
317661766fe9SRichard Henderson     tb->size = num_insns * 4;
317761766fe9SRichard Henderson     tb->icount = num_insns;
317861766fe9SRichard Henderson 
317961766fe9SRichard Henderson #ifdef DEBUG_DISAS
318061766fe9SRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
318161766fe9SRichard Henderson         && qemu_log_in_addr_range(tb->pc)) {
318261766fe9SRichard Henderson         qemu_log_lock();
31837ad439dfSRichard Henderson         switch (tb->pc) {
31847ad439dfSRichard Henderson         case 0x00:
31857ad439dfSRichard Henderson             qemu_log("IN:\n0x00000000:  (null)\n\n");
31867ad439dfSRichard Henderson             break;
31877ad439dfSRichard Henderson         case 0xb0:
31887ad439dfSRichard Henderson             qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
31897ad439dfSRichard Henderson             break;
31907ad439dfSRichard Henderson         case 0xe0:
31917ad439dfSRichard Henderson             qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
31927ad439dfSRichard Henderson             break;
31937ad439dfSRichard Henderson         case 0x100:
31947ad439dfSRichard Henderson             qemu_log("IN:\n0x00000100:  syscall\n\n");
31957ad439dfSRichard Henderson             break;
31967ad439dfSRichard Henderson         default:
319761766fe9SRichard Henderson             qemu_log("IN: %s\n", lookup_symbol(tb->pc));
319861766fe9SRichard Henderson             log_target_disas(cs, tb->pc, tb->size, 1);
319961766fe9SRichard Henderson             qemu_log("\n");
32007ad439dfSRichard Henderson             break;
32017ad439dfSRichard Henderson         }
320261766fe9SRichard Henderson         qemu_log_unlock();
320361766fe9SRichard Henderson     }
320461766fe9SRichard Henderson #endif
320561766fe9SRichard Henderson }
320661766fe9SRichard Henderson 
320761766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
320861766fe9SRichard Henderson                           target_ulong *data)
320961766fe9SRichard Henderson {
321061766fe9SRichard Henderson     env->iaoq_f = data[0];
321161766fe9SRichard Henderson     if (data[1] != -1) {
321261766fe9SRichard Henderson         env->iaoq_b = data[1];
321361766fe9SRichard Henderson     }
321461766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
321561766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
321661766fe9SRichard Henderson        that the instruction was not nullified.  */
321761766fe9SRichard Henderson     env->psw_n = 0;
321861766fe9SRichard Henderson }
3219