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    bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U);
 821    R_TYPE(instr, code);
 822    if (semihosting_enabled(is_user) && instr.imm5 == 1) {
 823        t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
 824        return;
 825    }
 826#endif
 827
 828    t_gen_helper_raise_exception(dc, EXCP_BREAK);
 829}
 830
 831static const Nios2Instruction r_type_instructions[] = {
 832    INSTRUCTION_ILLEGAL(),
 833    INSTRUCTION(eret),                                /* eret */
 834    INSTRUCTION(roli),                                /* roli */
 835    INSTRUCTION(rol),                                 /* rol */
 836    INSTRUCTION_NOP(),                                /* flushp */
 837    INSTRUCTION(ret),                                 /* ret */
 838    INSTRUCTION(nor),                                 /* nor */
 839    INSTRUCTION(mulxuu),                              /* mulxuu */
 840    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
 841    INSTRUCTION(bret),                                /* bret */
 842    INSTRUCTION_ILLEGAL(),
 843    INSTRUCTION(ror),                                 /* ror */
 844    INSTRUCTION_NOP(),                                /* flushi */
 845    INSTRUCTION(jmp),                                 /* jmp */
 846    INSTRUCTION(and),                                 /* and */
 847    INSTRUCTION_ILLEGAL(),
 848    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
 849    INSTRUCTION_ILLEGAL(),
 850    INSTRUCTION(slli),                                /* slli */
 851    INSTRUCTION(sll),                                 /* sll */
 852    INSTRUCTION(wrprs),                               /* wrprs */
 853    INSTRUCTION_ILLEGAL(),
 854    INSTRUCTION(or),                                  /* or */
 855    INSTRUCTION(mulxsu),                              /* mulxsu */
 856    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
 857    INSTRUCTION_ILLEGAL(),
 858    INSTRUCTION(srli),                                /* srli */
 859    INSTRUCTION(srl),                                 /* srl */
 860    INSTRUCTION(nextpc),                              /* nextpc */
 861    INSTRUCTION(callr),                               /* callr */
 862    INSTRUCTION(xor),                                 /* xor */
 863    INSTRUCTION(mulxss),                              /* mulxss */
 864    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
 865    INSTRUCTION_ILLEGAL(),
 866    INSTRUCTION_ILLEGAL(),
 867    INSTRUCTION_ILLEGAL(),
 868    INSTRUCTION(divu),                                /* divu */
 869    INSTRUCTION(divs),                                /* div */
 870    INSTRUCTION(rdctl),                               /* rdctl */
 871    INSTRUCTION(mul),                                 /* mul */
 872    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
 873    INSTRUCTION_NOP(),                                /* initi */
 874    INSTRUCTION_ILLEGAL(),
 875    INSTRUCTION_ILLEGAL(),
 876    INSTRUCTION_ILLEGAL(),
 877    INSTRUCTION(trap),                                /* trap */
 878    INSTRUCTION(wrctl),                               /* wrctl */
 879    INSTRUCTION_ILLEGAL(),
 880    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
 881    INSTRUCTION(add),                                 /* add */
 882    INSTRUCTION_ILLEGAL(),
 883    INSTRUCTION_ILLEGAL(),
 884    INSTRUCTION(gen_break),                           /* break */
 885    INSTRUCTION_ILLEGAL(),
 886    INSTRUCTION(nop),                                 /* nop */
 887    INSTRUCTION_ILLEGAL(),
 888    INSTRUCTION_ILLEGAL(),
 889    INSTRUCTION(sub),                                 /* sub */
 890    INSTRUCTION(srai),                                /* srai */
 891    INSTRUCTION(sra),                                 /* sra */
 892    INSTRUCTION_ILLEGAL(),
 893    INSTRUCTION_ILLEGAL(),
 894    INSTRUCTION_ILLEGAL(),
 895    INSTRUCTION_ILLEGAL(),
 896};
 897
 898static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
 899{
 900    uint8_t opx;
 901    const Nios2Instruction *instr;
 902
 903    opx = get_opxcode(code);
 904    if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
 905        goto illegal_op;
 906    }
 907
 908    instr = &r_type_instructions[opx];
 909    instr->handler(dc, code, instr->flags);
 910
 911    return;
 912
 913illegal_op:
 914    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 915}
 916
 917static const char * const gr_regnames[NUM_GP_REGS] = {
 918    "zero",       "at",         "r2",         "r3",
 919    "r4",         "r5",         "r6",         "r7",
 920    "r8",         "r9",         "r10",        "r11",
 921    "r12",        "r13",        "r14",        "r15",
 922    "r16",        "r17",        "r18",        "r19",
 923    "r20",        "r21",        "r22",        "r23",
 924    "et",         "bt",         "gp",         "sp",
 925    "fp",         "ea",         "ba",         "ra",
 926};
 927
 928#ifndef CONFIG_USER_ONLY
 929static const char * const cr_regnames[NUM_CR_REGS] = {
 930    "status",     "estatus",    "bstatus",    "ienable",
 931    "ipending",   "cpuid",      "res6",       "exception",
 932    "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
 933    "badaddr",    "config",     "mpubase",    "mpuacc",
 934    "res16",      "res17",      "res18",      "res19",
 935    "res20",      "res21",      "res22",      "res23",
 936    "res24",      "res25",      "res26",      "res27",
 937    "res28",      "res29",      "res30",      "res31",
 938};
 939#endif
 940
 941#include "exec/gen-icount.h"
 942
 943/* generate intermediate code for basic block 'tb'.  */
 944static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 945{
 946    DisasContext *dc = container_of(dcbase, DisasContext, base);
 947    CPUNios2State *env = cs->env_ptr;
 948    Nios2CPU *cpu = env_archcpu(env);
 949    int page_insns;
 950
 951    dc->mem_idx = cpu_mmu_index(env, false);
 952    dc->cr_state = cpu->cr_state;
 953    dc->tb_flags = dc->base.tb->flags;
 954    dc->eic_present = cpu->eic_present;
 955
 956    /* Bound the number of insns to execute to those left on the page.  */
 957    page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
 958    dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
 959}
 960
 961static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
 962{
 963}
 964
 965static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
 966{
 967    tcg_gen_insn_start(dcbase->pc_next);
 968}
 969
 970static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 971{
 972    DisasContext *dc = container_of(dcbase, DisasContext, base);
 973    CPUNios2State *env = cs->env_ptr;
 974    const Nios2Instruction *instr;
 975    uint32_t code, pc;
 976    uint8_t op;
 977
 978    pc = dc->base.pc_next;
 979    dc->pc = pc;
 980    dc->base.pc_next = pc + 4;
 981
 982    /* Decode an instruction */
 983    code = cpu_ldl_code(env, pc);
 984    op = get_opcode(code);
 985
 986    if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
 987        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 988        return;
 989    }
 990
 991    dc->sink = NULL;
 992
 993    instr = &i_type_instructions[op];
 994    instr->handler(dc, code, instr->flags);
 995
 996    if (dc->sink) {
 997        tcg_temp_free(dc->sink);
 998    }
 999}
1000
1001static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
1002{
1003    DisasContext *dc = container_of(dcbase, DisasContext, base);
1004
1005    /* Indicate where the next block should start */
1006    switch (dc->base.is_jmp) {
1007    case DISAS_TOO_MANY:
1008        gen_goto_tb(dc, 0, dc->base.pc_next);
1009        break;
1010
1011    case DISAS_UPDATE:
1012        /* Save the current PC, and return to the main loop. */
1013        tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
1014        tcg_gen_exit_tb(NULL, 0);
1015        break;
1016
1017    case DISAS_NORETURN:
1018        /* nothing more to generate */
1019        break;
1020
1021    default:
1022        g_assert_not_reached();
1023    }
1024}
1025
1026static void nios2_tr_disas_log(const DisasContextBase *dcbase,
1027                               CPUState *cpu, FILE *logfile)
1028{
1029    fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
1030    target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size);
1031}
1032
1033static const TranslatorOps nios2_tr_ops = {
1034    .init_disas_context = nios2_tr_init_disas_context,
1035    .tb_start           = nios2_tr_tb_start,
1036    .insn_start         = nios2_tr_insn_start,
1037    .translate_insn     = nios2_tr_translate_insn,
1038    .tb_stop            = nios2_tr_tb_stop,
1039    .disas_log          = nios2_tr_disas_log,
1040};
1041
1042void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns,
1043                           target_ulong pc, void *host_pc)
1044{
1045    DisasContext dc;
1046    translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
1047}
1048
1049void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1050{
1051    Nios2CPU *cpu = NIOS2_CPU(cs);
1052    CPUNios2State *env = &cpu->env;
1053    int i;
1054
1055    qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
1056
1057    for (i = 0; i < NUM_GP_REGS; i++) {
1058        qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
1059        if ((i + 1) % 4 == 0) {
1060            qemu_fprintf(f, "\n");
1061        }
1062    }
1063
1064#if !defined(CONFIG_USER_ONLY)
1065    int j;
1066
1067    for (i = j = 0; i < NUM_CR_REGS; i++) {
1068        if (!nios2_cr_reserved(&cpu->cr_state[i])) {
1069            qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
1070            if (++j % 4 == 0) {
1071                qemu_fprintf(f, "\n");
1072            }
1073        }
1074    }
1075    if (j % 4 != 0) {
1076        qemu_fprintf(f, "\n");
1077    }
1078    if (cpu->mmu_present) {
1079        qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
1080                     env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
1081                     FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
1082                     env->mmu.tlbacc_wr);
1083    }
1084#endif
1085    qemu_fprintf(f, "\n\n");
1086}
1087
1088void nios2_tcg_init(void)
1089{
1090#ifndef CONFIG_USER_ONLY
1091    TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
1092                                          offsetof(CPUNios2State, regs), "crs");
1093
1094    for (int i = 0; i < NUM_GP_REGS; i++) {
1095        cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
1096    }
1097
1098#define offsetof_regs0(N)  offsetof(CPUNios2State, shadow_regs[0][N])
1099#else
1100#define offsetof_regs0(N)  offsetof(CPUNios2State, regs[N])
1101#endif
1102
1103    for (int i = 0; i < NUM_GP_REGS; i++) {
1104        cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i),
1105                                      gr_regnames[i]);
1106    }
1107
1108#undef offsetof_regs0
1109
1110    cpu_pc = tcg_global_mem_new(cpu_env,
1111                                offsetof(CPUNios2State, pc), "pc");
1112}
1113