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