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