qemu/target/hppa/translate.c
<<
>>
Prefs
   1/*
   2 * HPPA emulation cpu translation for qemu.
   3 *
   4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.h"
  22#include "disas/disas.h"
  23#include "qemu/host-utils.h"
  24#include "exec/exec-all.h"
  25#include "tcg-op.h"
  26#include "exec/cpu_ldst.h"
  27
  28#include "exec/helper-proto.h"
  29#include "exec/helper-gen.h"
  30
  31#include "trace-tcg.h"
  32#include "exec/log.h"
  33
  34typedef struct DisasCond {
  35    TCGCond c;
  36    TCGv a0, a1;
  37    bool a0_is_n;
  38    bool a1_is_0;
  39} DisasCond;
  40
  41typedef struct DisasContext {
  42    struct TranslationBlock *tb;
  43    CPUState *cs;
  44
  45    target_ulong iaoq_f;
  46    target_ulong iaoq_b;
  47    target_ulong iaoq_n;
  48    TCGv iaoq_n_var;
  49
  50    int ntemps;
  51    TCGv temps[8];
  52
  53    DisasCond null_cond;
  54    TCGLabel *null_lab;
  55
  56    bool singlestep_enabled;
  57    bool psw_n_nonzero;
  58} DisasContext;
  59
  60/* Return values from translate_one, indicating the state of the TB.
  61   Note that zero indicates that we are not exiting the TB.  */
  62
  63typedef enum {
  64    NO_EXIT,
  65
  66    /* We have emitted one or more goto_tb.  No fixup required.  */
  67    EXIT_GOTO_TB,
  68
  69    /* We are not using a goto_tb (for whatever reason), but have updated
  70       the iaq (for whatever reason), so don't do it again on exit.  */
  71    EXIT_IAQ_N_UPDATED,
  72
  73    /* We are exiting the TB, but have neither emitted a goto_tb, nor
  74       updated the iaq for the next instruction to be executed.  */
  75    EXIT_IAQ_N_STALE,
  76
  77    /* We are ending the TB with a noreturn function call, e.g. longjmp.
  78       No following code will be executed.  */
  79    EXIT_NORETURN,
  80} ExitStatus;
  81
  82typedef struct DisasInsn {
  83    uint32_t insn, mask;
  84    ExitStatus (*trans)(DisasContext *ctx, uint32_t insn,
  85                        const struct DisasInsn *f);
  86    union {
  87        void (*ttt)(TCGv, TCGv, TCGv);
  88        void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
  89        void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
  90        void (*wew)(TCGv_i32, TCGv_env, TCGv_i32);
  91        void (*ded)(TCGv_i64, TCGv_env, TCGv_i64);
  92        void (*wed)(TCGv_i32, TCGv_env, TCGv_i64);
  93        void (*dew)(TCGv_i64, TCGv_env, TCGv_i32);
  94    } f;
  95} DisasInsn;
  96
  97/* global register indexes */
  98static TCGv_env cpu_env;
  99static TCGv cpu_gr[32];
 100static TCGv cpu_iaoq_f;
 101static TCGv cpu_iaoq_b;
 102static TCGv cpu_sar;
 103static TCGv cpu_psw_n;
 104static TCGv cpu_psw_v;
 105static TCGv cpu_psw_cb;
 106static TCGv cpu_psw_cb_msb;
 107static TCGv cpu_cr26;
 108static TCGv cpu_cr27;
 109
 110#include "exec/gen-icount.h"
 111
 112void hppa_translate_init(void)
 113{
 114#define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
 115
 116    typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
 117    static const GlobalVar vars[] = {
 118        DEF_VAR(sar),
 119        DEF_VAR(cr26),
 120        DEF_VAR(cr27),
 121        DEF_VAR(psw_n),
 122        DEF_VAR(psw_v),
 123        DEF_VAR(psw_cb),
 124        DEF_VAR(psw_cb_msb),
 125        DEF_VAR(iaoq_f),
 126        DEF_VAR(iaoq_b),
 127    };
 128
 129#undef DEF_VAR
 130
 131    /* Use the symbolic register names that match the disassembler.  */
 132    static const char gr_names[32][4] = {
 133        "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
 134        "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
 135        "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
 136        "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
 137    };
 138
 139    static bool done_init = 0;
 140    int i;
 141
 142    if (done_init) {
 143        return;
 144    }
 145    done_init = 1;
 146
 147    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 148    tcg_ctx.tcg_env = cpu_env;
 149
 150    TCGV_UNUSED(cpu_gr[0]);
 151    for (i = 1; i < 32; i++) {
 152        cpu_gr[i] = tcg_global_mem_new(cpu_env,
 153                                       offsetof(CPUHPPAState, gr[i]),
 154                                       gr_names[i]);
 155    }
 156
 157    for (i = 0; i < ARRAY_SIZE(vars); ++i) {
 158        const GlobalVar *v = &vars[i];
 159        *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
 160    }
 161}
 162
 163static DisasCond cond_make_f(void)
 164{
 165    DisasCond r = { .c = TCG_COND_NEVER };
 166    TCGV_UNUSED(r.a0);
 167    TCGV_UNUSED(r.a1);
 168    return r;
 169}
 170
 171static DisasCond cond_make_n(void)
 172{
 173    DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
 174    r.a0 = cpu_psw_n;
 175    TCGV_UNUSED(r.a1);
 176    return r;
 177}
 178
 179static DisasCond cond_make_0(TCGCond c, TCGv a0)
 180{
 181    DisasCond r = { .c = c, .a1_is_0 = true };
 182
 183    assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
 184    r.a0 = tcg_temp_new();
 185    tcg_gen_mov_tl(r.a0, a0);
 186    TCGV_UNUSED(r.a1);
 187
 188    return r;
 189}
 190
 191static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
 192{
 193    DisasCond r = { .c = c };
 194
 195    assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
 196    r.a0 = tcg_temp_new();
 197    tcg_gen_mov_tl(r.a0, a0);
 198    r.a1 = tcg_temp_new();
 199    tcg_gen_mov_tl(r.a1, a1);
 200
 201    return r;
 202}
 203
 204static void cond_prep(DisasCond *cond)
 205{
 206    if (cond->a1_is_0) {
 207        cond->a1_is_0 = false;
 208        cond->a1 = tcg_const_tl(0);
 209    }
 210}
 211
 212static void cond_free(DisasCond *cond)
 213{
 214    switch (cond->c) {
 215    default:
 216        if (!cond->a0_is_n) {
 217            tcg_temp_free(cond->a0);
 218        }
 219        if (!cond->a1_is_0) {
 220            tcg_temp_free(cond->a1);
 221        }
 222        cond->a0_is_n = false;
 223        cond->a1_is_0 = false;
 224        TCGV_UNUSED(cond->a0);
 225        TCGV_UNUSED(cond->a1);
 226        /* fallthru */
 227    case TCG_COND_ALWAYS:
 228        cond->c = TCG_COND_NEVER;
 229        break;
 230    case TCG_COND_NEVER:
 231        break;
 232    }
 233}
 234
 235static TCGv get_temp(DisasContext *ctx)
 236{
 237    unsigned i = ctx->ntemps++;
 238    g_assert(i < ARRAY_SIZE(ctx->temps));
 239    return ctx->temps[i] = tcg_temp_new();
 240}
 241
 242static TCGv load_const(DisasContext *ctx, target_long v)
 243{
 244    TCGv t = get_temp(ctx);
 245    tcg_gen_movi_tl(t, v);
 246    return t;
 247}
 248
 249static TCGv load_gpr(DisasContext *ctx, unsigned reg)
 250{
 251    if (reg == 0) {
 252        TCGv t = get_temp(ctx);
 253        tcg_gen_movi_tl(t, 0);
 254        return t;
 255    } else {
 256        return cpu_gr[reg];
 257    }
 258}
 259
 260static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
 261{
 262    if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
 263        return get_temp(ctx);
 264    } else {
 265        return cpu_gr[reg];
 266    }
 267}
 268
 269static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
 270{
 271    if (ctx->null_cond.c != TCG_COND_NEVER) {
 272        cond_prep(&ctx->null_cond);
 273        tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
 274                           ctx->null_cond.a1, dest, t);
 275    } else {
 276        tcg_gen_mov_tl(dest, t);
 277    }
 278}
 279
 280static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
 281{
 282    if (reg != 0) {
 283        save_or_nullify(ctx, cpu_gr[reg], t);
 284    }
 285}
 286
 287#ifdef HOST_WORDS_BIGENDIAN
 288# define HI_OFS  0
 289# define LO_OFS  4
 290#else
 291# define HI_OFS  4
 292# define LO_OFS  0
 293#endif
 294
 295static TCGv_i32 load_frw_i32(unsigned rt)
 296{
 297    TCGv_i32 ret = tcg_temp_new_i32();
 298    tcg_gen_ld_i32(ret, cpu_env,
 299                   offsetof(CPUHPPAState, fr[rt & 31])
 300                   + (rt & 32 ? LO_OFS : HI_OFS));
 301    return ret;
 302}
 303
 304static TCGv_i32 load_frw0_i32(unsigned rt)
 305{
 306    if (rt == 0) {
 307        return tcg_const_i32(0);
 308    } else {
 309        return load_frw_i32(rt);
 310    }
 311}
 312
 313static TCGv_i64 load_frw0_i64(unsigned rt)
 314{
 315    if (rt == 0) {
 316        return tcg_const_i64(0);
 317    } else {
 318        TCGv_i64 ret = tcg_temp_new_i64();
 319        tcg_gen_ld32u_i64(ret, cpu_env,
 320                          offsetof(CPUHPPAState, fr[rt & 31])
 321                          + (rt & 32 ? LO_OFS : HI_OFS));
 322        return ret;
 323    }
 324}
 325
 326static void save_frw_i32(unsigned rt, TCGv_i32 val)
 327{
 328    tcg_gen_st_i32(val, cpu_env,
 329                   offsetof(CPUHPPAState, fr[rt & 31])
 330                   + (rt & 32 ? LO_OFS : HI_OFS));
 331}
 332
 333#undef HI_OFS
 334#undef LO_OFS
 335
 336static TCGv_i64 load_frd(unsigned rt)
 337{
 338    TCGv_i64 ret = tcg_temp_new_i64();
 339    tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
 340    return ret;
 341}
 342
 343static TCGv_i64 load_frd0(unsigned rt)
 344{
 345    if (rt == 0) {
 346        return tcg_const_i64(0);
 347    } else {
 348        return load_frd(rt);
 349    }
 350}
 351
 352static void save_frd(unsigned rt, TCGv_i64 val)
 353{
 354    tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
 355}
 356
 357/* Skip over the implementation of an insn that has been nullified.
 358   Use this when the insn is too complex for a conditional move.  */
 359static void nullify_over(DisasContext *ctx)
 360{
 361    if (ctx->null_cond.c != TCG_COND_NEVER) {
 362        /* The always condition should have been handled in the main loop.  */
 363        assert(ctx->null_cond.c != TCG_COND_ALWAYS);
 364
 365        ctx->null_lab = gen_new_label();
 366        cond_prep(&ctx->null_cond);
 367
 368        /* If we're using PSW[N], copy it to a temp because... */
 369        if (ctx->null_cond.a0_is_n) {
 370            ctx->null_cond.a0_is_n = false;
 371            ctx->null_cond.a0 = tcg_temp_new();
 372            tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
 373        }
 374        /* ... we clear it before branching over the implementation,
 375           so that (1) it's clear after nullifying this insn and
 376           (2) if this insn nullifies the next, PSW[N] is valid.  */
 377        if (ctx->psw_n_nonzero) {
 378            ctx->psw_n_nonzero = false;
 379            tcg_gen_movi_tl(cpu_psw_n, 0);
 380        }
 381
 382        tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
 383                          ctx->null_cond.a1, ctx->null_lab);
 384        cond_free(&ctx->null_cond);
 385    }
 386}
 387
 388/* Save the current nullification state to PSW[N].  */
 389static void nullify_save(DisasContext *ctx)
 390{
 391    if (ctx->null_cond.c == TCG_COND_NEVER) {
 392        if (ctx->psw_n_nonzero) {
 393            tcg_gen_movi_tl(cpu_psw_n, 0);
 394        }
 395        return;
 396    }
 397    if (!ctx->null_cond.a0_is_n) {
 398        cond_prep(&ctx->null_cond);
 399        tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
 400                           ctx->null_cond.a0, ctx->null_cond.a1);
 401        ctx->psw_n_nonzero = true;
 402    }
 403    cond_free(&ctx->null_cond);
 404}
 405
 406/* Set a PSW[N] to X.  The intention is that this is used immediately
 407   before a goto_tb/exit_tb, so that there is no fallthru path to other
 408   code within the TB.  Therefore we do not update psw_n_nonzero.  */
 409static void nullify_set(DisasContext *ctx, bool x)
 410{
 411    if (ctx->psw_n_nonzero || x) {
 412        tcg_gen_movi_tl(cpu_psw_n, x);
 413    }
 414}
 415
 416/* Mark the end of an instruction that may have been nullified.
 417   This is the pair to nullify_over.  */
 418static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
 419{
 420    TCGLabel *null_lab = ctx->null_lab;
 421
 422    if (likely(null_lab == NULL)) {
 423        /* The current insn wasn't conditional or handled the condition
 424           applied to it without a branch, so the (new) setting of
 425           NULL_COND can be applied directly to the next insn.  */
 426        return status;
 427    }
 428    ctx->null_lab = NULL;
 429
 430    if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
 431        /* The next instruction will be unconditional,
 432           and NULL_COND already reflects that.  */
 433        gen_set_label(null_lab);
 434    } else {
 435        /* The insn that we just executed is itself nullifying the next
 436           instruction.  Store the condition in the PSW[N] global.
 437           We asserted PSW[N] = 0 in nullify_over, so that after the
 438           label we have the proper value in place.  */
 439        nullify_save(ctx);
 440        gen_set_label(null_lab);
 441        ctx->null_cond = cond_make_n();
 442    }
 443
 444    assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
 445    if (status == EXIT_NORETURN) {
 446        status = NO_EXIT;
 447    }
 448    return status;
 449}
 450
 451static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
 452{
 453    if (unlikely(ival == -1)) {
 454        tcg_gen_mov_tl(dest, vval);
 455    } else {
 456        tcg_gen_movi_tl(dest, ival);
 457    }
 458}
 459
 460static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
 461{
 462    return ctx->iaoq_f + disp + 8;
 463}
 464
 465static void gen_excp_1(int exception)
 466{
 467    TCGv_i32 t = tcg_const_i32(exception);
 468    gen_helper_excp(cpu_env, t);
 469    tcg_temp_free_i32(t);
 470}
 471
 472static ExitStatus gen_excp(DisasContext *ctx, int exception)
 473{
 474    copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
 475    copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
 476    nullify_save(ctx);
 477    gen_excp_1(exception);
 478    return EXIT_NORETURN;
 479}
 480
 481static ExitStatus gen_illegal(DisasContext *ctx)
 482{
 483    nullify_over(ctx);
 484    return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
 485}
 486
 487static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
 488{
 489    /* Suppress goto_tb in the case of single-steping and IO.  */
 490    if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
 491        return false;
 492    }
 493    return true;
 494}
 495
 496/* If the next insn is to be nullified, and it's on the same page,
 497   and we're not attempting to set a breakpoint on it, then we can
 498   totally skip the nullified insn.  This avoids creating and
 499   executing a TB that merely branches to the next TB.  */
 500static bool use_nullify_skip(DisasContext *ctx)
 501{
 502    return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
 503            && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
 504}
 505
 506static void gen_goto_tb(DisasContext *ctx, int which,
 507                        target_ulong f, target_ulong b)
 508{
 509    if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
 510        tcg_gen_goto_tb(which);
 511        tcg_gen_movi_tl(cpu_iaoq_f, f);
 512        tcg_gen_movi_tl(cpu_iaoq_b, b);
 513        tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
 514    } else {
 515        copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
 516        copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
 517        if (ctx->singlestep_enabled) {
 518            gen_excp_1(EXCP_DEBUG);
 519        } else {
 520            tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
 521        }
 522    }
 523}
 524
 525/* PA has a habit of taking the LSB of a field and using that as the sign,
 526   with the rest of the field becoming the least significant bits.  */
 527static target_long low_sextract(uint32_t val, int pos, int len)
 528{
 529    target_ulong x = -(target_ulong)extract32(val, pos, 1);
 530    x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
 531    return x;
 532}
 533
 534static unsigned assemble_rt64(uint32_t insn)
 535{
 536    unsigned r1 = extract32(insn, 6, 1);
 537    unsigned r0 = extract32(insn, 0, 5);
 538    return r1 * 32 + r0;
 539}
 540
 541static unsigned assemble_ra64(uint32_t insn)
 542{
 543    unsigned r1 = extract32(insn, 7, 1);
 544    unsigned r0 = extract32(insn, 21, 5);
 545    return r1 * 32 + r0;
 546}
 547
 548static unsigned assemble_rb64(uint32_t insn)
 549{
 550    unsigned r1 = extract32(insn, 12, 1);
 551    unsigned r0 = extract32(insn, 16, 5);
 552    return r1 * 32 + r0;
 553}
 554
 555static unsigned assemble_rc64(uint32_t insn)
 556{
 557    unsigned r2 = extract32(insn, 8, 1);
 558    unsigned r1 = extract32(insn, 13, 3);
 559    unsigned r0 = extract32(insn, 9, 2);
 560    return r2 * 32 + r1 * 4 + r0;
 561}
 562
 563static target_long assemble_12(uint32_t insn)
 564{
 565    target_ulong x = -(target_ulong)(insn & 1);
 566    x = (x <<  1) | extract32(insn, 2, 1);
 567    x = (x << 10) | extract32(insn, 3, 10);
 568    return x;
 569}
 570
 571static target_long assemble_16(uint32_t insn)
 572{
 573    /* Take the name from PA2.0, which produces a 16-bit number
 574       only with wide mode; otherwise a 14-bit number.  Since we don't
 575       implement wide mode, this is always the 14-bit number.  */
 576    return low_sextract(insn, 0, 14);
 577}
 578
 579static target_long assemble_16a(uint32_t insn)
 580{
 581    /* Take the name from PA2.0, which produces a 14-bit shifted number
 582       only with wide mode; otherwise a 12-bit shifted number.  Since we
 583       don't implement wide mode, this is always the 12-bit number.  */
 584    target_ulong x = -(target_ulong)(insn & 1);
 585    x = (x << 11) | extract32(insn, 2, 11);
 586    return x << 2;
 587}
 588
 589static target_long assemble_17(uint32_t insn)
 590{
 591    target_ulong x = -(target_ulong)(insn & 1);
 592    x = (x <<  5) | extract32(insn, 16, 5);
 593    x = (x <<  1) | extract32(insn, 2, 1);
 594    x = (x << 10) | extract32(insn, 3, 10);
 595    return x << 2;
 596}
 597
 598static target_long assemble_21(uint32_t insn)
 599{
 600    target_ulong x = -(target_ulong)(insn & 1);
 601    x = (x << 11) | extract32(insn, 1, 11);
 602    x = (x <<  2) | extract32(insn, 14, 2);
 603    x = (x <<  5) | extract32(insn, 16, 5);
 604    x = (x <<  2) | extract32(insn, 12, 2);
 605    return x << 11;
 606}
 607
 608static target_long assemble_22(uint32_t insn)
 609{
 610    target_ulong x = -(target_ulong)(insn & 1);
 611    x = (x << 10) | extract32(insn, 16, 10);
 612    x = (x <<  1) | extract32(insn, 2, 1);
 613    x = (x << 10) | extract32(insn, 3, 10);
 614    return x << 2;
 615}
 616
 617/* The parisc documentation describes only the general interpretation of
 618   the conditions, without describing their exact implementation.  The
 619   interpretations do not stand up well when considering ADD,C and SUB,B.
 620   However, considering the Addition, Subtraction and Logical conditions
 621   as a whole it would appear that these relations are similar to what
 622   a traditional NZCV set of flags would produce.  */
 623
 624static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
 625{
 626    DisasCond cond;
 627    TCGv tmp;
 628
 629    switch (cf >> 1) {
 630    case 0: /* Never / TR */
 631        cond = cond_make_f();
 632        break;
 633    case 1: /* = / <>        (Z / !Z) */
 634        cond = cond_make_0(TCG_COND_EQ, res);
 635        break;
 636    case 2: /* < / >=        (N / !N) */
 637        cond = cond_make_0(TCG_COND_LT, res);
 638        break;
 639    case 3: /* <= / >        (N | Z / !N & !Z) */
 640        cond = cond_make_0(TCG_COND_LE, res);
 641        break;
 642    case 4: /* NUV / UV      (!C / C) */
 643        cond = cond_make_0(TCG_COND_EQ, cb_msb);
 644        break;
 645    case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
 646        tmp = tcg_temp_new();
 647        tcg_gen_neg_tl(tmp, cb_msb);
 648        tcg_gen_and_tl(tmp, tmp, res);
 649        cond = cond_make_0(TCG_COND_EQ, tmp);
 650        tcg_temp_free(tmp);
 651        break;
 652    case 6: /* SV / NSV      (V / !V) */
 653        cond = cond_make_0(TCG_COND_LT, sv);
 654        break;
 655    case 7: /* OD / EV */
 656        tmp = tcg_temp_new();
 657        tcg_gen_andi_tl(tmp, res, 1);
 658        cond = cond_make_0(TCG_COND_NE, tmp);
 659        tcg_temp_free(tmp);
 660        break;
 661    default:
 662        g_assert_not_reached();
 663    }
 664    if (cf & 1) {
 665        cond.c = tcg_invert_cond(cond.c);
 666    }
 667
 668    return cond;
 669}
 670
 671/* Similar, but for the special case of subtraction without borrow, we
 672   can use the inputs directly.  This can allow other computation to be
 673   deleted as unused.  */
 674
 675static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
 676{
 677    DisasCond cond;
 678
 679    switch (cf >> 1) {
 680    case 1: /* = / <> */
 681        cond = cond_make(TCG_COND_EQ, in1, in2);
 682        break;
 683    case 2: /* < / >= */
 684        cond = cond_make(TCG_COND_LT, in1, in2);
 685        break;
 686    case 3: /* <= / > */
 687        cond = cond_make(TCG_COND_LE, in1, in2);
 688        break;
 689    case 4: /* << / >>= */
 690        cond = cond_make(TCG_COND_LTU, in1, in2);
 691        break;
 692    case 5: /* <<= / >> */
 693        cond = cond_make(TCG_COND_LEU, in1, in2);
 694        break;
 695    default:
 696        return do_cond(cf, res, sv, sv);
 697    }
 698    if (cf & 1) {
 699        cond.c = tcg_invert_cond(cond.c);
 700    }
 701
 702    return cond;
 703}
 704
 705/* Similar, but for logicals, where the carry and overflow bits are not
 706   computed, and use of them is undefined.  */
 707
 708static DisasCond do_log_cond(unsigned cf, TCGv res)
 709{
 710    switch (cf >> 1) {
 711    case 4: case 5: case 6:
 712        cf &= 1;
 713        break;
 714    }
 715    return do_cond(cf, res, res, res);
 716}
 717
 718/* Similar, but for shift/extract/deposit conditions.  */
 719
 720static DisasCond do_sed_cond(unsigned orig, TCGv res)
 721{
 722    unsigned c, f;
 723
 724    /* Convert the compressed condition codes to standard.
 725       0-2 are the same as logicals (nv,<,<=), while 3 is OD.
 726       4-7 are the reverse of 0-3.  */
 727    c = orig & 3;
 728    if (c == 3) {
 729        c = 7;
 730    }
 731    f = (orig & 4) / 4;
 732
 733    return do_log_cond(c * 2 + f, res);
 734}
 735
 736/* Similar, but for unit conditions.  */
 737
 738static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
 739{
 740    DisasCond cond;
 741    TCGv tmp, cb;
 742
 743    TCGV_UNUSED(cb);
 744    if (cf & 8) {
 745        /* Since we want to test lots of carry-out bits all at once, do not
 746         * do our normal thing and compute carry-in of bit B+1 since that
 747         * leaves us with carry bits spread across two words.
 748         */
 749        cb = tcg_temp_new();
 750        tmp = tcg_temp_new();
 751        tcg_gen_or_tl(cb, in1, in2);
 752        tcg_gen_and_tl(tmp, in1, in2);
 753        tcg_gen_andc_tl(cb, cb, res);
 754        tcg_gen_or_tl(cb, cb, tmp);
 755        tcg_temp_free(tmp);
 756    }
 757
 758    switch (cf >> 1) {
 759    case 0: /* never / TR */
 760    case 1: /* undefined */
 761    case 5: /* undefined */
 762        cond = cond_make_f();
 763        break;
 764
 765    case 2: /* SBZ / NBZ */
 766        /* See hasless(v,1) from
 767         * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
 768         */
 769        tmp = tcg_temp_new();
 770        tcg_gen_subi_tl(tmp, res, 0x01010101u);
 771        tcg_gen_andc_tl(tmp, tmp, res);
 772        tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
 773        cond = cond_make_0(TCG_COND_NE, tmp);
 774        tcg_temp_free(tmp);
 775        break;
 776
 777    case 3: /* SHZ / NHZ */
 778        tmp = tcg_temp_new();
 779        tcg_gen_subi_tl(tmp, res, 0x00010001u);
 780        tcg_gen_andc_tl(tmp, tmp, res);
 781        tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
 782        cond = cond_make_0(TCG_COND_NE, tmp);
 783        tcg_temp_free(tmp);
 784        break;
 785
 786    case 4: /* SDC / NDC */
 787        tcg_gen_andi_tl(cb, cb, 0x88888888u);
 788        cond = cond_make_0(TCG_COND_NE, cb);
 789        break;
 790
 791    case 6: /* SBC / NBC */
 792        tcg_gen_andi_tl(cb, cb, 0x80808080u);
 793        cond = cond_make_0(TCG_COND_NE, cb);
 794        break;
 795
 796    case 7: /* SHC / NHC */
 797        tcg_gen_andi_tl(cb, cb, 0x80008000u);
 798        cond = cond_make_0(TCG_COND_NE, cb);
 799        break;
 800
 801    default:
 802        g_assert_not_reached();
 803    }
 804    if (cf & 8) {
 805        tcg_temp_free(cb);
 806    }
 807    if (cf & 1) {
 808        cond.c = tcg_invert_cond(cond.c);
 809    }
 810
 811    return cond;
 812}
 813
 814/* Compute signed overflow for addition.  */
 815static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
 816{
 817    TCGv sv = get_temp(ctx);
 818    TCGv tmp = tcg_temp_new();
 819
 820    tcg_gen_xor_tl(sv, res, in1);
 821    tcg_gen_xor_tl(tmp, in1, in2);
 822    tcg_gen_andc_tl(sv, sv, tmp);
 823    tcg_temp_free(tmp);
 824
 825    return sv;
 826}
 827
 828/* Compute signed overflow for subtraction.  */
 829static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
 830{
 831    TCGv sv = get_temp(ctx);
 832    TCGv tmp = tcg_temp_new();
 833
 834    tcg_gen_xor_tl(sv, res, in1);
 835    tcg_gen_xor_tl(tmp, in1, in2);
 836    tcg_gen_and_tl(sv, sv, tmp);
 837    tcg_temp_free(tmp);
 838
 839    return sv;
 840}
 841
 842static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
 843                         unsigned shift, bool is_l, bool is_tsv, bool is_tc,
 844                         bool is_c, unsigned cf)
 845{
 846    TCGv dest, cb, cb_msb, sv, tmp;
 847    unsigned c = cf >> 1;
 848    DisasCond cond;
 849
 850    dest = tcg_temp_new();
 851    TCGV_UNUSED(cb);
 852    TCGV_UNUSED(cb_msb);
 853
 854    if (shift) {
 855        tmp = get_temp(ctx);
 856        tcg_gen_shli_tl(tmp, in1, shift);
 857        in1 = tmp;
 858    }
 859
 860    if (!is_l || c == 4 || c == 5) {
 861        TCGv zero = tcg_const_tl(0);
 862        cb_msb = get_temp(ctx);
 863        tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
 864        if (is_c) {
 865            tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
 866        }
 867        tcg_temp_free(zero);
 868        if (!is_l) {
 869            cb = get_temp(ctx);
 870            tcg_gen_xor_tl(cb, in1, in2);
 871            tcg_gen_xor_tl(cb, cb, dest);
 872        }
 873    } else {
 874        tcg_gen_add_tl(dest, in1, in2);
 875        if (is_c) {
 876            tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
 877        }
 878    }
 879
 880    /* Compute signed overflow if required.  */
 881    TCGV_UNUSED(sv);
 882    if (is_tsv || c == 6) {
 883        sv = do_add_sv(ctx, dest, in1, in2);
 884        if (is_tsv) {
 885            /* ??? Need to include overflow from shift.  */
 886            gen_helper_tsv(cpu_env, sv);
 887        }
 888    }
 889
 890    /* Emit any conditional trap before any writeback.  */
 891    cond = do_cond(cf, dest, cb_msb, sv);
 892    if (is_tc) {
 893        cond_prep(&cond);
 894        tmp = tcg_temp_new();
 895        tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
 896        gen_helper_tcond(cpu_env, tmp);
 897        tcg_temp_free(tmp);
 898    }
 899
 900    /* Write back the result.  */
 901    if (!is_l) {
 902        save_or_nullify(ctx, cpu_psw_cb, cb);
 903        save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
 904    }
 905    save_gpr(ctx, rt, dest);
 906    tcg_temp_free(dest);
 907
 908    /* Install the new nullification.  */
 909    cond_free(&ctx->null_cond);
 910    ctx->null_cond = cond;
 911    return NO_EXIT;
 912}
 913
 914static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
 915                         bool is_tsv, bool is_b, bool is_tc, unsigned cf)
 916{
 917    TCGv dest, sv, cb, cb_msb, zero, tmp;
 918    unsigned c = cf >> 1;
 919    DisasCond cond;
 920
 921    dest = tcg_temp_new();
 922    cb = tcg_temp_new();
 923    cb_msb = tcg_temp_new();
 924
 925    zero = tcg_const_tl(0);
 926    if (is_b) {
 927        /* DEST,C = IN1 + ~IN2 + C.  */
 928        tcg_gen_not_tl(cb, in2);
 929        tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
 930        tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
 931        tcg_gen_xor_tl(cb, cb, in1);
 932        tcg_gen_xor_tl(cb, cb, dest);
 933    } else {
 934        /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
 935           operations by seeding the high word with 1 and subtracting.  */
 936        tcg_gen_movi_tl(cb_msb, 1);
 937        tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
 938        tcg_gen_eqv_tl(cb, in1, in2);
 939        tcg_gen_xor_tl(cb, cb, dest);
 940    }
 941    tcg_temp_free(zero);
 942
 943    /* Compute signed overflow if required.  */
 944    TCGV_UNUSED(sv);
 945    if (is_tsv || c == 6) {
 946        sv = do_sub_sv(ctx, dest, in1, in2);
 947        if (is_tsv) {
 948            gen_helper_tsv(cpu_env, sv);
 949        }
 950    }
 951
 952    /* Compute the condition.  We cannot use the special case for borrow.  */
 953    if (!is_b) {
 954        cond = do_sub_cond(cf, dest, in1, in2, sv);
 955    } else {
 956        cond = do_cond(cf, dest, cb_msb, sv);
 957    }
 958
 959    /* Emit any conditional trap before any writeback.  */
 960    if (is_tc) {
 961        cond_prep(&cond);
 962        tmp = tcg_temp_new();
 963        tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
 964        gen_helper_tcond(cpu_env, tmp);
 965        tcg_temp_free(tmp);
 966    }
 967
 968    /* Write back the result.  */
 969    save_or_nullify(ctx, cpu_psw_cb, cb);
 970    save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
 971    save_gpr(ctx, rt, dest);
 972    tcg_temp_free(dest);
 973
 974    /* Install the new nullification.  */
 975    cond_free(&ctx->null_cond);
 976    ctx->null_cond = cond;
 977    return NO_EXIT;
 978}
 979
 980static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
 981                            TCGv in2, unsigned cf)
 982{
 983    TCGv dest, sv;
 984    DisasCond cond;
 985
 986    dest = tcg_temp_new();
 987    tcg_gen_sub_tl(dest, in1, in2);
 988
 989    /* Compute signed overflow if required.  */
 990    TCGV_UNUSED(sv);
 991    if ((cf >> 1) == 6) {
 992        sv = do_sub_sv(ctx, dest, in1, in2);
 993    }
 994
 995    /* Form the condition for the compare.  */
 996    cond = do_sub_cond(cf, dest, in1, in2, sv);
 997
 998    /* Clear.  */
 999    tcg_gen_movi_tl(dest, 0);
1000    save_gpr(ctx, rt, dest);
1001    tcg_temp_free(dest);
1002
1003    /* Install the new nullification.  */
1004    cond_free(&ctx->null_cond);
1005    ctx->null_cond = cond;
1006    return NO_EXIT;
1007}
1008
1009static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
1010                         unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
1011{
1012    TCGv dest = dest_gpr(ctx, rt);
1013
1014    /* Perform the operation, and writeback.  */
1015    fn(dest, in1, in2);
1016    save_gpr(ctx, rt, dest);
1017
1018    /* Install the new nullification.  */
1019    cond_free(&ctx->null_cond);
1020    if (cf) {
1021        ctx->null_cond = do_log_cond(cf, dest);
1022    }
1023    return NO_EXIT;
1024}
1025
1026static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
1027                          TCGv in2, unsigned cf, bool is_tc,
1028                          void (*fn)(TCGv, TCGv, TCGv))
1029{
1030    TCGv dest;
1031    DisasCond cond;
1032
1033    if (cf == 0) {
1034        dest = dest_gpr(ctx, rt);
1035        fn(dest, in1, in2);
1036        save_gpr(ctx, rt, dest);
1037        cond_free(&ctx->null_cond);
1038    } else {
1039        dest = tcg_temp_new();
1040        fn(dest, in1, in2);
1041
1042        cond = do_unit_cond(cf, dest, in1, in2);
1043
1044        if (is_tc) {
1045            TCGv tmp = tcg_temp_new();
1046            cond_prep(&cond);
1047            tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
1048            gen_helper_tcond(cpu_env, tmp);
1049            tcg_temp_free(tmp);
1050        }
1051        save_gpr(ctx, rt, dest);
1052
1053        cond_free(&ctx->null_cond);
1054        ctx->null_cond = cond;
1055    }
1056    return NO_EXIT;
1057}
1058
1059/* Emit a memory load.  The modify parameter should be
1060 * < 0 for pre-modify,
1061 * > 0 for post-modify,
1062 * = 0 for no base register update.
1063 */
1064static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
1065                       unsigned rx, int scale, target_long disp,
1066                       int modify, TCGMemOp mop)
1067{
1068    TCGv addr, base;
1069
1070    /* Caller uses nullify_over/nullify_end.  */
1071    assert(ctx->null_cond.c == TCG_COND_NEVER);
1072
1073    addr = tcg_temp_new();
1074    base = load_gpr(ctx, rb);
1075
1076    /* Note that RX is mutually exclusive with DISP.  */
1077    if (rx) {
1078        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1079        tcg_gen_add_tl(addr, addr, base);
1080    } else {
1081        tcg_gen_addi_tl(addr, base, disp);
1082    }
1083
1084    if (modify == 0) {
1085        tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
1086    } else {
1087        tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
1088                            MMU_USER_IDX, mop);
1089        save_gpr(ctx, rb, addr);
1090    }
1091    tcg_temp_free(addr);
1092}
1093
1094static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
1095                       unsigned rx, int scale, target_long disp,
1096                       int modify, TCGMemOp mop)
1097{
1098    TCGv addr, base;
1099
1100    /* Caller uses nullify_over/nullify_end.  */
1101    assert(ctx->null_cond.c == TCG_COND_NEVER);
1102
1103    addr = tcg_temp_new();
1104    base = load_gpr(ctx, rb);
1105
1106    /* Note that RX is mutually exclusive with DISP.  */
1107    if (rx) {
1108        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1109        tcg_gen_add_tl(addr, addr, base);
1110    } else {
1111        tcg_gen_addi_tl(addr, base, disp);
1112    }
1113
1114    if (modify == 0) {
1115        tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
1116    } else {
1117        tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
1118                            MMU_USER_IDX, mop);
1119        save_gpr(ctx, rb, addr);
1120    }
1121    tcg_temp_free(addr);
1122}
1123
1124static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
1125                        unsigned rx, int scale, target_long disp,
1126                        int modify, TCGMemOp mop)
1127{
1128    TCGv addr, base;
1129
1130    /* Caller uses nullify_over/nullify_end.  */
1131    assert(ctx->null_cond.c == TCG_COND_NEVER);
1132
1133    addr = tcg_temp_new();
1134    base = load_gpr(ctx, rb);
1135
1136    /* Note that RX is mutually exclusive with DISP.  */
1137    if (rx) {
1138        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1139        tcg_gen_add_tl(addr, addr, base);
1140    } else {
1141        tcg_gen_addi_tl(addr, base, disp);
1142    }
1143
1144    tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1145
1146    if (modify != 0) {
1147        save_gpr(ctx, rb, addr);
1148    }
1149    tcg_temp_free(addr);
1150}
1151
1152static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
1153                        unsigned rx, int scale, target_long disp,
1154                        int modify, TCGMemOp mop)
1155{
1156    TCGv addr, base;
1157
1158    /* Caller uses nullify_over/nullify_end.  */
1159    assert(ctx->null_cond.c == TCG_COND_NEVER);
1160
1161    addr = tcg_temp_new();
1162    base = load_gpr(ctx, rb);
1163
1164    /* Note that RX is mutually exclusive with DISP.  */
1165    if (rx) {
1166        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
1167        tcg_gen_add_tl(addr, addr, base);
1168    } else {
1169        tcg_gen_addi_tl(addr, base, disp);
1170    }
1171
1172    tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
1173
1174    if (modify != 0) {
1175        save_gpr(ctx, rb, addr);
1176    }
1177    tcg_temp_free(addr);
1178}
1179
1180#if TARGET_LONG_BITS == 64
1181#define do_load_tl  do_load_64
1182#define do_store_tl do_store_64
1183#else
1184#define do_load_tl  do_load_32
1185#define do_store_tl do_store_32
1186#endif
1187
1188static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb,
1189                          unsigned rx, int scale, target_long disp,
1190                          int modify, TCGMemOp mop)
1191{
1192    TCGv dest;
1193
1194    nullify_over(ctx);
1195
1196    if (modify == 0) {
1197        /* No base register update.  */
1198        dest = dest_gpr(ctx, rt);
1199    } else {
1200        /* Make sure if RT == RB, we see the result of the load.  */
1201        dest = get_temp(ctx);
1202    }
1203    do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
1204    save_gpr(ctx, rt, dest);
1205
1206    return nullify_end(ctx, NO_EXIT);
1207}
1208
1209static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
1210                            unsigned rx, int scale, target_long disp,
1211                            int modify)
1212{
1213    TCGv_i32 tmp;
1214
1215    nullify_over(ctx);
1216
1217    tmp = tcg_temp_new_i32();
1218    do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1219    save_frw_i32(rt, tmp);
1220    tcg_temp_free_i32(tmp);
1221
1222    if (rt == 0) {
1223        gen_helper_loaded_fr0(cpu_env);
1224    }
1225
1226    return nullify_end(ctx, NO_EXIT);
1227}
1228
1229static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
1230                            unsigned rx, int scale, target_long disp,
1231                            int modify)
1232{
1233    TCGv_i64 tmp;
1234
1235    nullify_over(ctx);
1236
1237    tmp = tcg_temp_new_i64();
1238    do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1239    save_frd(rt, tmp);
1240    tcg_temp_free_i64(tmp);
1241
1242    if (rt == 0) {
1243        gen_helper_loaded_fr0(cpu_env);
1244    }
1245
1246    return nullify_end(ctx, NO_EXIT);
1247}
1248
1249static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb,
1250                           target_long disp, int modify, TCGMemOp mop)
1251{
1252    nullify_over(ctx);
1253    do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
1254    return nullify_end(ctx, NO_EXIT);
1255}
1256
1257static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
1258                             unsigned rx, int scale, target_long disp,
1259                             int modify)
1260{
1261    TCGv_i32 tmp;
1262
1263    nullify_over(ctx);
1264
1265    tmp = load_frw_i32(rt);
1266    do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
1267    tcg_temp_free_i32(tmp);
1268
1269    return nullify_end(ctx, NO_EXIT);
1270}
1271
1272static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
1273                             unsigned rx, int scale, target_long disp,
1274                             int modify)
1275{
1276    TCGv_i64 tmp;
1277
1278    nullify_over(ctx);
1279
1280    tmp = load_frd(rt);
1281    do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
1282    tcg_temp_free_i64(tmp);
1283
1284    return nullify_end(ctx, NO_EXIT);
1285}
1286
1287static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
1288                             void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
1289{
1290    TCGv_i32 tmp;
1291
1292    nullify_over(ctx);
1293    tmp = load_frw0_i32(ra);
1294
1295    func(tmp, cpu_env, tmp);
1296
1297    save_frw_i32(rt, tmp);
1298    tcg_temp_free_i32(tmp);
1299    return nullify_end(ctx, NO_EXIT);
1300}
1301
1302static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
1303                             void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
1304{
1305    TCGv_i32 dst;
1306    TCGv_i64 src;
1307
1308    nullify_over(ctx);
1309    src = load_frd(ra);
1310    dst = tcg_temp_new_i32();
1311
1312    func(dst, cpu_env, src);
1313
1314    tcg_temp_free_i64(src);
1315    save_frw_i32(rt, dst);
1316    tcg_temp_free_i32(dst);
1317    return nullify_end(ctx, NO_EXIT);
1318}
1319
1320static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
1321                             void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
1322{
1323    TCGv_i64 tmp;
1324
1325    nullify_over(ctx);
1326    tmp = load_frd0(ra);
1327
1328    func(tmp, cpu_env, tmp);
1329
1330    save_frd(rt, tmp);
1331    tcg_temp_free_i64(tmp);
1332    return nullify_end(ctx, NO_EXIT);
1333}
1334
1335static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
1336                             void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
1337{
1338    TCGv_i32 src;
1339    TCGv_i64 dst;
1340
1341    nullify_over(ctx);
1342    src = load_frw0_i32(ra);
1343    dst = tcg_temp_new_i64();
1344
1345    func(dst, cpu_env, src);
1346
1347    tcg_temp_free_i32(src);
1348    save_frd(rt, dst);
1349    tcg_temp_free_i64(dst);
1350    return nullify_end(ctx, NO_EXIT);
1351}
1352
1353static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt,
1354                              unsigned ra, unsigned rb,
1355                              void (*func)(TCGv_i32, TCGv_env,
1356                                           TCGv_i32, TCGv_i32))
1357{
1358    TCGv_i32 a, b;
1359
1360    nullify_over(ctx);
1361    a = load_frw0_i32(ra);
1362    b = load_frw0_i32(rb);
1363
1364    func(a, cpu_env, a, b);
1365
1366    tcg_temp_free_i32(b);
1367    save_frw_i32(rt, a);
1368    tcg_temp_free_i32(a);
1369    return nullify_end(ctx, NO_EXIT);
1370}
1371
1372static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt,
1373                              unsigned ra, unsigned rb,
1374                              void (*func)(TCGv_i64, TCGv_env,
1375                                           TCGv_i64, TCGv_i64))
1376{
1377    TCGv_i64 a, b;
1378
1379    nullify_over(ctx);
1380    a = load_frd0(ra);
1381    b = load_frd0(rb);
1382
1383    func(a, cpu_env, a, b);
1384
1385    tcg_temp_free_i64(b);
1386    save_frd(rt, a);
1387    tcg_temp_free_i64(a);
1388    return nullify_end(ctx, NO_EXIT);
1389}
1390
1391/* Emit an unconditional branch to a direct target, which may or may not
1392   have already had nullification handled.  */
1393static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
1394                             unsigned link, bool is_n)
1395{
1396    if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
1397        if (link != 0) {
1398            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1399        }
1400        ctx->iaoq_n = dest;
1401        if (is_n) {
1402            ctx->null_cond.c = TCG_COND_ALWAYS;
1403        }
1404        return NO_EXIT;
1405    } else {
1406        nullify_over(ctx);
1407
1408        if (link != 0) {
1409            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1410        }
1411
1412        if (is_n && use_nullify_skip(ctx)) {
1413            nullify_set(ctx, 0);
1414            gen_goto_tb(ctx, 0, dest, dest + 4);
1415        } else {
1416            nullify_set(ctx, is_n);
1417            gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
1418        }
1419
1420        nullify_end(ctx, NO_EXIT);
1421
1422        nullify_set(ctx, 0);
1423        gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
1424        return EXIT_GOTO_TB;
1425    }
1426}
1427
1428/* Emit a conditional branch to a direct target.  If the branch itself
1429   is nullified, we should have already used nullify_over.  */
1430static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
1431                             DisasCond *cond)
1432{
1433    target_ulong dest = iaoq_dest(ctx, disp);
1434    TCGLabel *taken = NULL;
1435    TCGCond c = cond->c;
1436    bool n;
1437
1438    assert(ctx->null_cond.c == TCG_COND_NEVER);
1439
1440    /* Handle TRUE and NEVER as direct branches.  */
1441    if (c == TCG_COND_ALWAYS) {
1442        return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
1443    }
1444    if (c == TCG_COND_NEVER) {
1445        return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
1446    }
1447
1448    taken = gen_new_label();
1449    cond_prep(cond);
1450    tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
1451    cond_free(cond);
1452
1453    /* Not taken: Condition not satisfied; nullify on backward branches. */
1454    n = is_n && disp < 0;
1455    if (n && use_nullify_skip(ctx)) {
1456        nullify_set(ctx, 0);
1457        gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4);
1458    } else {
1459        if (!n && ctx->null_lab) {
1460            gen_set_label(ctx->null_lab);
1461            ctx->null_lab = NULL;
1462        }
1463        nullify_set(ctx, n);
1464        gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
1465    }
1466
1467    gen_set_label(taken);
1468
1469    /* Taken: Condition satisfied; nullify on forward branches.  */
1470    n = is_n && disp >= 0;
1471    if (n && use_nullify_skip(ctx)) {
1472        nullify_set(ctx, 0);
1473        gen_goto_tb(ctx, 1, dest, dest + 4);
1474    } else {
1475        nullify_set(ctx, n);
1476        gen_goto_tb(ctx, 1, ctx->iaoq_b, dest);
1477    }
1478
1479    /* Not taken: the branch itself was nullified.  */
1480    if (ctx->null_lab) {
1481        gen_set_label(ctx->null_lab);
1482        ctx->null_lab = NULL;
1483        return EXIT_IAQ_N_STALE;
1484    } else {
1485        return EXIT_GOTO_TB;
1486    }
1487}
1488
1489/* Emit an unconditional branch to an indirect target.  This handles
1490   nullification of the branch itself.  */
1491static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
1492                             unsigned link, bool is_n)
1493{
1494    TCGv a0, a1, next, tmp;
1495    TCGCond c;
1496
1497    assert(ctx->null_lab == NULL);
1498
1499    if (ctx->null_cond.c == TCG_COND_NEVER) {
1500        if (link != 0) {
1501            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
1502        }
1503        next = get_temp(ctx);
1504        tcg_gen_mov_tl(next, dest);
1505        ctx->iaoq_n = -1;
1506        ctx->iaoq_n_var = next;
1507        if (is_n) {
1508            ctx->null_cond.c = TCG_COND_ALWAYS;
1509        }
1510    } else if (is_n && use_nullify_skip(ctx)) {
1511        /* The (conditional) branch, B, nullifies the next insn, N,
1512           and we're allowed to skip execution N (no single-step or
1513           tracepoint in effect).  Since the goto_ptr that we must use
1514           for the indirect branch consumes no special resources, we
1515           can (conditionally) skip B and continue execution.  */
1516        /* The use_nullify_skip test implies we have a known control path.  */
1517        tcg_debug_assert(ctx->iaoq_b != -1);
1518        tcg_debug_assert(ctx->iaoq_n != -1);
1519
1520        /* We do have to handle the non-local temporary, DEST, before
1521           branching.  Since IOAQ_F is not really live at this point, we
1522           can simply store DEST optimistically.  Similarly with IAOQ_B.  */
1523        tcg_gen_mov_tl(cpu_iaoq_f, dest);
1524        tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
1525
1526        nullify_over(ctx);
1527        if (link != 0) {
1528            tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
1529        }
1530        tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
1531        return nullify_end(ctx, NO_EXIT);
1532    } else {
1533        cond_prep(&ctx->null_cond);
1534        c = ctx->null_cond.c;
1535        a0 = ctx->null_cond.a0;
1536        a1 = ctx->null_cond.a1;
1537
1538        tmp = tcg_temp_new();
1539        next = get_temp(ctx);
1540
1541        copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
1542        tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
1543        ctx->iaoq_n = -1;
1544        ctx->iaoq_n_var = next;
1545
1546        if (link != 0) {
1547            tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
1548        }
1549
1550        if (is_n) {
1551            /* The branch nullifies the next insn, which means the state of N
1552               after the branch is the inverse of the state of N that applied
1553               to the branch.  */
1554            tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
1555            cond_free(&ctx->null_cond);
1556            ctx->null_cond = cond_make_n();
1557            ctx->psw_n_nonzero = true;
1558        } else {
1559            cond_free(&ctx->null_cond);
1560        }
1561    }
1562
1563    return NO_EXIT;
1564}
1565
1566/* On Linux, page zero is normally marked execute only + gateway.
1567   Therefore normal read or write is supposed to fail, but specific
1568   offsets have kernel code mapped to raise permissions to implement
1569   system calls.  Handling this via an explicit check here, rather
1570   in than the "be disp(sr2,r0)" instruction that probably sent us
1571   here, is the easiest way to handle the branch delay slot on the
1572   aforementioned BE.  */
1573static ExitStatus do_page_zero(DisasContext *ctx)
1574{
1575    /* If by some means we get here with PSW[N]=1, that implies that
1576       the B,GATE instruction would be skipped, and we'd fault on the
1577       next insn within the privilaged page.  */
1578    switch (ctx->null_cond.c) {
1579    case TCG_COND_NEVER:
1580        break;
1581    case TCG_COND_ALWAYS:
1582        tcg_gen_movi_tl(cpu_psw_n, 0);
1583        goto do_sigill;
1584    default:
1585        /* Since this is always the first (and only) insn within the
1586           TB, we should know the state of PSW[N] from TB->FLAGS.  */
1587        g_assert_not_reached();
1588    }
1589
1590    /* Check that we didn't arrive here via some means that allowed
1591       non-sequential instruction execution.  Normally the PSW[B] bit
1592       detects this by disallowing the B,GATE instruction to execute
1593       under such conditions.  */
1594    if (ctx->iaoq_b != ctx->iaoq_f + 4) {
1595        goto do_sigill;
1596    }
1597
1598    switch (ctx->iaoq_f) {
1599    case 0x00: /* Null pointer call */
1600        gen_excp_1(EXCP_SIGSEGV);
1601        return EXIT_NORETURN;
1602
1603    case 0xb0: /* LWS */
1604        gen_excp_1(EXCP_SYSCALL_LWS);
1605        return EXIT_NORETURN;
1606
1607    case 0xe0: /* SET_THREAD_POINTER */
1608        tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
1609        tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
1610        tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
1611        return EXIT_IAQ_N_UPDATED;
1612
1613    case 0x100: /* SYSCALL */
1614        gen_excp_1(EXCP_SYSCALL);
1615        return EXIT_NORETURN;
1616
1617    default:
1618    do_sigill:
1619        gen_excp_1(EXCP_SIGILL);
1620        return EXIT_NORETURN;
1621    }
1622}
1623
1624static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
1625                            const DisasInsn *di)
1626{
1627    cond_free(&ctx->null_cond);
1628    return NO_EXIT;
1629}
1630
1631static ExitStatus trans_break(DisasContext *ctx, uint32_t insn,
1632                              const DisasInsn *di)
1633{
1634    nullify_over(ctx);
1635    return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
1636}
1637
1638static ExitStatus trans_sync(DisasContext *ctx, uint32_t insn,
1639                             const DisasInsn *di)
1640{
1641    /* No point in nullifying the memory barrier.  */
1642    tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1643
1644    cond_free(&ctx->null_cond);
1645    return NO_EXIT;
1646}
1647
1648static ExitStatus trans_mfia(DisasContext *ctx, uint32_t insn,
1649                             const DisasInsn *di)
1650{
1651    unsigned rt = extract32(insn, 0, 5);
1652    TCGv tmp = dest_gpr(ctx, rt);
1653    tcg_gen_movi_tl(tmp, ctx->iaoq_f);
1654    save_gpr(ctx, rt, tmp);
1655
1656    cond_free(&ctx->null_cond);
1657    return NO_EXIT;
1658}
1659
1660static ExitStatus trans_mfsp(DisasContext *ctx, uint32_t insn,
1661                             const DisasInsn *di)
1662{
1663    unsigned rt = extract32(insn, 0, 5);
1664    TCGv tmp = dest_gpr(ctx, rt);
1665
1666    /* ??? We don't implement space registers.  */
1667    tcg_gen_movi_tl(tmp, 0);
1668    save_gpr(ctx, rt, tmp);
1669
1670    cond_free(&ctx->null_cond);
1671    return NO_EXIT;
1672}
1673
1674static ExitStatus trans_mfctl(DisasContext *ctx, uint32_t insn,
1675                              const DisasInsn *di)
1676{
1677    unsigned rt = extract32(insn, 0, 5);
1678    unsigned ctl = extract32(insn, 21, 5);
1679    TCGv tmp;
1680
1681    switch (ctl) {
1682    case 11: /* SAR */
1683#ifdef TARGET_HPPA64
1684        if (extract32(insn, 14, 1) == 0) {
1685            /* MFSAR without ,W masks low 5 bits.  */
1686            tmp = dest_gpr(ctx, rt);
1687            tcg_gen_andi_tl(tmp, cpu_sar, 31);
1688            save_gpr(ctx, rt, tmp);
1689            break;
1690        }
1691#endif
1692        save_gpr(ctx, rt, cpu_sar);
1693        break;
1694    case 16: /* Interval Timer */
1695        tmp = dest_gpr(ctx, rt);
1696        tcg_gen_movi_tl(tmp, 0); /* FIXME */
1697        save_gpr(ctx, rt, tmp);
1698        break;
1699    case 26:
1700        save_gpr(ctx, rt, cpu_cr26);
1701        break;
1702    case 27:
1703        save_gpr(ctx, rt, cpu_cr27);
1704        break;
1705    default:
1706        /* All other control registers are privileged.  */
1707        return gen_illegal(ctx);
1708    }
1709
1710    cond_free(&ctx->null_cond);
1711    return NO_EXIT;
1712}
1713
1714static ExitStatus trans_mtctl(DisasContext *ctx, uint32_t insn,
1715                              const DisasInsn *di)
1716{
1717    unsigned rin = extract32(insn, 16, 5);
1718    unsigned ctl = extract32(insn, 21, 5);
1719    TCGv tmp;
1720
1721    if (ctl == 11) { /* SAR */
1722        tmp = tcg_temp_new();
1723        tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
1724        save_or_nullify(ctx, cpu_sar, tmp);
1725        tcg_temp_free(tmp);
1726    } else {
1727        /* All other control registers are privileged or read-only.  */
1728        return gen_illegal(ctx);
1729    }
1730
1731    cond_free(&ctx->null_cond);
1732    return NO_EXIT;
1733}
1734
1735static ExitStatus trans_mtsarcm(DisasContext *ctx, uint32_t insn,
1736                                const DisasInsn *di)
1737{
1738    unsigned rin = extract32(insn, 16, 5);
1739    TCGv tmp = tcg_temp_new();
1740
1741    tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
1742    tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
1743    save_or_nullify(ctx, cpu_sar, tmp);
1744    tcg_temp_free(tmp);
1745
1746    cond_free(&ctx->null_cond);
1747    return NO_EXIT;
1748}
1749
1750static ExitStatus trans_ldsid(DisasContext *ctx, uint32_t insn,
1751                              const DisasInsn *di)
1752{
1753    unsigned rt = extract32(insn, 0, 5);
1754    TCGv dest = dest_gpr(ctx, rt);
1755
1756    /* Since we don't implement space registers, this returns zero.  */
1757    tcg_gen_movi_tl(dest, 0);
1758    save_gpr(ctx, rt, dest);
1759
1760    cond_free(&ctx->null_cond);
1761    return NO_EXIT;
1762}
1763
1764static const DisasInsn table_system[] = {
1765    { 0x00000000u, 0xfc001fe0u, trans_break },
1766    /* We don't implement space register, so MTSP is a nop.  */
1767    { 0x00001820u, 0xffe01fffu, trans_nop },
1768    { 0x00001840u, 0xfc00ffffu, trans_mtctl },
1769    { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
1770    { 0x000014a0u, 0xffffffe0u, trans_mfia },
1771    { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
1772    { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
1773    { 0x00000400u, 0xffffffffu, trans_sync },
1774    { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
1775};
1776
1777static ExitStatus trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
1778                                     const DisasInsn *di)
1779{
1780    unsigned rb = extract32(insn, 21, 5);
1781    unsigned rx = extract32(insn, 16, 5);
1782    TCGv dest = dest_gpr(ctx, rb);
1783    TCGv src1 = load_gpr(ctx, rb);
1784    TCGv src2 = load_gpr(ctx, rx);
1785
1786    /* The only thing we need to do is the base register modification.  */
1787    tcg_gen_add_tl(dest, src1, src2);
1788    save_gpr(ctx, rb, dest);
1789
1790    cond_free(&ctx->null_cond);
1791    return NO_EXIT;
1792}
1793
1794static ExitStatus trans_probe(DisasContext *ctx, uint32_t insn,
1795                              const DisasInsn *di)
1796{
1797    unsigned rt = extract32(insn, 0, 5);
1798    unsigned rb = extract32(insn, 21, 5);
1799    unsigned is_write = extract32(insn, 6, 1);
1800    TCGv dest;
1801
1802    nullify_over(ctx);
1803
1804    /* ??? Do something with priv level operand.  */
1805    dest = dest_gpr(ctx, rt);
1806    if (is_write) {
1807        gen_helper_probe_w(dest, load_gpr(ctx, rb));
1808    } else {
1809        gen_helper_probe_r(dest, load_gpr(ctx, rb));
1810    }
1811    save_gpr(ctx, rt, dest);
1812    return nullify_end(ctx, NO_EXIT);
1813}
1814
1815static const DisasInsn table_mem_mgmt[] = {
1816    { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
1817    { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
1818    { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
1819    { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
1820    { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
1821    { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
1822    { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
1823    { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
1824    { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
1825    { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
1826    { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
1827    { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
1828    { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
1829    { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
1830    { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
1831};
1832
1833static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
1834                            const DisasInsn *di)
1835{
1836    unsigned r2 = extract32(insn, 21, 5);
1837    unsigned r1 = extract32(insn, 16, 5);
1838    unsigned cf = extract32(insn, 12, 4);
1839    unsigned ext = extract32(insn, 8, 4);
1840    unsigned shift = extract32(insn, 6, 2);
1841    unsigned rt = extract32(insn,  0, 5);
1842    TCGv tcg_r1, tcg_r2;
1843    bool is_c = false;
1844    bool is_l = false;
1845    bool is_tc = false;
1846    bool is_tsv = false;
1847    ExitStatus ret;
1848
1849    switch (ext) {
1850    case 0x6: /* ADD, SHLADD */
1851        break;
1852    case 0xa: /* ADD,L, SHLADD,L */
1853        is_l = true;
1854        break;
1855    case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
1856        is_tsv = true;
1857        break;
1858    case 0x7: /* ADD,C */
1859        is_c = true;
1860        break;
1861    case 0xf: /* ADD,C,TSV */
1862        is_c = is_tsv = true;
1863        break;
1864    default:
1865        return gen_illegal(ctx);
1866    }
1867
1868    if (cf) {
1869        nullify_over(ctx);
1870    }
1871    tcg_r1 = load_gpr(ctx, r1);
1872    tcg_r2 = load_gpr(ctx, r2);
1873    ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
1874    return nullify_end(ctx, ret);
1875}
1876
1877static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
1878                            const DisasInsn *di)
1879{
1880    unsigned r2 = extract32(insn, 21, 5);
1881    unsigned r1 = extract32(insn, 16, 5);
1882    unsigned cf = extract32(insn, 12, 4);
1883    unsigned ext = extract32(insn, 6, 6);
1884    unsigned rt = extract32(insn,  0, 5);
1885    TCGv tcg_r1, tcg_r2;
1886    bool is_b = false;
1887    bool is_tc = false;
1888    bool is_tsv = false;
1889    ExitStatus ret;
1890
1891    switch (ext) {
1892    case 0x10: /* SUB */
1893        break;
1894    case 0x30: /* SUB,TSV */
1895        is_tsv = true;
1896        break;
1897    case 0x14: /* SUB,B */
1898        is_b = true;
1899        break;
1900    case 0x34: /* SUB,B,TSV */
1901        is_b = is_tsv = true;
1902        break;
1903    case 0x13: /* SUB,TC */
1904        is_tc = true;
1905        break;
1906    case 0x33: /* SUB,TSV,TC */
1907        is_tc = is_tsv = true;
1908        break;
1909    default:
1910        return gen_illegal(ctx);
1911    }
1912
1913    if (cf) {
1914        nullify_over(ctx);
1915    }
1916    tcg_r1 = load_gpr(ctx, r1);
1917    tcg_r2 = load_gpr(ctx, r2);
1918    ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
1919    return nullify_end(ctx, ret);
1920}
1921
1922static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
1923                            const DisasInsn *di)
1924{
1925    unsigned r2 = extract32(insn, 21, 5);
1926    unsigned r1 = extract32(insn, 16, 5);
1927    unsigned cf = extract32(insn, 12, 4);
1928    unsigned rt = extract32(insn,  0, 5);
1929    TCGv tcg_r1, tcg_r2;
1930    ExitStatus ret;
1931
1932    if (cf) {
1933        nullify_over(ctx);
1934    }
1935    tcg_r1 = load_gpr(ctx, r1);
1936    tcg_r2 = load_gpr(ctx, r2);
1937    ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt);
1938    return nullify_end(ctx, ret);
1939}
1940
1941/* OR r,0,t -> COPY (according to gas) */
1942static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
1943                             const DisasInsn *di)
1944{
1945    unsigned r1 = extract32(insn, 16, 5);
1946    unsigned rt = extract32(insn,  0, 5);
1947
1948    if (r1 == 0) {
1949        TCGv dest = dest_gpr(ctx, rt);
1950        tcg_gen_movi_tl(dest, 0);
1951        save_gpr(ctx, rt, dest);
1952    } else {
1953        save_gpr(ctx, rt, cpu_gr[r1]);
1954    }
1955    cond_free(&ctx->null_cond);
1956    return NO_EXIT;
1957}
1958
1959static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
1960                               const DisasInsn *di)
1961{
1962    unsigned r2 = extract32(insn, 21, 5);
1963    unsigned r1 = extract32(insn, 16, 5);
1964    unsigned cf = extract32(insn, 12, 4);
1965    unsigned rt = extract32(insn,  0, 5);
1966    TCGv tcg_r1, tcg_r2;
1967    ExitStatus ret;
1968
1969    if (cf) {
1970        nullify_over(ctx);
1971    }
1972    tcg_r1 = load_gpr(ctx, r1);
1973    tcg_r2 = load_gpr(ctx, r2);
1974    ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
1975    return nullify_end(ctx, ret);
1976}
1977
1978static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
1979                             const DisasInsn *di)
1980{
1981    unsigned r2 = extract32(insn, 21, 5);
1982    unsigned r1 = extract32(insn, 16, 5);
1983    unsigned cf = extract32(insn, 12, 4);
1984    unsigned rt = extract32(insn,  0, 5);
1985    TCGv tcg_r1, tcg_r2;
1986    ExitStatus ret;
1987
1988    if (cf) {
1989        nullify_over(ctx);
1990    }
1991    tcg_r1 = load_gpr(ctx, r1);
1992    tcg_r2 = load_gpr(ctx, r2);
1993    ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
1994    return nullify_end(ctx, ret);
1995}
1996
1997static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
1998                               const DisasInsn *di)
1999{
2000    unsigned r2 = extract32(insn, 21, 5);
2001    unsigned r1 = extract32(insn, 16, 5);
2002    unsigned cf = extract32(insn, 12, 4);
2003    unsigned is_tc = extract32(insn, 6, 1);
2004    unsigned rt = extract32(insn,  0, 5);
2005    TCGv tcg_r1, tcg_r2, tmp;
2006    ExitStatus ret;
2007
2008    if (cf) {
2009        nullify_over(ctx);
2010    }
2011    tcg_r1 = load_gpr(ctx, r1);
2012    tcg_r2 = load_gpr(ctx, r2);
2013    tmp = get_temp(ctx);
2014    tcg_gen_not_tl(tmp, tcg_r2);
2015    ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
2016    return nullify_end(ctx, ret);
2017}
2018
2019static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
2020                             const DisasInsn *di)
2021{
2022    unsigned r2 = extract32(insn, 21, 5);
2023    unsigned cf = extract32(insn, 12, 4);
2024    unsigned is_i = extract32(insn, 6, 1);
2025    unsigned rt = extract32(insn,  0, 5);
2026    TCGv tmp;
2027    ExitStatus ret;
2028
2029    nullify_over(ctx);
2030
2031    tmp = get_temp(ctx);
2032    tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
2033    if (!is_i) {
2034        tcg_gen_not_tl(tmp, tmp);
2035    }
2036    tcg_gen_andi_tl(tmp, tmp, 0x11111111);
2037    tcg_gen_muli_tl(tmp, tmp, 6);
2038    ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
2039                  is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
2040
2041    return nullify_end(ctx, ret);
2042}
2043
2044static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
2045                           const DisasInsn *di)
2046{
2047    unsigned r2 = extract32(insn, 21, 5);
2048    unsigned r1 = extract32(insn, 16, 5);
2049    unsigned cf = extract32(insn, 12, 4);
2050    unsigned rt = extract32(insn,  0, 5);
2051    TCGv dest, add1, add2, addc, zero, in1, in2;
2052
2053    nullify_over(ctx);
2054
2055    in1 = load_gpr(ctx, r1);
2056    in2 = load_gpr(ctx, r2);
2057
2058    add1 = tcg_temp_new();
2059    add2 = tcg_temp_new();
2060    addc = tcg_temp_new();
2061    dest = tcg_temp_new();
2062    zero = tcg_const_tl(0);
2063
2064    /* Form R1 << 1 | PSW[CB]{8}.  */
2065    tcg_gen_add_tl(add1, in1, in1);
2066    tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
2067
2068    /* Add or subtract R2, depending on PSW[V].  Proper computation of
2069       carry{8} requires that we subtract via + ~R2 + 1, as described in
2070       the manual.  By extracting and masking V, we can produce the
2071       proper inputs to the addition without movcond.  */
2072    tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
2073    tcg_gen_xor_tl(add2, in2, addc);
2074    tcg_gen_andi_tl(addc, addc, 1);
2075    /* ??? This is only correct for 32-bit.  */
2076    tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
2077    tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
2078
2079    tcg_temp_free(addc);
2080    tcg_temp_free(zero);
2081
2082    /* Write back the result register.  */
2083    save_gpr(ctx, rt, dest);
2084
2085    /* Write back PSW[CB].  */
2086    tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
2087    tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
2088
2089    /* Write back PSW[V] for the division step.  */
2090    tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
2091    tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
2092
2093    /* Install the new nullification.  */
2094    if (cf) {
2095        TCGv sv;
2096        TCGV_UNUSED(sv);
2097        if (cf >> 1 == 6) {
2098            /* ??? The lshift is supposed to contribute to overflow.  */
2099            sv = do_add_sv(ctx, dest, add1, add2);
2100        }
2101        ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
2102    }
2103
2104    tcg_temp_free(add1);
2105    tcg_temp_free(add2);
2106    tcg_temp_free(dest);
2107
2108    return nullify_end(ctx, NO_EXIT);
2109}
2110
2111static const DisasInsn table_arith_log[] = {
2112    { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
2113    { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
2114    { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl },
2115    { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl },
2116    { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl },
2117    { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl },
2118    { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
2119    { 0x08000380u, 0xfc000fe0u, trans_uxor },
2120    { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
2121    { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
2122    { 0x08000440u, 0xfc000fe0u, trans_ds },
2123    { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
2124    { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
2125    { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
2126    { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
2127};
2128
2129static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
2130{
2131    target_long im = low_sextract(insn, 0, 11);
2132    unsigned e1 = extract32(insn, 11, 1);
2133    unsigned cf = extract32(insn, 12, 4);
2134    unsigned rt = extract32(insn, 16, 5);
2135    unsigned r2 = extract32(insn, 21, 5);
2136    unsigned o1 = extract32(insn, 26, 1);
2137    TCGv tcg_im, tcg_r2;
2138    ExitStatus ret;
2139
2140    if (cf) {
2141        nullify_over(ctx);
2142    }
2143
2144    tcg_im = load_const(ctx, im);
2145    tcg_r2 = load_gpr(ctx, r2);
2146    ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
2147
2148    return nullify_end(ctx, ret);
2149}
2150
2151static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
2152{
2153    target_long im = low_sextract(insn, 0, 11);
2154    unsigned e1 = extract32(insn, 11, 1);
2155    unsigned cf = extract32(insn, 12, 4);
2156    unsigned rt = extract32(insn, 16, 5);
2157    unsigned r2 = extract32(insn, 21, 5);
2158    TCGv tcg_im, tcg_r2;
2159    ExitStatus ret;
2160
2161    if (cf) {
2162        nullify_over(ctx);
2163    }
2164
2165    tcg_im = load_const(ctx, im);
2166    tcg_r2 = load_gpr(ctx, r2);
2167    ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
2168
2169    return nullify_end(ctx, ret);
2170}
2171
2172static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
2173{
2174    target_long im = low_sextract(insn, 0, 11);
2175    unsigned cf = extract32(insn, 12, 4);
2176    unsigned rt = extract32(insn, 16, 5);
2177    unsigned r2 = extract32(insn, 21, 5);
2178    TCGv tcg_im, tcg_r2;
2179    ExitStatus ret;
2180
2181    if (cf) {
2182        nullify_over(ctx);
2183    }
2184
2185    tcg_im = load_const(ctx, im);
2186    tcg_r2 = load_gpr(ctx, r2);
2187    ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
2188
2189    return nullify_end(ctx, ret);
2190}
2191
2192static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
2193                                 const DisasInsn *di)
2194{
2195    unsigned rt = extract32(insn, 0, 5);
2196    unsigned m = extract32(insn, 5, 1);
2197    unsigned sz = extract32(insn, 6, 2);
2198    unsigned a = extract32(insn, 13, 1);
2199    int disp = low_sextract(insn, 16, 5);
2200    unsigned rb = extract32(insn, 21, 5);
2201    int modify = (m ? (a ? -1 : 1) : 0);
2202    TCGMemOp mop = MO_TE | sz;
2203
2204    return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
2205}
2206
2207static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
2208                                 const DisasInsn *di)
2209{
2210    unsigned rt = extract32(insn, 0, 5);
2211    unsigned m = extract32(insn, 5, 1);
2212    unsigned sz = extract32(insn, 6, 2);
2213    unsigned u = extract32(insn, 13, 1);
2214    unsigned rx = extract32(insn, 16, 5);
2215    unsigned rb = extract32(insn, 21, 5);
2216    TCGMemOp mop = MO_TE | sz;
2217
2218    return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
2219}
2220
2221static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn,
2222                                 const DisasInsn *di)
2223{
2224    int disp = low_sextract(insn, 0, 5);
2225    unsigned m = extract32(insn, 5, 1);
2226    unsigned sz = extract32(insn, 6, 2);
2227    unsigned a = extract32(insn, 13, 1);
2228    unsigned rr = extract32(insn, 16, 5);
2229    unsigned rb = extract32(insn, 21, 5);
2230    int modify = (m ? (a ? -1 : 1) : 0);
2231    TCGMemOp mop = MO_TE | sz;
2232
2233    return do_store(ctx, rr, rb, disp, modify, mop);
2234}
2235
2236static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn,
2237                             const DisasInsn *di)
2238{
2239    unsigned rt = extract32(insn, 0, 5);
2240    unsigned m = extract32(insn, 5, 1);
2241    unsigned i = extract32(insn, 12, 1);
2242    unsigned au = extract32(insn, 13, 1);
2243    unsigned rx = extract32(insn, 16, 5);
2244    unsigned rb = extract32(insn, 21, 5);
2245    TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
2246    TCGv zero, addr, base, dest;
2247    int modify, disp = 0, scale = 0;
2248
2249    nullify_over(ctx);
2250
2251    /* ??? Share more code with do_load and do_load_{32,64}.  */
2252
2253    if (i) {
2254        modify = (m ? (au ? -1 : 1) : 0);
2255        disp = low_sextract(rx, 0, 5);
2256        rx = 0;
2257    } else {
2258        modify = m;
2259        if (au) {
2260            scale = mop & MO_SIZE;
2261        }
2262    }
2263    if (modify) {
2264        /* Base register modification.  Make sure if RT == RB, we see
2265           the result of the load.  */
2266        dest = get_temp(ctx);
2267    } else {
2268        dest = dest_gpr(ctx, rt);
2269    }
2270
2271    addr = tcg_temp_new();
2272    base = load_gpr(ctx, rb);
2273    if (rx) {
2274        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
2275        tcg_gen_add_tl(addr, addr, base);
2276    } else {
2277        tcg_gen_addi_tl(addr, base, disp);
2278    }
2279
2280    zero = tcg_const_tl(0);
2281    tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
2282                           zero, MMU_USER_IDX, mop);
2283    if (modify) {
2284        save_gpr(ctx, rb, addr);
2285    }
2286    save_gpr(ctx, rt, dest);
2287
2288    return nullify_end(ctx, NO_EXIT);
2289}
2290
2291static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn,
2292                             const DisasInsn *di)
2293{
2294    target_long disp = low_sextract(insn, 0, 5);
2295    unsigned m = extract32(insn, 5, 1);
2296    unsigned a = extract32(insn, 13, 1);
2297    unsigned rt = extract32(insn, 16, 5);
2298    unsigned rb = extract32(insn, 21, 5);
2299    TCGv addr, val;
2300
2301    nullify_over(ctx);
2302
2303    addr = tcg_temp_new();
2304    if (m || disp == 0) {
2305        tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
2306    } else {
2307        tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
2308    }
2309    val = load_gpr(ctx, rt);
2310
2311    if (a) {
2312        gen_helper_stby_e(cpu_env, addr, val);
2313    } else {
2314        gen_helper_stby_b(cpu_env, addr, val);
2315    }
2316
2317    if (m) {
2318        tcg_gen_addi_tl(addr, addr, disp);
2319        tcg_gen_andi_tl(addr, addr, ~3);
2320        save_gpr(ctx, rb, addr);
2321    }
2322    tcg_temp_free(addr);
2323
2324    return nullify_end(ctx, NO_EXIT);
2325}
2326
2327static const DisasInsn table_index_mem[] = {
2328    { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
2329    { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
2330    { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
2331    { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
2332    { 0x0c001300u, 0xfc0013c0, trans_stby },
2333};
2334
2335static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
2336{
2337    unsigned rt = extract32(insn, 21, 5);
2338    target_long i = assemble_21(insn);
2339    TCGv tcg_rt = dest_gpr(ctx, rt);
2340
2341    tcg_gen_movi_tl(tcg_rt, i);
2342    save_gpr(ctx, rt, tcg_rt);
2343    cond_free(&ctx->null_cond);
2344
2345    return NO_EXIT;
2346}
2347
2348static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
2349{
2350    unsigned rt = extract32(insn, 21, 5);
2351    target_long i = assemble_21(insn);
2352    TCGv tcg_rt = load_gpr(ctx, rt);
2353    TCGv tcg_r1 = dest_gpr(ctx, 1);
2354
2355    tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
2356    save_gpr(ctx, 1, tcg_r1);
2357    cond_free(&ctx->null_cond);
2358
2359    return NO_EXIT;
2360}
2361
2362static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
2363{
2364    unsigned rb = extract32(insn, 21, 5);
2365    unsigned rt = extract32(insn, 16, 5);
2366    target_long i = assemble_16(insn);
2367    TCGv tcg_rt = dest_gpr(ctx, rt);
2368
2369    /* Special case rb == 0, for the LDI pseudo-op.
2370       The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
2371    if (rb == 0) {
2372        tcg_gen_movi_tl(tcg_rt, i);
2373    } else {
2374        tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
2375    }
2376    save_gpr(ctx, rt, tcg_rt);
2377    cond_free(&ctx->null_cond);
2378
2379    return NO_EXIT;
2380}
2381
2382static ExitStatus trans_load(DisasContext *ctx, uint32_t insn,
2383                             bool is_mod, TCGMemOp mop)
2384{
2385    unsigned rb = extract32(insn, 21, 5);
2386    unsigned rt = extract32(insn, 16, 5);
2387    target_long i = assemble_16(insn);
2388
2389    return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2390}
2391
2392static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn)
2393{
2394    unsigned rb = extract32(insn, 21, 5);
2395    unsigned rt = extract32(insn, 16, 5);
2396    target_long i = assemble_16a(insn);
2397    unsigned ext2 = extract32(insn, 1, 2);
2398
2399    switch (ext2) {
2400    case 0:
2401    case 1:
2402        /* FLDW without modification.  */
2403        return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2404    case 2:
2405        /* LDW with modification.  Note that the sign of I selects
2406           post-dec vs pre-inc.  */
2407        return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
2408    default:
2409        return gen_illegal(ctx);
2410    }
2411}
2412
2413static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn)
2414{
2415    target_long i = assemble_16a(insn);
2416    unsigned t1 = extract32(insn, 1, 1);
2417    unsigned a = extract32(insn, 2, 1);
2418    unsigned t0 = extract32(insn, 16, 5);
2419    unsigned rb = extract32(insn, 21, 5);
2420
2421    /* FLDW with modification.  */
2422    return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2423}
2424
2425static ExitStatus trans_store(DisasContext *ctx, uint32_t insn,
2426                              bool is_mod, TCGMemOp mop)
2427{
2428    unsigned rb = extract32(insn, 21, 5);
2429    unsigned rt = extract32(insn, 16, 5);
2430    target_long i = assemble_16(insn);
2431
2432    return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
2433}
2434
2435static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn)
2436{
2437    unsigned rb = extract32(insn, 21, 5);
2438    unsigned rt = extract32(insn, 16, 5);
2439    target_long i = assemble_16a(insn);
2440    unsigned ext2 = extract32(insn, 1, 2);
2441
2442    switch (ext2) {
2443    case 0:
2444    case 1:
2445        /* FSTW without modification.  */
2446        return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
2447    case 2:
2448        /* LDW with modification.  */
2449        return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
2450    default:
2451        return gen_illegal(ctx);
2452    }
2453}
2454
2455static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn)
2456{
2457    target_long i = assemble_16a(insn);
2458    unsigned t1 = extract32(insn, 1, 1);
2459    unsigned a = extract32(insn, 2, 1);
2460    unsigned t0 = extract32(insn, 16, 5);
2461    unsigned rb = extract32(insn, 21, 5);
2462
2463    /* FSTW with modification.  */
2464    return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
2465}
2466
2467static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn)
2468{
2469    unsigned t0 = extract32(insn, 0, 5);
2470    unsigned m = extract32(insn, 5, 1);
2471    unsigned t1 = extract32(insn, 6, 1);
2472    unsigned ext3 = extract32(insn, 7, 3);
2473    /* unsigned cc = extract32(insn, 10, 2); */
2474    unsigned i = extract32(insn, 12, 1);
2475    unsigned ua = extract32(insn, 13, 1);
2476    unsigned rx = extract32(insn, 16, 5);
2477    unsigned rb = extract32(insn, 21, 5);
2478    unsigned rt = t1 * 32 + t0;
2479    int modify = (m ? (ua ? -1 : 1) : 0);
2480    int disp, scale;
2481
2482    if (i == 0) {
2483        scale = (ua ? 2 : 0);
2484        disp = 0;
2485        modify = m;
2486    } else {
2487        disp = low_sextract(rx, 0, 5);
2488        scale = 0;
2489        rx = 0;
2490        modify = (m ? (ua ? -1 : 1) : 0);
2491    }
2492
2493    switch (ext3) {
2494    case 0: /* FLDW */
2495        return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
2496    case 4: /* FSTW */
2497        return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
2498    }
2499    return gen_illegal(ctx);
2500}
2501
2502static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn)
2503{
2504    unsigned rt = extract32(insn, 0, 5);
2505    unsigned m = extract32(insn, 5, 1);
2506    unsigned ext4 = extract32(insn, 6, 4);
2507    /* unsigned cc = extract32(insn, 10, 2); */
2508    unsigned i = extract32(insn, 12, 1);
2509    unsigned ua = extract32(insn, 13, 1);
2510    unsigned rx = extract32(insn, 16, 5);
2511    unsigned rb = extract32(insn, 21, 5);
2512    int modify = (m ? (ua ? -1 : 1) : 0);
2513    int disp, scale;
2514
2515    if (i == 0) {
2516        scale = (ua ? 3 : 0);
2517        disp = 0;
2518        modify = m;
2519    } else {
2520        disp = low_sextract(rx, 0, 5);
2521        scale = 0;
2522        rx = 0;
2523        modify = (m ? (ua ? -1 : 1) : 0);
2524    }
2525
2526    switch (ext4) {
2527    case 0: /* FLDD */
2528        return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
2529    case 8: /* FSTD */
2530        return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
2531    default:
2532        return gen_illegal(ctx);
2533    }
2534}
2535
2536static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
2537                             bool is_true, bool is_imm, bool is_dw)
2538{
2539    target_long disp = assemble_12(insn) * 4;
2540    unsigned n = extract32(insn, 1, 1);
2541    unsigned c = extract32(insn, 13, 3);
2542    unsigned r = extract32(insn, 21, 5);
2543    unsigned cf = c * 2 + !is_true;
2544    TCGv dest, in1, in2, sv;
2545    DisasCond cond;
2546
2547    nullify_over(ctx);
2548
2549    if (is_imm) {
2550        in1 = load_const(ctx, low_sextract(insn, 16, 5));
2551    } else {
2552        in1 = load_gpr(ctx, extract32(insn, 16, 5));
2553    }
2554    in2 = load_gpr(ctx, r);
2555    dest = get_temp(ctx);
2556
2557    tcg_gen_sub_tl(dest, in1, in2);
2558
2559    TCGV_UNUSED(sv);
2560    if (c == 6) {
2561        sv = do_sub_sv(ctx, dest, in1, in2);
2562    }
2563
2564    cond = do_sub_cond(cf, dest, in1, in2, sv);
2565    return do_cbranch(ctx, disp, n, &cond);
2566}
2567
2568static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
2569                             bool is_true, bool is_imm)
2570{
2571    target_long disp = assemble_12(insn) * 4;
2572    unsigned n = extract32(insn, 1, 1);
2573    unsigned c = extract32(insn, 13, 3);
2574    unsigned r = extract32(insn, 21, 5);
2575    unsigned cf = c * 2 + !is_true;
2576    TCGv dest, in1, in2, sv, cb_msb;
2577    DisasCond cond;
2578
2579    nullify_over(ctx);
2580
2581    if (is_imm) {
2582        in1 = load_const(ctx, low_sextract(insn, 16, 5));
2583    } else {
2584        in1 = load_gpr(ctx, extract32(insn, 16, 5));
2585    }
2586    in2 = load_gpr(ctx, r);
2587    dest = dest_gpr(ctx, r);
2588    TCGV_UNUSED(sv);
2589    TCGV_UNUSED(cb_msb);
2590
2591    switch (c) {
2592    default:
2593        tcg_gen_add_tl(dest, in1, in2);
2594        break;
2595    case 4: case 5:
2596        cb_msb = get_temp(ctx);
2597        tcg_gen_movi_tl(cb_msb, 0);
2598        tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
2599        break;
2600    case 6:
2601        tcg_gen_add_tl(dest, in1, in2);
2602        sv = do_add_sv(ctx, dest, in1, in2);
2603        break;
2604    }
2605
2606    cond = do_cond(cf, dest, cb_msb, sv);
2607    return do_cbranch(ctx, disp, n, &cond);
2608}
2609
2610static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
2611{
2612    target_long disp = assemble_12(insn) * 4;
2613    unsigned n = extract32(insn, 1, 1);
2614    unsigned c = extract32(insn, 15, 1);
2615    unsigned r = extract32(insn, 16, 5);
2616    unsigned p = extract32(insn, 21, 5);
2617    unsigned i = extract32(insn, 26, 1);
2618    TCGv tmp, tcg_r;
2619    DisasCond cond;
2620
2621    nullify_over(ctx);
2622
2623    tmp = tcg_temp_new();
2624    tcg_r = load_gpr(ctx, r);
2625    if (i) {
2626        tcg_gen_shli_tl(tmp, tcg_r, p);
2627    } else {
2628        tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
2629    }
2630
2631    cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
2632    tcg_temp_free(tmp);
2633    return do_cbranch(ctx, disp, n, &cond);
2634}
2635
2636static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
2637{
2638    target_long disp = assemble_12(insn) * 4;
2639    unsigned n = extract32(insn, 1, 1);
2640    unsigned c = extract32(insn, 13, 3);
2641    unsigned t = extract32(insn, 16, 5);
2642    unsigned r = extract32(insn, 21, 5);
2643    TCGv dest;
2644    DisasCond cond;
2645
2646    nullify_over(ctx);
2647
2648    dest = dest_gpr(ctx, r);
2649    if (is_imm) {
2650        tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
2651    } else if (t == 0) {
2652        tcg_gen_movi_tl(dest, 0);
2653    } else {
2654        tcg_gen_mov_tl(dest, cpu_gr[t]);
2655    }
2656
2657    cond = do_sed_cond(c, dest);
2658    return do_cbranch(ctx, disp, n, &cond);
2659}
2660
2661static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
2662                                 const DisasInsn *di)
2663{
2664    unsigned rt = extract32(insn, 0, 5);
2665    unsigned c = extract32(insn, 13, 3);
2666    unsigned r1 = extract32(insn, 16, 5);
2667    unsigned r2 = extract32(insn, 21, 5);
2668    TCGv dest;
2669
2670    if (c) {
2671        nullify_over(ctx);
2672    }
2673
2674    dest = dest_gpr(ctx, rt);
2675    if (r1 == 0) {
2676        tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
2677        tcg_gen_shr_tl(dest, dest, cpu_sar);
2678    } else if (r1 == r2) {
2679        TCGv_i32 t32 = tcg_temp_new_i32();
2680        tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
2681        tcg_gen_rotr_i32(t32, t32, cpu_sar);
2682        tcg_gen_extu_i32_tl(dest, t32);
2683        tcg_temp_free_i32(t32);
2684    } else {
2685        TCGv_i64 t = tcg_temp_new_i64();
2686        TCGv_i64 s = tcg_temp_new_i64();
2687
2688        tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
2689        tcg_gen_extu_tl_i64(s, cpu_sar);
2690        tcg_gen_shr_i64(t, t, s);
2691        tcg_gen_trunc_i64_tl(dest, t);
2692
2693        tcg_temp_free_i64(t);
2694        tcg_temp_free_i64(s);
2695    }
2696    save_gpr(ctx, rt, dest);
2697
2698    /* Install the new nullification.  */
2699    cond_free(&ctx->null_cond);
2700    if (c) {
2701        ctx->null_cond = do_sed_cond(c, dest);
2702    }
2703    return nullify_end(ctx, NO_EXIT);
2704}
2705
2706static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
2707                                  const DisasInsn *di)
2708{
2709    unsigned rt = extract32(insn, 0, 5);
2710    unsigned cpos = extract32(insn, 5, 5);
2711    unsigned c = extract32(insn, 13, 3);
2712    unsigned r1 = extract32(insn, 16, 5);
2713    unsigned r2 = extract32(insn, 21, 5);
2714    unsigned sa = 31 - cpos;
2715    TCGv dest, t2;
2716
2717    if (c) {
2718        nullify_over(ctx);
2719    }
2720
2721    dest = dest_gpr(ctx, rt);
2722    t2 = load_gpr(ctx, r2);
2723    if (r1 == r2) {
2724        TCGv_i32 t32 = tcg_temp_new_i32();
2725        tcg_gen_trunc_tl_i32(t32, t2);
2726        tcg_gen_rotri_i32(t32, t32, sa);
2727        tcg_gen_extu_i32_tl(dest, t32);
2728        tcg_temp_free_i32(t32);
2729    } else if (r1 == 0) {
2730        tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
2731    } else {
2732        TCGv t0 = tcg_temp_new();
2733        tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
2734        tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
2735        tcg_temp_free(t0);
2736    }
2737    save_gpr(ctx, rt, dest);
2738
2739    /* Install the new nullification.  */
2740    cond_free(&ctx->null_cond);
2741    if (c) {
2742        ctx->null_cond = do_sed_cond(c, dest);
2743    }
2744    return nullify_end(ctx, NO_EXIT);
2745}
2746
2747static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
2748                                  const DisasInsn *di)
2749{
2750    unsigned clen = extract32(insn, 0, 5);
2751    unsigned is_se = extract32(insn, 10, 1);
2752    unsigned c = extract32(insn, 13, 3);
2753    unsigned rt = extract32(insn, 16, 5);
2754    unsigned rr = extract32(insn, 21, 5);
2755    unsigned len = 32 - clen;
2756    TCGv dest, src, tmp;
2757
2758    if (c) {
2759        nullify_over(ctx);
2760    }
2761
2762    dest = dest_gpr(ctx, rt);
2763    src = load_gpr(ctx, rr);
2764    tmp = tcg_temp_new();
2765
2766    /* Recall that SAR is using big-endian bit numbering.  */
2767    tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
2768    if (is_se) {
2769        tcg_gen_sar_tl(dest, src, tmp);
2770        tcg_gen_sextract_tl(dest, dest, 0, len);
2771    } else {
2772        tcg_gen_shr_tl(dest, src, tmp);
2773        tcg_gen_extract_tl(dest, dest, 0, len);
2774    }
2775    tcg_temp_free(tmp);
2776    save_gpr(ctx, rt, dest);
2777
2778    /* Install the new nullification.  */
2779    cond_free(&ctx->null_cond);
2780    if (c) {
2781        ctx->null_cond = do_sed_cond(c, dest);
2782    }
2783    return nullify_end(ctx, NO_EXIT);
2784}
2785
2786static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
2787                                  const DisasInsn *di)
2788{
2789    unsigned clen = extract32(insn, 0, 5);
2790    unsigned pos = extract32(insn, 5, 5);
2791    unsigned is_se = extract32(insn, 10, 1);
2792    unsigned c = extract32(insn, 13, 3);
2793    unsigned rt = extract32(insn, 16, 5);
2794    unsigned rr = extract32(insn, 21, 5);
2795    unsigned len = 32 - clen;
2796    unsigned cpos = 31 - pos;
2797    TCGv dest, src;
2798
2799    if (c) {
2800        nullify_over(ctx);
2801    }
2802
2803    dest = dest_gpr(ctx, rt);
2804    src = load_gpr(ctx, rr);
2805    if (is_se) {
2806        tcg_gen_sextract_tl(dest, src, cpos, len);
2807    } else {
2808        tcg_gen_extract_tl(dest, src, cpos, len);
2809    }
2810    save_gpr(ctx, rt, dest);
2811
2812    /* Install the new nullification.  */
2813    cond_free(&ctx->null_cond);
2814    if (c) {
2815        ctx->null_cond = do_sed_cond(c, dest);
2816    }
2817    return nullify_end(ctx, NO_EXIT);
2818}
2819
2820static const DisasInsn table_sh_ex[] = {
2821    { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
2822    { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
2823    { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
2824    { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
2825};
2826
2827static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
2828                                   const DisasInsn *di)
2829{
2830    unsigned clen = extract32(insn, 0, 5);
2831    unsigned cpos = extract32(insn, 5, 5);
2832    unsigned nz = extract32(insn, 10, 1);
2833    unsigned c = extract32(insn, 13, 3);
2834    target_long val = low_sextract(insn, 16, 5);
2835    unsigned rt = extract32(insn, 21, 5);
2836    unsigned len = 32 - clen;
2837    target_long mask0, mask1;
2838    TCGv dest;
2839
2840    if (c) {
2841        nullify_over(ctx);
2842    }
2843    if (cpos + len > 32) {
2844        len = 32 - cpos;
2845    }
2846
2847    dest = dest_gpr(ctx, rt);
2848    mask0 = deposit64(0, cpos, len, val);
2849    mask1 = deposit64(-1, cpos, len, val);
2850
2851    if (nz) {
2852        TCGv src = load_gpr(ctx, rt);
2853        if (mask1 != -1) {
2854            tcg_gen_andi_tl(dest, src, mask1);
2855            src = dest;
2856        }
2857        tcg_gen_ori_tl(dest, src, mask0);
2858    } else {
2859        tcg_gen_movi_tl(dest, mask0);
2860    }
2861    save_gpr(ctx, rt, dest);
2862
2863    /* Install the new nullification.  */
2864    cond_free(&ctx->null_cond);
2865    if (c) {
2866        ctx->null_cond = do_sed_cond(c, dest);
2867    }
2868    return nullify_end(ctx, NO_EXIT);
2869}
2870
2871static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
2872                                 const DisasInsn *di)
2873{
2874    unsigned clen = extract32(insn, 0, 5);
2875    unsigned cpos = extract32(insn, 5, 5);
2876    unsigned nz = extract32(insn, 10, 1);
2877    unsigned c = extract32(insn, 13, 3);
2878    unsigned rr = extract32(insn, 16, 5);
2879    unsigned rt = extract32(insn, 21, 5);
2880    unsigned rs = nz ? rt : 0;
2881    unsigned len = 32 - clen;
2882    TCGv dest, val;
2883
2884    if (c) {
2885        nullify_over(ctx);
2886    }
2887    if (cpos + len > 32) {
2888        len = 32 - cpos;
2889    }
2890
2891    dest = dest_gpr(ctx, rt);
2892    val = load_gpr(ctx, rr);
2893    if (rs == 0) {
2894        tcg_gen_deposit_z_tl(dest, val, cpos, len);
2895    } else {
2896        tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
2897    }
2898    save_gpr(ctx, rt, dest);
2899
2900    /* Install the new nullification.  */
2901    cond_free(&ctx->null_cond);
2902    if (c) {
2903        ctx->null_cond = do_sed_cond(c, dest);
2904    }
2905    return nullify_end(ctx, NO_EXIT);
2906}
2907
2908static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
2909                                 const DisasInsn *di)
2910{
2911    unsigned clen = extract32(insn, 0, 5);
2912    unsigned nz = extract32(insn, 10, 1);
2913    unsigned i = extract32(insn, 12, 1);
2914    unsigned c = extract32(insn, 13, 3);
2915    unsigned rt = extract32(insn, 21, 5);
2916    unsigned rs = nz ? rt : 0;
2917    unsigned len = 32 - clen;
2918    TCGv val, mask, tmp, shift, dest;
2919    unsigned msb = 1U << (len - 1);
2920
2921    if (c) {
2922        nullify_over(ctx);
2923    }
2924
2925    if (i) {
2926        val = load_const(ctx, low_sextract(insn, 16, 5));
2927    } else {
2928        val = load_gpr(ctx, extract32(insn, 16, 5));
2929    }
2930    dest = dest_gpr(ctx, rt);
2931    shift = tcg_temp_new();
2932    tmp = tcg_temp_new();
2933
2934    /* Convert big-endian bit numbering in SAR to left-shift.  */
2935    tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
2936
2937    mask = tcg_const_tl(msb + (msb - 1));
2938    tcg_gen_and_tl(tmp, val, mask);
2939    if (rs) {
2940        tcg_gen_shl_tl(mask, mask, shift);
2941        tcg_gen_shl_tl(tmp, tmp, shift);
2942        tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
2943        tcg_gen_or_tl(dest, dest, tmp);
2944    } else {
2945        tcg_gen_shl_tl(dest, tmp, shift);
2946    }
2947    tcg_temp_free(shift);
2948    tcg_temp_free(mask);
2949    tcg_temp_free(tmp);
2950    save_gpr(ctx, rt, dest);
2951
2952    /* Install the new nullification.  */
2953    cond_free(&ctx->null_cond);
2954    if (c) {
2955        ctx->null_cond = do_sed_cond(c, dest);
2956    }
2957    return nullify_end(ctx, NO_EXIT);
2958}
2959
2960static const DisasInsn table_depw[] = {
2961    { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
2962    { 0xd4000800u, 0xfc001800u, trans_depw_imm },
2963    { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
2964};
2965
2966static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
2967{
2968    unsigned n = extract32(insn, 1, 1);
2969    unsigned b = extract32(insn, 21, 5);
2970    target_long disp = assemble_17(insn);
2971
2972    /* unsigned s = low_uextract(insn, 13, 3); */
2973    /* ??? It seems like there should be a good way of using
2974       "be disp(sr2, r0)", the canonical gateway entry mechanism
2975       to our advantage.  But that appears to be inconvenient to
2976       manage along side branch delay slots.  Therefore we handle
2977       entry into the gateway page via absolute address.  */
2978
2979    /* Since we don't implement spaces, just branch.  Do notice the special
2980       case of "be disp(*,r0)" using a direct branch to disp, so that we can
2981       goto_tb to the TB containing the syscall.  */
2982    if (b == 0) {
2983        return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
2984    } else {
2985        TCGv tmp = get_temp(ctx);
2986        tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
2987        return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
2988    }
2989}
2990
2991static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
2992                           const DisasInsn *di)
2993{
2994    unsigned n = extract32(insn, 1, 1);
2995    unsigned link = extract32(insn, 21, 5);
2996    target_long disp = assemble_17(insn);
2997
2998    return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
2999}
3000
3001static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
3002                                const DisasInsn *di)
3003{
3004    unsigned n = extract32(insn, 1, 1);
3005    target_long disp = assemble_22(insn);
3006
3007    return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
3008}
3009
3010static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
3011                            const DisasInsn *di)
3012{
3013    unsigned n = extract32(insn, 1, 1);
3014    unsigned rx = extract32(insn, 16, 5);
3015    unsigned link = extract32(insn, 21, 5);
3016    TCGv tmp = get_temp(ctx);
3017
3018    tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
3019    tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
3020    return do_ibranch(ctx, tmp, link, n);
3021}
3022
3023static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
3024                           const DisasInsn *di)
3025{
3026    unsigned n = extract32(insn, 1, 1);
3027    unsigned rx = extract32(insn, 16, 5);
3028    unsigned rb = extract32(insn, 21, 5);
3029    TCGv dest;
3030
3031    if (rx == 0) {
3032        dest = load_gpr(ctx, rb);
3033    } else {
3034        dest = get_temp(ctx);
3035        tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
3036        tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
3037    }
3038    return do_ibranch(ctx, dest, 0, n);
3039}
3040
3041static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
3042                            const DisasInsn *di)
3043{
3044    unsigned n = extract32(insn, 1, 1);
3045    unsigned rb = extract32(insn, 21, 5);
3046    unsigned link = extract32(insn, 13, 1) ? 2 : 0;
3047
3048    return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
3049}
3050
3051static const DisasInsn table_branch[] = {
3052    { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
3053    { 0xe800a000u, 0xfc00e000u, trans_bl_long },
3054    { 0xe8004000u, 0xfc00fffdu, trans_blr },
3055    { 0xe800c000u, 0xfc00fffdu, trans_bv },
3056    { 0xe800d000u, 0xfc00dffcu, trans_bve },
3057};
3058
3059static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
3060                                   const DisasInsn *di)
3061{
3062    unsigned rt = extract32(insn, 0, 5);
3063    unsigned ra = extract32(insn, 21, 5);
3064    return do_fop_wew(ctx, rt, ra, di->f.wew);
3065}
3066
3067static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
3068                                   const DisasInsn *di)
3069{
3070    unsigned rt = assemble_rt64(insn);
3071    unsigned ra = assemble_ra64(insn);
3072    return do_fop_wew(ctx, rt, ra, di->f.wew);
3073}
3074
3075static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn,
3076                                const DisasInsn *di)
3077{
3078    unsigned rt = extract32(insn, 0, 5);
3079    unsigned ra = extract32(insn, 21, 5);
3080    return do_fop_ded(ctx, rt, ra, di->f.ded);
3081}
3082
3083static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
3084                                   const DisasInsn *di)
3085{
3086    unsigned rt = extract32(insn, 0, 5);
3087    unsigned ra = extract32(insn, 21, 5);
3088    return do_fop_wed(ctx, rt, ra, di->f.wed);
3089}
3090
3091static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
3092                                   const DisasInsn *di)
3093{
3094    unsigned rt = assemble_rt64(insn);
3095    unsigned ra = extract32(insn, 21, 5);
3096    return do_fop_wed(ctx, rt, ra, di->f.wed);
3097}
3098
3099static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
3100                                   const DisasInsn *di)
3101{
3102    unsigned rt = extract32(insn, 0, 5);
3103    unsigned ra = extract32(insn, 21, 5);
3104    return do_fop_dew(ctx, rt, ra, di->f.dew);
3105}
3106
3107static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
3108                                   const DisasInsn *di)
3109{
3110    unsigned rt = extract32(insn, 0, 5);
3111    unsigned ra = assemble_ra64(insn);
3112    return do_fop_dew(ctx, rt, ra, di->f.dew);
3113}
3114
3115static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
3116                                    const DisasInsn *di)
3117{
3118    unsigned rt = extract32(insn, 0, 5);
3119    unsigned rb = extract32(insn, 16, 5);
3120    unsigned ra = extract32(insn, 21, 5);
3121    return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3122}
3123
3124static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
3125                                    const DisasInsn *di)
3126{
3127    unsigned rt = assemble_rt64(insn);
3128    unsigned rb = assemble_rb64(insn);
3129    unsigned ra = assemble_ra64(insn);
3130    return do_fop_weww(ctx, rt, ra, rb, di->f.weww);
3131}
3132
3133static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn,
3134                                 const DisasInsn *di)
3135{
3136    unsigned rt = extract32(insn, 0, 5);
3137    unsigned rb = extract32(insn, 16, 5);
3138    unsigned ra = extract32(insn, 21, 5);
3139    return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd);
3140}
3141
3142static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3143{
3144    tcg_gen_mov_i32(dst, src);
3145}
3146
3147static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3148{
3149    tcg_gen_mov_i64(dst, src);
3150}
3151
3152static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3153{
3154    tcg_gen_andi_i32(dst, src, INT32_MAX);
3155}
3156
3157static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3158{
3159    tcg_gen_andi_i64(dst, src, INT64_MAX);
3160}
3161
3162static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3163{
3164    tcg_gen_xori_i32(dst, src, INT32_MIN);
3165}
3166
3167static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3168{
3169    tcg_gen_xori_i64(dst, src, INT64_MIN);
3170}
3171
3172static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
3173{
3174    tcg_gen_ori_i32(dst, src, INT32_MIN);
3175}
3176
3177static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
3178{
3179    tcg_gen_ori_i64(dst, src, INT64_MIN);
3180}
3181
3182static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
3183                            unsigned y, unsigned c)
3184{
3185    TCGv_i32 ta, tb, tc, ty;
3186
3187    nullify_over(ctx);
3188
3189    ta = load_frw0_i32(ra);
3190    tb = load_frw0_i32(rb);
3191    ty = tcg_const_i32(y);
3192    tc = tcg_const_i32(c);
3193
3194    gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
3195
3196    tcg_temp_free_i32(ta);
3197    tcg_temp_free_i32(tb);
3198    tcg_temp_free_i32(ty);
3199    tcg_temp_free_i32(tc);
3200
3201    return nullify_end(ctx, NO_EXIT);
3202}
3203
3204static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
3205                                  const DisasInsn *di)
3206{
3207    unsigned c = extract32(insn, 0, 5);
3208    unsigned y = extract32(insn, 13, 3);
3209    unsigned rb = extract32(insn, 16, 5);
3210    unsigned ra = extract32(insn, 21, 5);
3211    return do_fcmp_s(ctx, ra, rb, y, c);
3212}
3213
3214static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
3215                                  const DisasInsn *di)
3216{
3217    unsigned c = extract32(insn, 0, 5);
3218    unsigned y = extract32(insn, 13, 3);
3219    unsigned rb = assemble_rb64(insn);
3220    unsigned ra = assemble_ra64(insn);
3221    return do_fcmp_s(ctx, ra, rb, y, c);
3222}
3223
3224static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn,
3225                               const DisasInsn *di)
3226{
3227    unsigned c = extract32(insn, 0, 5);
3228    unsigned y = extract32(insn, 13, 3);
3229    unsigned rb = extract32(insn, 16, 5);
3230    unsigned ra = extract32(insn, 21, 5);
3231    TCGv_i64 ta, tb;
3232    TCGv_i32 tc, ty;
3233
3234    nullify_over(ctx);
3235
3236    ta = load_frd0(ra);
3237    tb = load_frd0(rb);
3238    ty = tcg_const_i32(y);
3239    tc = tcg_const_i32(c);
3240
3241    gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
3242
3243    tcg_temp_free_i64(ta);
3244    tcg_temp_free_i64(tb);
3245    tcg_temp_free_i32(ty);
3246    tcg_temp_free_i32(tc);
3247
3248    return nullify_end(ctx, NO_EXIT);
3249}
3250
3251static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn,
3252                                const DisasInsn *di)
3253{
3254    unsigned y = extract32(insn, 13, 3);
3255    unsigned cbit = (y ^ 1) - 1;
3256    TCGv t;
3257
3258    nullify_over(ctx);
3259
3260    t = tcg_temp_new();
3261    tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3262    tcg_gen_extract_tl(t, t, 21 - cbit, 1);
3263    ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3264    tcg_temp_free(t);
3265
3266    return nullify_end(ctx, NO_EXIT);
3267}
3268
3269static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn,
3270                                const DisasInsn *di)
3271{
3272    unsigned c = extract32(insn, 0, 5);
3273    int mask;
3274    bool inv = false;
3275    TCGv t;
3276
3277    nullify_over(ctx);
3278
3279    t = tcg_temp_new();
3280    tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
3281
3282    switch (c) {
3283    case 0: /* simple */
3284        tcg_gen_andi_tl(t, t, 0x4000000);
3285        ctx->null_cond = cond_make_0(TCG_COND_NE, t);
3286        goto done;
3287    case 2: /* rej */
3288        inv = true;
3289        /* fallthru */
3290    case 1: /* acc */
3291        mask = 0x43ff800;
3292        break;
3293    case 6: /* rej8 */
3294        inv = true;
3295        /* fallthru */
3296    case 5: /* acc8 */
3297        mask = 0x43f8000;
3298        break;
3299    case 9: /* acc6 */
3300        mask = 0x43e0000;
3301        break;
3302    case 13: /* acc4 */
3303        mask = 0x4380000;
3304        break;
3305    case 17: /* acc2 */
3306        mask = 0x4200000;
3307        break;
3308    default:
3309        return gen_illegal(ctx);
3310    }
3311    if (inv) {
3312        TCGv c = load_const(ctx, mask);
3313        tcg_gen_or_tl(t, t, c);
3314        ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
3315    } else {
3316        tcg_gen_andi_tl(t, t, mask);
3317        ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
3318    }
3319 done:
3320    return nullify_end(ctx, NO_EXIT);
3321}
3322
3323static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn,
3324                              const DisasInsn *di)
3325{
3326    unsigned rt = extract32(insn, 0, 5);
3327    unsigned rb = assemble_rb64(insn);
3328    unsigned ra = assemble_ra64(insn);
3329    TCGv_i64 a, b;
3330
3331    nullify_over(ctx);
3332
3333    a = load_frw0_i64(ra);
3334    b = load_frw0_i64(rb);
3335    tcg_gen_mul_i64(a, a, b);
3336    save_frd(rt, a);
3337    tcg_temp_free_i64(a);
3338    tcg_temp_free_i64(b);
3339
3340    return nullify_end(ctx, NO_EXIT);
3341}
3342
3343#define FOP_DED  trans_fop_ded, .f.ded
3344#define FOP_DEDD trans_fop_dedd, .f.dedd
3345
3346#define FOP_WEW  trans_fop_wew_0c, .f.wew
3347#define FOP_DEW  trans_fop_dew_0c, .f.dew
3348#define FOP_WED  trans_fop_wed_0c, .f.wed
3349#define FOP_WEWW trans_fop_weww_0c, .f.weww
3350
3351static const DisasInsn table_float_0c[] = {
3352    /* floating point class zero */
3353    { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
3354    { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
3355    { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
3356    { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
3357    { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
3358    { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
3359
3360    { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3361    { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3362    { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3363    { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3364    { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3365    { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3366
3367    /* floating point class three */
3368    { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
3369    { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
3370    { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
3371    { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
3372
3373    { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3374    { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3375    { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3376    { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3377
3378    /* floating point class one */
3379    /* float/float */
3380    { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
3381    { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
3382    /* int/float */
3383    { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
3384    { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
3385    { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
3386    { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3387    /* float/int */
3388    { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
3389    { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
3390    { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
3391    { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3392    /* float/int truncate */
3393    { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
3394    { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
3395    { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
3396    { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3397    /* uint/float */
3398    { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
3399    { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
3400    { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
3401    { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3402    /* float/uint */
3403    { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
3404    { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
3405    { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
3406    { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3407    /* float/uint truncate */
3408    { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
3409    { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
3410    { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
3411    { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3412
3413    /* floating point class two */
3414    { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
3415    { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
3416    { 0x30002420, 0xffffffe0, trans_ftest_q },
3417    { 0x30000420, 0xffff1fff, trans_ftest_t },
3418
3419    /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
3420       This is machine/revision == 0, which is reserved for simulator.  */
3421    { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
3422};
3423
3424#undef FOP_WEW
3425#undef FOP_DEW
3426#undef FOP_WED
3427#undef FOP_WEWW
3428#define FOP_WEW  trans_fop_wew_0e, .f.wew
3429#define FOP_DEW  trans_fop_dew_0e, .f.dew
3430#define FOP_WED  trans_fop_wed_0e, .f.wed
3431#define FOP_WEWW trans_fop_weww_0e, .f.weww
3432
3433static const DisasInsn table_float_0e[] = {
3434    /* floating point class zero */
3435    { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
3436    { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
3437    { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
3438    { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
3439    { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
3440    { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
3441
3442    { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
3443    { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
3444    { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
3445    { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
3446    { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
3447    { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
3448
3449    /* floating point class three */
3450    { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
3451    { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
3452    { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
3453    { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
3454
3455    { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
3456    { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
3457    { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
3458    { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
3459
3460    { 0x38004700, 0xfc00ef60, trans_xmpyu },
3461
3462    /* floating point class one */
3463    /* float/float */
3464    { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
3465    { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
3466    /* int/float */
3467    { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
3468    { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
3469    { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
3470    { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
3471    /* float/int */
3472    { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
3473    { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
3474    { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
3475    { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
3476    /* float/int truncate */
3477    { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
3478    { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
3479    { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
3480    { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
3481    /* uint/float */
3482    { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
3483    { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
3484    { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
3485    { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
3486    /* float/uint */
3487    { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
3488    { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
3489    { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
3490    { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
3491    /* float/uint truncate */
3492    { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
3493    { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
3494    { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
3495    { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
3496
3497    /* floating point class two */
3498    { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
3499    { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
3500};
3501
3502#undef FOP_WEW
3503#undef FOP_DEW
3504#undef FOP_WED
3505#undef FOP_WEWW
3506#undef FOP_DED
3507#undef FOP_DEDD
3508
3509/* Convert the fmpyadd single-precision register encodings to standard.  */
3510static inline int fmpyadd_s_reg(unsigned r)
3511{
3512    return (r & 16) * 2 + 16 + (r & 15);
3513}
3514
3515static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub)
3516{
3517    unsigned tm = extract32(insn, 0, 5);
3518    unsigned f = extract32(insn, 5, 1);
3519    unsigned ra = extract32(insn, 6, 5);
3520    unsigned ta = extract32(insn, 11, 5);
3521    unsigned rm2 = extract32(insn, 16, 5);
3522    unsigned rm1 = extract32(insn, 21, 5);
3523
3524    nullify_over(ctx);
3525
3526    /* Independent multiply & add/sub, with undefined behaviour
3527       if outputs overlap inputs.  */
3528    if (f == 0) {
3529        tm = fmpyadd_s_reg(tm);
3530        ra = fmpyadd_s_reg(ra);
3531        ta = fmpyadd_s_reg(ta);
3532        rm2 = fmpyadd_s_reg(rm2);
3533        rm1 = fmpyadd_s_reg(rm1);
3534        do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
3535        do_fop_weww(ctx, ta, ta, ra,
3536                    is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
3537    } else {
3538        do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
3539        do_fop_dedd(ctx, ta, ta, ra,
3540                    is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
3541    }
3542
3543    return nullify_end(ctx, NO_EXIT);
3544}
3545
3546static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
3547                                   const DisasInsn *di)
3548{
3549    unsigned rt = assemble_rt64(insn);
3550    unsigned neg = extract32(insn, 5, 1);
3551    unsigned rm1 = assemble_ra64(insn);
3552    unsigned rm2 = assemble_rb64(insn);
3553    unsigned ra3 = assemble_rc64(insn);
3554    TCGv_i32 a, b, c;
3555
3556    nullify_over(ctx);
3557    a = load_frw0_i32(rm1);
3558    b = load_frw0_i32(rm2);
3559    c = load_frw0_i32(ra3);
3560
3561    if (neg) {
3562        gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
3563    } else {
3564        gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
3565    }
3566
3567    tcg_temp_free_i32(b);
3568    tcg_temp_free_i32(c);
3569    save_frw_i32(rt, a);
3570    tcg_temp_free_i32(a);
3571    return nullify_end(ctx, NO_EXIT);
3572}
3573
3574static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
3575                                   const DisasInsn *di)
3576{
3577    unsigned rt = extract32(insn, 0, 5);
3578    unsigned neg = extract32(insn, 5, 1);
3579    unsigned rm1 = extract32(insn, 21, 5);
3580    unsigned rm2 = extract32(insn, 16, 5);
3581    unsigned ra3 = assemble_rc64(insn);
3582    TCGv_i64 a, b, c;
3583
3584    nullify_over(ctx);
3585    a = load_frd0(rm1);
3586    b = load_frd0(rm2);
3587    c = load_frd0(ra3);
3588
3589    if (neg) {
3590        gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
3591    } else {
3592        gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
3593    }
3594
3595    tcg_temp_free_i64(b);
3596    tcg_temp_free_i64(c);
3597    save_frd(rt, a);
3598    tcg_temp_free_i64(a);
3599    return nullify_end(ctx, NO_EXIT);
3600}
3601
3602static const DisasInsn table_fp_fused[] = {
3603    { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
3604    { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
3605};
3606
3607static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
3608                                      const DisasInsn table[], size_t n)
3609{
3610    size_t i;
3611    for (i = 0; i < n; ++i) {
3612        if ((insn & table[i].mask) == table[i].insn) {
3613            return table[i].trans(ctx, insn, &table[i]);
3614        }
3615    }
3616    return gen_illegal(ctx);
3617}
3618
3619#define translate_table(ctx, insn, table) \
3620    translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
3621
3622static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
3623{
3624    uint32_t opc = extract32(insn, 26, 6);
3625
3626    switch (opc) {
3627    case 0x00: /* system op */
3628        return translate_table(ctx, insn, table_system);
3629    case 0x01:
3630        return translate_table(ctx, insn, table_mem_mgmt);
3631    case 0x02:
3632        return translate_table(ctx, insn, table_arith_log);
3633    case 0x03:
3634        return translate_table(ctx, insn, table_index_mem);
3635    case 0x06:
3636        return trans_fmpyadd(ctx, insn, false);
3637    case 0x08:
3638        return trans_ldil(ctx, insn);
3639    case 0x09:
3640        return trans_copr_w(ctx, insn);
3641    case 0x0A:
3642        return trans_addil(ctx, insn);
3643    case 0x0B:
3644        return trans_copr_dw(ctx, insn);
3645    case 0x0C:
3646        return translate_table(ctx, insn, table_float_0c);
3647    case 0x0D:
3648        return trans_ldo(ctx, insn);
3649    case 0x0E:
3650        return translate_table(ctx, insn, table_float_0e);
3651
3652    case 0x10:
3653        return trans_load(ctx, insn, false, MO_UB);
3654    case 0x11:
3655        return trans_load(ctx, insn, false, MO_TEUW);
3656    case 0x12:
3657        return trans_load(ctx, insn, false, MO_TEUL);
3658    case 0x13:
3659        return trans_load(ctx, insn, true, MO_TEUL);
3660    case 0x16:
3661        return trans_fload_mod(ctx, insn);
3662    case 0x17:
3663        return trans_load_w(ctx, insn);
3664    case 0x18:
3665        return trans_store(ctx, insn, false, MO_UB);
3666    case 0x19:
3667        return trans_store(ctx, insn, false, MO_TEUW);
3668    case 0x1A:
3669        return trans_store(ctx, insn, false, MO_TEUL);
3670    case 0x1B:
3671        return trans_store(ctx, insn, true, MO_TEUL);
3672    case 0x1E:
3673        return trans_fstore_mod(ctx, insn);
3674    case 0x1F:
3675        return trans_store_w(ctx, insn);
3676
3677    case 0x20:
3678        return trans_cmpb(ctx, insn, true, false, false);
3679    case 0x21:
3680        return trans_cmpb(ctx, insn, true, true, false);
3681    case 0x22:
3682        return trans_cmpb(ctx, insn, false, false, false);
3683    case 0x23:
3684        return trans_cmpb(ctx, insn, false, true, false);
3685    case 0x24:
3686        return trans_cmpiclr(ctx, insn);
3687    case 0x25:
3688        return trans_subi(ctx, insn);
3689    case 0x26:
3690        return trans_fmpyadd(ctx, insn, true);
3691    case 0x27:
3692        return trans_cmpb(ctx, insn, true, false, true);
3693    case 0x28:
3694        return trans_addb(ctx, insn, true, false);
3695    case 0x29:
3696        return trans_addb(ctx, insn, true, true);
3697    case 0x2A:
3698        return trans_addb(ctx, insn, false, false);
3699    case 0x2B:
3700        return trans_addb(ctx, insn, false, true);
3701    case 0x2C:
3702    case 0x2D:
3703        return trans_addi(ctx, insn);
3704    case 0x2E:
3705        return translate_table(ctx, insn, table_fp_fused);
3706    case 0x2F:
3707        return trans_cmpb(ctx, insn, false, false, true);
3708
3709    case 0x30:
3710    case 0x31:
3711        return trans_bb(ctx, insn);
3712    case 0x32:
3713        return trans_movb(ctx, insn, false);
3714    case 0x33:
3715        return trans_movb(ctx, insn, true);
3716    case 0x34:
3717        return translate_table(ctx, insn, table_sh_ex);
3718    case 0x35:
3719        return translate_table(ctx, insn, table_depw);
3720    case 0x38:
3721        return trans_be(ctx, insn, false);
3722    case 0x39:
3723        return trans_be(ctx, insn, true);
3724    case 0x3A:
3725        return translate_table(ctx, insn, table_branch);
3726
3727    case 0x04: /* spopn */
3728    case 0x05: /* diag */
3729    case 0x0F: /* product specific */
3730        break;
3731
3732    case 0x07: /* unassigned */
3733    case 0x15: /* unassigned */
3734    case 0x1D: /* unassigned */
3735    case 0x37: /* unassigned */
3736    case 0x3F: /* unassigned */
3737    default:
3738        break;
3739    }
3740    return gen_illegal(ctx);
3741}
3742
3743void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
3744{
3745    CPUHPPAState *env = cs->env_ptr;
3746    DisasContext ctx;
3747    ExitStatus ret;
3748    int num_insns, max_insns, i;
3749
3750    ctx.tb = tb;
3751    ctx.cs = cs;
3752    ctx.iaoq_f = tb->pc;
3753    ctx.iaoq_b = tb->cs_base;
3754    ctx.singlestep_enabled = cs->singlestep_enabled;
3755
3756    ctx.ntemps = 0;
3757    for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
3758        TCGV_UNUSED(ctx.temps[i]);
3759    }
3760
3761    /* Compute the maximum number of insns to execute, as bounded by
3762       (1) icount, (2) single-stepping, (3) branch delay slots, or
3763       (4) the number of insns remaining on the current page.  */
3764    max_insns = tb->cflags & CF_COUNT_MASK;
3765    if (max_insns == 0) {
3766        max_insns = CF_COUNT_MASK;
3767    }
3768    if (ctx.singlestep_enabled || singlestep) {
3769        max_insns = 1;
3770    } else if (max_insns > TCG_MAX_INSNS) {
3771        max_insns = TCG_MAX_INSNS;
3772    }
3773
3774    num_insns = 0;
3775    gen_tb_start(tb);
3776
3777    /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
3778    ctx.null_cond = cond_make_f();
3779    ctx.psw_n_nonzero = false;
3780    if (tb->flags & 1) {
3781        ctx.null_cond.c = TCG_COND_ALWAYS;
3782        ctx.psw_n_nonzero = true;
3783    }
3784    ctx.null_lab = NULL;
3785
3786    do {
3787        tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
3788        num_insns++;
3789
3790        if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
3791            ret = gen_excp(&ctx, EXCP_DEBUG);
3792            break;
3793        }
3794        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
3795            gen_io_start();
3796        }
3797
3798        if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
3799            ret = do_page_zero(&ctx);
3800            assert(ret != NO_EXIT);
3801        } else {
3802            /* Always fetch the insn, even if nullified, so that we check
3803               the page permissions for execute.  */
3804            uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
3805
3806            /* Set up the IA queue for the next insn.
3807               This will be overwritten by a branch.  */
3808            if (ctx.iaoq_b == -1) {
3809                ctx.iaoq_n = -1;
3810                ctx.iaoq_n_var = get_temp(&ctx);
3811                tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
3812            } else {
3813                ctx.iaoq_n = ctx.iaoq_b + 4;
3814                TCGV_UNUSED(ctx.iaoq_n_var);
3815            }
3816
3817            if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
3818                ctx.null_cond.c = TCG_COND_NEVER;
3819                ret = NO_EXIT;
3820            } else {
3821                ret = translate_one(&ctx, insn);
3822                assert(ctx.null_lab == NULL);
3823            }
3824        }
3825
3826        for (i = 0; i < ctx.ntemps; ++i) {
3827            tcg_temp_free(ctx.temps[i]);
3828            TCGV_UNUSED(ctx.temps[i]);
3829        }
3830        ctx.ntemps = 0;
3831
3832        /* If we see non-linear instructions, exhaust instruction count,
3833           or run out of buffer space, stop generation.  */
3834        /* ??? The non-linear instruction restriction is purely due to
3835           the debugging dump.  Otherwise we *could* follow unconditional
3836           branches within the same page.  */
3837        if (ret == NO_EXIT
3838            && (ctx.iaoq_b != ctx.iaoq_f + 4
3839                || num_insns >= max_insns
3840                || tcg_op_buf_full())) {
3841            if (ctx.null_cond.c == TCG_COND_NEVER
3842                || ctx.null_cond.c == TCG_COND_ALWAYS) {
3843                nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
3844                gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
3845                ret = EXIT_GOTO_TB;
3846            } else {
3847                ret = EXIT_IAQ_N_STALE;
3848            }
3849        }
3850
3851        ctx.iaoq_f = ctx.iaoq_b;
3852        ctx.iaoq_b = ctx.iaoq_n;
3853        if (ret == EXIT_NORETURN
3854            || ret == EXIT_GOTO_TB
3855            || ret == EXIT_IAQ_N_UPDATED) {
3856            break;
3857        }
3858        if (ctx.iaoq_f == -1) {
3859            tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
3860            copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
3861            nullify_save(&ctx);
3862            ret = EXIT_IAQ_N_UPDATED;
3863            break;
3864        }
3865        if (ctx.iaoq_b == -1) {
3866            tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
3867        }
3868    } while (ret == NO_EXIT);
3869
3870    if (tb->cflags & CF_LAST_IO) {
3871        gen_io_end();
3872    }
3873
3874    switch (ret) {
3875    case EXIT_GOTO_TB:
3876    case EXIT_NORETURN:
3877        break;
3878    case EXIT_IAQ_N_STALE:
3879        copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
3880        copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
3881        nullify_save(&ctx);
3882        /* FALLTHRU */
3883    case EXIT_IAQ_N_UPDATED:
3884        if (ctx.singlestep_enabled) {
3885            gen_excp_1(EXCP_DEBUG);
3886        } else {
3887            tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
3888        }
3889        break;
3890    default:
3891        abort();
3892    }
3893
3894    gen_tb_end(tb, num_insns);
3895
3896    tb->size = num_insns * 4;
3897    tb->icount = num_insns;
3898
3899#ifdef DEBUG_DISAS
3900    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
3901        && qemu_log_in_addr_range(tb->pc)) {
3902        qemu_log_lock();
3903        switch (tb->pc) {
3904        case 0x00:
3905            qemu_log("IN:\n0x00000000:  (null)\n\n");
3906            break;
3907        case 0xb0:
3908            qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
3909            break;
3910        case 0xe0:
3911            qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
3912            break;
3913        case 0x100:
3914            qemu_log("IN:\n0x00000100:  syscall\n\n");
3915            break;
3916        default:
3917            qemu_log("IN: %s\n", lookup_symbol(tb->pc));
3918            log_target_disas(cs, tb->pc, tb->size, 1);
3919            qemu_log("\n");
3920            break;
3921        }
3922        qemu_log_unlock();
3923    }
3924#endif
3925}
3926
3927void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
3928                          target_ulong *data)
3929{
3930    env->iaoq_f = data[0];
3931    if (data[1] != -1) {
3932        env->iaoq_b = data[1];
3933    }
3934    /* Since we were executing the instruction at IAOQ_F, and took some
3935       sort of action that provoked the cpu_restore_state, we can infer
3936       that the instruction was not nullified.  */
3937    env->psw_n = 0;
3938}
3939