xref: /openbmc/qemu/target/hppa/translate.c (revision 0b1347d259460a633e07e6bdae312992862238ba)
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 
281129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified.
282129e9cc3SRichard Henderson    Use this when the insn is too complex for a conditional move.  */
283129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx)
284129e9cc3SRichard Henderson {
285129e9cc3SRichard Henderson     if (ctx->null_cond.c != TCG_COND_NEVER) {
286129e9cc3SRichard Henderson         /* The always condition should have been handled in the main loop.  */
287129e9cc3SRichard Henderson         assert(ctx->null_cond.c != TCG_COND_ALWAYS);
288129e9cc3SRichard Henderson 
289129e9cc3SRichard Henderson         ctx->null_lab = gen_new_label();
290129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
291129e9cc3SRichard Henderson 
292129e9cc3SRichard Henderson         /* If we're using PSW[N], copy it to a temp because... */
293129e9cc3SRichard Henderson         if (ctx->null_cond.a0_is_n) {
294129e9cc3SRichard Henderson             ctx->null_cond.a0_is_n = false;
295129e9cc3SRichard Henderson             ctx->null_cond.a0 = tcg_temp_new();
296129e9cc3SRichard Henderson             tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
297129e9cc3SRichard Henderson         }
298129e9cc3SRichard Henderson         /* ... we clear it before branching over the implementation,
299129e9cc3SRichard Henderson            so that (1) it's clear after nullifying this insn and
300129e9cc3SRichard Henderson            (2) if this insn nullifies the next, PSW[N] is valid.  */
301129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
302129e9cc3SRichard Henderson             ctx->psw_n_nonzero = false;
303129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
304129e9cc3SRichard Henderson         }
305129e9cc3SRichard Henderson 
306129e9cc3SRichard Henderson         tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
307129e9cc3SRichard Henderson                           ctx->null_cond.a1, ctx->null_lab);
308129e9cc3SRichard Henderson         cond_free(&ctx->null_cond);
309129e9cc3SRichard Henderson     }
310129e9cc3SRichard Henderson }
311129e9cc3SRichard Henderson 
312129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N].  */
313129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx)
314129e9cc3SRichard Henderson {
315129e9cc3SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
316129e9cc3SRichard Henderson         if (ctx->psw_n_nonzero) {
317129e9cc3SRichard Henderson             tcg_gen_movi_tl(cpu_psw_n, 0);
318129e9cc3SRichard Henderson         }
319129e9cc3SRichard Henderson         return;
320129e9cc3SRichard Henderson     }
321129e9cc3SRichard Henderson     if (!ctx->null_cond.a0_is_n) {
322129e9cc3SRichard Henderson         cond_prep(&ctx->null_cond);
323129e9cc3SRichard Henderson         tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
324129e9cc3SRichard Henderson                            ctx->null_cond.a0, ctx->null_cond.a1);
325129e9cc3SRichard Henderson         ctx->psw_n_nonzero = true;
326129e9cc3SRichard Henderson     }
327129e9cc3SRichard Henderson     cond_free(&ctx->null_cond);
328129e9cc3SRichard Henderson }
329129e9cc3SRichard Henderson 
330129e9cc3SRichard Henderson /* Set a PSW[N] to X.  The intention is that this is used immediately
331129e9cc3SRichard Henderson    before a goto_tb/exit_tb, so that there is no fallthru path to other
332129e9cc3SRichard Henderson    code within the TB.  Therefore we do not update psw_n_nonzero.  */
333129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x)
334129e9cc3SRichard Henderson {
335129e9cc3SRichard Henderson     if (ctx->psw_n_nonzero || x) {
336129e9cc3SRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, x);
337129e9cc3SRichard Henderson     }
338129e9cc3SRichard Henderson }
339129e9cc3SRichard Henderson 
340129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified.
341129e9cc3SRichard Henderson    This is the pair to nullify_over.  */
342129e9cc3SRichard Henderson static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
343129e9cc3SRichard Henderson {
344129e9cc3SRichard Henderson     TCGLabel *null_lab = ctx->null_lab;
345129e9cc3SRichard Henderson 
346129e9cc3SRichard Henderson     if (likely(null_lab == NULL)) {
347129e9cc3SRichard Henderson         /* The current insn wasn't conditional or handled the condition
348129e9cc3SRichard Henderson            applied to it without a branch, so the (new) setting of
349129e9cc3SRichard Henderson            NULL_COND can be applied directly to the next insn.  */
350129e9cc3SRichard Henderson         return status;
351129e9cc3SRichard Henderson     }
352129e9cc3SRichard Henderson     ctx->null_lab = NULL;
353129e9cc3SRichard Henderson 
354129e9cc3SRichard Henderson     if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
355129e9cc3SRichard Henderson         /* The next instruction will be unconditional,
356129e9cc3SRichard Henderson            and NULL_COND already reflects that.  */
357129e9cc3SRichard Henderson         gen_set_label(null_lab);
358129e9cc3SRichard Henderson     } else {
359129e9cc3SRichard Henderson         /* The insn that we just executed is itself nullifying the next
360129e9cc3SRichard Henderson            instruction.  Store the condition in the PSW[N] global.
361129e9cc3SRichard Henderson            We asserted PSW[N] = 0 in nullify_over, so that after the
362129e9cc3SRichard Henderson            label we have the proper value in place.  */
363129e9cc3SRichard Henderson         nullify_save(ctx);
364129e9cc3SRichard Henderson         gen_set_label(null_lab);
365129e9cc3SRichard Henderson         ctx->null_cond = cond_make_n();
366129e9cc3SRichard Henderson     }
367129e9cc3SRichard Henderson 
368129e9cc3SRichard Henderson     assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
369129e9cc3SRichard Henderson     if (status == EXIT_NORETURN) {
370129e9cc3SRichard Henderson         status = NO_EXIT;
371129e9cc3SRichard Henderson     }
372129e9cc3SRichard Henderson     return status;
373129e9cc3SRichard Henderson }
374129e9cc3SRichard Henderson 
37561766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
37661766fe9SRichard Henderson {
37761766fe9SRichard Henderson     if (unlikely(ival == -1)) {
37861766fe9SRichard Henderson         tcg_gen_mov_tl(dest, vval);
37961766fe9SRichard Henderson     } else {
38061766fe9SRichard Henderson         tcg_gen_movi_tl(dest, ival);
38161766fe9SRichard Henderson     }
38261766fe9SRichard Henderson }
38361766fe9SRichard Henderson 
38461766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
38561766fe9SRichard Henderson {
38661766fe9SRichard Henderson     return ctx->iaoq_f + disp + 8;
38761766fe9SRichard Henderson }
38861766fe9SRichard Henderson 
38961766fe9SRichard Henderson static void gen_excp_1(int exception)
39061766fe9SRichard Henderson {
39161766fe9SRichard Henderson     TCGv_i32 t = tcg_const_i32(exception);
39261766fe9SRichard Henderson     gen_helper_excp(cpu_env, t);
39361766fe9SRichard Henderson     tcg_temp_free_i32(t);
39461766fe9SRichard Henderson }
39561766fe9SRichard Henderson 
39661766fe9SRichard Henderson static ExitStatus gen_excp(DisasContext *ctx, int exception)
39761766fe9SRichard Henderson {
39861766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
39961766fe9SRichard Henderson     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
400129e9cc3SRichard Henderson     nullify_save(ctx);
40161766fe9SRichard Henderson     gen_excp_1(exception);
40261766fe9SRichard Henderson     return EXIT_NORETURN;
40361766fe9SRichard Henderson }
40461766fe9SRichard Henderson 
40561766fe9SRichard Henderson static ExitStatus gen_illegal(DisasContext *ctx)
40661766fe9SRichard Henderson {
407129e9cc3SRichard Henderson     nullify_over(ctx);
408129e9cc3SRichard Henderson     return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
40961766fe9SRichard Henderson }
41061766fe9SRichard Henderson 
41161766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
41261766fe9SRichard Henderson {
41361766fe9SRichard Henderson     /* Suppress goto_tb in the case of single-steping and IO.  */
41461766fe9SRichard Henderson     if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
41561766fe9SRichard Henderson         return false;
41661766fe9SRichard Henderson     }
41761766fe9SRichard Henderson     return true;
41861766fe9SRichard Henderson }
41961766fe9SRichard Henderson 
420129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page,
421129e9cc3SRichard Henderson    and we're not attempting to set a breakpoint on it, then we can
422129e9cc3SRichard Henderson    totally skip the nullified insn.  This avoids creating and
423129e9cc3SRichard Henderson    executing a TB that merely branches to the next TB.  */
424129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx)
425129e9cc3SRichard Henderson {
426129e9cc3SRichard Henderson     return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
427129e9cc3SRichard Henderson             && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
428129e9cc3SRichard Henderson }
429129e9cc3SRichard Henderson 
43061766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which,
43161766fe9SRichard Henderson                         target_ulong f, target_ulong b)
43261766fe9SRichard Henderson {
43361766fe9SRichard Henderson     if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
43461766fe9SRichard Henderson         tcg_gen_goto_tb(which);
43561766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_f, f);
43661766fe9SRichard Henderson         tcg_gen_movi_tl(cpu_iaoq_b, b);
43761766fe9SRichard Henderson         tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
43861766fe9SRichard Henderson     } else {
43961766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
44061766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
44161766fe9SRichard Henderson         if (ctx->singlestep_enabled) {
44261766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
44361766fe9SRichard Henderson         } else {
44461766fe9SRichard Henderson             tcg_gen_exit_tb(0);
44561766fe9SRichard Henderson         }
44661766fe9SRichard Henderson     }
44761766fe9SRichard Henderson }
44861766fe9SRichard Henderson 
449b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
450b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
451b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
452b2167459SRichard Henderson {
453b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
454b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
455b2167459SRichard Henderson     return x;
456b2167459SRichard Henderson }
457b2167459SRichard Henderson 
45898cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn)
45998cd9ca7SRichard Henderson {
46098cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
46198cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
46298cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
46398cd9ca7SRichard Henderson     return x;
46498cd9ca7SRichard Henderson }
46598cd9ca7SRichard Henderson 
466b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
467b2167459SRichard Henderson {
468b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
469b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
470b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
471b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
472b2167459SRichard Henderson }
473b2167459SRichard Henderson 
47498cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn)
47598cd9ca7SRichard Henderson {
47698cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
47798cd9ca7SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
47898cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
47998cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
48098cd9ca7SRichard Henderson     return x << 2;
48198cd9ca7SRichard Henderson }
48298cd9ca7SRichard Henderson 
483b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
484b2167459SRichard Henderson {
485b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
486b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
487b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
488b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
489b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
490b2167459SRichard Henderson     return x << 11;
491b2167459SRichard Henderson }
492b2167459SRichard Henderson 
49398cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn)
49498cd9ca7SRichard Henderson {
49598cd9ca7SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
49698cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 16, 10);
49798cd9ca7SRichard Henderson     x = (x <<  1) | extract32(insn, 2, 1);
49898cd9ca7SRichard Henderson     x = (x << 10) | extract32(insn, 3, 10);
49998cd9ca7SRichard Henderson     return x << 2;
50098cd9ca7SRichard Henderson }
50198cd9ca7SRichard Henderson 
502b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
503b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
504b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
505b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
506b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
507b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
508b2167459SRichard Henderson 
509b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
510b2167459SRichard Henderson {
511b2167459SRichard Henderson     DisasCond cond;
512b2167459SRichard Henderson     TCGv tmp;
513b2167459SRichard Henderson 
514b2167459SRichard Henderson     switch (cf >> 1) {
515b2167459SRichard Henderson     case 0: /* Never / TR */
516b2167459SRichard Henderson         cond = cond_make_f();
517b2167459SRichard Henderson         break;
518b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
519b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
520b2167459SRichard Henderson         break;
521b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
522b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
523b2167459SRichard Henderson         break;
524b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
525b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
526b2167459SRichard Henderson         break;
527b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
528b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
529b2167459SRichard Henderson         break;
530b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
531b2167459SRichard Henderson         tmp = tcg_temp_new();
532b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
533b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
534b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
535b2167459SRichard Henderson         tcg_temp_free(tmp);
536b2167459SRichard Henderson         break;
537b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
538b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
539b2167459SRichard Henderson         break;
540b2167459SRichard Henderson     case 7: /* OD / EV */
541b2167459SRichard Henderson         tmp = tcg_temp_new();
542b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
543b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
544b2167459SRichard Henderson         tcg_temp_free(tmp);
545b2167459SRichard Henderson         break;
546b2167459SRichard Henderson     default:
547b2167459SRichard Henderson         g_assert_not_reached();
548b2167459SRichard Henderson     }
549b2167459SRichard Henderson     if (cf & 1) {
550b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
551b2167459SRichard Henderson     }
552b2167459SRichard Henderson 
553b2167459SRichard Henderson     return cond;
554b2167459SRichard Henderson }
555b2167459SRichard Henderson 
556b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
557b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
558b2167459SRichard Henderson    deleted as unused.  */
559b2167459SRichard Henderson 
560b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
561b2167459SRichard Henderson {
562b2167459SRichard Henderson     DisasCond cond;
563b2167459SRichard Henderson 
564b2167459SRichard Henderson     switch (cf >> 1) {
565b2167459SRichard Henderson     case 1: /* = / <> */
566b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
567b2167459SRichard Henderson         break;
568b2167459SRichard Henderson     case 2: /* < / >= */
569b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
570b2167459SRichard Henderson         break;
571b2167459SRichard Henderson     case 3: /* <= / > */
572b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
573b2167459SRichard Henderson         break;
574b2167459SRichard Henderson     case 4: /* << / >>= */
575b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
576b2167459SRichard Henderson         break;
577b2167459SRichard Henderson     case 5: /* <<= / >> */
578b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
579b2167459SRichard Henderson         break;
580b2167459SRichard Henderson     default:
581b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
582b2167459SRichard Henderson     }
583b2167459SRichard Henderson     if (cf & 1) {
584b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
585b2167459SRichard Henderson     }
586b2167459SRichard Henderson 
587b2167459SRichard Henderson     return cond;
588b2167459SRichard Henderson }
589b2167459SRichard Henderson 
590b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
591b2167459SRichard Henderson    computed, and use of them is undefined.  */
592b2167459SRichard Henderson 
593b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
594b2167459SRichard Henderson {
595b2167459SRichard Henderson     switch (cf >> 1) {
596b2167459SRichard Henderson     case 4: case 5: case 6:
597b2167459SRichard Henderson         cf &= 1;
598b2167459SRichard Henderson         break;
599b2167459SRichard Henderson     }
600b2167459SRichard Henderson     return do_cond(cf, res, res, res);
601b2167459SRichard Henderson }
602b2167459SRichard Henderson 
60398cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions.  */
60498cd9ca7SRichard Henderson 
60598cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res)
60698cd9ca7SRichard Henderson {
60798cd9ca7SRichard Henderson     unsigned c, f;
60898cd9ca7SRichard Henderson 
60998cd9ca7SRichard Henderson     /* Convert the compressed condition codes to standard.
61098cd9ca7SRichard Henderson        0-2 are the same as logicals (nv,<,<=), while 3 is OD.
61198cd9ca7SRichard Henderson        4-7 are the reverse of 0-3.  */
61298cd9ca7SRichard Henderson     c = orig & 3;
61398cd9ca7SRichard Henderson     if (c == 3) {
61498cd9ca7SRichard Henderson         c = 7;
61598cd9ca7SRichard Henderson     }
61698cd9ca7SRichard Henderson     f = (orig & 4) / 4;
61798cd9ca7SRichard Henderson 
61898cd9ca7SRichard Henderson     return do_log_cond(c * 2 + f, res);
61998cd9ca7SRichard Henderson }
62098cd9ca7SRichard Henderson 
621b2167459SRichard Henderson /* Similar, but for unit conditions.  */
622b2167459SRichard Henderson 
623b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
624b2167459SRichard Henderson {
625b2167459SRichard Henderson     DisasCond cond;
626b2167459SRichard Henderson     TCGv tmp, cb;
627b2167459SRichard Henderson 
628b2167459SRichard Henderson     TCGV_UNUSED(cb);
629b2167459SRichard Henderson     if (cf & 8) {
630b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
631b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
632b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
633b2167459SRichard Henderson          */
634b2167459SRichard Henderson         cb = tcg_temp_new();
635b2167459SRichard Henderson         tmp = tcg_temp_new();
636b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
637b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
638b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
639b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
640b2167459SRichard Henderson         tcg_temp_free(tmp);
641b2167459SRichard Henderson     }
642b2167459SRichard Henderson 
643b2167459SRichard Henderson     switch (cf >> 1) {
644b2167459SRichard Henderson     case 0: /* never / TR */
645b2167459SRichard Henderson     case 1: /* undefined */
646b2167459SRichard Henderson     case 5: /* undefined */
647b2167459SRichard Henderson         cond = cond_make_f();
648b2167459SRichard Henderson         break;
649b2167459SRichard Henderson 
650b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
651b2167459SRichard Henderson         /* See hasless(v,1) from
652b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
653b2167459SRichard Henderson          */
654b2167459SRichard Henderson         tmp = tcg_temp_new();
655b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
656b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
657b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
658b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
659b2167459SRichard Henderson         tcg_temp_free(tmp);
660b2167459SRichard Henderson         break;
661b2167459SRichard Henderson 
662b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
663b2167459SRichard Henderson         tmp = tcg_temp_new();
664b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
665b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
666b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
667b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
668b2167459SRichard Henderson         tcg_temp_free(tmp);
669b2167459SRichard Henderson         break;
670b2167459SRichard Henderson 
671b2167459SRichard Henderson     case 4: /* SDC / NDC */
672b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
673b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
674b2167459SRichard Henderson         break;
675b2167459SRichard Henderson 
676b2167459SRichard Henderson     case 6: /* SBC / NBC */
677b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
678b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
679b2167459SRichard Henderson         break;
680b2167459SRichard Henderson 
681b2167459SRichard Henderson     case 7: /* SHC / NHC */
682b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
683b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
684b2167459SRichard Henderson         break;
685b2167459SRichard Henderson 
686b2167459SRichard Henderson     default:
687b2167459SRichard Henderson         g_assert_not_reached();
688b2167459SRichard Henderson     }
689b2167459SRichard Henderson     if (cf & 8) {
690b2167459SRichard Henderson         tcg_temp_free(cb);
691b2167459SRichard Henderson     }
692b2167459SRichard Henderson     if (cf & 1) {
693b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
694b2167459SRichard Henderson     }
695b2167459SRichard Henderson 
696b2167459SRichard Henderson     return cond;
697b2167459SRichard Henderson }
698b2167459SRichard Henderson 
699b2167459SRichard Henderson /* Compute signed overflow for addition.  */
700b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
701b2167459SRichard Henderson {
702b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
703b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
704b2167459SRichard Henderson 
705b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
706b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
707b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
708b2167459SRichard Henderson     tcg_temp_free(tmp);
709b2167459SRichard Henderson 
710b2167459SRichard Henderson     return sv;
711b2167459SRichard Henderson }
712b2167459SRichard Henderson 
713b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
714b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
715b2167459SRichard Henderson {
716b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
717b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
718b2167459SRichard Henderson 
719b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
720b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
721b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
722b2167459SRichard Henderson     tcg_temp_free(tmp);
723b2167459SRichard Henderson 
724b2167459SRichard Henderson     return sv;
725b2167459SRichard Henderson }
726b2167459SRichard Henderson 
727b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
728b2167459SRichard Henderson                          unsigned shift, bool is_l, bool is_tsv, bool is_tc,
729b2167459SRichard Henderson                          bool is_c, unsigned cf)
730b2167459SRichard Henderson {
731b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
732b2167459SRichard Henderson     unsigned c = cf >> 1;
733b2167459SRichard Henderson     DisasCond cond;
734b2167459SRichard Henderson 
735b2167459SRichard Henderson     dest = tcg_temp_new();
736b2167459SRichard Henderson     TCGV_UNUSED(cb);
737b2167459SRichard Henderson     TCGV_UNUSED(cb_msb);
738b2167459SRichard Henderson 
739b2167459SRichard Henderson     if (shift) {
740b2167459SRichard Henderson         tmp = get_temp(ctx);
741b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
742b2167459SRichard Henderson         in1 = tmp;
743b2167459SRichard Henderson     }
744b2167459SRichard Henderson 
745b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
746b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
747b2167459SRichard Henderson         cb_msb = get_temp(ctx);
748b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
749b2167459SRichard Henderson         if (is_c) {
750b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
751b2167459SRichard Henderson         }
752b2167459SRichard Henderson         tcg_temp_free(zero);
753b2167459SRichard Henderson         if (!is_l) {
754b2167459SRichard Henderson             cb = get_temp(ctx);
755b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
756b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
757b2167459SRichard Henderson         }
758b2167459SRichard Henderson     } else {
759b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
760b2167459SRichard Henderson         if (is_c) {
761b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
762b2167459SRichard Henderson         }
763b2167459SRichard Henderson     }
764b2167459SRichard Henderson 
765b2167459SRichard Henderson     /* Compute signed overflow if required.  */
766b2167459SRichard Henderson     TCGV_UNUSED(sv);
767b2167459SRichard Henderson     if (is_tsv || c == 6) {
768b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
769b2167459SRichard Henderson         if (is_tsv) {
770b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
771b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
772b2167459SRichard Henderson         }
773b2167459SRichard Henderson     }
774b2167459SRichard Henderson 
775b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
776b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
777b2167459SRichard Henderson     if (is_tc) {
778b2167459SRichard Henderson         cond_prep(&cond);
779b2167459SRichard Henderson         tmp = tcg_temp_new();
780b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
781b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
782b2167459SRichard Henderson         tcg_temp_free(tmp);
783b2167459SRichard Henderson     }
784b2167459SRichard Henderson 
785b2167459SRichard Henderson     /* Write back the result.  */
786b2167459SRichard Henderson     if (!is_l) {
787b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
788b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
789b2167459SRichard Henderson     }
790b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
791b2167459SRichard Henderson     tcg_temp_free(dest);
792b2167459SRichard Henderson 
793b2167459SRichard Henderson     /* Install the new nullification.  */
794b2167459SRichard Henderson     cond_free(&ctx->null_cond);
795b2167459SRichard Henderson     ctx->null_cond = cond;
796b2167459SRichard Henderson     return NO_EXIT;
797b2167459SRichard Henderson }
798b2167459SRichard Henderson 
799b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
800b2167459SRichard Henderson                          bool is_tsv, bool is_b, bool is_tc, unsigned cf)
801b2167459SRichard Henderson {
802b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
803b2167459SRichard Henderson     unsigned c = cf >> 1;
804b2167459SRichard Henderson     DisasCond cond;
805b2167459SRichard Henderson 
806b2167459SRichard Henderson     dest = tcg_temp_new();
807b2167459SRichard Henderson     cb = tcg_temp_new();
808b2167459SRichard Henderson     cb_msb = tcg_temp_new();
809b2167459SRichard Henderson 
810b2167459SRichard Henderson     zero = tcg_const_tl(0);
811b2167459SRichard Henderson     if (is_b) {
812b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
813b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
814b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
815b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
816b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
817b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
818b2167459SRichard Henderson     } else {
819b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
820b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
821b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
822b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
823b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
824b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
825b2167459SRichard Henderson     }
826b2167459SRichard Henderson     tcg_temp_free(zero);
827b2167459SRichard Henderson 
828b2167459SRichard Henderson     /* Compute signed overflow if required.  */
829b2167459SRichard Henderson     TCGV_UNUSED(sv);
830b2167459SRichard Henderson     if (is_tsv || c == 6) {
831b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
832b2167459SRichard Henderson         if (is_tsv) {
833b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
834b2167459SRichard Henderson         }
835b2167459SRichard Henderson     }
836b2167459SRichard Henderson 
837b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
838b2167459SRichard Henderson     if (!is_b) {
839b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
840b2167459SRichard Henderson     } else {
841b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
842b2167459SRichard Henderson     }
843b2167459SRichard Henderson 
844b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
845b2167459SRichard Henderson     if (is_tc) {
846b2167459SRichard Henderson         cond_prep(&cond);
847b2167459SRichard Henderson         tmp = tcg_temp_new();
848b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
849b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
850b2167459SRichard Henderson         tcg_temp_free(tmp);
851b2167459SRichard Henderson     }
852b2167459SRichard Henderson 
853b2167459SRichard Henderson     /* Write back the result.  */
854b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
855b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
856b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
857b2167459SRichard Henderson     tcg_temp_free(dest);
858b2167459SRichard Henderson 
859b2167459SRichard Henderson     /* Install the new nullification.  */
860b2167459SRichard Henderson     cond_free(&ctx->null_cond);
861b2167459SRichard Henderson     ctx->null_cond = cond;
862b2167459SRichard Henderson     return NO_EXIT;
863b2167459SRichard Henderson }
864b2167459SRichard Henderson 
865b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
866b2167459SRichard Henderson                             TCGv in2, unsigned cf)
867b2167459SRichard Henderson {
868b2167459SRichard Henderson     TCGv dest, sv;
869b2167459SRichard Henderson     DisasCond cond;
870b2167459SRichard Henderson 
871b2167459SRichard Henderson     dest = tcg_temp_new();
872b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
873b2167459SRichard Henderson 
874b2167459SRichard Henderson     /* Compute signed overflow if required.  */
875b2167459SRichard Henderson     TCGV_UNUSED(sv);
876b2167459SRichard Henderson     if ((cf >> 1) == 6) {
877b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
878b2167459SRichard Henderson     }
879b2167459SRichard Henderson 
880b2167459SRichard Henderson     /* Form the condition for the compare.  */
881b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
882b2167459SRichard Henderson 
883b2167459SRichard Henderson     /* Clear.  */
884b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
885b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
886b2167459SRichard Henderson     tcg_temp_free(dest);
887b2167459SRichard Henderson 
888b2167459SRichard Henderson     /* Install the new nullification.  */
889b2167459SRichard Henderson     cond_free(&ctx->null_cond);
890b2167459SRichard Henderson     ctx->null_cond = cond;
891b2167459SRichard Henderson     return NO_EXIT;
892b2167459SRichard Henderson }
893b2167459SRichard Henderson 
894b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
895b2167459SRichard Henderson                          unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
896b2167459SRichard Henderson {
897b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
898b2167459SRichard Henderson 
899b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
900b2167459SRichard Henderson     fn(dest, in1, in2);
901b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
902b2167459SRichard Henderson 
903b2167459SRichard Henderson     /* Install the new nullification.  */
904b2167459SRichard Henderson     cond_free(&ctx->null_cond);
905b2167459SRichard Henderson     if (cf) {
906b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
907b2167459SRichard Henderson     }
908b2167459SRichard Henderson     return NO_EXIT;
909b2167459SRichard Henderson }
910b2167459SRichard Henderson 
911b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
912b2167459SRichard Henderson                           TCGv in2, unsigned cf, bool is_tc,
913b2167459SRichard Henderson                           void (*fn)(TCGv, TCGv, TCGv))
914b2167459SRichard Henderson {
915b2167459SRichard Henderson     TCGv dest;
916b2167459SRichard Henderson     DisasCond cond;
917b2167459SRichard Henderson 
918b2167459SRichard Henderson     if (cf == 0) {
919b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
920b2167459SRichard Henderson         fn(dest, in1, in2);
921b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
922b2167459SRichard Henderson         cond_free(&ctx->null_cond);
923b2167459SRichard Henderson     } else {
924b2167459SRichard Henderson         dest = tcg_temp_new();
925b2167459SRichard Henderson         fn(dest, in1, in2);
926b2167459SRichard Henderson 
927b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
928b2167459SRichard Henderson 
929b2167459SRichard Henderson         if (is_tc) {
930b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
931b2167459SRichard Henderson             cond_prep(&cond);
932b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
933b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
934b2167459SRichard Henderson             tcg_temp_free(tmp);
935b2167459SRichard Henderson         }
936b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
937b2167459SRichard Henderson 
938b2167459SRichard Henderson         cond_free(&ctx->null_cond);
939b2167459SRichard Henderson         ctx->null_cond = cond;
940b2167459SRichard Henderson     }
941b2167459SRichard Henderson     return NO_EXIT;
942b2167459SRichard Henderson }
943b2167459SRichard Henderson 
94498cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not
94598cd9ca7SRichard Henderson    have already had nullification handled.  */
94698cd9ca7SRichard Henderson static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
94798cd9ca7SRichard Henderson                              unsigned link, bool is_n)
94898cd9ca7SRichard Henderson {
94998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
95098cd9ca7SRichard Henderson         if (link != 0) {
95198cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
95298cd9ca7SRichard Henderson         }
95398cd9ca7SRichard Henderson         ctx->iaoq_n = dest;
95498cd9ca7SRichard Henderson         if (is_n) {
95598cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
95698cd9ca7SRichard Henderson         }
95798cd9ca7SRichard Henderson         return NO_EXIT;
95898cd9ca7SRichard Henderson     } else {
95998cd9ca7SRichard Henderson         nullify_over(ctx);
96098cd9ca7SRichard Henderson 
96198cd9ca7SRichard Henderson         if (link != 0) {
96298cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
96398cd9ca7SRichard Henderson         }
96498cd9ca7SRichard Henderson 
96598cd9ca7SRichard Henderson         if (is_n && use_nullify_skip(ctx)) {
96698cd9ca7SRichard Henderson             nullify_set(ctx, 0);
96798cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, dest, dest + 4);
96898cd9ca7SRichard Henderson         } else {
96998cd9ca7SRichard Henderson             nullify_set(ctx, is_n);
97098cd9ca7SRichard Henderson             gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
97198cd9ca7SRichard Henderson         }
97298cd9ca7SRichard Henderson 
97398cd9ca7SRichard Henderson         nullify_end(ctx, NO_EXIT);
97498cd9ca7SRichard Henderson 
97598cd9ca7SRichard Henderson         nullify_set(ctx, 0);
97698cd9ca7SRichard Henderson         gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
97798cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
97898cd9ca7SRichard Henderson     }
97998cd9ca7SRichard Henderson }
98098cd9ca7SRichard Henderson 
98198cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target.  If the branch itself
98298cd9ca7SRichard Henderson    is nullified, we should have already used nullify_over.  */
98398cd9ca7SRichard Henderson static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
98498cd9ca7SRichard Henderson                              DisasCond *cond)
98598cd9ca7SRichard Henderson {
98698cd9ca7SRichard Henderson     target_ulong dest = iaoq_dest(ctx, disp);
98798cd9ca7SRichard Henderson     TCGLabel *taken = NULL;
98898cd9ca7SRichard Henderson     TCGCond c = cond->c;
98998cd9ca7SRichard Henderson     int which = 0;
99098cd9ca7SRichard Henderson     bool n;
99198cd9ca7SRichard Henderson 
99298cd9ca7SRichard Henderson     assert(ctx->null_cond.c == TCG_COND_NEVER);
99398cd9ca7SRichard Henderson 
99498cd9ca7SRichard Henderson     /* Handle TRUE and NEVER as direct branches.  */
99598cd9ca7SRichard Henderson     if (c == TCG_COND_ALWAYS) {
99698cd9ca7SRichard Henderson         return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
99798cd9ca7SRichard Henderson     }
99898cd9ca7SRichard Henderson     if (c == TCG_COND_NEVER) {
99998cd9ca7SRichard Henderson         return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
100098cd9ca7SRichard Henderson     }
100198cd9ca7SRichard Henderson 
100298cd9ca7SRichard Henderson     taken = gen_new_label();
100398cd9ca7SRichard Henderson     cond_prep(cond);
100498cd9ca7SRichard Henderson     tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
100598cd9ca7SRichard Henderson     cond_free(cond);
100698cd9ca7SRichard Henderson 
100798cd9ca7SRichard Henderson     /* Not taken: Condition not satisfied; nullify on backward branches. */
100898cd9ca7SRichard Henderson     n = is_n && disp < 0;
100998cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
101098cd9ca7SRichard Henderson         nullify_set(ctx, 0);
101198cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4);
101298cd9ca7SRichard Henderson     } else {
101398cd9ca7SRichard Henderson         if (!n && ctx->null_lab) {
101498cd9ca7SRichard Henderson             gen_set_label(ctx->null_lab);
101598cd9ca7SRichard Henderson             ctx->null_lab = NULL;
101698cd9ca7SRichard Henderson         }
101798cd9ca7SRichard Henderson         nullify_set(ctx, n);
101898cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n);
101998cd9ca7SRichard Henderson     }
102098cd9ca7SRichard Henderson 
102198cd9ca7SRichard Henderson     gen_set_label(taken);
102298cd9ca7SRichard Henderson 
102398cd9ca7SRichard Henderson     /* Taken: Condition satisfied; nullify on forward branches.  */
102498cd9ca7SRichard Henderson     n = is_n && disp >= 0;
102598cd9ca7SRichard Henderson     if (n && use_nullify_skip(ctx)) {
102698cd9ca7SRichard Henderson         nullify_set(ctx, 0);
102798cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, dest, dest + 4);
102898cd9ca7SRichard Henderson     } else {
102998cd9ca7SRichard Henderson         nullify_set(ctx, n);
103098cd9ca7SRichard Henderson         gen_goto_tb(ctx, which++, ctx->iaoq_b, dest);
103198cd9ca7SRichard Henderson     }
103298cd9ca7SRichard Henderson 
103398cd9ca7SRichard Henderson     /* Not taken: the branch itself was nullified.  */
103498cd9ca7SRichard Henderson     if (ctx->null_lab) {
103598cd9ca7SRichard Henderson         gen_set_label(ctx->null_lab);
103698cd9ca7SRichard Henderson         ctx->null_lab = NULL;
103798cd9ca7SRichard Henderson         if (which < 2) {
103898cd9ca7SRichard Henderson             nullify_set(ctx, 0);
103998cd9ca7SRichard Henderson             gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n);
104098cd9ca7SRichard Henderson             return EXIT_GOTO_TB;
104198cd9ca7SRichard Henderson         } else {
104298cd9ca7SRichard Henderson             return EXIT_IAQ_N_STALE;
104398cd9ca7SRichard Henderson         }
104498cd9ca7SRichard Henderson     } else {
104598cd9ca7SRichard Henderson         return EXIT_GOTO_TB;
104698cd9ca7SRichard Henderson     }
104798cd9ca7SRichard Henderson }
104898cd9ca7SRichard Henderson 
104998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target.  This handles
105098cd9ca7SRichard Henderson    nullification of the branch itself.  */
105198cd9ca7SRichard Henderson static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
105298cd9ca7SRichard Henderson                              unsigned link, bool is_n)
105398cd9ca7SRichard Henderson {
105498cd9ca7SRichard Henderson     TCGv a0, a1, next, tmp;
105598cd9ca7SRichard Henderson     TCGCond c;
105698cd9ca7SRichard Henderson 
105798cd9ca7SRichard Henderson     assert(ctx->null_lab == NULL);
105898cd9ca7SRichard Henderson 
105998cd9ca7SRichard Henderson     if (ctx->null_cond.c == TCG_COND_NEVER) {
106098cd9ca7SRichard Henderson         if (link != 0) {
106198cd9ca7SRichard Henderson             copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
106298cd9ca7SRichard Henderson         }
106398cd9ca7SRichard Henderson         next = get_temp(ctx);
106498cd9ca7SRichard Henderson         tcg_gen_mov_tl(next, dest);
106598cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
106698cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
106798cd9ca7SRichard Henderson         if (is_n) {
106898cd9ca7SRichard Henderson             ctx->null_cond.c = TCG_COND_ALWAYS;
106998cd9ca7SRichard Henderson         }
107098cd9ca7SRichard Henderson     } else if (is_n && use_nullify_skip(ctx)) {
107198cd9ca7SRichard Henderson         /* The (conditional) branch, B, nullifies the next insn, N,
107298cd9ca7SRichard Henderson            and we're allowed to skip execution N (no single-step or
107398cd9ca7SRichard Henderson            tracepoint in effect).  Since the exit_tb that we must use
107498cd9ca7SRichard Henderson            for the indirect branch consumes no special resources, we
107598cd9ca7SRichard Henderson            can (conditionally) skip B and continue execution.  */
107698cd9ca7SRichard Henderson         /* The use_nullify_skip test implies we have a known control path.  */
107798cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_b != -1);
107898cd9ca7SRichard Henderson         tcg_debug_assert(ctx->iaoq_n != -1);
107998cd9ca7SRichard Henderson 
108098cd9ca7SRichard Henderson         /* We do have to handle the non-local temporary, DEST, before
108198cd9ca7SRichard Henderson            branching.  Since IOAQ_F is not really live at this point, we
108298cd9ca7SRichard Henderson            can simply store DEST optimistically.  Similarly with IAOQ_B.  */
108398cd9ca7SRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, dest);
108498cd9ca7SRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
108598cd9ca7SRichard Henderson 
108698cd9ca7SRichard Henderson         nullify_over(ctx);
108798cd9ca7SRichard Henderson         if (link != 0) {
108898cd9ca7SRichard Henderson             tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
108998cd9ca7SRichard Henderson         }
109098cd9ca7SRichard Henderson         tcg_gen_exit_tb(0);
109198cd9ca7SRichard Henderson         return nullify_end(ctx, NO_EXIT);
109298cd9ca7SRichard Henderson     } else {
109398cd9ca7SRichard Henderson         cond_prep(&ctx->null_cond);
109498cd9ca7SRichard Henderson         c = ctx->null_cond.c;
109598cd9ca7SRichard Henderson         a0 = ctx->null_cond.a0;
109698cd9ca7SRichard Henderson         a1 = ctx->null_cond.a1;
109798cd9ca7SRichard Henderson 
109898cd9ca7SRichard Henderson         tmp = tcg_temp_new();
109998cd9ca7SRichard Henderson         next = get_temp(ctx);
110098cd9ca7SRichard Henderson 
110198cd9ca7SRichard Henderson         copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
110298cd9ca7SRichard Henderson         tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
110398cd9ca7SRichard Henderson         ctx->iaoq_n = -1;
110498cd9ca7SRichard Henderson         ctx->iaoq_n_var = next;
110598cd9ca7SRichard Henderson 
110698cd9ca7SRichard Henderson         if (link != 0) {
110798cd9ca7SRichard Henderson             tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
110898cd9ca7SRichard Henderson         }
110998cd9ca7SRichard Henderson 
111098cd9ca7SRichard Henderson         if (is_n) {
111198cd9ca7SRichard Henderson             /* The branch nullifies the next insn, which means the state of N
111298cd9ca7SRichard Henderson                after the branch is the inverse of the state of N that applied
111398cd9ca7SRichard Henderson                to the branch.  */
111498cd9ca7SRichard Henderson             tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
111598cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
111698cd9ca7SRichard Henderson             ctx->null_cond = cond_make_n();
111798cd9ca7SRichard Henderson             ctx->psw_n_nonzero = true;
111898cd9ca7SRichard Henderson         } else {
111998cd9ca7SRichard Henderson             cond_free(&ctx->null_cond);
112098cd9ca7SRichard Henderson         }
112198cd9ca7SRichard Henderson     }
112298cd9ca7SRichard Henderson 
112398cd9ca7SRichard Henderson     return NO_EXIT;
112498cd9ca7SRichard Henderson }
112598cd9ca7SRichard Henderson 
11267ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway.
11277ad439dfSRichard Henderson    Therefore normal read or write is supposed to fail, but specific
11287ad439dfSRichard Henderson    offsets have kernel code mapped to raise permissions to implement
11297ad439dfSRichard Henderson    system calls.  Handling this via an explicit check here, rather
11307ad439dfSRichard Henderson    in than the "be disp(sr2,r0)" instruction that probably sent us
11317ad439dfSRichard Henderson    here, is the easiest way to handle the branch delay slot on the
11327ad439dfSRichard Henderson    aforementioned BE.  */
11337ad439dfSRichard Henderson static ExitStatus do_page_zero(DisasContext *ctx)
11347ad439dfSRichard Henderson {
11357ad439dfSRichard Henderson     /* If by some means we get here with PSW[N]=1, that implies that
11367ad439dfSRichard Henderson        the B,GATE instruction would be skipped, and we'd fault on the
11377ad439dfSRichard Henderson        next insn within the privilaged page.  */
11387ad439dfSRichard Henderson     switch (ctx->null_cond.c) {
11397ad439dfSRichard Henderson     case TCG_COND_NEVER:
11407ad439dfSRichard Henderson         break;
11417ad439dfSRichard Henderson     case TCG_COND_ALWAYS:
11427ad439dfSRichard Henderson         tcg_gen_movi_tl(cpu_psw_n, 0);
11437ad439dfSRichard Henderson         goto do_sigill;
11447ad439dfSRichard Henderson     default:
11457ad439dfSRichard Henderson         /* Since this is always the first (and only) insn within the
11467ad439dfSRichard Henderson            TB, we should know the state of PSW[N] from TB->FLAGS.  */
11477ad439dfSRichard Henderson         g_assert_not_reached();
11487ad439dfSRichard Henderson     }
11497ad439dfSRichard Henderson 
11507ad439dfSRichard Henderson     /* Check that we didn't arrive here via some means that allowed
11517ad439dfSRichard Henderson        non-sequential instruction execution.  Normally the PSW[B] bit
11527ad439dfSRichard Henderson        detects this by disallowing the B,GATE instruction to execute
11537ad439dfSRichard Henderson        under such conditions.  */
11547ad439dfSRichard Henderson     if (ctx->iaoq_b != ctx->iaoq_f + 4) {
11557ad439dfSRichard Henderson         goto do_sigill;
11567ad439dfSRichard Henderson     }
11577ad439dfSRichard Henderson 
11587ad439dfSRichard Henderson     switch (ctx->iaoq_f) {
11597ad439dfSRichard Henderson     case 0x00: /* Null pointer call */
11607ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGSEGV);
11617ad439dfSRichard Henderson         return EXIT_NORETURN;
11627ad439dfSRichard Henderson 
11637ad439dfSRichard Henderson     case 0xb0: /* LWS */
11647ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL_LWS);
11657ad439dfSRichard Henderson         return EXIT_NORETURN;
11667ad439dfSRichard Henderson 
11677ad439dfSRichard Henderson     case 0xe0: /* SET_THREAD_POINTER */
11687ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
11697ad439dfSRichard Henderson         tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
11707ad439dfSRichard Henderson         tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
11717ad439dfSRichard Henderson         return EXIT_IAQ_N_UPDATED;
11727ad439dfSRichard Henderson 
11737ad439dfSRichard Henderson     case 0x100: /* SYSCALL */
11747ad439dfSRichard Henderson         gen_excp_1(EXCP_SYSCALL);
11757ad439dfSRichard Henderson         return EXIT_NORETURN;
11767ad439dfSRichard Henderson 
11777ad439dfSRichard Henderson     default:
11787ad439dfSRichard Henderson     do_sigill:
11797ad439dfSRichard Henderson         gen_excp_1(EXCP_SIGILL);
11807ad439dfSRichard Henderson         return EXIT_NORETURN;
11817ad439dfSRichard Henderson     }
11827ad439dfSRichard Henderson }
11837ad439dfSRichard Henderson 
1184b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
1185b2167459SRichard Henderson                             const DisasInsn *di)
1186b2167459SRichard Henderson {
1187b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1188b2167459SRichard Henderson     return NO_EXIT;
1189b2167459SRichard Henderson }
1190b2167459SRichard Henderson 
1191b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
1192b2167459SRichard Henderson                             const DisasInsn *di)
1193b2167459SRichard Henderson {
1194b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1195b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1196b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1197b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
1198b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
1199b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1200b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1201b2167459SRichard Henderson     bool is_c = false;
1202b2167459SRichard Henderson     bool is_l = false;
1203b2167459SRichard Henderson     bool is_tc = false;
1204b2167459SRichard Henderson     bool is_tsv = false;
1205b2167459SRichard Henderson     ExitStatus ret;
1206b2167459SRichard Henderson 
1207b2167459SRichard Henderson     switch (ext) {
1208b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
1209b2167459SRichard Henderson         break;
1210b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
1211b2167459SRichard Henderson         is_l = true;
1212b2167459SRichard Henderson         break;
1213b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1214b2167459SRichard Henderson         is_tsv = true;
1215b2167459SRichard Henderson         break;
1216b2167459SRichard Henderson     case 0x7: /* ADD,C */
1217b2167459SRichard Henderson         is_c = true;
1218b2167459SRichard Henderson         break;
1219b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
1220b2167459SRichard Henderson         is_c = is_tsv = true;
1221b2167459SRichard Henderson         break;
1222b2167459SRichard Henderson     default:
1223b2167459SRichard Henderson         return gen_illegal(ctx);
1224b2167459SRichard Henderson     }
1225b2167459SRichard Henderson 
1226b2167459SRichard Henderson     if (cf) {
1227b2167459SRichard Henderson         nullify_over(ctx);
1228b2167459SRichard Henderson     }
1229b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1230b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1231b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1232b2167459SRichard Henderson     return nullify_end(ctx, ret);
1233b2167459SRichard Henderson }
1234b2167459SRichard Henderson 
1235b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
1236b2167459SRichard Henderson                             const DisasInsn *di)
1237b2167459SRichard Henderson {
1238b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1239b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1240b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1241b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
1242b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1243b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1244b2167459SRichard Henderson     bool is_b = false;
1245b2167459SRichard Henderson     bool is_tc = false;
1246b2167459SRichard Henderson     bool is_tsv = false;
1247b2167459SRichard Henderson     ExitStatus ret;
1248b2167459SRichard Henderson 
1249b2167459SRichard Henderson     switch (ext) {
1250b2167459SRichard Henderson     case 0x10: /* SUB */
1251b2167459SRichard Henderson         break;
1252b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
1253b2167459SRichard Henderson         is_tsv = true;
1254b2167459SRichard Henderson         break;
1255b2167459SRichard Henderson     case 0x14: /* SUB,B */
1256b2167459SRichard Henderson         is_b = true;
1257b2167459SRichard Henderson         break;
1258b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
1259b2167459SRichard Henderson         is_b = is_tsv = true;
1260b2167459SRichard Henderson         break;
1261b2167459SRichard Henderson     case 0x13: /* SUB,TC */
1262b2167459SRichard Henderson         is_tc = true;
1263b2167459SRichard Henderson         break;
1264b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
1265b2167459SRichard Henderson         is_tc = is_tsv = true;
1266b2167459SRichard Henderson         break;
1267b2167459SRichard Henderson     default:
1268b2167459SRichard Henderson         return gen_illegal(ctx);
1269b2167459SRichard Henderson     }
1270b2167459SRichard Henderson 
1271b2167459SRichard Henderson     if (cf) {
1272b2167459SRichard Henderson         nullify_over(ctx);
1273b2167459SRichard Henderson     }
1274b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1275b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1276b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1277b2167459SRichard Henderson     return nullify_end(ctx, ret);
1278b2167459SRichard Henderson }
1279b2167459SRichard Henderson 
1280b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
1281b2167459SRichard Henderson                             const DisasInsn *di)
1282b2167459SRichard Henderson {
1283b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1284b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1285b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1286b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1287b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1288b2167459SRichard Henderson     ExitStatus ret;
1289b2167459SRichard Henderson 
1290b2167459SRichard Henderson     if (cf) {
1291b2167459SRichard Henderson         nullify_over(ctx);
1292b2167459SRichard Henderson     }
1293b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1294b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1295b2167459SRichard Henderson     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt);
1296b2167459SRichard Henderson     return nullify_end(ctx, ret);
1297b2167459SRichard Henderson }
1298b2167459SRichard Henderson 
1299b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1300b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1301b2167459SRichard Henderson                              const DisasInsn *di)
1302b2167459SRichard Henderson {
1303b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1304b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1305b2167459SRichard Henderson 
1306b2167459SRichard Henderson     if (r1 == 0) {
1307b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1308b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1309b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1310b2167459SRichard Henderson     } else {
1311b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1312b2167459SRichard Henderson     }
1313b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1314b2167459SRichard Henderson     return NO_EXIT;
1315b2167459SRichard Henderson }
1316b2167459SRichard Henderson 
1317b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1318b2167459SRichard Henderson                                const DisasInsn *di)
1319b2167459SRichard Henderson {
1320b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1321b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1322b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1323b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1324b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1325b2167459SRichard Henderson     ExitStatus ret;
1326b2167459SRichard Henderson 
1327b2167459SRichard Henderson     if (cf) {
1328b2167459SRichard Henderson         nullify_over(ctx);
1329b2167459SRichard Henderson     }
1330b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1331b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1332b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1333b2167459SRichard Henderson     return nullify_end(ctx, ret);
1334b2167459SRichard Henderson }
1335b2167459SRichard Henderson 
1336b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1337b2167459SRichard Henderson                              const DisasInsn *di)
1338b2167459SRichard Henderson {
1339b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1340b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1341b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1342b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1343b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1344b2167459SRichard Henderson     ExitStatus ret;
1345b2167459SRichard Henderson 
1346b2167459SRichard Henderson     if (cf) {
1347b2167459SRichard Henderson         nullify_over(ctx);
1348b2167459SRichard Henderson     }
1349b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1350b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1351b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1352b2167459SRichard Henderson     return nullify_end(ctx, ret);
1353b2167459SRichard Henderson }
1354b2167459SRichard Henderson 
1355b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1356b2167459SRichard Henderson                                const DisasInsn *di)
1357b2167459SRichard Henderson {
1358b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1359b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1360b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1361b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
1362b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1363b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
1364b2167459SRichard Henderson     ExitStatus ret;
1365b2167459SRichard Henderson 
1366b2167459SRichard Henderson     if (cf) {
1367b2167459SRichard Henderson         nullify_over(ctx);
1368b2167459SRichard Henderson     }
1369b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1370b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1371b2167459SRichard Henderson     tmp = get_temp(ctx);
1372b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
1373b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
1374b2167459SRichard Henderson     return nullify_end(ctx, ret);
1375b2167459SRichard Henderson }
1376b2167459SRichard Henderson 
1377b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
1378b2167459SRichard Henderson                              const DisasInsn *di)
1379b2167459SRichard Henderson {
1380b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1381b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1382b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
1383b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1384b2167459SRichard Henderson     TCGv tmp;
1385b2167459SRichard Henderson     ExitStatus ret;
1386b2167459SRichard Henderson 
1387b2167459SRichard Henderson     nullify_over(ctx);
1388b2167459SRichard Henderson 
1389b2167459SRichard Henderson     tmp = get_temp(ctx);
1390b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
1391b2167459SRichard Henderson     if (!is_i) {
1392b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
1393b2167459SRichard Henderson     }
1394b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
1395b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
1396b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
1397b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
1398b2167459SRichard Henderson 
1399b2167459SRichard Henderson     return nullify_end(ctx, ret);
1400b2167459SRichard Henderson }
1401b2167459SRichard Henderson 
1402b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
1403b2167459SRichard Henderson                            const DisasInsn *di)
1404b2167459SRichard Henderson {
1405b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1406b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1407b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1408b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1409b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
1410b2167459SRichard Henderson 
1411b2167459SRichard Henderson     nullify_over(ctx);
1412b2167459SRichard Henderson 
1413b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
1414b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
1415b2167459SRichard Henderson 
1416b2167459SRichard Henderson     add1 = tcg_temp_new();
1417b2167459SRichard Henderson     add2 = tcg_temp_new();
1418b2167459SRichard Henderson     addc = tcg_temp_new();
1419b2167459SRichard Henderson     dest = tcg_temp_new();
1420b2167459SRichard Henderson     zero = tcg_const_tl(0);
1421b2167459SRichard Henderson 
1422b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
1423b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
1424b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
1425b2167459SRichard Henderson 
1426b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
1427b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
1428b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
1429b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
1430b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
1431b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
1432b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
1433b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
1434b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
1435b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
1436b2167459SRichard Henderson 
1437b2167459SRichard Henderson     tcg_temp_free(addc);
1438b2167459SRichard Henderson     tcg_temp_free(zero);
1439b2167459SRichard Henderson 
1440b2167459SRichard Henderson     /* Write back the result register.  */
1441b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1442b2167459SRichard Henderson 
1443b2167459SRichard Henderson     /* Write back PSW[CB].  */
1444b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
1445b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
1446b2167459SRichard Henderson 
1447b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
1448b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
1449b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
1450b2167459SRichard Henderson 
1451b2167459SRichard Henderson     /* Install the new nullification.  */
1452b2167459SRichard Henderson     if (cf) {
1453b2167459SRichard Henderson         TCGv sv;
1454b2167459SRichard Henderson         TCGV_UNUSED(sv);
1455b2167459SRichard Henderson         if (cf >> 1 == 6) {
1456b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
1457b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
1458b2167459SRichard Henderson         }
1459b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
1460b2167459SRichard Henderson     }
1461b2167459SRichard Henderson 
1462b2167459SRichard Henderson     tcg_temp_free(add1);
1463b2167459SRichard Henderson     tcg_temp_free(add2);
1464b2167459SRichard Henderson     tcg_temp_free(dest);
1465b2167459SRichard Henderson 
1466b2167459SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1467b2167459SRichard Henderson }
1468b2167459SRichard Henderson 
1469b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
1470b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
1471b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
1472b2167459SRichard Henderson     { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl },
1473b2167459SRichard Henderson     { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl },
1474b2167459SRichard Henderson     { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl },
1475b2167459SRichard Henderson     { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl },
1476b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
1477b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
1478b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
1479b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
1480b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
1481b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
1482b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
1483b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
1484b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
1485b2167459SRichard Henderson };
1486b2167459SRichard Henderson 
1487b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
1488b2167459SRichard Henderson {
1489b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1490b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1491b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1492b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1493b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1494b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
1495b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1496b2167459SRichard Henderson     ExitStatus ret;
1497b2167459SRichard Henderson 
1498b2167459SRichard Henderson     if (cf) {
1499b2167459SRichard Henderson         nullify_over(ctx);
1500b2167459SRichard Henderson     }
1501b2167459SRichard Henderson 
1502b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1503b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1504b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
1505b2167459SRichard Henderson 
1506b2167459SRichard Henderson     return nullify_end(ctx, ret);
1507b2167459SRichard Henderson }
1508b2167459SRichard Henderson 
1509b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
1510b2167459SRichard Henderson {
1511b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1512b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1513b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1514b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1515b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1516b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1517b2167459SRichard Henderson     ExitStatus ret;
1518b2167459SRichard Henderson 
1519b2167459SRichard Henderson     if (cf) {
1520b2167459SRichard Henderson         nullify_over(ctx);
1521b2167459SRichard Henderson     }
1522b2167459SRichard Henderson 
1523b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1524b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1525b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
1526b2167459SRichard Henderson 
1527b2167459SRichard Henderson     return nullify_end(ctx, ret);
1528b2167459SRichard Henderson }
1529b2167459SRichard Henderson 
1530b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
1531b2167459SRichard Henderson {
1532b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1533b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1534b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1535b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1536b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1537b2167459SRichard Henderson     ExitStatus ret;
1538b2167459SRichard Henderson 
1539b2167459SRichard Henderson     if (cf) {
1540b2167459SRichard Henderson         nullify_over(ctx);
1541b2167459SRichard Henderson     }
1542b2167459SRichard Henderson 
1543b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1544b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1545b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
1546b2167459SRichard Henderson 
1547b2167459SRichard Henderson     return nullify_end(ctx, ret);
1548b2167459SRichard Henderson }
1549b2167459SRichard Henderson 
1550b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
1551b2167459SRichard Henderson {
1552b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1553b2167459SRichard Henderson     target_long i = assemble_21(insn);
1554b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
1555b2167459SRichard Henderson 
1556b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
1557b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
1558b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1559b2167459SRichard Henderson 
1560b2167459SRichard Henderson     return NO_EXIT;
1561b2167459SRichard Henderson }
1562b2167459SRichard Henderson 
1563b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
1564b2167459SRichard Henderson {
1565b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1566b2167459SRichard Henderson     target_long i = assemble_21(insn);
1567b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
1568b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
1569b2167459SRichard Henderson 
1570b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
1571b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
1572b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1573b2167459SRichard Henderson 
1574b2167459SRichard Henderson     return NO_EXIT;
1575b2167459SRichard Henderson }
1576b2167459SRichard Henderson 
1577b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
1578b2167459SRichard Henderson {
1579b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
1580b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1581b2167459SRichard Henderson     target_long i = assemble_16(insn);
1582b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
1583b2167459SRichard Henderson 
1584b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
1585b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
1586b2167459SRichard Henderson     if (rb == 0) {
1587b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
1588b2167459SRichard Henderson     } else {
1589b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
1590b2167459SRichard Henderson     }
1591b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
1592b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1593b2167459SRichard Henderson 
1594b2167459SRichard Henderson     return NO_EXIT;
1595b2167459SRichard Henderson }
1596b2167459SRichard Henderson 
159798cd9ca7SRichard Henderson static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
159898cd9ca7SRichard Henderson                              bool is_true, bool is_imm, bool is_dw)
159998cd9ca7SRichard Henderson {
160098cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
160198cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
160298cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
160398cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
160498cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
160598cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv;
160698cd9ca7SRichard Henderson     DisasCond cond;
160798cd9ca7SRichard Henderson 
160898cd9ca7SRichard Henderson     nullify_over(ctx);
160998cd9ca7SRichard Henderson 
161098cd9ca7SRichard Henderson     if (is_imm) {
161198cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
161298cd9ca7SRichard Henderson     } else {
161398cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
161498cd9ca7SRichard Henderson     }
161598cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
161698cd9ca7SRichard Henderson     dest = get_temp(ctx);
161798cd9ca7SRichard Henderson 
161898cd9ca7SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
161998cd9ca7SRichard Henderson 
162098cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
162198cd9ca7SRichard Henderson     if (c == 6) {
162298cd9ca7SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
162398cd9ca7SRichard Henderson     }
162498cd9ca7SRichard Henderson 
162598cd9ca7SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
162698cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
162798cd9ca7SRichard Henderson }
162898cd9ca7SRichard Henderson 
162998cd9ca7SRichard Henderson static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
163098cd9ca7SRichard Henderson                              bool is_true, bool is_imm)
163198cd9ca7SRichard Henderson {
163298cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
163398cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
163498cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
163598cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
163698cd9ca7SRichard Henderson     unsigned cf = c * 2 + !is_true;
163798cd9ca7SRichard Henderson     TCGv dest, in1, in2, sv, cb_msb;
163898cd9ca7SRichard Henderson     DisasCond cond;
163998cd9ca7SRichard Henderson 
164098cd9ca7SRichard Henderson     nullify_over(ctx);
164198cd9ca7SRichard Henderson 
164298cd9ca7SRichard Henderson     if (is_imm) {
164398cd9ca7SRichard Henderson         in1 = load_const(ctx, low_sextract(insn, 16, 5));
164498cd9ca7SRichard Henderson     } else {
164598cd9ca7SRichard Henderson         in1 = load_gpr(ctx, extract32(insn, 16, 5));
164698cd9ca7SRichard Henderson     }
164798cd9ca7SRichard Henderson     in2 = load_gpr(ctx, r);
164898cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
164998cd9ca7SRichard Henderson     TCGV_UNUSED(sv);
165098cd9ca7SRichard Henderson     TCGV_UNUSED(cb_msb);
165198cd9ca7SRichard Henderson 
165298cd9ca7SRichard Henderson     switch (c) {
165398cd9ca7SRichard Henderson     default:
165498cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
165598cd9ca7SRichard Henderson         break;
165698cd9ca7SRichard Henderson     case 4: case 5:
165798cd9ca7SRichard Henderson         cb_msb = get_temp(ctx);
165898cd9ca7SRichard Henderson         tcg_gen_movi_tl(cb_msb, 0);
165998cd9ca7SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
166098cd9ca7SRichard Henderson         break;
166198cd9ca7SRichard Henderson     case 6:
166298cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
166398cd9ca7SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
166498cd9ca7SRichard Henderson         break;
166598cd9ca7SRichard Henderson     }
166698cd9ca7SRichard Henderson 
166798cd9ca7SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
166898cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
166998cd9ca7SRichard Henderson }
167098cd9ca7SRichard Henderson 
167198cd9ca7SRichard Henderson static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
167298cd9ca7SRichard Henderson {
167398cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
167498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
167598cd9ca7SRichard Henderson     unsigned c = extract32(insn, 15, 1);
167698cd9ca7SRichard Henderson     unsigned r = extract32(insn, 16, 5);
167798cd9ca7SRichard Henderson     unsigned p = extract32(insn, 21, 5);
167898cd9ca7SRichard Henderson     unsigned i = extract32(insn, 26, 1);
167998cd9ca7SRichard Henderson     TCGv tmp, tcg_r;
168098cd9ca7SRichard Henderson     DisasCond cond;
168198cd9ca7SRichard Henderson 
168298cd9ca7SRichard Henderson     nullify_over(ctx);
168398cd9ca7SRichard Henderson 
168498cd9ca7SRichard Henderson     tmp = tcg_temp_new();
168598cd9ca7SRichard Henderson     tcg_r = load_gpr(ctx, r);
168698cd9ca7SRichard Henderson     if (i) {
168798cd9ca7SRichard Henderson         tcg_gen_shli_tl(tmp, tcg_r, p);
168898cd9ca7SRichard Henderson     } else {
168998cd9ca7SRichard Henderson         tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
169098cd9ca7SRichard Henderson     }
169198cd9ca7SRichard Henderson 
169298cd9ca7SRichard Henderson     cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
169398cd9ca7SRichard Henderson     tcg_temp_free(tmp);
169498cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
169598cd9ca7SRichard Henderson }
169698cd9ca7SRichard Henderson 
169798cd9ca7SRichard Henderson static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
169898cd9ca7SRichard Henderson {
169998cd9ca7SRichard Henderson     target_long disp = assemble_12(insn) * 4;
170098cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
170198cd9ca7SRichard Henderson     unsigned c = extract32(insn, 13, 3);
170298cd9ca7SRichard Henderson     unsigned t = extract32(insn, 16, 5);
170398cd9ca7SRichard Henderson     unsigned r = extract32(insn, 21, 5);
170498cd9ca7SRichard Henderson     TCGv dest;
170598cd9ca7SRichard Henderson     DisasCond cond;
170698cd9ca7SRichard Henderson 
170798cd9ca7SRichard Henderson     nullify_over(ctx);
170898cd9ca7SRichard Henderson 
170998cd9ca7SRichard Henderson     dest = dest_gpr(ctx, r);
171098cd9ca7SRichard Henderson     if (is_imm) {
171198cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
171298cd9ca7SRichard Henderson     } else if (t == 0) {
171398cd9ca7SRichard Henderson         tcg_gen_movi_tl(dest, 0);
171498cd9ca7SRichard Henderson     } else {
171598cd9ca7SRichard Henderson         tcg_gen_mov_tl(dest, cpu_gr[t]);
171698cd9ca7SRichard Henderson     }
171798cd9ca7SRichard Henderson 
171898cd9ca7SRichard Henderson     cond = do_sed_cond(c, dest);
171998cd9ca7SRichard Henderson     return do_cbranch(ctx, disp, n, &cond);
172098cd9ca7SRichard Henderson }
172198cd9ca7SRichard Henderson 
1722*0b1347d2SRichard Henderson static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
1723*0b1347d2SRichard Henderson                                  const DisasInsn *di)
1724*0b1347d2SRichard Henderson {
1725*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1726*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1727*0b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1728*0b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1729*0b1347d2SRichard Henderson     TCGv dest;
1730*0b1347d2SRichard Henderson 
1731*0b1347d2SRichard Henderson     if (c) {
1732*0b1347d2SRichard Henderson         nullify_over(ctx);
1733*0b1347d2SRichard Henderson     }
1734*0b1347d2SRichard Henderson 
1735*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1736*0b1347d2SRichard Henderson     if (r1 == 0) {
1737*0b1347d2SRichard Henderson         tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
1738*0b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, dest, cpu_sar);
1739*0b1347d2SRichard Henderson     } else if (r1 == r2) {
1740*0b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
1741*0b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
1742*0b1347d2SRichard Henderson         tcg_gen_rotr_i32(t32, t32, cpu_sar);
1743*0b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
1744*0b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
1745*0b1347d2SRichard Henderson     } else {
1746*0b1347d2SRichard Henderson         TCGv_i64 t = tcg_temp_new_i64();
1747*0b1347d2SRichard Henderson         TCGv_i64 s = tcg_temp_new_i64();
1748*0b1347d2SRichard Henderson 
1749*0b1347d2SRichard Henderson         tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
1750*0b1347d2SRichard Henderson         tcg_gen_extu_tl_i64(s, cpu_sar);
1751*0b1347d2SRichard Henderson         tcg_gen_shr_i64(t, t, s);
1752*0b1347d2SRichard Henderson         tcg_gen_trunc_i64_tl(dest, t);
1753*0b1347d2SRichard Henderson 
1754*0b1347d2SRichard Henderson         tcg_temp_free_i64(t);
1755*0b1347d2SRichard Henderson         tcg_temp_free_i64(s);
1756*0b1347d2SRichard Henderson     }
1757*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1758*0b1347d2SRichard Henderson 
1759*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1760*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1761*0b1347d2SRichard Henderson     if (c) {
1762*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1763*0b1347d2SRichard Henderson     }
1764*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1765*0b1347d2SRichard Henderson }
1766*0b1347d2SRichard Henderson 
1767*0b1347d2SRichard Henderson static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
1768*0b1347d2SRichard Henderson                                   const DisasInsn *di)
1769*0b1347d2SRichard Henderson {
1770*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 0, 5);
1771*0b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
1772*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1773*0b1347d2SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1774*0b1347d2SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1775*0b1347d2SRichard Henderson     unsigned sa = 31 - cpos;
1776*0b1347d2SRichard Henderson     TCGv dest, t2;
1777*0b1347d2SRichard Henderson 
1778*0b1347d2SRichard Henderson     if (c) {
1779*0b1347d2SRichard Henderson         nullify_over(ctx);
1780*0b1347d2SRichard Henderson     }
1781*0b1347d2SRichard Henderson 
1782*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1783*0b1347d2SRichard Henderson     t2 = load_gpr(ctx, r2);
1784*0b1347d2SRichard Henderson     if (r1 == r2) {
1785*0b1347d2SRichard Henderson         TCGv_i32 t32 = tcg_temp_new_i32();
1786*0b1347d2SRichard Henderson         tcg_gen_trunc_tl_i32(t32, t2);
1787*0b1347d2SRichard Henderson         tcg_gen_rotri_i32(t32, t32, sa);
1788*0b1347d2SRichard Henderson         tcg_gen_extu_i32_tl(dest, t32);
1789*0b1347d2SRichard Henderson         tcg_temp_free_i32(t32);
1790*0b1347d2SRichard Henderson     } else if (r1 == 0) {
1791*0b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
1792*0b1347d2SRichard Henderson     } else {
1793*0b1347d2SRichard Henderson         TCGv t0 = tcg_temp_new();
1794*0b1347d2SRichard Henderson         tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
1795*0b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
1796*0b1347d2SRichard Henderson         tcg_temp_free(t0);
1797*0b1347d2SRichard Henderson     }
1798*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1799*0b1347d2SRichard Henderson 
1800*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1801*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1802*0b1347d2SRichard Henderson     if (c) {
1803*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1804*0b1347d2SRichard Henderson     }
1805*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1806*0b1347d2SRichard Henderson }
1807*0b1347d2SRichard Henderson 
1808*0b1347d2SRichard Henderson static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
1809*0b1347d2SRichard Henderson                                   const DisasInsn *di)
1810*0b1347d2SRichard Henderson {
1811*0b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
1812*0b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
1813*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1814*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1815*0b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
1816*0b1347d2SRichard Henderson     unsigned len = 32 - clen;
1817*0b1347d2SRichard Henderson     TCGv dest, src, tmp;
1818*0b1347d2SRichard Henderson 
1819*0b1347d2SRichard Henderson     if (c) {
1820*0b1347d2SRichard Henderson         nullify_over(ctx);
1821*0b1347d2SRichard Henderson     }
1822*0b1347d2SRichard Henderson 
1823*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1824*0b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
1825*0b1347d2SRichard Henderson     tmp = tcg_temp_new();
1826*0b1347d2SRichard Henderson 
1827*0b1347d2SRichard Henderson     /* Recall that SAR is using big-endian bit numbering.  */
1828*0b1347d2SRichard Henderson     tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
1829*0b1347d2SRichard Henderson     if (is_se) {
1830*0b1347d2SRichard Henderson         tcg_gen_sar_tl(dest, src, tmp);
1831*0b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, dest, 0, len);
1832*0b1347d2SRichard Henderson     } else {
1833*0b1347d2SRichard Henderson         tcg_gen_shr_tl(dest, src, tmp);
1834*0b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, dest, 0, len);
1835*0b1347d2SRichard Henderson     }
1836*0b1347d2SRichard Henderson     tcg_temp_free(tmp);
1837*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1838*0b1347d2SRichard Henderson 
1839*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1840*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1841*0b1347d2SRichard Henderson     if (c) {
1842*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1843*0b1347d2SRichard Henderson     }
1844*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1845*0b1347d2SRichard Henderson }
1846*0b1347d2SRichard Henderson 
1847*0b1347d2SRichard Henderson static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
1848*0b1347d2SRichard Henderson                                   const DisasInsn *di)
1849*0b1347d2SRichard Henderson {
1850*0b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
1851*0b1347d2SRichard Henderson     unsigned pos = extract32(insn, 5, 5);
1852*0b1347d2SRichard Henderson     unsigned is_se = extract32(insn, 10, 1);
1853*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1854*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1855*0b1347d2SRichard Henderson     unsigned rr = extract32(insn, 21, 5);
1856*0b1347d2SRichard Henderson     unsigned len = 32 - clen;
1857*0b1347d2SRichard Henderson     unsigned cpos = 31 - pos;
1858*0b1347d2SRichard Henderson     TCGv dest, src;
1859*0b1347d2SRichard Henderson 
1860*0b1347d2SRichard Henderson     if (c) {
1861*0b1347d2SRichard Henderson         nullify_over(ctx);
1862*0b1347d2SRichard Henderson     }
1863*0b1347d2SRichard Henderson 
1864*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1865*0b1347d2SRichard Henderson     src = load_gpr(ctx, rr);
1866*0b1347d2SRichard Henderson     if (is_se) {
1867*0b1347d2SRichard Henderson         tcg_gen_sextract_tl(dest, src, cpos, len);
1868*0b1347d2SRichard Henderson     } else {
1869*0b1347d2SRichard Henderson         tcg_gen_extract_tl(dest, src, cpos, len);
1870*0b1347d2SRichard Henderson     }
1871*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1872*0b1347d2SRichard Henderson 
1873*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1874*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1875*0b1347d2SRichard Henderson     if (c) {
1876*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1877*0b1347d2SRichard Henderson     }
1878*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1879*0b1347d2SRichard Henderson }
1880*0b1347d2SRichard Henderson 
1881*0b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = {
1882*0b1347d2SRichard Henderson     { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
1883*0b1347d2SRichard Henderson     { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
1884*0b1347d2SRichard Henderson     { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
1885*0b1347d2SRichard Henderson     { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
1886*0b1347d2SRichard Henderson };
1887*0b1347d2SRichard Henderson 
1888*0b1347d2SRichard Henderson static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
1889*0b1347d2SRichard Henderson                                    const DisasInsn *di)
1890*0b1347d2SRichard Henderson {
1891*0b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
1892*0b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
1893*0b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
1894*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1895*0b1347d2SRichard Henderson     target_long val = low_sextract(insn, 16, 5);
1896*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1897*0b1347d2SRichard Henderson     unsigned len = 32 - clen;
1898*0b1347d2SRichard Henderson     target_long mask0, mask1;
1899*0b1347d2SRichard Henderson     TCGv dest;
1900*0b1347d2SRichard Henderson 
1901*0b1347d2SRichard Henderson     if (c) {
1902*0b1347d2SRichard Henderson         nullify_over(ctx);
1903*0b1347d2SRichard Henderson     }
1904*0b1347d2SRichard Henderson     if (cpos + len > 32) {
1905*0b1347d2SRichard Henderson         len = 32 - cpos;
1906*0b1347d2SRichard Henderson     }
1907*0b1347d2SRichard Henderson 
1908*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1909*0b1347d2SRichard Henderson     mask0 = deposit64(0, cpos, len, val);
1910*0b1347d2SRichard Henderson     mask1 = deposit64(-1, cpos, len, val);
1911*0b1347d2SRichard Henderson 
1912*0b1347d2SRichard Henderson     if (nz) {
1913*0b1347d2SRichard Henderson         TCGv src = load_gpr(ctx, rt);
1914*0b1347d2SRichard Henderson         if (mask1 != -1) {
1915*0b1347d2SRichard Henderson             tcg_gen_andi_tl(dest, src, mask1);
1916*0b1347d2SRichard Henderson             src = dest;
1917*0b1347d2SRichard Henderson         }
1918*0b1347d2SRichard Henderson         tcg_gen_ori_tl(dest, src, mask0);
1919*0b1347d2SRichard Henderson     } else {
1920*0b1347d2SRichard Henderson         tcg_gen_movi_tl(dest, mask0);
1921*0b1347d2SRichard Henderson     }
1922*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1923*0b1347d2SRichard Henderson 
1924*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1925*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1926*0b1347d2SRichard Henderson     if (c) {
1927*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1928*0b1347d2SRichard Henderson     }
1929*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1930*0b1347d2SRichard Henderson }
1931*0b1347d2SRichard Henderson 
1932*0b1347d2SRichard Henderson static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
1933*0b1347d2SRichard Henderson                                  const DisasInsn *di)
1934*0b1347d2SRichard Henderson {
1935*0b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
1936*0b1347d2SRichard Henderson     unsigned cpos = extract32(insn, 5, 5);
1937*0b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
1938*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1939*0b1347d2SRichard Henderson     unsigned rr = extract32(insn, 16, 5);
1940*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1941*0b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
1942*0b1347d2SRichard Henderson     unsigned len = 32 - clen;
1943*0b1347d2SRichard Henderson     TCGv dest, val;
1944*0b1347d2SRichard Henderson 
1945*0b1347d2SRichard Henderson     if (c) {
1946*0b1347d2SRichard Henderson         nullify_over(ctx);
1947*0b1347d2SRichard Henderson     }
1948*0b1347d2SRichard Henderson     if (cpos + len > 32) {
1949*0b1347d2SRichard Henderson         len = 32 - cpos;
1950*0b1347d2SRichard Henderson     }
1951*0b1347d2SRichard Henderson 
1952*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1953*0b1347d2SRichard Henderson     val = load_gpr(ctx, rr);
1954*0b1347d2SRichard Henderson     if (rs == 0) {
1955*0b1347d2SRichard Henderson         tcg_gen_deposit_z_tl(dest, val, cpos, len);
1956*0b1347d2SRichard Henderson     } else {
1957*0b1347d2SRichard Henderson         tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
1958*0b1347d2SRichard Henderson     }
1959*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
1960*0b1347d2SRichard Henderson 
1961*0b1347d2SRichard Henderson     /* Install the new nullification.  */
1962*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
1963*0b1347d2SRichard Henderson     if (c) {
1964*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
1965*0b1347d2SRichard Henderson     }
1966*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1967*0b1347d2SRichard Henderson }
1968*0b1347d2SRichard Henderson 
1969*0b1347d2SRichard Henderson static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
1970*0b1347d2SRichard Henderson                                  const DisasInsn *di)
1971*0b1347d2SRichard Henderson {
1972*0b1347d2SRichard Henderson     unsigned clen = extract32(insn, 0, 5);
1973*0b1347d2SRichard Henderson     unsigned nz = extract32(insn, 10, 1);
1974*0b1347d2SRichard Henderson     unsigned i = extract32(insn, 12, 1);
1975*0b1347d2SRichard Henderson     unsigned c = extract32(insn, 13, 3);
1976*0b1347d2SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1977*0b1347d2SRichard Henderson     unsigned rs = nz ? rt : 0;
1978*0b1347d2SRichard Henderson     unsigned len = 32 - clen;
1979*0b1347d2SRichard Henderson     TCGv val, mask, tmp, shift, dest;
1980*0b1347d2SRichard Henderson     unsigned msb = 1U << (len - 1);
1981*0b1347d2SRichard Henderson 
1982*0b1347d2SRichard Henderson     if (c) {
1983*0b1347d2SRichard Henderson         nullify_over(ctx);
1984*0b1347d2SRichard Henderson     }
1985*0b1347d2SRichard Henderson 
1986*0b1347d2SRichard Henderson     if (i) {
1987*0b1347d2SRichard Henderson         val = load_const(ctx, low_sextract(insn, 16, 5));
1988*0b1347d2SRichard Henderson     } else {
1989*0b1347d2SRichard Henderson         val = load_gpr(ctx, extract32(insn, 16, 5));
1990*0b1347d2SRichard Henderson     }
1991*0b1347d2SRichard Henderson     dest = dest_gpr(ctx, rt);
1992*0b1347d2SRichard Henderson     shift = tcg_temp_new();
1993*0b1347d2SRichard Henderson     tmp = tcg_temp_new();
1994*0b1347d2SRichard Henderson 
1995*0b1347d2SRichard Henderson     /* Convert big-endian bit numbering in SAR to left-shift.  */
1996*0b1347d2SRichard Henderson     tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
1997*0b1347d2SRichard Henderson 
1998*0b1347d2SRichard Henderson     mask = tcg_const_tl(msb + (msb - 1));
1999*0b1347d2SRichard Henderson     tcg_gen_and_tl(tmp, val, mask);
2000*0b1347d2SRichard Henderson     if (rs) {
2001*0b1347d2SRichard Henderson         tcg_gen_shl_tl(mask, mask, shift);
2002*0b1347d2SRichard Henderson         tcg_gen_shl_tl(tmp, tmp, shift);
2003*0b1347d2SRichard Henderson         tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
2004*0b1347d2SRichard Henderson         tcg_gen_or_tl(dest, dest, tmp);
2005*0b1347d2SRichard Henderson     } else {
2006*0b1347d2SRichard Henderson         tcg_gen_shl_tl(dest, tmp, shift);
2007*0b1347d2SRichard Henderson     }
2008*0b1347d2SRichard Henderson     tcg_temp_free(shift);
2009*0b1347d2SRichard Henderson     tcg_temp_free(mask);
2010*0b1347d2SRichard Henderson     tcg_temp_free(tmp);
2011*0b1347d2SRichard Henderson     save_gpr(ctx, rt, dest);
2012*0b1347d2SRichard Henderson 
2013*0b1347d2SRichard Henderson     /* Install the new nullification.  */
2014*0b1347d2SRichard Henderson     cond_free(&ctx->null_cond);
2015*0b1347d2SRichard Henderson     if (c) {
2016*0b1347d2SRichard Henderson         ctx->null_cond = do_sed_cond(c, dest);
2017*0b1347d2SRichard Henderson     }
2018*0b1347d2SRichard Henderson     return nullify_end(ctx, NO_EXIT);
2019*0b1347d2SRichard Henderson }
2020*0b1347d2SRichard Henderson 
2021*0b1347d2SRichard Henderson static const DisasInsn table_depw[] = {
2022*0b1347d2SRichard Henderson     { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
2023*0b1347d2SRichard Henderson     { 0xd4000800u, 0xfc001800u, trans_depw_imm },
2024*0b1347d2SRichard Henderson     { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
2025*0b1347d2SRichard Henderson };
2026*0b1347d2SRichard Henderson 
202798cd9ca7SRichard Henderson static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
202898cd9ca7SRichard Henderson {
202998cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
203098cd9ca7SRichard Henderson     unsigned b = extract32(insn, 21, 5);
203198cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
203298cd9ca7SRichard Henderson 
203398cd9ca7SRichard Henderson     /* unsigned s = low_uextract(insn, 13, 3); */
203498cd9ca7SRichard Henderson     /* ??? It seems like there should be a good way of using
203598cd9ca7SRichard Henderson        "be disp(sr2, r0)", the canonical gateway entry mechanism
203698cd9ca7SRichard Henderson        to our advantage.  But that appears to be inconvenient to
203798cd9ca7SRichard Henderson        manage along side branch delay slots.  Therefore we handle
203898cd9ca7SRichard Henderson        entry into the gateway page via absolute address.  */
203998cd9ca7SRichard Henderson 
204098cd9ca7SRichard Henderson     /* Since we don't implement spaces, just branch.  Do notice the special
204198cd9ca7SRichard Henderson        case of "be disp(*,r0)" using a direct branch to disp, so that we can
204298cd9ca7SRichard Henderson        goto_tb to the TB containing the syscall.  */
204398cd9ca7SRichard Henderson     if (b == 0) {
204498cd9ca7SRichard Henderson         return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
204598cd9ca7SRichard Henderson     } else {
204698cd9ca7SRichard Henderson         TCGv tmp = get_temp(ctx);
204798cd9ca7SRichard Henderson         tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
204898cd9ca7SRichard Henderson         return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
204998cd9ca7SRichard Henderson     }
205098cd9ca7SRichard Henderson }
205198cd9ca7SRichard Henderson 
205298cd9ca7SRichard Henderson static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
205398cd9ca7SRichard Henderson                            const DisasInsn *di)
205498cd9ca7SRichard Henderson {
205598cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
205698cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
205798cd9ca7SRichard Henderson     target_long disp = assemble_17(insn);
205898cd9ca7SRichard Henderson 
205998cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
206098cd9ca7SRichard Henderson }
206198cd9ca7SRichard Henderson 
206298cd9ca7SRichard Henderson static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
206398cd9ca7SRichard Henderson                                 const DisasInsn *di)
206498cd9ca7SRichard Henderson {
206598cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
206698cd9ca7SRichard Henderson     target_long disp = assemble_22(insn);
206798cd9ca7SRichard Henderson 
206898cd9ca7SRichard Henderson     return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
206998cd9ca7SRichard Henderson }
207098cd9ca7SRichard Henderson 
207198cd9ca7SRichard Henderson static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
207298cd9ca7SRichard Henderson                             const DisasInsn *di)
207398cd9ca7SRichard Henderson {
207498cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
207598cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
207698cd9ca7SRichard Henderson     unsigned link = extract32(insn, 21, 5);
207798cd9ca7SRichard Henderson     TCGv tmp = get_temp(ctx);
207898cd9ca7SRichard Henderson 
207998cd9ca7SRichard Henderson     tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
208098cd9ca7SRichard Henderson     tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
208198cd9ca7SRichard Henderson     return do_ibranch(ctx, tmp, link, n);
208298cd9ca7SRichard Henderson }
208398cd9ca7SRichard Henderson 
208498cd9ca7SRichard Henderson static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
208598cd9ca7SRichard Henderson                            const DisasInsn *di)
208698cd9ca7SRichard Henderson {
208798cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
208898cd9ca7SRichard Henderson     unsigned rx = extract32(insn, 16, 5);
208998cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
209098cd9ca7SRichard Henderson     TCGv dest;
209198cd9ca7SRichard Henderson 
209298cd9ca7SRichard Henderson     if (rx == 0) {
209398cd9ca7SRichard Henderson         dest = load_gpr(ctx, rb);
209498cd9ca7SRichard Henderson     } else {
209598cd9ca7SRichard Henderson         dest = get_temp(ctx);
209698cd9ca7SRichard Henderson         tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
209798cd9ca7SRichard Henderson         tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
209898cd9ca7SRichard Henderson     }
209998cd9ca7SRichard Henderson     return do_ibranch(ctx, dest, 0, n);
210098cd9ca7SRichard Henderson }
210198cd9ca7SRichard Henderson 
210298cd9ca7SRichard Henderson static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
210398cd9ca7SRichard Henderson                             const DisasInsn *di)
210498cd9ca7SRichard Henderson {
210598cd9ca7SRichard Henderson     unsigned n = extract32(insn, 1, 1);
210698cd9ca7SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
210798cd9ca7SRichard Henderson     unsigned link = extract32(insn, 13, 1) ? 2 : 0;
210898cd9ca7SRichard Henderson 
210998cd9ca7SRichard Henderson     return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
211098cd9ca7SRichard Henderson }
211198cd9ca7SRichard Henderson 
211298cd9ca7SRichard Henderson static const DisasInsn table_branch[] = {
211398cd9ca7SRichard Henderson     { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
211498cd9ca7SRichard Henderson     { 0xe800a000u, 0xfc00e000u, trans_bl_long },
211598cd9ca7SRichard Henderson     { 0xe8004000u, 0xfc00fffdu, trans_blr },
211698cd9ca7SRichard Henderson     { 0xe800c000u, 0xfc00fffdu, trans_bv },
211798cd9ca7SRichard Henderson     { 0xe800d000u, 0xfc00dffcu, trans_bve },
211898cd9ca7SRichard Henderson };
211998cd9ca7SRichard Henderson 
212061766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
212161766fe9SRichard Henderson                                       const DisasInsn table[], size_t n)
212261766fe9SRichard Henderson {
212361766fe9SRichard Henderson     size_t i;
212461766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
212561766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
212661766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
212761766fe9SRichard Henderson         }
212861766fe9SRichard Henderson     }
212961766fe9SRichard Henderson     return gen_illegal(ctx);
213061766fe9SRichard Henderson }
213161766fe9SRichard Henderson 
213261766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
213361766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
213461766fe9SRichard Henderson 
213561766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
213661766fe9SRichard Henderson {
213761766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
213861766fe9SRichard Henderson 
213961766fe9SRichard Henderson     switch (opc) {
2140b2167459SRichard Henderson     case 0x02:
2141b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
2142b2167459SRichard Henderson     case 0x08:
2143b2167459SRichard Henderson         return trans_ldil(ctx, insn);
2144b2167459SRichard Henderson     case 0x0A:
2145b2167459SRichard Henderson         return trans_addil(ctx, insn);
2146b2167459SRichard Henderson     case 0x0D:
2147b2167459SRichard Henderson         return trans_ldo(ctx, insn);
214898cd9ca7SRichard Henderson     case 0x20:
214998cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, false);
215098cd9ca7SRichard Henderson     case 0x21:
215198cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, true, false);
215298cd9ca7SRichard Henderson     case 0x22:
215398cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, false);
215498cd9ca7SRichard Henderson     case 0x23:
215598cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, true, false);
2156b2167459SRichard Henderson     case 0x24:
2157b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
2158b2167459SRichard Henderson     case 0x25:
2159b2167459SRichard Henderson         return trans_subi(ctx, insn);
216098cd9ca7SRichard Henderson     case 0x27:
216198cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, true, false, true);
216298cd9ca7SRichard Henderson     case 0x28:
216398cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, false);
216498cd9ca7SRichard Henderson     case 0x29:
216598cd9ca7SRichard Henderson         return trans_addb(ctx, insn, true, true);
216698cd9ca7SRichard Henderson     case 0x2A:
216798cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, false);
216898cd9ca7SRichard Henderson     case 0x2B:
216998cd9ca7SRichard Henderson         return trans_addb(ctx, insn, false, true);
2170b2167459SRichard Henderson     case 0x2C:
2171b2167459SRichard Henderson     case 0x2D:
2172b2167459SRichard Henderson         return trans_addi(ctx, insn);
217398cd9ca7SRichard Henderson     case 0x2F:
217498cd9ca7SRichard Henderson         return trans_cmpb(ctx, insn, false, false, true);
217598cd9ca7SRichard Henderson     case 0x30:
217698cd9ca7SRichard Henderson     case 0x31:
217798cd9ca7SRichard Henderson         return trans_bb(ctx, insn);
217898cd9ca7SRichard Henderson     case 0x32:
217998cd9ca7SRichard Henderson         return trans_movb(ctx, insn, false);
218098cd9ca7SRichard Henderson     case 0x33:
218198cd9ca7SRichard Henderson         return trans_movb(ctx, insn, true);
2182*0b1347d2SRichard Henderson     case 0x34:
2183*0b1347d2SRichard Henderson         return translate_table(ctx, insn, table_sh_ex);
2184*0b1347d2SRichard Henderson     case 0x35:
2185*0b1347d2SRichard Henderson         return translate_table(ctx, insn, table_depw);
218698cd9ca7SRichard Henderson     case 0x38:
218798cd9ca7SRichard Henderson         return trans_be(ctx, insn, false);
218898cd9ca7SRichard Henderson     case 0x39:
218998cd9ca7SRichard Henderson         return trans_be(ctx, insn, true);
219098cd9ca7SRichard Henderson     case 0x3A:
219198cd9ca7SRichard Henderson         return translate_table(ctx, insn, table_branch);
219261766fe9SRichard Henderson     default:
219361766fe9SRichard Henderson         break;
219461766fe9SRichard Henderson     }
219561766fe9SRichard Henderson     return gen_illegal(ctx);
219661766fe9SRichard Henderson }
219761766fe9SRichard Henderson 
219861766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
219961766fe9SRichard Henderson {
220061766fe9SRichard Henderson     HPPACPU *cpu = hppa_env_get_cpu(env);
220161766fe9SRichard Henderson     CPUState *cs = CPU(cpu);
220261766fe9SRichard Henderson     DisasContext ctx;
220361766fe9SRichard Henderson     ExitStatus ret;
220461766fe9SRichard Henderson     int num_insns, max_insns, i;
220561766fe9SRichard Henderson 
220661766fe9SRichard Henderson     ctx.tb = tb;
220761766fe9SRichard Henderson     ctx.cs = cs;
220861766fe9SRichard Henderson     ctx.iaoq_f = tb->pc;
220961766fe9SRichard Henderson     ctx.iaoq_b = tb->cs_base;
221061766fe9SRichard Henderson     ctx.singlestep_enabled = cs->singlestep_enabled;
221161766fe9SRichard Henderson 
221261766fe9SRichard Henderson     ctx.ntemps = 0;
221361766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
221461766fe9SRichard Henderson         TCGV_UNUSED(ctx.temps[i]);
221561766fe9SRichard Henderson     }
221661766fe9SRichard Henderson 
221761766fe9SRichard Henderson     /* Compute the maximum number of insns to execute, as bounded by
221861766fe9SRichard Henderson        (1) icount, (2) single-stepping, (3) branch delay slots, or
221961766fe9SRichard Henderson        (4) the number of insns remaining on the current page.  */
222061766fe9SRichard Henderson     max_insns = tb->cflags & CF_COUNT_MASK;
222161766fe9SRichard Henderson     if (max_insns == 0) {
222261766fe9SRichard Henderson         max_insns = CF_COUNT_MASK;
222361766fe9SRichard Henderson     }
222461766fe9SRichard Henderson     if (ctx.singlestep_enabled || singlestep) {
222561766fe9SRichard Henderson         max_insns = 1;
222661766fe9SRichard Henderson     } else if (max_insns > TCG_MAX_INSNS) {
222761766fe9SRichard Henderson         max_insns = TCG_MAX_INSNS;
222861766fe9SRichard Henderson     }
222961766fe9SRichard Henderson 
223061766fe9SRichard Henderson     num_insns = 0;
223161766fe9SRichard Henderson     gen_tb_start(tb);
223261766fe9SRichard Henderson 
2233129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
2234129e9cc3SRichard Henderson     ctx.null_cond = cond_make_f();
2235129e9cc3SRichard Henderson     ctx.psw_n_nonzero = false;
2236129e9cc3SRichard Henderson     if (tb->flags & 1) {
2237129e9cc3SRichard Henderson         ctx.null_cond.c = TCG_COND_ALWAYS;
2238129e9cc3SRichard Henderson         ctx.psw_n_nonzero = true;
2239129e9cc3SRichard Henderson     }
2240129e9cc3SRichard Henderson     ctx.null_lab = NULL;
2241129e9cc3SRichard Henderson 
224261766fe9SRichard Henderson     do {
224361766fe9SRichard Henderson         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
224461766fe9SRichard Henderson         num_insns++;
224561766fe9SRichard Henderson 
224661766fe9SRichard Henderson         if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
224761766fe9SRichard Henderson             ret = gen_excp(&ctx, EXCP_DEBUG);
224861766fe9SRichard Henderson             break;
224961766fe9SRichard Henderson         }
225061766fe9SRichard Henderson         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
225161766fe9SRichard Henderson             gen_io_start();
225261766fe9SRichard Henderson         }
225361766fe9SRichard Henderson 
22547ad439dfSRichard Henderson         if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
22557ad439dfSRichard Henderson             ret = do_page_zero(&ctx);
22567ad439dfSRichard Henderson             assert(ret != NO_EXIT);
22577ad439dfSRichard Henderson         } else {
225861766fe9SRichard Henderson             /* Always fetch the insn, even if nullified, so that we check
225961766fe9SRichard Henderson                the page permissions for execute.  */
226061766fe9SRichard Henderson             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
226161766fe9SRichard Henderson 
226261766fe9SRichard Henderson             /* Set up the IA queue for the next insn.
226361766fe9SRichard Henderson                This will be overwritten by a branch.  */
226461766fe9SRichard Henderson             if (ctx.iaoq_b == -1) {
226561766fe9SRichard Henderson                 ctx.iaoq_n = -1;
226661766fe9SRichard Henderson                 ctx.iaoq_n_var = get_temp(&ctx);
226761766fe9SRichard Henderson                 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
226861766fe9SRichard Henderson             } else {
226961766fe9SRichard Henderson                 ctx.iaoq_n = ctx.iaoq_b + 4;
227061766fe9SRichard Henderson                 TCGV_UNUSED(ctx.iaoq_n_var);
227161766fe9SRichard Henderson             }
227261766fe9SRichard Henderson 
2273129e9cc3SRichard Henderson             if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
2274129e9cc3SRichard Henderson                 ctx.null_cond.c = TCG_COND_NEVER;
2275129e9cc3SRichard Henderson                 ret = NO_EXIT;
2276129e9cc3SRichard Henderson             } else {
227761766fe9SRichard Henderson                 ret = translate_one(&ctx, insn);
2278129e9cc3SRichard Henderson                 assert(ctx.null_lab == NULL);
2279129e9cc3SRichard Henderson             }
228061766fe9SRichard Henderson         }
228161766fe9SRichard Henderson 
228261766fe9SRichard Henderson         for (i = 0; i < ctx.ntemps; ++i) {
228361766fe9SRichard Henderson             tcg_temp_free(ctx.temps[i]);
228461766fe9SRichard Henderson             TCGV_UNUSED(ctx.temps[i]);
228561766fe9SRichard Henderson         }
228661766fe9SRichard Henderson         ctx.ntemps = 0;
228761766fe9SRichard Henderson 
228861766fe9SRichard Henderson         /* If we see non-linear instructions, exhaust instruction count,
228961766fe9SRichard Henderson            or run out of buffer space, stop generation.  */
229061766fe9SRichard Henderson         /* ??? The non-linear instruction restriction is purely due to
229161766fe9SRichard Henderson            the debugging dump.  Otherwise we *could* follow unconditional
229261766fe9SRichard Henderson            branches within the same page.  */
229361766fe9SRichard Henderson         if (ret == NO_EXIT
229461766fe9SRichard Henderson             && (ctx.iaoq_b != ctx.iaoq_f + 4
229561766fe9SRichard Henderson                 || num_insns >= max_insns
229661766fe9SRichard Henderson                 || tcg_op_buf_full())) {
2297129e9cc3SRichard Henderson             if (ctx.null_cond.c == TCG_COND_NEVER
2298129e9cc3SRichard Henderson                 || ctx.null_cond.c == TCG_COND_ALWAYS) {
2299129e9cc3SRichard Henderson                 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
2300129e9cc3SRichard Henderson                 gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
2301129e9cc3SRichard Henderson                 ret = EXIT_GOTO_TB;
2302129e9cc3SRichard Henderson             } else {
230361766fe9SRichard Henderson                 ret = EXIT_IAQ_N_STALE;
230461766fe9SRichard Henderson             }
2305129e9cc3SRichard Henderson         }
230661766fe9SRichard Henderson 
230761766fe9SRichard Henderson         ctx.iaoq_f = ctx.iaoq_b;
230861766fe9SRichard Henderson         ctx.iaoq_b = ctx.iaoq_n;
230961766fe9SRichard Henderson         if (ret == EXIT_NORETURN
231061766fe9SRichard Henderson             || ret == EXIT_GOTO_TB
231161766fe9SRichard Henderson             || ret == EXIT_IAQ_N_UPDATED) {
231261766fe9SRichard Henderson             break;
231361766fe9SRichard Henderson         }
231461766fe9SRichard Henderson         if (ctx.iaoq_f == -1) {
231561766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
231661766fe9SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
2317129e9cc3SRichard Henderson             nullify_save(&ctx);
231861766fe9SRichard Henderson             ret = EXIT_IAQ_N_UPDATED;
231961766fe9SRichard Henderson             break;
232061766fe9SRichard Henderson         }
232161766fe9SRichard Henderson         if (ctx.iaoq_b == -1) {
232261766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
232361766fe9SRichard Henderson         }
232461766fe9SRichard Henderson     } while (ret == NO_EXIT);
232561766fe9SRichard Henderson 
232661766fe9SRichard Henderson     if (tb->cflags & CF_LAST_IO) {
232761766fe9SRichard Henderson         gen_io_end();
232861766fe9SRichard Henderson     }
232961766fe9SRichard Henderson 
233061766fe9SRichard Henderson     switch (ret) {
233161766fe9SRichard Henderson     case EXIT_GOTO_TB:
233261766fe9SRichard Henderson     case EXIT_NORETURN:
233361766fe9SRichard Henderson         break;
233461766fe9SRichard Henderson     case EXIT_IAQ_N_STALE:
233561766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
233661766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
2337129e9cc3SRichard Henderson         nullify_save(&ctx);
233861766fe9SRichard Henderson         /* FALLTHRU */
233961766fe9SRichard Henderson     case EXIT_IAQ_N_UPDATED:
234061766fe9SRichard Henderson         if (ctx.singlestep_enabled) {
234161766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
234261766fe9SRichard Henderson         } else {
234361766fe9SRichard Henderson             tcg_gen_exit_tb(0);
234461766fe9SRichard Henderson         }
234561766fe9SRichard Henderson         break;
234661766fe9SRichard Henderson     default:
234761766fe9SRichard Henderson         abort();
234861766fe9SRichard Henderson     }
234961766fe9SRichard Henderson 
235061766fe9SRichard Henderson     gen_tb_end(tb, num_insns);
235161766fe9SRichard Henderson 
235261766fe9SRichard Henderson     tb->size = num_insns * 4;
235361766fe9SRichard Henderson     tb->icount = num_insns;
235461766fe9SRichard Henderson 
235561766fe9SRichard Henderson #ifdef DEBUG_DISAS
235661766fe9SRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
235761766fe9SRichard Henderson         && qemu_log_in_addr_range(tb->pc)) {
235861766fe9SRichard Henderson         qemu_log_lock();
23597ad439dfSRichard Henderson         switch (tb->pc) {
23607ad439dfSRichard Henderson         case 0x00:
23617ad439dfSRichard Henderson             qemu_log("IN:\n0x00000000:  (null)\n\n");
23627ad439dfSRichard Henderson             break;
23637ad439dfSRichard Henderson         case 0xb0:
23647ad439dfSRichard Henderson             qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
23657ad439dfSRichard Henderson             break;
23667ad439dfSRichard Henderson         case 0xe0:
23677ad439dfSRichard Henderson             qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
23687ad439dfSRichard Henderson             break;
23697ad439dfSRichard Henderson         case 0x100:
23707ad439dfSRichard Henderson             qemu_log("IN:\n0x00000100:  syscall\n\n");
23717ad439dfSRichard Henderson             break;
23727ad439dfSRichard Henderson         default:
237361766fe9SRichard Henderson             qemu_log("IN: %s\n", lookup_symbol(tb->pc));
237461766fe9SRichard Henderson             log_target_disas(cs, tb->pc, tb->size, 1);
237561766fe9SRichard Henderson             qemu_log("\n");
23767ad439dfSRichard Henderson             break;
23777ad439dfSRichard Henderson         }
237861766fe9SRichard Henderson         qemu_log_unlock();
237961766fe9SRichard Henderson     }
238061766fe9SRichard Henderson #endif
238161766fe9SRichard Henderson }
238261766fe9SRichard Henderson 
238361766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
238461766fe9SRichard Henderson                           target_ulong *data)
238561766fe9SRichard Henderson {
238661766fe9SRichard Henderson     env->iaoq_f = data[0];
238761766fe9SRichard Henderson     if (data[1] != -1) {
238861766fe9SRichard Henderson         env->iaoq_b = data[1];
238961766fe9SRichard Henderson     }
239061766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
239161766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
239261766fe9SRichard Henderson        that the instruction was not nullified.  */
239361766fe9SRichard Henderson     env->psw_n = 0;
239461766fe9SRichard Henderson }
2395