xref: /openbmc/qemu/target/hppa/translate.c (revision b2167459ae46bcaa07a84fc7e9df1743000be81f)
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);
86*b2167459SRichard Henderson     union {
87*b2167459SRichard Henderson         void (*f_ttt)(TCGv, TCGv, TCGv);
88*b2167459SRichard 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 
449*b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign,
450*b2167459SRichard Henderson    with the rest of the field becoming the least significant bits.  */
451*b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len)
452*b2167459SRichard Henderson {
453*b2167459SRichard Henderson     target_ulong x = -(target_ulong)extract32(val, pos, 1);
454*b2167459SRichard Henderson     x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
455*b2167459SRichard Henderson     return x;
456*b2167459SRichard Henderson }
457*b2167459SRichard Henderson 
458*b2167459SRichard Henderson static target_long assemble_16(uint32_t insn)
459*b2167459SRichard Henderson {
460*b2167459SRichard Henderson     /* Take the name from PA2.0, which produces a 16-bit number
461*b2167459SRichard Henderson        only with wide mode; otherwise a 14-bit number.  Since we don't
462*b2167459SRichard Henderson        implement wide mode, this is always the 14-bit number.  */
463*b2167459SRichard Henderson     return low_sextract(insn, 0, 14);
464*b2167459SRichard Henderson }
465*b2167459SRichard Henderson 
466*b2167459SRichard Henderson static target_long assemble_21(uint32_t insn)
467*b2167459SRichard Henderson {
468*b2167459SRichard Henderson     target_ulong x = -(target_ulong)(insn & 1);
469*b2167459SRichard Henderson     x = (x << 11) | extract32(insn, 1, 11);
470*b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 14, 2);
471*b2167459SRichard Henderson     x = (x <<  5) | extract32(insn, 16, 5);
472*b2167459SRichard Henderson     x = (x <<  2) | extract32(insn, 12, 2);
473*b2167459SRichard Henderson     return x << 11;
474*b2167459SRichard Henderson }
475*b2167459SRichard Henderson 
476*b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of
477*b2167459SRichard Henderson    the conditions, without describing their exact implementation.  The
478*b2167459SRichard Henderson    interpretations do not stand up well when considering ADD,C and SUB,B.
479*b2167459SRichard Henderson    However, considering the Addition, Subtraction and Logical conditions
480*b2167459SRichard Henderson    as a whole it would appear that these relations are similar to what
481*b2167459SRichard Henderson    a traditional NZCV set of flags would produce.  */
482*b2167459SRichard Henderson 
483*b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
484*b2167459SRichard Henderson {
485*b2167459SRichard Henderson     DisasCond cond;
486*b2167459SRichard Henderson     TCGv tmp;
487*b2167459SRichard Henderson 
488*b2167459SRichard Henderson     switch (cf >> 1) {
489*b2167459SRichard Henderson     case 0: /* Never / TR */
490*b2167459SRichard Henderson         cond = cond_make_f();
491*b2167459SRichard Henderson         break;
492*b2167459SRichard Henderson     case 1: /* = / <>        (Z / !Z) */
493*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, res);
494*b2167459SRichard Henderson         break;
495*b2167459SRichard Henderson     case 2: /* < / >=        (N / !N) */
496*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, res);
497*b2167459SRichard Henderson         break;
498*b2167459SRichard Henderson     case 3: /* <= / >        (N | Z / !N & !Z) */
499*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LE, res);
500*b2167459SRichard Henderson         break;
501*b2167459SRichard Henderson     case 4: /* NUV / UV      (!C / C) */
502*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, cb_msb);
503*b2167459SRichard Henderson         break;
504*b2167459SRichard Henderson     case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
505*b2167459SRichard Henderson         tmp = tcg_temp_new();
506*b2167459SRichard Henderson         tcg_gen_neg_tl(tmp, cb_msb);
507*b2167459SRichard Henderson         tcg_gen_and_tl(tmp, tmp, res);
508*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_EQ, tmp);
509*b2167459SRichard Henderson         tcg_temp_free(tmp);
510*b2167459SRichard Henderson         break;
511*b2167459SRichard Henderson     case 6: /* SV / NSV      (V / !V) */
512*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_LT, sv);
513*b2167459SRichard Henderson         break;
514*b2167459SRichard Henderson     case 7: /* OD / EV */
515*b2167459SRichard Henderson         tmp = tcg_temp_new();
516*b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, res, 1);
517*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
518*b2167459SRichard Henderson         tcg_temp_free(tmp);
519*b2167459SRichard Henderson         break;
520*b2167459SRichard Henderson     default:
521*b2167459SRichard Henderson         g_assert_not_reached();
522*b2167459SRichard Henderson     }
523*b2167459SRichard Henderson     if (cf & 1) {
524*b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
525*b2167459SRichard Henderson     }
526*b2167459SRichard Henderson 
527*b2167459SRichard Henderson     return cond;
528*b2167459SRichard Henderson }
529*b2167459SRichard Henderson 
530*b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we
531*b2167459SRichard Henderson    can use the inputs directly.  This can allow other computation to be
532*b2167459SRichard Henderson    deleted as unused.  */
533*b2167459SRichard Henderson 
534*b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
535*b2167459SRichard Henderson {
536*b2167459SRichard Henderson     DisasCond cond;
537*b2167459SRichard Henderson 
538*b2167459SRichard Henderson     switch (cf >> 1) {
539*b2167459SRichard Henderson     case 1: /* = / <> */
540*b2167459SRichard Henderson         cond = cond_make(TCG_COND_EQ, in1, in2);
541*b2167459SRichard Henderson         break;
542*b2167459SRichard Henderson     case 2: /* < / >= */
543*b2167459SRichard Henderson         cond = cond_make(TCG_COND_LT, in1, in2);
544*b2167459SRichard Henderson         break;
545*b2167459SRichard Henderson     case 3: /* <= / > */
546*b2167459SRichard Henderson         cond = cond_make(TCG_COND_LE, in1, in2);
547*b2167459SRichard Henderson         break;
548*b2167459SRichard Henderson     case 4: /* << / >>= */
549*b2167459SRichard Henderson         cond = cond_make(TCG_COND_LTU, in1, in2);
550*b2167459SRichard Henderson         break;
551*b2167459SRichard Henderson     case 5: /* <<= / >> */
552*b2167459SRichard Henderson         cond = cond_make(TCG_COND_LEU, in1, in2);
553*b2167459SRichard Henderson         break;
554*b2167459SRichard Henderson     default:
555*b2167459SRichard Henderson         return do_cond(cf, res, sv, sv);
556*b2167459SRichard Henderson     }
557*b2167459SRichard Henderson     if (cf & 1) {
558*b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
559*b2167459SRichard Henderson     }
560*b2167459SRichard Henderson 
561*b2167459SRichard Henderson     return cond;
562*b2167459SRichard Henderson }
563*b2167459SRichard Henderson 
564*b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not
565*b2167459SRichard Henderson    computed, and use of them is undefined.  */
566*b2167459SRichard Henderson 
567*b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res)
568*b2167459SRichard Henderson {
569*b2167459SRichard Henderson     switch (cf >> 1) {
570*b2167459SRichard Henderson     case 4: case 5: case 6:
571*b2167459SRichard Henderson         cf &= 1;
572*b2167459SRichard Henderson         break;
573*b2167459SRichard Henderson     }
574*b2167459SRichard Henderson     return do_cond(cf, res, res, res);
575*b2167459SRichard Henderson }
576*b2167459SRichard Henderson 
577*b2167459SRichard Henderson /* Similar, but for unit conditions.  */
578*b2167459SRichard Henderson 
579*b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
580*b2167459SRichard Henderson {
581*b2167459SRichard Henderson     DisasCond cond;
582*b2167459SRichard Henderson     TCGv tmp, cb;
583*b2167459SRichard Henderson 
584*b2167459SRichard Henderson     TCGV_UNUSED(cb);
585*b2167459SRichard Henderson     if (cf & 8) {
586*b2167459SRichard Henderson         /* Since we want to test lots of carry-out bits all at once, do not
587*b2167459SRichard Henderson          * do our normal thing and compute carry-in of bit B+1 since that
588*b2167459SRichard Henderson          * leaves us with carry bits spread across two words.
589*b2167459SRichard Henderson          */
590*b2167459SRichard Henderson         cb = tcg_temp_new();
591*b2167459SRichard Henderson         tmp = tcg_temp_new();
592*b2167459SRichard Henderson         tcg_gen_or_tl(cb, in1, in2);
593*b2167459SRichard Henderson         tcg_gen_and_tl(tmp, in1, in2);
594*b2167459SRichard Henderson         tcg_gen_andc_tl(cb, cb, res);
595*b2167459SRichard Henderson         tcg_gen_or_tl(cb, cb, tmp);
596*b2167459SRichard Henderson         tcg_temp_free(tmp);
597*b2167459SRichard Henderson     }
598*b2167459SRichard Henderson 
599*b2167459SRichard Henderson     switch (cf >> 1) {
600*b2167459SRichard Henderson     case 0: /* never / TR */
601*b2167459SRichard Henderson     case 1: /* undefined */
602*b2167459SRichard Henderson     case 5: /* undefined */
603*b2167459SRichard Henderson         cond = cond_make_f();
604*b2167459SRichard Henderson         break;
605*b2167459SRichard Henderson 
606*b2167459SRichard Henderson     case 2: /* SBZ / NBZ */
607*b2167459SRichard Henderson         /* See hasless(v,1) from
608*b2167459SRichard Henderson          * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
609*b2167459SRichard Henderson          */
610*b2167459SRichard Henderson         tmp = tcg_temp_new();
611*b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x01010101u);
612*b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
613*b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
614*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
615*b2167459SRichard Henderson         tcg_temp_free(tmp);
616*b2167459SRichard Henderson         break;
617*b2167459SRichard Henderson 
618*b2167459SRichard Henderson     case 3: /* SHZ / NHZ */
619*b2167459SRichard Henderson         tmp = tcg_temp_new();
620*b2167459SRichard Henderson         tcg_gen_subi_tl(tmp, res, 0x00010001u);
621*b2167459SRichard Henderson         tcg_gen_andc_tl(tmp, tmp, res);
622*b2167459SRichard Henderson         tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
623*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, tmp);
624*b2167459SRichard Henderson         tcg_temp_free(tmp);
625*b2167459SRichard Henderson         break;
626*b2167459SRichard Henderson 
627*b2167459SRichard Henderson     case 4: /* SDC / NDC */
628*b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x88888888u);
629*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
630*b2167459SRichard Henderson         break;
631*b2167459SRichard Henderson 
632*b2167459SRichard Henderson     case 6: /* SBC / NBC */
633*b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80808080u);
634*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
635*b2167459SRichard Henderson         break;
636*b2167459SRichard Henderson 
637*b2167459SRichard Henderson     case 7: /* SHC / NHC */
638*b2167459SRichard Henderson         tcg_gen_andi_tl(cb, cb, 0x80008000u);
639*b2167459SRichard Henderson         cond = cond_make_0(TCG_COND_NE, cb);
640*b2167459SRichard Henderson         break;
641*b2167459SRichard Henderson 
642*b2167459SRichard Henderson     default:
643*b2167459SRichard Henderson         g_assert_not_reached();
644*b2167459SRichard Henderson     }
645*b2167459SRichard Henderson     if (cf & 8) {
646*b2167459SRichard Henderson         tcg_temp_free(cb);
647*b2167459SRichard Henderson     }
648*b2167459SRichard Henderson     if (cf & 1) {
649*b2167459SRichard Henderson         cond.c = tcg_invert_cond(cond.c);
650*b2167459SRichard Henderson     }
651*b2167459SRichard Henderson 
652*b2167459SRichard Henderson     return cond;
653*b2167459SRichard Henderson }
654*b2167459SRichard Henderson 
655*b2167459SRichard Henderson /* Compute signed overflow for addition.  */
656*b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
657*b2167459SRichard Henderson {
658*b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
659*b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
660*b2167459SRichard Henderson 
661*b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
662*b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
663*b2167459SRichard Henderson     tcg_gen_andc_tl(sv, sv, tmp);
664*b2167459SRichard Henderson     tcg_temp_free(tmp);
665*b2167459SRichard Henderson 
666*b2167459SRichard Henderson     return sv;
667*b2167459SRichard Henderson }
668*b2167459SRichard Henderson 
669*b2167459SRichard Henderson /* Compute signed overflow for subtraction.  */
670*b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
671*b2167459SRichard Henderson {
672*b2167459SRichard Henderson     TCGv sv = get_temp(ctx);
673*b2167459SRichard Henderson     TCGv tmp = tcg_temp_new();
674*b2167459SRichard Henderson 
675*b2167459SRichard Henderson     tcg_gen_xor_tl(sv, res, in1);
676*b2167459SRichard Henderson     tcg_gen_xor_tl(tmp, in1, in2);
677*b2167459SRichard Henderson     tcg_gen_and_tl(sv, sv, tmp);
678*b2167459SRichard Henderson     tcg_temp_free(tmp);
679*b2167459SRichard Henderson 
680*b2167459SRichard Henderson     return sv;
681*b2167459SRichard Henderson }
682*b2167459SRichard Henderson 
683*b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
684*b2167459SRichard Henderson                          unsigned shift, bool is_l, bool is_tsv, bool is_tc,
685*b2167459SRichard Henderson                          bool is_c, unsigned cf)
686*b2167459SRichard Henderson {
687*b2167459SRichard Henderson     TCGv dest, cb, cb_msb, sv, tmp;
688*b2167459SRichard Henderson     unsigned c = cf >> 1;
689*b2167459SRichard Henderson     DisasCond cond;
690*b2167459SRichard Henderson 
691*b2167459SRichard Henderson     dest = tcg_temp_new();
692*b2167459SRichard Henderson     TCGV_UNUSED(cb);
693*b2167459SRichard Henderson     TCGV_UNUSED(cb_msb);
694*b2167459SRichard Henderson 
695*b2167459SRichard Henderson     if (shift) {
696*b2167459SRichard Henderson         tmp = get_temp(ctx);
697*b2167459SRichard Henderson         tcg_gen_shli_tl(tmp, in1, shift);
698*b2167459SRichard Henderson         in1 = tmp;
699*b2167459SRichard Henderson     }
700*b2167459SRichard Henderson 
701*b2167459SRichard Henderson     if (!is_l || c == 4 || c == 5) {
702*b2167459SRichard Henderson         TCGv zero = tcg_const_tl(0);
703*b2167459SRichard Henderson         cb_msb = get_temp(ctx);
704*b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
705*b2167459SRichard Henderson         if (is_c) {
706*b2167459SRichard Henderson             tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
707*b2167459SRichard Henderson         }
708*b2167459SRichard Henderson         tcg_temp_free(zero);
709*b2167459SRichard Henderson         if (!is_l) {
710*b2167459SRichard Henderson             cb = get_temp(ctx);
711*b2167459SRichard Henderson             tcg_gen_xor_tl(cb, in1, in2);
712*b2167459SRichard Henderson             tcg_gen_xor_tl(cb, cb, dest);
713*b2167459SRichard Henderson         }
714*b2167459SRichard Henderson     } else {
715*b2167459SRichard Henderson         tcg_gen_add_tl(dest, in1, in2);
716*b2167459SRichard Henderson         if (is_c) {
717*b2167459SRichard Henderson             tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
718*b2167459SRichard Henderson         }
719*b2167459SRichard Henderson     }
720*b2167459SRichard Henderson 
721*b2167459SRichard Henderson     /* Compute signed overflow if required.  */
722*b2167459SRichard Henderson     TCGV_UNUSED(sv);
723*b2167459SRichard Henderson     if (is_tsv || c == 6) {
724*b2167459SRichard Henderson         sv = do_add_sv(ctx, dest, in1, in2);
725*b2167459SRichard Henderson         if (is_tsv) {
726*b2167459SRichard Henderson             /* ??? Need to include overflow from shift.  */
727*b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
728*b2167459SRichard Henderson         }
729*b2167459SRichard Henderson     }
730*b2167459SRichard Henderson 
731*b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
732*b2167459SRichard Henderson     cond = do_cond(cf, dest, cb_msb, sv);
733*b2167459SRichard Henderson     if (is_tc) {
734*b2167459SRichard Henderson         cond_prep(&cond);
735*b2167459SRichard Henderson         tmp = tcg_temp_new();
736*b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
737*b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
738*b2167459SRichard Henderson         tcg_temp_free(tmp);
739*b2167459SRichard Henderson     }
740*b2167459SRichard Henderson 
741*b2167459SRichard Henderson     /* Write back the result.  */
742*b2167459SRichard Henderson     if (!is_l) {
743*b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb, cb);
744*b2167459SRichard Henderson         save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
745*b2167459SRichard Henderson     }
746*b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
747*b2167459SRichard Henderson     tcg_temp_free(dest);
748*b2167459SRichard Henderson 
749*b2167459SRichard Henderson     /* Install the new nullification.  */
750*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
751*b2167459SRichard Henderson     ctx->null_cond = cond;
752*b2167459SRichard Henderson     return NO_EXIT;
753*b2167459SRichard Henderson }
754*b2167459SRichard Henderson 
755*b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
756*b2167459SRichard Henderson                          bool is_tsv, bool is_b, bool is_tc, unsigned cf)
757*b2167459SRichard Henderson {
758*b2167459SRichard Henderson     TCGv dest, sv, cb, cb_msb, zero, tmp;
759*b2167459SRichard Henderson     unsigned c = cf >> 1;
760*b2167459SRichard Henderson     DisasCond cond;
761*b2167459SRichard Henderson 
762*b2167459SRichard Henderson     dest = tcg_temp_new();
763*b2167459SRichard Henderson     cb = tcg_temp_new();
764*b2167459SRichard Henderson     cb_msb = tcg_temp_new();
765*b2167459SRichard Henderson 
766*b2167459SRichard Henderson     zero = tcg_const_tl(0);
767*b2167459SRichard Henderson     if (is_b) {
768*b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + C.  */
769*b2167459SRichard Henderson         tcg_gen_not_tl(cb, in2);
770*b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
771*b2167459SRichard Henderson         tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
772*b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, in1);
773*b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
774*b2167459SRichard Henderson     } else {
775*b2167459SRichard Henderson         /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
776*b2167459SRichard Henderson            operations by seeding the high word with 1 and subtracting.  */
777*b2167459SRichard Henderson         tcg_gen_movi_tl(cb_msb, 1);
778*b2167459SRichard Henderson         tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
779*b2167459SRichard Henderson         tcg_gen_eqv_tl(cb, in1, in2);
780*b2167459SRichard Henderson         tcg_gen_xor_tl(cb, cb, dest);
781*b2167459SRichard Henderson     }
782*b2167459SRichard Henderson     tcg_temp_free(zero);
783*b2167459SRichard Henderson 
784*b2167459SRichard Henderson     /* Compute signed overflow if required.  */
785*b2167459SRichard Henderson     TCGV_UNUSED(sv);
786*b2167459SRichard Henderson     if (is_tsv || c == 6) {
787*b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
788*b2167459SRichard Henderson         if (is_tsv) {
789*b2167459SRichard Henderson             gen_helper_tsv(cpu_env, sv);
790*b2167459SRichard Henderson         }
791*b2167459SRichard Henderson     }
792*b2167459SRichard Henderson 
793*b2167459SRichard Henderson     /* Compute the condition.  We cannot use the special case for borrow.  */
794*b2167459SRichard Henderson     if (!is_b) {
795*b2167459SRichard Henderson         cond = do_sub_cond(cf, dest, in1, in2, sv);
796*b2167459SRichard Henderson     } else {
797*b2167459SRichard Henderson         cond = do_cond(cf, dest, cb_msb, sv);
798*b2167459SRichard Henderson     }
799*b2167459SRichard Henderson 
800*b2167459SRichard Henderson     /* Emit any conditional trap before any writeback.  */
801*b2167459SRichard Henderson     if (is_tc) {
802*b2167459SRichard Henderson         cond_prep(&cond);
803*b2167459SRichard Henderson         tmp = tcg_temp_new();
804*b2167459SRichard Henderson         tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
805*b2167459SRichard Henderson         gen_helper_tcond(cpu_env, tmp);
806*b2167459SRichard Henderson         tcg_temp_free(tmp);
807*b2167459SRichard Henderson     }
808*b2167459SRichard Henderson 
809*b2167459SRichard Henderson     /* Write back the result.  */
810*b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb, cb);
811*b2167459SRichard Henderson     save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
812*b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
813*b2167459SRichard Henderson     tcg_temp_free(dest);
814*b2167459SRichard Henderson 
815*b2167459SRichard Henderson     /* Install the new nullification.  */
816*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
817*b2167459SRichard Henderson     ctx->null_cond = cond;
818*b2167459SRichard Henderson     return NO_EXIT;
819*b2167459SRichard Henderson }
820*b2167459SRichard Henderson 
821*b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
822*b2167459SRichard Henderson                             TCGv in2, unsigned cf)
823*b2167459SRichard Henderson {
824*b2167459SRichard Henderson     TCGv dest, sv;
825*b2167459SRichard Henderson     DisasCond cond;
826*b2167459SRichard Henderson 
827*b2167459SRichard Henderson     dest = tcg_temp_new();
828*b2167459SRichard Henderson     tcg_gen_sub_tl(dest, in1, in2);
829*b2167459SRichard Henderson 
830*b2167459SRichard Henderson     /* Compute signed overflow if required.  */
831*b2167459SRichard Henderson     TCGV_UNUSED(sv);
832*b2167459SRichard Henderson     if ((cf >> 1) == 6) {
833*b2167459SRichard Henderson         sv = do_sub_sv(ctx, dest, in1, in2);
834*b2167459SRichard Henderson     }
835*b2167459SRichard Henderson 
836*b2167459SRichard Henderson     /* Form the condition for the compare.  */
837*b2167459SRichard Henderson     cond = do_sub_cond(cf, dest, in1, in2, sv);
838*b2167459SRichard Henderson 
839*b2167459SRichard Henderson     /* Clear.  */
840*b2167459SRichard Henderson     tcg_gen_movi_tl(dest, 0);
841*b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
842*b2167459SRichard Henderson     tcg_temp_free(dest);
843*b2167459SRichard Henderson 
844*b2167459SRichard Henderson     /* Install the new nullification.  */
845*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
846*b2167459SRichard Henderson     ctx->null_cond = cond;
847*b2167459SRichard Henderson     return NO_EXIT;
848*b2167459SRichard Henderson }
849*b2167459SRichard Henderson 
850*b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
851*b2167459SRichard Henderson                          unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
852*b2167459SRichard Henderson {
853*b2167459SRichard Henderson     TCGv dest = dest_gpr(ctx, rt);
854*b2167459SRichard Henderson 
855*b2167459SRichard Henderson     /* Perform the operation, and writeback.  */
856*b2167459SRichard Henderson     fn(dest, in1, in2);
857*b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
858*b2167459SRichard Henderson 
859*b2167459SRichard Henderson     /* Install the new nullification.  */
860*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
861*b2167459SRichard Henderson     if (cf) {
862*b2167459SRichard Henderson         ctx->null_cond = do_log_cond(cf, dest);
863*b2167459SRichard Henderson     }
864*b2167459SRichard Henderson     return NO_EXIT;
865*b2167459SRichard Henderson }
866*b2167459SRichard Henderson 
867*b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
868*b2167459SRichard Henderson                           TCGv in2, unsigned cf, bool is_tc,
869*b2167459SRichard Henderson                           void (*fn)(TCGv, TCGv, TCGv))
870*b2167459SRichard Henderson {
871*b2167459SRichard Henderson     TCGv dest;
872*b2167459SRichard Henderson     DisasCond cond;
873*b2167459SRichard Henderson 
874*b2167459SRichard Henderson     if (cf == 0) {
875*b2167459SRichard Henderson         dest = dest_gpr(ctx, rt);
876*b2167459SRichard Henderson         fn(dest, in1, in2);
877*b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
878*b2167459SRichard Henderson         cond_free(&ctx->null_cond);
879*b2167459SRichard Henderson     } else {
880*b2167459SRichard Henderson         dest = tcg_temp_new();
881*b2167459SRichard Henderson         fn(dest, in1, in2);
882*b2167459SRichard Henderson 
883*b2167459SRichard Henderson         cond = do_unit_cond(cf, dest, in1, in2);
884*b2167459SRichard Henderson 
885*b2167459SRichard Henderson         if (is_tc) {
886*b2167459SRichard Henderson             TCGv tmp = tcg_temp_new();
887*b2167459SRichard Henderson             cond_prep(&cond);
888*b2167459SRichard Henderson             tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
889*b2167459SRichard Henderson             gen_helper_tcond(cpu_env, tmp);
890*b2167459SRichard Henderson             tcg_temp_free(tmp);
891*b2167459SRichard Henderson         }
892*b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
893*b2167459SRichard Henderson 
894*b2167459SRichard Henderson         cond_free(&ctx->null_cond);
895*b2167459SRichard Henderson         ctx->null_cond = cond;
896*b2167459SRichard Henderson     }
897*b2167459SRichard Henderson     return NO_EXIT;
898*b2167459SRichard Henderson }
899*b2167459SRichard Henderson 
900*b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
901*b2167459SRichard Henderson                             const DisasInsn *di)
902*b2167459SRichard Henderson {
903*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
904*b2167459SRichard Henderson     return NO_EXIT;
905*b2167459SRichard Henderson }
906*b2167459SRichard Henderson 
907*b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
908*b2167459SRichard Henderson                             const DisasInsn *di)
909*b2167459SRichard Henderson {
910*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
911*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
912*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
913*b2167459SRichard Henderson     unsigned ext = extract32(insn, 8, 4);
914*b2167459SRichard Henderson     unsigned shift = extract32(insn, 6, 2);
915*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
916*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
917*b2167459SRichard Henderson     bool is_c = false;
918*b2167459SRichard Henderson     bool is_l = false;
919*b2167459SRichard Henderson     bool is_tc = false;
920*b2167459SRichard Henderson     bool is_tsv = false;
921*b2167459SRichard Henderson     ExitStatus ret;
922*b2167459SRichard Henderson 
923*b2167459SRichard Henderson     switch (ext) {
924*b2167459SRichard Henderson     case 0x6: /* ADD, SHLADD */
925*b2167459SRichard Henderson         break;
926*b2167459SRichard Henderson     case 0xa: /* ADD,L, SHLADD,L */
927*b2167459SRichard Henderson         is_l = true;
928*b2167459SRichard Henderson         break;
929*b2167459SRichard Henderson     case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
930*b2167459SRichard Henderson         is_tsv = true;
931*b2167459SRichard Henderson         break;
932*b2167459SRichard Henderson     case 0x7: /* ADD,C */
933*b2167459SRichard Henderson         is_c = true;
934*b2167459SRichard Henderson         break;
935*b2167459SRichard Henderson     case 0xf: /* ADD,C,TSV */
936*b2167459SRichard Henderson         is_c = is_tsv = true;
937*b2167459SRichard Henderson         break;
938*b2167459SRichard Henderson     default:
939*b2167459SRichard Henderson         return gen_illegal(ctx);
940*b2167459SRichard Henderson     }
941*b2167459SRichard Henderson 
942*b2167459SRichard Henderson     if (cf) {
943*b2167459SRichard Henderson         nullify_over(ctx);
944*b2167459SRichard Henderson     }
945*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
946*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
947*b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
948*b2167459SRichard Henderson     return nullify_end(ctx, ret);
949*b2167459SRichard Henderson }
950*b2167459SRichard Henderson 
951*b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
952*b2167459SRichard Henderson                             const DisasInsn *di)
953*b2167459SRichard Henderson {
954*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
955*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
956*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
957*b2167459SRichard Henderson     unsigned ext = extract32(insn, 6, 6);
958*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
959*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
960*b2167459SRichard Henderson     bool is_b = false;
961*b2167459SRichard Henderson     bool is_tc = false;
962*b2167459SRichard Henderson     bool is_tsv = false;
963*b2167459SRichard Henderson     ExitStatus ret;
964*b2167459SRichard Henderson 
965*b2167459SRichard Henderson     switch (ext) {
966*b2167459SRichard Henderson     case 0x10: /* SUB */
967*b2167459SRichard Henderson         break;
968*b2167459SRichard Henderson     case 0x30: /* SUB,TSV */
969*b2167459SRichard Henderson         is_tsv = true;
970*b2167459SRichard Henderson         break;
971*b2167459SRichard Henderson     case 0x14: /* SUB,B */
972*b2167459SRichard Henderson         is_b = true;
973*b2167459SRichard Henderson         break;
974*b2167459SRichard Henderson     case 0x34: /* SUB,B,TSV */
975*b2167459SRichard Henderson         is_b = is_tsv = true;
976*b2167459SRichard Henderson         break;
977*b2167459SRichard Henderson     case 0x13: /* SUB,TC */
978*b2167459SRichard Henderson         is_tc = true;
979*b2167459SRichard Henderson         break;
980*b2167459SRichard Henderson     case 0x33: /* SUB,TSV,TC */
981*b2167459SRichard Henderson         is_tc = is_tsv = true;
982*b2167459SRichard Henderson         break;
983*b2167459SRichard Henderson     default:
984*b2167459SRichard Henderson         return gen_illegal(ctx);
985*b2167459SRichard Henderson     }
986*b2167459SRichard Henderson 
987*b2167459SRichard Henderson     if (cf) {
988*b2167459SRichard Henderson         nullify_over(ctx);
989*b2167459SRichard Henderson     }
990*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
991*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
992*b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
993*b2167459SRichard Henderson     return nullify_end(ctx, ret);
994*b2167459SRichard Henderson }
995*b2167459SRichard Henderson 
996*b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
997*b2167459SRichard Henderson                             const DisasInsn *di)
998*b2167459SRichard Henderson {
999*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1000*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1001*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1002*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1003*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1004*b2167459SRichard Henderson     ExitStatus ret;
1005*b2167459SRichard Henderson 
1006*b2167459SRichard Henderson     if (cf) {
1007*b2167459SRichard Henderson         nullify_over(ctx);
1008*b2167459SRichard Henderson     }
1009*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1010*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1011*b2167459SRichard Henderson     ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt);
1012*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1013*b2167459SRichard Henderson }
1014*b2167459SRichard Henderson 
1015*b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */
1016*b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1017*b2167459SRichard Henderson                              const DisasInsn *di)
1018*b2167459SRichard Henderson {
1019*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1020*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1021*b2167459SRichard Henderson 
1022*b2167459SRichard Henderson     if (r1 == 0) {
1023*b2167459SRichard Henderson         TCGv dest = dest_gpr(ctx, rt);
1024*b2167459SRichard Henderson         tcg_gen_movi_tl(dest, 0);
1025*b2167459SRichard Henderson         save_gpr(ctx, rt, dest);
1026*b2167459SRichard Henderson     } else {
1027*b2167459SRichard Henderson         save_gpr(ctx, rt, cpu_gr[r1]);
1028*b2167459SRichard Henderson     }
1029*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1030*b2167459SRichard Henderson     return NO_EXIT;
1031*b2167459SRichard Henderson }
1032*b2167459SRichard Henderson 
1033*b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1034*b2167459SRichard Henderson                                const DisasInsn *di)
1035*b2167459SRichard Henderson {
1036*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1037*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1038*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1039*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1040*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1041*b2167459SRichard Henderson     ExitStatus ret;
1042*b2167459SRichard Henderson 
1043*b2167459SRichard Henderson     if (cf) {
1044*b2167459SRichard Henderson         nullify_over(ctx);
1045*b2167459SRichard Henderson     }
1046*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1047*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1048*b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1049*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1050*b2167459SRichard Henderson }
1051*b2167459SRichard Henderson 
1052*b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1053*b2167459SRichard Henderson                              const DisasInsn *di)
1054*b2167459SRichard Henderson {
1055*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1056*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1057*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1058*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1059*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2;
1060*b2167459SRichard Henderson     ExitStatus ret;
1061*b2167459SRichard Henderson 
1062*b2167459SRichard Henderson     if (cf) {
1063*b2167459SRichard Henderson         nullify_over(ctx);
1064*b2167459SRichard Henderson     }
1065*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1066*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1067*b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1068*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1069*b2167459SRichard Henderson }
1070*b2167459SRichard Henderson 
1071*b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1072*b2167459SRichard Henderson                                const DisasInsn *di)
1073*b2167459SRichard Henderson {
1074*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1075*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1076*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1077*b2167459SRichard Henderson     unsigned is_tc = extract32(insn, 6, 1);
1078*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1079*b2167459SRichard Henderson     TCGv tcg_r1, tcg_r2, tmp;
1080*b2167459SRichard Henderson     ExitStatus ret;
1081*b2167459SRichard Henderson 
1082*b2167459SRichard Henderson     if (cf) {
1083*b2167459SRichard Henderson         nullify_over(ctx);
1084*b2167459SRichard Henderson     }
1085*b2167459SRichard Henderson     tcg_r1 = load_gpr(ctx, r1);
1086*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1087*b2167459SRichard Henderson     tmp = get_temp(ctx);
1088*b2167459SRichard Henderson     tcg_gen_not_tl(tmp, tcg_r2);
1089*b2167459SRichard Henderson     ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
1090*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1091*b2167459SRichard Henderson }
1092*b2167459SRichard Henderson 
1093*b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
1094*b2167459SRichard Henderson                              const DisasInsn *di)
1095*b2167459SRichard Henderson {
1096*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1097*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1098*b2167459SRichard Henderson     unsigned is_i = extract32(insn, 6, 1);
1099*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1100*b2167459SRichard Henderson     TCGv tmp;
1101*b2167459SRichard Henderson     ExitStatus ret;
1102*b2167459SRichard Henderson 
1103*b2167459SRichard Henderson     nullify_over(ctx);
1104*b2167459SRichard Henderson 
1105*b2167459SRichard Henderson     tmp = get_temp(ctx);
1106*b2167459SRichard Henderson     tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
1107*b2167459SRichard Henderson     if (!is_i) {
1108*b2167459SRichard Henderson         tcg_gen_not_tl(tmp, tmp);
1109*b2167459SRichard Henderson     }
1110*b2167459SRichard Henderson     tcg_gen_andi_tl(tmp, tmp, 0x11111111);
1111*b2167459SRichard Henderson     tcg_gen_muli_tl(tmp, tmp, 6);
1112*b2167459SRichard Henderson     ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
1113*b2167459SRichard Henderson                   is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
1114*b2167459SRichard Henderson 
1115*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1116*b2167459SRichard Henderson }
1117*b2167459SRichard Henderson 
1118*b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
1119*b2167459SRichard Henderson                            const DisasInsn *di)
1120*b2167459SRichard Henderson {
1121*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1122*b2167459SRichard Henderson     unsigned r1 = extract32(insn, 16, 5);
1123*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1124*b2167459SRichard Henderson     unsigned rt = extract32(insn,  0, 5);
1125*b2167459SRichard Henderson     TCGv dest, add1, add2, addc, zero, in1, in2;
1126*b2167459SRichard Henderson 
1127*b2167459SRichard Henderson     nullify_over(ctx);
1128*b2167459SRichard Henderson 
1129*b2167459SRichard Henderson     in1 = load_gpr(ctx, r1);
1130*b2167459SRichard Henderson     in2 = load_gpr(ctx, r2);
1131*b2167459SRichard Henderson 
1132*b2167459SRichard Henderson     add1 = tcg_temp_new();
1133*b2167459SRichard Henderson     add2 = tcg_temp_new();
1134*b2167459SRichard Henderson     addc = tcg_temp_new();
1135*b2167459SRichard Henderson     dest = tcg_temp_new();
1136*b2167459SRichard Henderson     zero = tcg_const_tl(0);
1137*b2167459SRichard Henderson 
1138*b2167459SRichard Henderson     /* Form R1 << 1 | PSW[CB]{8}.  */
1139*b2167459SRichard Henderson     tcg_gen_add_tl(add1, in1, in1);
1140*b2167459SRichard Henderson     tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
1141*b2167459SRichard Henderson 
1142*b2167459SRichard Henderson     /* Add or subtract R2, depending on PSW[V].  Proper computation of
1143*b2167459SRichard Henderson        carry{8} requires that we subtract via + ~R2 + 1, as described in
1144*b2167459SRichard Henderson        the manual.  By extracting and masking V, we can produce the
1145*b2167459SRichard Henderson        proper inputs to the addition without movcond.  */
1146*b2167459SRichard Henderson     tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
1147*b2167459SRichard Henderson     tcg_gen_xor_tl(add2, in2, addc);
1148*b2167459SRichard Henderson     tcg_gen_andi_tl(addc, addc, 1);
1149*b2167459SRichard Henderson     /* ??? This is only correct for 32-bit.  */
1150*b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
1151*b2167459SRichard Henderson     tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
1152*b2167459SRichard Henderson 
1153*b2167459SRichard Henderson     tcg_temp_free(addc);
1154*b2167459SRichard Henderson     tcg_temp_free(zero);
1155*b2167459SRichard Henderson 
1156*b2167459SRichard Henderson     /* Write back the result register.  */
1157*b2167459SRichard Henderson     save_gpr(ctx, rt, dest);
1158*b2167459SRichard Henderson 
1159*b2167459SRichard Henderson     /* Write back PSW[CB].  */
1160*b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
1161*b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
1162*b2167459SRichard Henderson 
1163*b2167459SRichard Henderson     /* Write back PSW[V] for the division step.  */
1164*b2167459SRichard Henderson     tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
1165*b2167459SRichard Henderson     tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
1166*b2167459SRichard Henderson 
1167*b2167459SRichard Henderson     /* Install the new nullification.  */
1168*b2167459SRichard Henderson     if (cf) {
1169*b2167459SRichard Henderson         TCGv sv;
1170*b2167459SRichard Henderson         TCGV_UNUSED(sv);
1171*b2167459SRichard Henderson         if (cf >> 1 == 6) {
1172*b2167459SRichard Henderson             /* ??? The lshift is supposed to contribute to overflow.  */
1173*b2167459SRichard Henderson             sv = do_add_sv(ctx, dest, add1, add2);
1174*b2167459SRichard Henderson         }
1175*b2167459SRichard Henderson         ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
1176*b2167459SRichard Henderson     }
1177*b2167459SRichard Henderson 
1178*b2167459SRichard Henderson     tcg_temp_free(add1);
1179*b2167459SRichard Henderson     tcg_temp_free(add2);
1180*b2167459SRichard Henderson     tcg_temp_free(dest);
1181*b2167459SRichard Henderson 
1182*b2167459SRichard Henderson     return nullify_end(ctx, NO_EXIT);
1183*b2167459SRichard Henderson }
1184*b2167459SRichard Henderson 
1185*b2167459SRichard Henderson static const DisasInsn table_arith_log[] = {
1186*b2167459SRichard Henderson     { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
1187*b2167459SRichard Henderson     { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
1188*b2167459SRichard Henderson     { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl },
1189*b2167459SRichard Henderson     { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl },
1190*b2167459SRichard Henderson     { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl },
1191*b2167459SRichard Henderson     { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl },
1192*b2167459SRichard Henderson     { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
1193*b2167459SRichard Henderson     { 0x08000380u, 0xfc000fe0u, trans_uxor },
1194*b2167459SRichard Henderson     { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
1195*b2167459SRichard Henderson     { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
1196*b2167459SRichard Henderson     { 0x08000440u, 0xfc000fe0u, trans_ds },
1197*b2167459SRichard Henderson     { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
1198*b2167459SRichard Henderson     { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
1199*b2167459SRichard Henderson     { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
1200*b2167459SRichard Henderson     { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
1201*b2167459SRichard Henderson };
1202*b2167459SRichard Henderson 
1203*b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
1204*b2167459SRichard Henderson {
1205*b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1206*b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1207*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1208*b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1209*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1210*b2167459SRichard Henderson     unsigned o1 = extract32(insn, 26, 1);
1211*b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1212*b2167459SRichard Henderson     ExitStatus ret;
1213*b2167459SRichard Henderson 
1214*b2167459SRichard Henderson     if (cf) {
1215*b2167459SRichard Henderson         nullify_over(ctx);
1216*b2167459SRichard Henderson     }
1217*b2167459SRichard Henderson 
1218*b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1219*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1220*b2167459SRichard Henderson     ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
1221*b2167459SRichard Henderson 
1222*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1223*b2167459SRichard Henderson }
1224*b2167459SRichard Henderson 
1225*b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
1226*b2167459SRichard Henderson {
1227*b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1228*b2167459SRichard Henderson     unsigned e1 = extract32(insn, 11, 1);
1229*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1230*b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1231*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1232*b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1233*b2167459SRichard Henderson     ExitStatus ret;
1234*b2167459SRichard Henderson 
1235*b2167459SRichard Henderson     if (cf) {
1236*b2167459SRichard Henderson         nullify_over(ctx);
1237*b2167459SRichard Henderson     }
1238*b2167459SRichard Henderson 
1239*b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1240*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1241*b2167459SRichard Henderson     ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
1242*b2167459SRichard Henderson 
1243*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1244*b2167459SRichard Henderson }
1245*b2167459SRichard Henderson 
1246*b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
1247*b2167459SRichard Henderson {
1248*b2167459SRichard Henderson     target_long im = low_sextract(insn, 0, 11);
1249*b2167459SRichard Henderson     unsigned cf = extract32(insn, 12, 4);
1250*b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1251*b2167459SRichard Henderson     unsigned r2 = extract32(insn, 21, 5);
1252*b2167459SRichard Henderson     TCGv tcg_im, tcg_r2;
1253*b2167459SRichard Henderson     ExitStatus ret;
1254*b2167459SRichard Henderson 
1255*b2167459SRichard Henderson     if (cf) {
1256*b2167459SRichard Henderson         nullify_over(ctx);
1257*b2167459SRichard Henderson     }
1258*b2167459SRichard Henderson 
1259*b2167459SRichard Henderson     tcg_im = load_const(ctx, im);
1260*b2167459SRichard Henderson     tcg_r2 = load_gpr(ctx, r2);
1261*b2167459SRichard Henderson     ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
1262*b2167459SRichard Henderson 
1263*b2167459SRichard Henderson     return nullify_end(ctx, ret);
1264*b2167459SRichard Henderson }
1265*b2167459SRichard Henderson 
1266*b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
1267*b2167459SRichard Henderson {
1268*b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1269*b2167459SRichard Henderson     target_long i = assemble_21(insn);
1270*b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
1271*b2167459SRichard Henderson 
1272*b2167459SRichard Henderson     tcg_gen_movi_tl(tcg_rt, i);
1273*b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
1274*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1275*b2167459SRichard Henderson 
1276*b2167459SRichard Henderson     return NO_EXIT;
1277*b2167459SRichard Henderson }
1278*b2167459SRichard Henderson 
1279*b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
1280*b2167459SRichard Henderson {
1281*b2167459SRichard Henderson     unsigned rt = extract32(insn, 21, 5);
1282*b2167459SRichard Henderson     target_long i = assemble_21(insn);
1283*b2167459SRichard Henderson     TCGv tcg_rt = load_gpr(ctx, rt);
1284*b2167459SRichard Henderson     TCGv tcg_r1 = dest_gpr(ctx, 1);
1285*b2167459SRichard Henderson 
1286*b2167459SRichard Henderson     tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
1287*b2167459SRichard Henderson     save_gpr(ctx, 1, tcg_r1);
1288*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1289*b2167459SRichard Henderson 
1290*b2167459SRichard Henderson     return NO_EXIT;
1291*b2167459SRichard Henderson }
1292*b2167459SRichard Henderson 
1293*b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
1294*b2167459SRichard Henderson {
1295*b2167459SRichard Henderson     unsigned rb = extract32(insn, 21, 5);
1296*b2167459SRichard Henderson     unsigned rt = extract32(insn, 16, 5);
1297*b2167459SRichard Henderson     target_long i = assemble_16(insn);
1298*b2167459SRichard Henderson     TCGv tcg_rt = dest_gpr(ctx, rt);
1299*b2167459SRichard Henderson 
1300*b2167459SRichard Henderson     /* Special case rb == 0, for the LDI pseudo-op.
1301*b2167459SRichard Henderson        The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
1302*b2167459SRichard Henderson     if (rb == 0) {
1303*b2167459SRichard Henderson         tcg_gen_movi_tl(tcg_rt, i);
1304*b2167459SRichard Henderson     } else {
1305*b2167459SRichard Henderson         tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
1306*b2167459SRichard Henderson     }
1307*b2167459SRichard Henderson     save_gpr(ctx, rt, tcg_rt);
1308*b2167459SRichard Henderson     cond_free(&ctx->null_cond);
1309*b2167459SRichard Henderson 
1310*b2167459SRichard Henderson     return NO_EXIT;
1311*b2167459SRichard Henderson }
1312*b2167459SRichard Henderson 
131361766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
131461766fe9SRichard Henderson                                       const DisasInsn table[], size_t n)
131561766fe9SRichard Henderson {
131661766fe9SRichard Henderson     size_t i;
131761766fe9SRichard Henderson     for (i = 0; i < n; ++i) {
131861766fe9SRichard Henderson         if ((insn & table[i].mask) == table[i].insn) {
131961766fe9SRichard Henderson             return table[i].trans(ctx, insn, &table[i]);
132061766fe9SRichard Henderson         }
132161766fe9SRichard Henderson     }
132261766fe9SRichard Henderson     return gen_illegal(ctx);
132361766fe9SRichard Henderson }
132461766fe9SRichard Henderson 
132561766fe9SRichard Henderson #define translate_table(ctx, insn, table) \
132661766fe9SRichard Henderson     translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
132761766fe9SRichard Henderson 
132861766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
132961766fe9SRichard Henderson {
133061766fe9SRichard Henderson     uint32_t opc = extract32(insn, 26, 6);
133161766fe9SRichard Henderson 
133261766fe9SRichard Henderson     switch (opc) {
1333*b2167459SRichard Henderson     case 0x02:
1334*b2167459SRichard Henderson         return translate_table(ctx, insn, table_arith_log);
1335*b2167459SRichard Henderson     case 0x08:
1336*b2167459SRichard Henderson         return trans_ldil(ctx, insn);
1337*b2167459SRichard Henderson     case 0x0A:
1338*b2167459SRichard Henderson         return trans_addil(ctx, insn);
1339*b2167459SRichard Henderson     case 0x0D:
1340*b2167459SRichard Henderson         return trans_ldo(ctx, insn);
1341*b2167459SRichard Henderson     case 0x24:
1342*b2167459SRichard Henderson         return trans_cmpiclr(ctx, insn);
1343*b2167459SRichard Henderson     case 0x25:
1344*b2167459SRichard Henderson         return trans_subi(ctx, insn);
1345*b2167459SRichard Henderson     case 0x2C:
1346*b2167459SRichard Henderson     case 0x2D:
1347*b2167459SRichard Henderson         return trans_addi(ctx, insn);
134861766fe9SRichard Henderson     default:
134961766fe9SRichard Henderson         break;
135061766fe9SRichard Henderson     }
135161766fe9SRichard Henderson     return gen_illegal(ctx);
135261766fe9SRichard Henderson }
135361766fe9SRichard Henderson 
135461766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
135561766fe9SRichard Henderson {
135661766fe9SRichard Henderson     HPPACPU *cpu = hppa_env_get_cpu(env);
135761766fe9SRichard Henderson     CPUState *cs = CPU(cpu);
135861766fe9SRichard Henderson     DisasContext ctx;
135961766fe9SRichard Henderson     ExitStatus ret;
136061766fe9SRichard Henderson     int num_insns, max_insns, i;
136161766fe9SRichard Henderson 
136261766fe9SRichard Henderson     ctx.tb = tb;
136361766fe9SRichard Henderson     ctx.cs = cs;
136461766fe9SRichard Henderson     ctx.iaoq_f = tb->pc;
136561766fe9SRichard Henderson     ctx.iaoq_b = tb->cs_base;
136661766fe9SRichard Henderson     ctx.singlestep_enabled = cs->singlestep_enabled;
136761766fe9SRichard Henderson 
136861766fe9SRichard Henderson     ctx.ntemps = 0;
136961766fe9SRichard Henderson     for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
137061766fe9SRichard Henderson         TCGV_UNUSED(ctx.temps[i]);
137161766fe9SRichard Henderson     }
137261766fe9SRichard Henderson 
137361766fe9SRichard Henderson     /* Compute the maximum number of insns to execute, as bounded by
137461766fe9SRichard Henderson        (1) icount, (2) single-stepping, (3) branch delay slots, or
137561766fe9SRichard Henderson        (4) the number of insns remaining on the current page.  */
137661766fe9SRichard Henderson     max_insns = tb->cflags & CF_COUNT_MASK;
137761766fe9SRichard Henderson     if (max_insns == 0) {
137861766fe9SRichard Henderson         max_insns = CF_COUNT_MASK;
137961766fe9SRichard Henderson     }
138061766fe9SRichard Henderson     if (ctx.singlestep_enabled || singlestep) {
138161766fe9SRichard Henderson         max_insns = 1;
138261766fe9SRichard Henderson     } else if (max_insns > TCG_MAX_INSNS) {
138361766fe9SRichard Henderson         max_insns = TCG_MAX_INSNS;
138461766fe9SRichard Henderson     }
138561766fe9SRichard Henderson 
138661766fe9SRichard Henderson     num_insns = 0;
138761766fe9SRichard Henderson     gen_tb_start(tb);
138861766fe9SRichard Henderson 
1389129e9cc3SRichard Henderson     /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
1390129e9cc3SRichard Henderson     ctx.null_cond = cond_make_f();
1391129e9cc3SRichard Henderson     ctx.psw_n_nonzero = false;
1392129e9cc3SRichard Henderson     if (tb->flags & 1) {
1393129e9cc3SRichard Henderson         ctx.null_cond.c = TCG_COND_ALWAYS;
1394129e9cc3SRichard Henderson         ctx.psw_n_nonzero = true;
1395129e9cc3SRichard Henderson     }
1396129e9cc3SRichard Henderson     ctx.null_lab = NULL;
1397129e9cc3SRichard Henderson 
139861766fe9SRichard Henderson     do {
139961766fe9SRichard Henderson         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
140061766fe9SRichard Henderson         num_insns++;
140161766fe9SRichard Henderson 
140261766fe9SRichard Henderson         if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
140361766fe9SRichard Henderson             ret = gen_excp(&ctx, EXCP_DEBUG);
140461766fe9SRichard Henderson             break;
140561766fe9SRichard Henderson         }
140661766fe9SRichard Henderson         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
140761766fe9SRichard Henderson             gen_io_start();
140861766fe9SRichard Henderson         }
140961766fe9SRichard Henderson 
141061766fe9SRichard Henderson         {
141161766fe9SRichard Henderson             /* Always fetch the insn, even if nullified, so that we check
141261766fe9SRichard Henderson                the page permissions for execute.  */
141361766fe9SRichard Henderson             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
141461766fe9SRichard Henderson 
141561766fe9SRichard Henderson             /* Set up the IA queue for the next insn.
141661766fe9SRichard Henderson                This will be overwritten by a branch.  */
141761766fe9SRichard Henderson             if (ctx.iaoq_b == -1) {
141861766fe9SRichard Henderson                 ctx.iaoq_n = -1;
141961766fe9SRichard Henderson                 ctx.iaoq_n_var = get_temp(&ctx);
142061766fe9SRichard Henderson                 tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
142161766fe9SRichard Henderson             } else {
142261766fe9SRichard Henderson                 ctx.iaoq_n = ctx.iaoq_b + 4;
142361766fe9SRichard Henderson                 TCGV_UNUSED(ctx.iaoq_n_var);
142461766fe9SRichard Henderson             }
142561766fe9SRichard Henderson 
1426129e9cc3SRichard Henderson             if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
1427129e9cc3SRichard Henderson                 ctx.null_cond.c = TCG_COND_NEVER;
1428129e9cc3SRichard Henderson                 ret = NO_EXIT;
1429129e9cc3SRichard Henderson             } else {
143061766fe9SRichard Henderson                 ret = translate_one(&ctx, insn);
1431129e9cc3SRichard Henderson                 assert(ctx.null_lab == NULL);
1432129e9cc3SRichard Henderson             }
143361766fe9SRichard Henderson         }
143461766fe9SRichard Henderson 
143561766fe9SRichard Henderson         for (i = 0; i < ctx.ntemps; ++i) {
143661766fe9SRichard Henderson             tcg_temp_free(ctx.temps[i]);
143761766fe9SRichard Henderson             TCGV_UNUSED(ctx.temps[i]);
143861766fe9SRichard Henderson         }
143961766fe9SRichard Henderson         ctx.ntemps = 0;
144061766fe9SRichard Henderson 
144161766fe9SRichard Henderson         /* If we see non-linear instructions, exhaust instruction count,
144261766fe9SRichard Henderson            or run out of buffer space, stop generation.  */
144361766fe9SRichard Henderson         /* ??? The non-linear instruction restriction is purely due to
144461766fe9SRichard Henderson            the debugging dump.  Otherwise we *could* follow unconditional
144561766fe9SRichard Henderson            branches within the same page.  */
144661766fe9SRichard Henderson         if (ret == NO_EXIT
144761766fe9SRichard Henderson             && (ctx.iaoq_b != ctx.iaoq_f + 4
144861766fe9SRichard Henderson                 || num_insns >= max_insns
144961766fe9SRichard Henderson                 || tcg_op_buf_full())) {
1450129e9cc3SRichard Henderson             if (ctx.null_cond.c == TCG_COND_NEVER
1451129e9cc3SRichard Henderson                 || ctx.null_cond.c == TCG_COND_ALWAYS) {
1452129e9cc3SRichard Henderson                 nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
1453129e9cc3SRichard Henderson                 gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
1454129e9cc3SRichard Henderson                 ret = EXIT_GOTO_TB;
1455129e9cc3SRichard Henderson             } else {
145661766fe9SRichard Henderson                 ret = EXIT_IAQ_N_STALE;
145761766fe9SRichard Henderson             }
1458129e9cc3SRichard Henderson         }
145961766fe9SRichard Henderson 
146061766fe9SRichard Henderson         ctx.iaoq_f = ctx.iaoq_b;
146161766fe9SRichard Henderson         ctx.iaoq_b = ctx.iaoq_n;
146261766fe9SRichard Henderson         if (ret == EXIT_NORETURN
146361766fe9SRichard Henderson             || ret == EXIT_GOTO_TB
146461766fe9SRichard Henderson             || ret == EXIT_IAQ_N_UPDATED) {
146561766fe9SRichard Henderson             break;
146661766fe9SRichard Henderson         }
146761766fe9SRichard Henderson         if (ctx.iaoq_f == -1) {
146861766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
146961766fe9SRichard Henderson             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
1470129e9cc3SRichard Henderson             nullify_save(&ctx);
147161766fe9SRichard Henderson             ret = EXIT_IAQ_N_UPDATED;
147261766fe9SRichard Henderson             break;
147361766fe9SRichard Henderson         }
147461766fe9SRichard Henderson         if (ctx.iaoq_b == -1) {
147561766fe9SRichard Henderson             tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
147661766fe9SRichard Henderson         }
147761766fe9SRichard Henderson     } while (ret == NO_EXIT);
147861766fe9SRichard Henderson 
147961766fe9SRichard Henderson     if (tb->cflags & CF_LAST_IO) {
148061766fe9SRichard Henderson         gen_io_end();
148161766fe9SRichard Henderson     }
148261766fe9SRichard Henderson 
148361766fe9SRichard Henderson     switch (ret) {
148461766fe9SRichard Henderson     case EXIT_GOTO_TB:
148561766fe9SRichard Henderson     case EXIT_NORETURN:
148661766fe9SRichard Henderson         break;
148761766fe9SRichard Henderson     case EXIT_IAQ_N_STALE:
148861766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
148961766fe9SRichard Henderson         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
1490129e9cc3SRichard Henderson         nullify_save(&ctx);
149161766fe9SRichard Henderson         /* FALLTHRU */
149261766fe9SRichard Henderson     case EXIT_IAQ_N_UPDATED:
149361766fe9SRichard Henderson         if (ctx.singlestep_enabled) {
149461766fe9SRichard Henderson             gen_excp_1(EXCP_DEBUG);
149561766fe9SRichard Henderson         } else {
149661766fe9SRichard Henderson             tcg_gen_exit_tb(0);
149761766fe9SRichard Henderson         }
149861766fe9SRichard Henderson         break;
149961766fe9SRichard Henderson     default:
150061766fe9SRichard Henderson         abort();
150161766fe9SRichard Henderson     }
150261766fe9SRichard Henderson 
150361766fe9SRichard Henderson     gen_tb_end(tb, num_insns);
150461766fe9SRichard Henderson 
150561766fe9SRichard Henderson     tb->size = num_insns * 4;
150661766fe9SRichard Henderson     tb->icount = num_insns;
150761766fe9SRichard Henderson 
150861766fe9SRichard Henderson #ifdef DEBUG_DISAS
150961766fe9SRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
151061766fe9SRichard Henderson         && qemu_log_in_addr_range(tb->pc)) {
151161766fe9SRichard Henderson         qemu_log_lock();
151261766fe9SRichard Henderson         qemu_log("IN: %s\n", lookup_symbol(tb->pc));
151361766fe9SRichard Henderson         log_target_disas(cs, tb->pc, tb->size, 1);
151461766fe9SRichard Henderson         qemu_log("\n");
151561766fe9SRichard Henderson         qemu_log_unlock();
151661766fe9SRichard Henderson     }
151761766fe9SRichard Henderson #endif
151861766fe9SRichard Henderson }
151961766fe9SRichard Henderson 
152061766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
152161766fe9SRichard Henderson                           target_ulong *data)
152261766fe9SRichard Henderson {
152361766fe9SRichard Henderson     env->iaoq_f = data[0];
152461766fe9SRichard Henderson     if (data[1] != -1) {
152561766fe9SRichard Henderson         env->iaoq_b = data[1];
152661766fe9SRichard Henderson     }
152761766fe9SRichard Henderson     /* Since we were executing the instruction at IAOQ_F, and took some
152861766fe9SRichard Henderson        sort of action that provoked the cpu_restore_state, we can infer
152961766fe9SRichard Henderson        that the instruction was not nullified.  */
153061766fe9SRichard Henderson     env->psw_n = 0;
153161766fe9SRichard Henderson }
1532