qemu/target/nios2/translate.c
<<
>>
Prefs
   1/*
   2 * Altera Nios II emulation for qemu: main translation routines.
   3 *
   4 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
   5 * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
   6 * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
   7 *  (Portions of this file that were originally from nios2sim-ng.)
   8 *
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2.1 of the License, or (at your option) any later version.
  13 *
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, see
  21 * <http://www.gnu.org/licenses/lgpl-2.1.html>
  22 */
  23
  24#include "qemu/osdep.h"
  25#include "cpu.h"
  26#include "tcg/tcg-op.h"
  27#include "exec/exec-all.h"
  28#include "disas/disas.h"
  29#include "exec/helper-proto.h"
  30#include "exec/helper-gen.h"
  31#include "exec/log.h"
  32#include "exec/cpu_ldst.h"
  33#include "exec/translator.h"
  34#include "qemu/qemu-print.h"
  35#include "exec/gen-icount.h"
  36#include "semihosting/semihost.h"
  37
  38/* is_jmp field values */
  39#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
  40
  41#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
  42#define INSTRUCTION(func)                  \
  43        INSTRUCTION_FLG(func, 0)
  44#define INSTRUCTION_NOP()                  \
  45        INSTRUCTION_FLG(nop, 0)
  46#define INSTRUCTION_UNIMPLEMENTED()        \
  47        INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
  48#define INSTRUCTION_ILLEGAL()              \
  49        INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
  50
  51/* Special R-Type instruction opcode */
  52#define INSN_R_TYPE 0x3A
  53
  54/* I-Type instruction parsing */
  55typedef struct {
  56    uint8_t op;
  57    union {
  58        uint16_t u;
  59        int16_t s;
  60    } imm16;
  61    uint8_t b;
  62    uint8_t a;
  63} InstrIType;
  64
  65#define I_TYPE(instr, code)                \
  66    InstrIType (instr) = {                 \
  67        .op    = extract32((code), 0, 6),  \
  68        .imm16.u = extract32((code), 6, 16), \
  69        .b     = extract32((code), 22, 5), \
  70        .a     = extract32((code), 27, 5), \
  71    }
  72
  73typedef target_ulong ImmFromIType(const InstrIType *);
  74
  75static target_ulong imm_unsigned(const InstrIType *i)
  76{
  77    return i->imm16.u;
  78}
  79
  80static target_ulong imm_signed(const InstrIType *i)
  81{
  82    return i->imm16.s;
  83}
  84
  85static target_ulong imm_shifted(const InstrIType *i)
  86{
  87    return i->imm16.u << 16;
  88}
  89
  90/* R-Type instruction parsing */
  91typedef struct {
  92    uint8_t op;
  93    uint8_t imm5;
  94    uint8_t opx;
  95    uint8_t c;
  96    uint8_t b;
  97    uint8_t a;
  98} InstrRType;
  99
 100#define R_TYPE(instr, code)                \
 101    InstrRType (instr) = {                 \
 102        .op    = extract32((code), 0, 6),  \
 103        .imm5  = extract32((code), 6, 5),  \
 104        .opx   = extract32((code), 11, 6), \
 105        .c     = extract32((code), 17, 5), \
 106        .b     = extract32((code), 22, 5), \
 107        .a     = extract32((code), 27, 5), \
 108    }
 109
 110/* J-Type instruction parsing */
 111typedef struct {
 112    uint8_t op;
 113    uint32_t imm26;
 114} InstrJType;
 115
 116#define J_TYPE(instr, code)                \
 117    InstrJType (instr) = {                 \
 118        .op    = extract32((code), 0, 6),  \
 119        .imm26 = extract32((code), 6, 26), \
 120    }
 121
 122typedef void GenFn2i(TCGv, TCGv, target_long);
 123typedef void GenFn3(TCGv, TCGv, TCGv);
 124typedef void GenFn4(TCGv, TCGv, TCGv, TCGv);
 125
 126typedef struct DisasContext {
 127    DisasContextBase  base;
 128    target_ulong      pc;
 129    int               mem_idx;
 130    uint32_t          tb_flags;
 131    TCGv              sink;
 132    const ControlRegState *cr_state;
 133    bool              eic_present;
 134} DisasContext;
 135
 136static TCGv cpu_R[NUM_GP_REGS];
 137static TCGv cpu_pc;
 138#ifndef CONFIG_USER_ONLY
 139static TCGv cpu_crs_R[NUM_GP_REGS];
 140#endif
 141
 142typedef struct Nios2Instruction {
 143    void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
 144    uint32_t  flags;
 145} Nios2Instruction;
 146
 147static uint8_t get_opcode(uint32_t code)
 148{
 149    I_TYPE(instr, code);
 150    return instr.op;
 151}
 152
 153static uint8_t get_opxcode(uint32_t code)
 154{
 155    R_TYPE(instr, code);
 156    return instr.opx;
 157}
 158
 159static TCGv load_gpr(DisasContext *dc, unsigned reg)
 160{
 161    assert(reg < NUM_GP_REGS);
 162
 163    /*
 164     * With shadow register sets, register r0 does not necessarily contain 0,
 165     * but it is overwhelmingly likely that it does -- software is supposed
 166     * to have set r0 to 0 in every shadow register set before use.
 167     */
 168    if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
 169        return tcg_constant_tl(0);
 170    }
 171    if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
 172        return cpu_R[reg];
 173    }
 174#ifdef CONFIG_USER_ONLY
 175    g_assert_not_reached();
 176#else
 177    return cpu_crs_R[reg];
 178#endif
 179}
 180
 181static TCGv dest_gpr(DisasContext *dc, unsigned reg)
 182{
 183    assert(reg < NUM_GP_REGS);
 184
 185    /*
 186     * The spec for shadow register sets isn't clear, but we assume that
 187     * writes to r0 are discarded regardless of CRS.
 188     */
 189    if (unlikely(reg == R_ZERO)) {
 190        if (dc->sink == NULL) {
 191            dc->sink = tcg_temp_new();
 192        }
 193        return dc->sink;
 194    }
 195    if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
 196        return cpu_R[reg];
 197    }
 198#ifdef CONFIG_USER_ONLY
 199    g_assert_not_reached();
 200#else
 201    return cpu_crs_R[reg];
 202#endif
 203}
 204
 205static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
 206{
 207    /* Note that PC is advanced for all hardware exceptions. */
 208    tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
 209    gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
 210    dc->base.is_jmp = DISAS_NORETURN;
 211}
 212
 213static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
 214{
 215    const TranslationBlock *tb = dc->base.tb;
 216
 217    if (translator_use_goto_tb(&dc->base, dest)) {
 218        tcg_gen_goto_tb(n);
 219        tcg_gen_movi_tl(cpu_pc, dest);
 220        tcg_gen_exit_tb(tb, n);
 221    } else {
 222        tcg_gen_movi_tl(cpu_pc, dest);
 223        tcg_gen_lookup_and_goto_ptr();
 224    }
 225    dc->base.is_jmp = DISAS_NORETURN;
 226}
 227
 228static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
 229{
 230    TCGLabel *l = gen_new_label();
 231    TCGv test = tcg_temp_new();
 232    TCGv dest = load_gpr(dc, regno);
 233
 234    tcg_gen_andi_tl(test, dest, 3);
 235    tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
 236    tcg_temp_free(test);
 237
 238    tcg_gen_mov_tl(cpu_pc, dest);
 239    if (is_call) {
 240        tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
 241    }
 242    tcg_gen_lookup_and_goto_ptr();
 243
 244    gen_set_label(l);
 245    tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
 246    t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
 247
 248    dc->base.is_jmp = DISAS_NORETURN;
 249}
 250
 251static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
 252{
 253    t_gen_helper_raise_exception(dc, flags);
 254}
 255
 256static bool gen_check_supervisor(DisasContext *dc)
 257{
 258    if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) {
 259        /* CPU in user mode, privileged instruction called, stop. */
 260        t_gen_helper_raise_exception(dc, EXCP_SUPERI);
 261        return false;
 262    }
 263    return true;
 264}
 265
 266/*
 267 * Used as a placeholder for all instructions which do not have
 268 * an effect on the simulator (e.g. flush, sync)
 269 */
 270static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
 271{
 272    /* Nothing to do here */
 273}
 274
 275/*
 276 * J-Type instructions
 277 */
 278static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
 279{
 280    J_TYPE(instr, code);
 281    gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
 282}
 283
 284static void call(DisasContext *dc, uint32_t code, uint32_t flags)
 285{
 286    tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
 287    jmpi(dc, code, flags);
 288}
 289
 290/*
 291 * I-Type instructions
 292 */
 293/* Load instructions */
 294static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
 295{
 296    I_TYPE(instr, code);
 297
 298    TCGv addr = tcg_temp_new();
 299    TCGv data = dest_gpr(dc, instr.b);
 300
 301    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 302    tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
 303    tcg_temp_free(addr);
 304}
 305
 306/* Store instructions */
 307static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
 308{
 309    I_TYPE(instr, code);
 310    TCGv val = load_gpr(dc, instr.b);
 311
 312    TCGv addr = tcg_temp_new();
 313    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 314    tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
 315    tcg_temp_free(addr);
 316}
 317
 318/* Branch instructions */
 319static void br(DisasContext *dc, uint32_t code, uint32_t flags)
 320{
 321    I_TYPE(instr, code);
 322
 323    gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
 324}
 325
 326static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
 327{
 328    I_TYPE(instr, code);
 329
 330    TCGLabel *l1 = gen_new_label();
 331    tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
 332    gen_goto_tb(dc, 0, dc->base.pc_next);
 333    gen_set_label(l1);
 334    gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
 335}
 336
 337/* Comparison instructions */
 338static void do_i_cmpxx(DisasContext *dc, uint32_t insn,
 339                       TCGCond cond, ImmFromIType *imm)
 340{
 341    I_TYPE(instr, insn);
 342    tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b),
 343                        load_gpr(dc, instr.a), imm(&instr));
 344}
 345
 346#define gen_i_cmpxx(fname, imm)                                             \
 347    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 348    { do_i_cmpxx(dc, code, flags, imm); }
 349
 350gen_i_cmpxx(gen_cmpxxsi, imm_signed)
 351gen_i_cmpxx(gen_cmpxxui, imm_unsigned)
 352
 353/* Math/logic instructions */
 354static void do_i_math_logic(DisasContext *dc, uint32_t insn,
 355                            GenFn2i *fn, ImmFromIType *imm,
 356                            bool x_op_0_eq_x)
 357{
 358    I_TYPE(instr, insn);
 359    target_ulong val;
 360
 361    if (unlikely(instr.b == R_ZERO)) {
 362        /* Store to R_ZERO is ignored -- this catches the canonical NOP. */
 363        return;
 364    }
 365
 366    val = imm(&instr);
 367
 368    if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) {
 369        /* This catches the canonical expansions of movi and movhi. */
 370        tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0);
 371    } else {
 372        fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val);
 373    }
 374}
 375
 376#define gen_i_math_logic(fname, insn, x_op_0, imm)                          \
 377    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 378    { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); }
 379
 380gen_i_math_logic(addi,  addi, 1, imm_signed)
 381gen_i_math_logic(muli,  muli, 0, imm_signed)
 382
 383gen_i_math_logic(andi,  andi, 0, imm_unsigned)
 384gen_i_math_logic(ori,   ori,  1, imm_unsigned)
 385gen_i_math_logic(xori,  xori, 1, imm_unsigned)
 386
 387gen_i_math_logic(andhi, andi, 0, imm_shifted)
 388gen_i_math_logic(orhi , ori,  1, imm_shifted)
 389gen_i_math_logic(xorhi, xori, 1, imm_shifted)
 390
 391/* rB <- prs.rA + sigma(IMM16) */
 392static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
 393{
 394    if (!dc->eic_present) {
 395        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 396        return;
 397    }
 398    if (!gen_check_supervisor(dc)) {
 399        return;
 400    }
 401
 402#ifdef CONFIG_USER_ONLY
 403    g_assert_not_reached();
 404#else
 405    I_TYPE(instr, code);
 406    TCGv dest = dest_gpr(dc, instr.b);
 407    gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
 408    tcg_gen_addi_tl(dest, dest, instr.imm16.s);
 409#endif
 410}
 411
 412/* Prototype only, defined below */
 413static void handle_r_type_instr(DisasContext *dc, uint32_t code,
 414                                uint32_t flags);
 415
 416static const Nios2Instruction i_type_instructions[] = {
 417    INSTRUCTION(call),                                /* call */
 418    INSTRUCTION(jmpi),                                /* jmpi */
 419    INSTRUCTION_ILLEGAL(),
 420    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
 421    INSTRUCTION(addi),                                /* addi */
 422    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
 423    INSTRUCTION(br),                                  /* br */
 424    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
 425    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
 426    INSTRUCTION_ILLEGAL(),
 427    INSTRUCTION_ILLEGAL(),
 428    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
 429    INSTRUCTION(andi),                                /* andi */
 430    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
 431    INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
 432    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
 433    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
 434    INSTRUCTION_ILLEGAL(),
 435    INSTRUCTION_ILLEGAL(),
 436    INSTRUCTION_NOP(),                                /* initda */
 437    INSTRUCTION(ori),                                 /* ori */
 438    INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
 439    INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
 440    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
 441    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
 442    INSTRUCTION_ILLEGAL(),
 443    INSTRUCTION_ILLEGAL(),
 444    INSTRUCTION_NOP(),                                /* flushda */
 445    INSTRUCTION(xori),                                /* xori */
 446    INSTRUCTION_ILLEGAL(),
 447    INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
 448    INSTRUCTION_ILLEGAL(),
 449    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
 450    INSTRUCTION_ILLEGAL(),
 451    INSTRUCTION_ILLEGAL(),
 452    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
 453    INSTRUCTION(muli),                                /* muli */
 454    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
 455    INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
 456    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
 457    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
 458    INSTRUCTION_ILLEGAL(),
 459    INSTRUCTION_ILLEGAL(),
 460    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
 461    INSTRUCTION(andhi),                               /* andhi */
 462    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
 463    INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
 464    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
 465    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
 466    INSTRUCTION_ILLEGAL(),
 467    INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
 468    INSTRUCTION_NOP(),                                /* initd */
 469    INSTRUCTION(orhi),                                /* orhi */
 470    INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
 471    INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
 472    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
 473    INSTRUCTION(rdprs),                               /* rdprs */
 474    INSTRUCTION_ILLEGAL(),
 475    INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
 476    INSTRUCTION_NOP(),                                /* flushd */
 477    INSTRUCTION(xorhi),                               /* xorhi */
 478    INSTRUCTION_ILLEGAL(),
 479    INSTRUCTION_ILLEGAL(),
 480    INSTRUCTION_ILLEGAL(),
 481};
 482
 483/*
 484 * R-Type instructions
 485 */
 486/*
 487 * status <- estatus
 488 * PC <- ea
 489 */
 490static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 491{
 492    if (!gen_check_supervisor(dc)) {
 493        return;
 494    }
 495
 496#ifdef CONFIG_USER_ONLY
 497    g_assert_not_reached();
 498#else
 499    if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) {
 500        TCGv tmp = tcg_temp_new();
 501        tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS]));
 502        gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA));
 503        tcg_temp_free(tmp);
 504    } else {
 505        gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA));
 506    }
 507    dc->base.is_jmp = DISAS_NORETURN;
 508#endif
 509}
 510
 511/* PC <- ra */
 512static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 513{
 514    gen_jumpr(dc, R_RA, false);
 515}
 516
 517/*
 518 * status <- bstatus
 519 * PC <- ba
 520 */
 521static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
 522{
 523    if (!gen_check_supervisor(dc)) {
 524        return;
 525    }
 526
 527#ifdef CONFIG_USER_ONLY
 528    g_assert_not_reached();
 529#else
 530    TCGv tmp = tcg_temp_new();
 531    tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS]));
 532    gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA));
 533    tcg_temp_free(tmp);
 534
 535    dc->base.is_jmp = DISAS_NORETURN;
 536#endif
 537}
 538
 539/* PC <- rA */
 540static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
 541{
 542    R_TYPE(instr, code);
 543
 544    gen_jumpr(dc, instr.a, false);
 545}
 546
 547/* rC <- PC + 4 */
 548static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
 549{
 550    R_TYPE(instr, code);
 551
 552    tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
 553}
 554
 555/*
 556 * ra <- PC + 4
 557 * PC <- rA
 558 */
 559static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 560{
 561    R_TYPE(instr, code);
 562
 563    gen_jumpr(dc, instr.a, true);
 564}
 565
 566/* rC <- ctlN */
 567static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 568{
 569    if (!gen_check_supervisor(dc)) {
 570        return;
 571    }
 572
 573#ifdef CONFIG_USER_ONLY
 574    g_assert_not_reached();
 575#else
 576    R_TYPE(instr, code);
 577    TCGv t1, t2, dest = dest_gpr(dc, instr.c);
 578
 579    /* Reserved registers read as zero. */
 580    if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
 581        tcg_gen_movi_tl(dest, 0);
 582        return;
 583    }
 584
 585    switch (instr.imm5) {
 586    case CR_IPENDING:
 587        /*
 588         * The value of the ipending register is synthetic.
 589         * In hw, this is the AND of a set of hardware irq lines
 590         * with the ienable register.  In qemu, we re-use the space
 591         * of CR_IPENDING to store the set of irq lines, and so we
 592         * must perform the AND here, and anywhere else we need the
 593         * guest value of ipending.
 594         */
 595        t1 = tcg_temp_new();
 596        t2 = tcg_temp_new();
 597        tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING]));
 598        tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE]));
 599        tcg_gen_and_tl(dest, t1, t2);
 600        tcg_temp_free(t1);
 601        tcg_temp_free(t2);
 602        break;
 603    default:
 604        tcg_gen_ld_tl(dest, cpu_env,
 605                      offsetof(CPUNios2State, ctrl[instr.imm5]));
 606        break;
 607    }
 608#endif
 609}
 610
 611/* ctlN <- rA */
 612static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 613{
 614    if (!gen_check_supervisor(dc)) {
 615        return;
 616    }
 617
 618#ifdef CONFIG_USER_ONLY
 619    g_assert_not_reached();
 620#else
 621    R_TYPE(instr, code);
 622    TCGv v = load_gpr(dc, instr.a);
 623    uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
 624    uint32_t wr = dc->cr_state[instr.imm5].writable;
 625    uint32_t ro = dc->cr_state[instr.imm5].readonly;
 626
 627    /* Skip reserved or readonly registers. */
 628    if (wr == 0) {
 629        return;
 630    }
 631
 632    switch (instr.imm5) {
 633    case CR_PTEADDR:
 634        gen_helper_mmu_write_pteaddr(cpu_env, v);
 635        break;
 636    case CR_TLBACC:
 637        gen_helper_mmu_write_tlbacc(cpu_env, v);
 638        break;
 639    case CR_TLBMISC:
 640        gen_helper_mmu_write_tlbmisc(cpu_env, v);
 641        break;
 642    case CR_STATUS:
 643    case CR_IENABLE:
 644        /* If interrupts were enabled using WRCTL, trigger them. */
 645        dc->base.is_jmp = DISAS_UPDATE;
 646        /* fall through */
 647    default:
 648        if (wr == -1) {
 649            /* The register is entirely writable. */
 650            tcg_gen_st_tl(v, cpu_env, ofs);
 651        } else {
 652            /*
 653             * The register is partially read-only or reserved:
 654             * merge the value.
 655             */
 656            TCGv n = tcg_temp_new();
 657
 658            tcg_gen_andi_tl(n, v, wr);
 659
 660            if (ro != 0) {
 661                TCGv o = tcg_temp_new();
 662                tcg_gen_ld_tl(o, cpu_env, ofs);
 663                tcg_gen_andi_tl(o, o, ro);
 664                tcg_gen_or_tl(n, n, o);
 665                tcg_temp_free(o);
 666            }
 667
 668            tcg_gen_st_tl(n, cpu_env, ofs);
 669            tcg_temp_free(n);
 670        }
 671        break;
 672    }
 673#endif
 674}
 675
 676/* prs.rC <- rA */
 677static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
 678{
 679    if (!dc->eic_present) {
 680        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 681        return;
 682    }
 683    if (!gen_check_supervisor(dc)) {
 684        return;
 685    }
 686
 687#ifdef CONFIG_USER_ONLY
 688    g_assert_not_reached();
 689#else
 690    R_TYPE(instr, code);
 691    gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
 692                     load_gpr(dc, instr.a));
 693    /*
 694     * The expected write to PRS[r0] is 0, from CRS[r0].
 695     * If not, and CRS == PRS (which we cannot tell from here),
 696     * we may now have a non-zero value in our current r0.
 697     * By ending the TB, we re-evaluate tb_flags and find out.
 698     */
 699    if (instr.c == 0
 700        && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) {
 701        dc->base.is_jmp = DISAS_UPDATE;
 702    }
 703#endif
 704}
 705
 706/* Comparison instructions */
 707static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 708{
 709    R_TYPE(instr, code);
 710    tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
 711                       load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 712}
 713
 714/* Math/logic instructions */
 715static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn)
 716{
 717    R_TYPE(instr, insn);
 718    fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5);
 719}
 720
 721static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn)
 722{
 723    R_TYPE(instr, insn);
 724    fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 725}
 726
 727#define gen_ri_math_logic(fname, insn)                                      \
 728    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 729    { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); }
 730
 731#define gen_rr_math_logic(fname, insn)                                      \
 732    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 733    { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); }
 734
 735gen_rr_math_logic(add,  add)
 736gen_rr_math_logic(sub,  sub)
 737gen_rr_math_logic(mul,  mul)
 738
 739gen_rr_math_logic(and,  and)
 740gen_rr_math_logic(or,   or)
 741gen_rr_math_logic(xor,  xor)
 742gen_rr_math_logic(nor,  nor)
 743
 744gen_ri_math_logic(srai, sari)
 745gen_ri_math_logic(srli, shri)
 746gen_ri_math_logic(slli, shli)
 747gen_ri_math_logic(roli, rotli)
 748
 749static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn)
 750{
 751    R_TYPE(instr, insn);
 752    TCGv discard = tcg_temp_new();
 753
 754    fn(discard, dest_gpr(dc, instr.c),
 755       load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 756    tcg_temp_free(discard);
 757}
 758
 759#define gen_rr_mul_high(fname, insn)                                        \
 760    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 761    { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); }
 762
 763gen_rr_mul_high(mulxss, muls2)
 764gen_rr_mul_high(mulxuu, mulu2)
 765gen_rr_mul_high(mulxsu, mulsu2)
 766
 767static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn)
 768{
 769    R_TYPE(instr, insn);
 770    TCGv sh = tcg_temp_new();
 771
 772    tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31);
 773    fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh);
 774    tcg_temp_free(sh);
 775}
 776
 777#define gen_rr_shift(fname, insn)                                           \
 778    static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
 779    { do_rr_shift(dc, code, tcg_gen_##insn##_tl); }
 780
 781gen_rr_shift(sra, sar)
 782gen_rr_shift(srl, shr)
 783gen_rr_shift(sll, shl)
 784gen_rr_shift(rol, rotl)
 785gen_rr_shift(ror, rotr)
 786
 787static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 788{
 789    R_TYPE(instr, (code));
 790    gen_helper_divs(dest_gpr(dc, instr.c), cpu_env,
 791                    load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 792}
 793
 794static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 795{
 796    R_TYPE(instr, (code));
 797    gen_helper_divu(dest_gpr(dc, instr.c), cpu_env,
 798                    load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 799}
 800
 801static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
 802{
 803#ifdef CONFIG_USER_ONLY
 804    /*
 805     * The imm5 field is not stored anywhere on real hw; the kernel
 806     * has to load the insn and extract the field.  But we can make
 807     * things easier for cpu_loop if we pop this into env->error_code.
 808     */
 809    R_TYPE(instr, code);
 810    tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
 811                   offsetof(CPUNios2State, error_code));
 812#endif
 813    t_gen_helper_raise_exception(dc, EXCP_TRAP);
 814}
 815
 816static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
 817{
 818#ifndef CONFIG_USER_ONLY
 819    /* The semihosting instruction is "break 1".  */
 820    R_TYPE(instr, code);
 821    if (semihosting_enabled() && instr.imm5 == 1) {
 822        t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
 823        return;
 824    }
 825#endif
 826
 827    t_gen_helper_raise_exception(dc, EXCP_BREAK);
 828}
 829
 830static const Nios2Instruction r_type_instructions[] = {
 831    INSTRUCTION_ILLEGAL(),
 832    INSTRUCTION(eret),                                /* eret */
 833    INSTRUCTION(roli),                                /* roli */
 834    INSTRUCTION(rol),                                 /* rol */
 835    INSTRUCTION_NOP(),                                /* flushp */
 836    INSTRUCTION(ret),                                 /* ret */
 837    INSTRUCTION(nor),                                 /* nor */
 838    INSTRUCTION(mulxuu),                              /* mulxuu */
 839    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
 840    INSTRUCTION(bret),                                /* bret */
 841    INSTRUCTION_ILLEGAL(),
 842    INSTRUCTION(ror),                                 /* ror */
 843    INSTRUCTION_NOP(),                                /* flushi */
 844    INSTRUCTION(jmp),                                 /* jmp */
 845    INSTRUCTION(and),                                 /* and */
 846    INSTRUCTION_ILLEGAL(),
 847    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
 848    INSTRUCTION_ILLEGAL(),
 849    INSTRUCTION(slli),                                /* slli */
 850    INSTRUCTION(sll),                                 /* sll */
 851    INSTRUCTION(wrprs),                               /* wrprs */
 852    INSTRUCTION_ILLEGAL(),
 853    INSTRUCTION(or),                                  /* or */
 854    INSTRUCTION(mulxsu),                              /* mulxsu */
 855    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
 856    INSTRUCTION_ILLEGAL(),
 857    INSTRUCTION(srli),                                /* srli */
 858    INSTRUCTION(srl),                                 /* srl */
 859    INSTRUCTION(nextpc),                              /* nextpc */
 860    INSTRUCTION(callr),                               /* callr */
 861    INSTRUCTION(xor),                                 /* xor */
 862    INSTRUCTION(mulxss),                              /* mulxss */
 863    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
 864    INSTRUCTION_ILLEGAL(),
 865    INSTRUCTION_ILLEGAL(),
 866    INSTRUCTION_ILLEGAL(),
 867    INSTRUCTION(divu),                                /* divu */
 868    INSTRUCTION(divs),                                /* div */
 869    INSTRUCTION(rdctl),                               /* rdctl */
 870    INSTRUCTION(mul),                                 /* mul */
 871    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
 872    INSTRUCTION_NOP(),                                /* initi */
 873    INSTRUCTION_ILLEGAL(),
 874    INSTRUCTION_ILLEGAL(),
 875    INSTRUCTION_ILLEGAL(),
 876    INSTRUCTION(trap),                                /* trap */
 877    INSTRUCTION(wrctl),                               /* wrctl */
 878    INSTRUCTION_ILLEGAL(),
 879    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
 880    INSTRUCTION(add),                                 /* add */
 881    INSTRUCTION_ILLEGAL(),
 882    INSTRUCTION_ILLEGAL(),
 883    INSTRUCTION(gen_break),                           /* break */
 884    INSTRUCTION_ILLEGAL(),
 885    INSTRUCTION(nop),                                 /* nop */
 886    INSTRUCTION_ILLEGAL(),
 887    INSTRUCTION_ILLEGAL(),
 888    INSTRUCTION(sub),                                 /* sub */
 889    INSTRUCTION(srai),                                /* srai */
 890    INSTRUCTION(sra),                                 /* sra */
 891    INSTRUCTION_ILLEGAL(),
 892    INSTRUCTION_ILLEGAL(),
 893    INSTRUCTION_ILLEGAL(),
 894    INSTRUCTION_ILLEGAL(),
 895};
 896
 897static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
 898{
 899    uint8_t opx;
 900    const Nios2Instruction *instr;
 901
 902    opx = get_opxcode(code);
 903    if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
 904        goto illegal_op;
 905    }
 906
 907    instr = &r_type_instructions[opx];
 908    instr->handler(dc, code, instr->flags);
 909
 910    return;
 911
 912illegal_op:
 913    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 914}
 915
 916static const char * const gr_regnames[NUM_GP_REGS] = {
 917    "zero",       "at",         "r2",         "r3",
 918    "r4",         "r5",         "r6",         "r7",
 919    "r8",         "r9",         "r10",        "r11",
 920    "r12",        "r13",        "r14",        "r15",
 921    "r16",        "r17",        "r18",        "r19",
 922    "r20",        "r21",        "r22",        "r23",
 923    "et",         "bt",         "gp",         "sp",
 924    "fp",         "ea",         "ba",         "ra",
 925};
 926
 927#ifndef CONFIG_USER_ONLY
 928static const char * const cr_regnames[NUM_CR_REGS] = {
 929    "status",     "estatus",    "bstatus",    "ienable",
 930    "ipending",   "cpuid",      "res6",       "exception",
 931    "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
 932    "badaddr",    "config",     "mpubase",    "mpuacc",
 933    "res16",      "res17",      "res18",      "res19",
 934    "res20",      "res21",      "res22",      "res23",
 935    "res24",      "res25",      "res26",      "res27",
 936    "res28",      "res29",      "res30",      "res31",
 937};
 938#endif
 939
 940#include "exec/gen-icount.h"
 941
 942/* generate intermediate code for basic block 'tb'.  */
 943static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 944{
 945    DisasContext *dc = container_of(dcbase, DisasContext, base);
 946    CPUNios2State *env = cs->env_ptr;
 947    Nios2CPU *cpu = env_archcpu(env);
 948    int page_insns;
 949
 950    dc->mem_idx = cpu_mmu_index(env, false);
 951    dc->cr_state = cpu->cr_state;
 952    dc->tb_flags = dc->base.tb->flags;
 953    dc->eic_present = cpu->eic_present;
 954
 955    /* Bound the number of insns to execute to those left on the page.  */
 956    page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
 957    dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
 958}
 959
 960static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
 961{
 962}
 963
 964static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
 965{
 966    tcg_gen_insn_start(dcbase->pc_next);
 967}
 968
 969static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 970{
 971    DisasContext *dc = container_of(dcbase, DisasContext, base);
 972    CPUNios2State *env = cs->env_ptr;
 973    const Nios2Instruction *instr;
 974    uint32_t code, pc;
 975    uint8_t op;
 976
 977    pc = dc->base.pc_next;
 978    dc->pc = pc;
 979    dc->base.pc_next = pc + 4;
 980
 981    /* Decode an instruction */
 982    code = cpu_ldl_code(env, pc);
 983    op = get_opcode(code);
 984
 985    if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
 986        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 987        return;
 988    }
 989
 990    dc->sink = NULL;
 991
 992    instr = &i_type_instructions[op];
 993    instr->handler(dc, code, instr->flags);
 994
 995    if (dc->sink) {
 996        tcg_temp_free(dc->sink);
 997    }
 998}
 999
1000static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
1001{
1002    DisasContext *dc = container_of(dcbase, DisasContext, base);
1003
1004    /* Indicate where the next block should start */
1005    switch (dc->base.is_jmp) {
1006    case DISAS_TOO_MANY:
1007        gen_goto_tb(dc, 0, dc->base.pc_next);
1008        break;
1009
1010    case DISAS_UPDATE:
1011        /* Save the current PC, and return to the main loop. */
1012        tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1013        tcg_gen_exit_tb(NULL, 0);
1014        break;
1015
1016    case DISAS_NORETURN:
1017        /* nothing more to generate */
1018        break;
1019
1020    default:
1021        g_assert_not_reached();
1022    }
1023}
1024
1025static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1026                               CPUState *cpu, FILE *logfile)
1027{
1028    fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1029    target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
1030}
1031
1032static const TranslatorOps nios2_tr_ops = {
1033    .init_disas_context = nios2_tr_init_disas_context,
1034    .tb_start           = nios2_tr_tb_start,
1035    .insn_start         = nios2_tr_insn_start,
1036    .translate_insn     = nios2_tr_translate_insn,
1037    .tb_stop            = nios2_tr_tb_stop,
1038    .disas_log          = nios2_tr_disas_log,
1039};
1040
1041void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
1042{
1043    DisasContext dc;
1044    translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns);
1045}
1046
1047void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1048{
1049    Nios2CPU *cpu = NIOS2_CPU(cs);
1050    CPUNios2State *env = &cpu->env;
1051    int i;
1052
1053    qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
1054
1055    for (i = 0; i < NUM_GP_REGS; i++) {
1056        qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
1057        if ((i + 1) % 4 == 0) {
1058            qemu_fprintf(f, "\n");
1059        }
1060    }
1061
1062#if !defined(CONFIG_USER_ONLY)
1063    int j;
1064
1065    for (i = j = 0; i < NUM_CR_REGS; i++) {
1066        if (!nios2_cr_reserved(&cpu->cr_state[i])) {
1067            qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
1068            if (++j % 4 == 0) {
1069                qemu_fprintf(f, "\n");
1070            }
1071        }
1072    }
1073    if (j % 4 != 0) {
1074        qemu_fprintf(f, "\n");
1075    }
1076    if (cpu->mmu_present) {
1077        qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1078                     env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
1079                     FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
1080                     env->mmu.tlbacc_wr);
1081    }
1082#endif
1083    qemu_fprintf(f, "\n\n");
1084}
1085
1086void nios2_tcg_init(void)
1087{
1088#ifndef CONFIG_USER_ONLY
1089    TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
1090                                          offsetof(CPUNios2State, regs), "crs");
1091
1092    for (int i = 0; i < NUM_GP_REGS; i++) {
1093        cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
1094    }
1095
1096#define offsetof_regs0(N)  offsetof(CPUNios2State, shadow_regs[0][N])
1097#else
1098#define offsetof_regs0(N)  offsetof(CPUNios2State, regs[N])
1099#endif
1100
1101    for (int i = 0; i < NUM_GP_REGS; i++) {
1102        cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
1103                                      gr_regnames[i]);
1104    }
1105
1106#undef offsetof_regs0
1107
1108    cpu_pc = tcg_global_mem_new(cpu_env,
1109                                offsetof(CPUNios2State, pc), "pc");
1110}
1111
1112void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
1113                          target_ulong *data)
1114{
1115    env->pc = data[0];
1116}
1117