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 "cpu.h"
  25#include "tcg-op.h"
  26#include "exec/exec-all.h"
  27#include "disas/disas.h"
  28#include "exec/helper-proto.h"
  29#include "exec/helper-gen.h"
  30#include "exec/log.h"
  31#include "exec/cpu_ldst.h"
  32
  33#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
  34#define INSTRUCTION(func)                  \
  35        INSTRUCTION_FLG(func, 0)
  36#define INSTRUCTION_NOP()                  \
  37        INSTRUCTION_FLG(nop, 0)
  38#define INSTRUCTION_UNIMPLEMENTED()        \
  39        INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
  40#define INSTRUCTION_ILLEGAL()              \
  41        INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
  42
  43/* Special R-Type instruction opcode */
  44#define INSN_R_TYPE 0x3A
  45
  46/* I-Type instruction parsing */
  47#define I_TYPE(instr, code)                \
  48    struct {                               \
  49        uint8_t op;                        \
  50        union {                            \
  51            uint16_t u;                    \
  52            int16_t s;                     \
  53        } imm16;                           \
  54        uint8_t b;                         \
  55        uint8_t a;                         \
  56    } (instr) = {                          \
  57        .op    = extract32((code), 0, 6),  \
  58        .imm16.u = extract32((code), 6, 16), \
  59        .b     = extract32((code), 22, 5), \
  60        .a     = extract32((code), 27, 5), \
  61    }
  62
  63/* R-Type instruction parsing */
  64#define R_TYPE(instr, code)                \
  65    struct {                               \
  66        uint8_t op;                        \
  67        uint8_t imm5;                      \
  68        uint8_t opx;                       \
  69        uint8_t c;                         \
  70        uint8_t b;                         \
  71        uint8_t a;                         \
  72    } (instr) = {                          \
  73        .op    = extract32((code), 0, 6),  \
  74        .imm5  = extract32((code), 6, 5),  \
  75        .opx   = extract32((code), 11, 6), \
  76        .c     = extract32((code), 17, 5), \
  77        .b     = extract32((code), 22, 5), \
  78        .a     = extract32((code), 27, 5), \
  79    }
  80
  81/* J-Type instruction parsing */
  82#define J_TYPE(instr, code)                \
  83    struct {                               \
  84        uint8_t op;                        \
  85        uint32_t imm26;                    \
  86    } (instr) = {                          \
  87        .op    = extract32((code), 0, 6),  \
  88        .imm26 = extract32((code), 6, 26), \
  89    }
  90
  91typedef struct DisasContext {
  92    TCGv_ptr          cpu_env;
  93    TCGv             *cpu_R;
  94    TCGv_i32          zero;
  95    int               is_jmp;
  96    target_ulong      pc;
  97    TranslationBlock *tb;
  98    int               mem_idx;
  99    bool              singlestep_enabled;
 100} DisasContext;
 101
 102typedef struct Nios2Instruction {
 103    void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
 104    uint32_t  flags;
 105} Nios2Instruction;
 106
 107static uint8_t get_opcode(uint32_t code)
 108{
 109    I_TYPE(instr, code);
 110    return instr.op;
 111}
 112
 113static uint8_t get_opxcode(uint32_t code)
 114{
 115    R_TYPE(instr, code);
 116    return instr.opx;
 117}
 118
 119static TCGv load_zero(DisasContext *dc)
 120{
 121    if (TCGV_IS_UNUSED_I32(dc->zero)) {
 122        dc->zero = tcg_const_i32(0);
 123    }
 124    return dc->zero;
 125}
 126
 127static TCGv load_gpr(DisasContext *dc, uint8_t reg)
 128{
 129    if (likely(reg != R_ZERO)) {
 130        return dc->cpu_R[reg];
 131    } else {
 132        return load_zero(dc);
 133    }
 134}
 135
 136static void t_gen_helper_raise_exception(DisasContext *dc,
 137                                         uint32_t index)
 138{
 139    TCGv_i32 tmp = tcg_const_i32(index);
 140
 141    tcg_gen_movi_tl(dc->cpu_R[R_PC], dc->pc);
 142    gen_helper_raise_exception(dc->cpu_env, tmp);
 143    tcg_temp_free_i32(tmp);
 144    dc->is_jmp = DISAS_UPDATE;
 145}
 146
 147static bool use_goto_tb(DisasContext *dc, uint32_t dest)
 148{
 149    if (unlikely(dc->singlestep_enabled)) {
 150        return false;
 151    }
 152
 153#ifndef CONFIG_USER_ONLY
 154    return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
 155#else
 156    return true;
 157#endif
 158}
 159
 160static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
 161{
 162    TranslationBlock *tb = dc->tb;
 163
 164    if (use_goto_tb(dc, dest)) {
 165        tcg_gen_goto_tb(n);
 166        tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
 167        tcg_gen_exit_tb((uintptr_t)tb + n);
 168    } else {
 169        tcg_gen_movi_tl(dc->cpu_R[R_PC], dest);
 170        tcg_gen_exit_tb(0);
 171    }
 172}
 173
 174static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
 175{
 176    t_gen_helper_raise_exception(dc, flags);
 177}
 178
 179static void gen_check_supervisor(DisasContext *dc)
 180{
 181    if (dc->tb->flags & CR_STATUS_U) {
 182        /* CPU in user mode, privileged instruction called, stop. */
 183        t_gen_helper_raise_exception(dc, EXCP_SUPERI);
 184    }
 185}
 186
 187/*
 188 * Used as a placeholder for all instructions which do not have
 189 * an effect on the simulator (e.g. flush, sync)
 190 */
 191static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
 192{
 193    /* Nothing to do here */
 194}
 195
 196/*
 197 * J-Type instructions
 198 */
 199static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
 200{
 201    J_TYPE(instr, code);
 202    gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
 203    dc->is_jmp = DISAS_TB_JUMP;
 204}
 205
 206static void call(DisasContext *dc, uint32_t code, uint32_t flags)
 207{
 208    tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
 209    jmpi(dc, code, flags);
 210}
 211
 212/*
 213 * I-Type instructions
 214 */
 215/* Load instructions */
 216static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
 217{
 218    I_TYPE(instr, code);
 219
 220    TCGv addr = tcg_temp_new();
 221    TCGv data;
 222
 223    /*
 224     * WARNING: Loads into R_ZERO are ignored, but we must generate the
 225     *          memory access itself to emulate the CPU precisely. Load
 226     *          from a protected page to R_ZERO will cause SIGSEGV on
 227     *          the Nios2 CPU.
 228     */
 229    if (likely(instr.b != R_ZERO)) {
 230        data = dc->cpu_R[instr.b];
 231    } else {
 232        data = tcg_temp_new();
 233    }
 234
 235    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 236    tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
 237
 238    if (unlikely(instr.b == R_ZERO)) {
 239        tcg_temp_free(data);
 240    }
 241
 242    tcg_temp_free(addr);
 243}
 244
 245/* Store instructions */
 246static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
 247{
 248    I_TYPE(instr, code);
 249    TCGv val = load_gpr(dc, instr.b);
 250
 251    TCGv addr = tcg_temp_new();
 252    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 253    tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
 254    tcg_temp_free(addr);
 255}
 256
 257/* Branch instructions */
 258static void br(DisasContext *dc, uint32_t code, uint32_t flags)
 259{
 260    I_TYPE(instr, code);
 261
 262    gen_goto_tb(dc, 0, dc->pc + 4 + (instr.imm16.s & -4));
 263    dc->is_jmp = DISAS_TB_JUMP;
 264}
 265
 266static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
 267{
 268    I_TYPE(instr, code);
 269
 270    TCGLabel *l1 = gen_new_label();
 271    tcg_gen_brcond_tl(flags, dc->cpu_R[instr.a], dc->cpu_R[instr.b], l1);
 272    gen_goto_tb(dc, 0, dc->pc + 4);
 273    gen_set_label(l1);
 274    gen_goto_tb(dc, 1, dc->pc + 4 + (instr.imm16.s & -4));
 275    dc->is_jmp = DISAS_TB_JUMP;
 276}
 277
 278/* Comparison instructions */
 279#define gen_i_cmpxx(fname, op3)                                              \
 280static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)         \
 281{                                                                            \
 282    I_TYPE(instr, (code));                                                   \
 283    tcg_gen_setcondi_tl(flags, (dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a],   \
 284                        (op3));                                              \
 285}
 286
 287gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
 288gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
 289
 290/* Math/logic instructions */
 291#define gen_i_math_logic(fname, insn, resimm, op3)                          \
 292static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)        \
 293{                                                                           \
 294    I_TYPE(instr, (code));                                                  \
 295    if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */     \
 296        return;                                                             \
 297    } else if (instr.a == R_ZERO) { /* MOVxI optimizations */               \
 298        tcg_gen_movi_tl(dc->cpu_R[instr.b], (resimm) ? (op3) : 0);          \
 299    } else {                                                                \
 300        tcg_gen_##insn##_tl((dc)->cpu_R[instr.b], (dc)->cpu_R[instr.a],     \
 301                            (op3));                                         \
 302    }                                                                       \
 303}
 304
 305gen_i_math_logic(addi,  addi, 1, instr.imm16.s)
 306gen_i_math_logic(muli,  muli, 0, instr.imm16.s)
 307
 308gen_i_math_logic(andi,  andi, 0, instr.imm16.u)
 309gen_i_math_logic(ori,   ori,  1, instr.imm16.u)
 310gen_i_math_logic(xori,  xori, 1, instr.imm16.u)
 311
 312gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
 313gen_i_math_logic(orhi , ori,  1, instr.imm16.u << 16)
 314gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
 315
 316/* Prototype only, defined below */
 317static void handle_r_type_instr(DisasContext *dc, uint32_t code,
 318                                uint32_t flags);
 319
 320static const Nios2Instruction i_type_instructions[] = {
 321    INSTRUCTION(call),                                /* call */
 322    INSTRUCTION(jmpi),                                /* jmpi */
 323    INSTRUCTION_ILLEGAL(),
 324    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
 325    INSTRUCTION(addi),                                /* addi */
 326    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
 327    INSTRUCTION(br),                                  /* br */
 328    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
 329    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
 330    INSTRUCTION_ILLEGAL(),
 331    INSTRUCTION_ILLEGAL(),
 332    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
 333    INSTRUCTION(andi),                                /* andi */
 334    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
 335    INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
 336    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
 337    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
 338    INSTRUCTION_ILLEGAL(),
 339    INSTRUCTION_ILLEGAL(),
 340    INSTRUCTION_NOP(),                                /* initda */
 341    INSTRUCTION(ori),                                 /* ori */
 342    INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
 343    INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
 344    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
 345    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
 346    INSTRUCTION_ILLEGAL(),
 347    INSTRUCTION_ILLEGAL(),
 348    INSTRUCTION_NOP(),                                /* flushda */
 349    INSTRUCTION(xori),                                /* xori */
 350    INSTRUCTION_ILLEGAL(),
 351    INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
 352    INSTRUCTION_ILLEGAL(),
 353    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
 354    INSTRUCTION_ILLEGAL(),
 355    INSTRUCTION_ILLEGAL(),
 356    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
 357    INSTRUCTION(muli),                                /* muli */
 358    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
 359    INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
 360    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
 361    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
 362    INSTRUCTION_ILLEGAL(),
 363    INSTRUCTION_ILLEGAL(),
 364    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
 365    INSTRUCTION(andhi),                               /* andhi */
 366    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
 367    INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
 368    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
 369    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
 370    INSTRUCTION_ILLEGAL(),
 371    INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
 372    INSTRUCTION_NOP(),                                /* initd */
 373    INSTRUCTION(orhi),                                /* orhi */
 374    INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
 375    INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
 376    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
 377    INSTRUCTION_UNIMPLEMENTED(),                      /* rdprs */
 378    INSTRUCTION_ILLEGAL(),
 379    INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
 380    INSTRUCTION_NOP(),                                /* flushd */
 381    INSTRUCTION(xorhi),                               /* xorhi */
 382    INSTRUCTION_ILLEGAL(),
 383    INSTRUCTION_ILLEGAL(),
 384    INSTRUCTION_ILLEGAL(),
 385};
 386
 387/*
 388 * R-Type instructions
 389 */
 390/*
 391 * status <- estatus
 392 * PC <- ea
 393 */
 394static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 395{
 396    tcg_gen_mov_tl(dc->cpu_R[CR_STATUS], dc->cpu_R[CR_ESTATUS]);
 397    tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_EA]);
 398
 399    dc->is_jmp = DISAS_JUMP;
 400}
 401
 402/* PC <- ra */
 403static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 404{
 405    tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_RA]);
 406
 407    dc->is_jmp = DISAS_JUMP;
 408}
 409
 410/* PC <- ba */
 411static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
 412{
 413    tcg_gen_mov_tl(dc->cpu_R[R_PC], dc->cpu_R[R_BA]);
 414
 415    dc->is_jmp = DISAS_JUMP;
 416}
 417
 418/* PC <- rA */
 419static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
 420{
 421    R_TYPE(instr, code);
 422
 423    tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
 424
 425    dc->is_jmp = DISAS_JUMP;
 426}
 427
 428/* rC <- PC + 4 */
 429static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
 430{
 431    R_TYPE(instr, code);
 432
 433    if (likely(instr.c != R_ZERO)) {
 434        tcg_gen_movi_tl(dc->cpu_R[instr.c], dc->pc + 4);
 435    }
 436}
 437
 438/*
 439 * ra <- PC + 4
 440 * PC <- rA
 441 */
 442static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 443{
 444    R_TYPE(instr, code);
 445
 446    tcg_gen_mov_tl(dc->cpu_R[R_PC], load_gpr(dc, instr.a));
 447    tcg_gen_movi_tl(dc->cpu_R[R_RA], dc->pc + 4);
 448
 449    dc->is_jmp = DISAS_JUMP;
 450}
 451
 452/* rC <- ctlN */
 453static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 454{
 455    R_TYPE(instr, code);
 456
 457    gen_check_supervisor(dc);
 458
 459    switch (instr.imm5 + CR_BASE) {
 460    case CR_PTEADDR:
 461    case CR_TLBACC:
 462    case CR_TLBMISC:
 463    {
 464#if !defined(CONFIG_USER_ONLY)
 465        if (likely(instr.c != R_ZERO)) {
 466            tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
 467#ifdef DEBUG_MMU
 468            TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
 469            gen_helper_mmu_read_debug(dc->cpu_R[instr.c], dc->cpu_env, tmp);
 470            tcg_temp_free_i32(tmp);
 471#endif
 472        }
 473#endif
 474        break;
 475    }
 476
 477    default:
 478        if (likely(instr.c != R_ZERO)) {
 479            tcg_gen_mov_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.imm5 + CR_BASE]);
 480        }
 481        break;
 482    }
 483}
 484
 485/* ctlN <- rA */
 486static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 487{
 488    R_TYPE(instr, code);
 489
 490    gen_check_supervisor(dc);
 491
 492    switch (instr.imm5 + CR_BASE) {
 493    case CR_PTEADDR:
 494    case CR_TLBACC:
 495    case CR_TLBMISC:
 496    {
 497#if !defined(CONFIG_USER_ONLY)
 498        TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
 499        gen_helper_mmu_write(dc->cpu_env, tmp, load_gpr(dc, instr.a));
 500        tcg_temp_free_i32(tmp);
 501#endif
 502        break;
 503    }
 504
 505    default:
 506        tcg_gen_mov_tl(dc->cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
 507        break;
 508    }
 509
 510    /* If interrupts were enabled using WRCTL, trigger them. */
 511#if !defined(CONFIG_USER_ONLY)
 512    if ((instr.imm5 + CR_BASE) == CR_STATUS) {
 513        gen_helper_check_interrupts(dc->cpu_env);
 514    }
 515#endif
 516}
 517
 518/* Comparison instructions */
 519static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 520{
 521    R_TYPE(instr, code);
 522    if (likely(instr.c != R_ZERO)) {
 523        tcg_gen_setcond_tl(flags, dc->cpu_R[instr.c], dc->cpu_R[instr.a],
 524                           dc->cpu_R[instr.b]);
 525    }
 526}
 527
 528/* Math/logic instructions */
 529#define gen_r_math_logic(fname, insn, op3)                                 \
 530static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 531{                                                                          \
 532    R_TYPE(instr, (code));                                                 \
 533    if (likely(instr.c != R_ZERO)) {                                       \
 534        tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a),      \
 535                       (op3));                                             \
 536    }                                                                      \
 537}
 538
 539gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
 540gen_r_math_logic(sub,  sub_tl,   load_gpr(dc, instr.b))
 541gen_r_math_logic(mul,  mul_tl,   load_gpr(dc, instr.b))
 542
 543gen_r_math_logic(and,  and_tl,   load_gpr(dc, instr.b))
 544gen_r_math_logic(or,   or_tl,    load_gpr(dc, instr.b))
 545gen_r_math_logic(xor,  xor_tl,   load_gpr(dc, instr.b))
 546gen_r_math_logic(nor,  nor_tl,   load_gpr(dc, instr.b))
 547
 548gen_r_math_logic(srai, sari_tl,  instr.imm5)
 549gen_r_math_logic(srli, shri_tl,  instr.imm5)
 550gen_r_math_logic(slli, shli_tl,  instr.imm5)
 551gen_r_math_logic(roli, rotli_tl, instr.imm5)
 552
 553#define gen_r_mul(fname, insn)                                         \
 554static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
 555{                                                                      \
 556    R_TYPE(instr, (code));                                             \
 557    if (likely(instr.c != R_ZERO)) {                                   \
 558        TCGv t0 = tcg_temp_new();                                      \
 559        tcg_gen_##insn(t0, dc->cpu_R[instr.c],                         \
 560                       load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \
 561        tcg_temp_free(t0);                                             \
 562    }                                                                  \
 563}
 564
 565gen_r_mul(mulxss, muls2_tl)
 566gen_r_mul(mulxuu, mulu2_tl)
 567gen_r_mul(mulxsu, mulsu2_tl)
 568
 569#define gen_r_shift_s(fname, insn)                                         \
 570static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 571{                                                                          \
 572    R_TYPE(instr, (code));                                                 \
 573    if (likely(instr.c != R_ZERO)) {                                       \
 574        TCGv t0 = tcg_temp_new();                                          \
 575        tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
 576        tcg_gen_##insn((dc)->cpu_R[instr.c], load_gpr((dc), instr.a), t0); \
 577        tcg_temp_free(t0);                                                 \
 578    }                                                                      \
 579}
 580
 581gen_r_shift_s(sra, sar_tl)
 582gen_r_shift_s(srl, shr_tl)
 583gen_r_shift_s(sll, shl_tl)
 584gen_r_shift_s(rol, rotl_tl)
 585gen_r_shift_s(ror, rotr_tl)
 586
 587static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 588{
 589    R_TYPE(instr, (code));
 590
 591    /* Stores into R_ZERO are ignored */
 592    if (unlikely(instr.c == R_ZERO)) {
 593        return;
 594    }
 595
 596    TCGv t0 = tcg_temp_new();
 597    TCGv t1 = tcg_temp_new();
 598    TCGv t2 = tcg_temp_new();
 599    TCGv t3 = tcg_temp_new();
 600
 601    tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
 602    tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
 603    tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
 604    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
 605    tcg_gen_and_tl(t2, t2, t3);
 606    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
 607    tcg_gen_or_tl(t2, t2, t3);
 608    tcg_gen_movi_tl(t3, 0);
 609    tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
 610    tcg_gen_div_tl(dc->cpu_R[instr.c], t0, t1);
 611    tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
 612
 613    tcg_temp_free(t3);
 614    tcg_temp_free(t2);
 615    tcg_temp_free(t1);
 616    tcg_temp_free(t0);
 617}
 618
 619static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 620{
 621    R_TYPE(instr, (code));
 622
 623    /* Stores into R_ZERO are ignored */
 624    if (unlikely(instr.c == R_ZERO)) {
 625        return;
 626    }
 627
 628    TCGv t0 = tcg_temp_new();
 629    TCGv t1 = tcg_temp_new();
 630    TCGv t2 = tcg_const_tl(0);
 631    TCGv t3 = tcg_const_tl(1);
 632
 633    tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
 634    tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
 635    tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
 636    tcg_gen_divu_tl(dc->cpu_R[instr.c], t0, t1);
 637    tcg_gen_ext32s_tl(dc->cpu_R[instr.c], dc->cpu_R[instr.c]);
 638
 639    tcg_temp_free(t3);
 640    tcg_temp_free(t2);
 641    tcg_temp_free(t1);
 642    tcg_temp_free(t0);
 643}
 644
 645static const Nios2Instruction r_type_instructions[] = {
 646    INSTRUCTION_ILLEGAL(),
 647    INSTRUCTION(eret),                                /* eret */
 648    INSTRUCTION(roli),                                /* roli */
 649    INSTRUCTION(rol),                                 /* rol */
 650    INSTRUCTION_NOP(),                                /* flushp */
 651    INSTRUCTION(ret),                                 /* ret */
 652    INSTRUCTION(nor),                                 /* nor */
 653    INSTRUCTION(mulxuu),                              /* mulxuu */
 654    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
 655    INSTRUCTION(bret),                                /* bret */
 656    INSTRUCTION_ILLEGAL(),
 657    INSTRUCTION(ror),                                 /* ror */
 658    INSTRUCTION_NOP(),                                /* flushi */
 659    INSTRUCTION(jmp),                                 /* jmp */
 660    INSTRUCTION(and),                                 /* and */
 661    INSTRUCTION_ILLEGAL(),
 662    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
 663    INSTRUCTION_ILLEGAL(),
 664    INSTRUCTION(slli),                                /* slli */
 665    INSTRUCTION(sll),                                 /* sll */
 666    INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
 667    INSTRUCTION_ILLEGAL(),
 668    INSTRUCTION(or),                                  /* or */
 669    INSTRUCTION(mulxsu),                              /* mulxsu */
 670    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
 671    INSTRUCTION_ILLEGAL(),
 672    INSTRUCTION(srli),                                /* srli */
 673    INSTRUCTION(srl),                                 /* srl */
 674    INSTRUCTION(nextpc),                              /* nextpc */
 675    INSTRUCTION(callr),                               /* callr */
 676    INSTRUCTION(xor),                                 /* xor */
 677    INSTRUCTION(mulxss),                              /* mulxss */
 678    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
 679    INSTRUCTION_ILLEGAL(),
 680    INSTRUCTION_ILLEGAL(),
 681    INSTRUCTION_ILLEGAL(),
 682    INSTRUCTION(divu),                                /* divu */
 683    INSTRUCTION(divs),                                /* div */
 684    INSTRUCTION(rdctl),                               /* rdctl */
 685    INSTRUCTION(mul),                                 /* mul */
 686    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
 687    INSTRUCTION_NOP(),                                /* initi */
 688    INSTRUCTION_ILLEGAL(),
 689    INSTRUCTION_ILLEGAL(),
 690    INSTRUCTION_ILLEGAL(),
 691    INSTRUCTION_FLG(gen_excp, EXCP_TRAP),             /* trap */
 692    INSTRUCTION(wrctl),                               /* wrctl */
 693    INSTRUCTION_ILLEGAL(),
 694    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
 695    INSTRUCTION(add),                                 /* add */
 696    INSTRUCTION_ILLEGAL(),
 697    INSTRUCTION_ILLEGAL(),
 698    INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
 699    INSTRUCTION_ILLEGAL(),
 700    INSTRUCTION(nop),                                 /* nop */
 701    INSTRUCTION_ILLEGAL(),
 702    INSTRUCTION_ILLEGAL(),
 703    INSTRUCTION(sub),                                 /* sub */
 704    INSTRUCTION(srai),                                /* srai */
 705    INSTRUCTION(sra),                                 /* sra */
 706    INSTRUCTION_ILLEGAL(),
 707    INSTRUCTION_ILLEGAL(),
 708    INSTRUCTION_ILLEGAL(),
 709    INSTRUCTION_ILLEGAL(),
 710};
 711
 712static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
 713{
 714    uint8_t opx;
 715    const Nios2Instruction *instr;
 716
 717    opx = get_opxcode(code);
 718    if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
 719        goto illegal_op;
 720    }
 721
 722    instr = &r_type_instructions[opx];
 723    instr->handler(dc, code, instr->flags);
 724
 725    return;
 726
 727illegal_op:
 728    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 729}
 730
 731static void handle_instruction(DisasContext *dc, CPUNios2State *env)
 732{
 733    uint32_t code;
 734    uint8_t op;
 735    const Nios2Instruction *instr;
 736#if defined(CONFIG_USER_ONLY)
 737    /* FIXME: Is this needed ? */
 738    if (dc->pc >= 0x1000 && dc->pc < 0x2000) {
 739        env->regs[R_PC] = dc->pc;
 740        t_gen_helper_raise_exception(dc, 0xaa);
 741        return;
 742    }
 743#endif
 744    code = cpu_ldl_code(env, dc->pc);
 745    op = get_opcode(code);
 746
 747    if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
 748        goto illegal_op;
 749    }
 750
 751    TCGV_UNUSED_I32(dc->zero);
 752
 753    instr = &i_type_instructions[op];
 754    instr->handler(dc, code, instr->flags);
 755
 756    if (!TCGV_IS_UNUSED_I32(dc->zero)) {
 757        tcg_temp_free(dc->zero);
 758    }
 759
 760    return;
 761
 762illegal_op:
 763    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 764}
 765
 766static const char * const regnames[] = {
 767    "zero",       "at",         "r2",         "r3",
 768    "r4",         "r5",         "r6",         "r7",
 769    "r8",         "r9",         "r10",        "r11",
 770    "r12",        "r13",        "r14",        "r15",
 771    "r16",        "r17",        "r18",        "r19",
 772    "r20",        "r21",        "r22",        "r23",
 773    "et",         "bt",         "gp",         "sp",
 774    "fp",         "ea",         "ba",         "ra",
 775    "status",     "estatus",    "bstatus",    "ienable",
 776    "ipending",   "cpuid",      "reserved0",  "exception",
 777    "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
 778    "badaddr",    "config",     "mpubase",    "mpuacc",
 779    "reserved2",  "reserved3",  "reserved4",  "reserved5",
 780    "reserved6",  "reserved7",  "reserved8",  "reserved9",
 781    "reserved10", "reserved11", "reserved12", "reserved13",
 782    "reserved14", "reserved15", "reserved16", "reserved17",
 783    "rpc"
 784};
 785
 786static TCGv_ptr cpu_env;
 787static TCGv cpu_R[NUM_CORE_REGS];
 788
 789#include "exec/gen-icount.h"
 790
 791static void gen_exception(DisasContext *dc, uint32_t excp)
 792{
 793    TCGv_i32 tmp = tcg_const_i32(excp);
 794
 795    tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
 796    gen_helper_raise_exception(cpu_env, tmp);
 797    tcg_temp_free_i32(tmp);
 798    dc->is_jmp = DISAS_UPDATE;
 799}
 800
 801/* generate intermediate code for basic block 'tb'.  */
 802void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
 803{
 804    CPUNios2State *env = cs->env_ptr;
 805    DisasContext dc1, *dc = &dc1;
 806    int num_insns;
 807    int max_insns;
 808
 809    /* Initialize DC */
 810    dc->cpu_env = cpu_env;
 811    dc->cpu_R   = cpu_R;
 812    dc->is_jmp  = DISAS_NEXT;
 813    dc->pc      = tb->pc;
 814    dc->tb      = tb;
 815    dc->mem_idx = cpu_mmu_index(env, false);
 816    dc->singlestep_enabled = cs->singlestep_enabled;
 817
 818    /* Set up instruction counts */
 819    num_insns = 0;
 820    if (cs->singlestep_enabled || singlestep) {
 821        max_insns = 1;
 822    } else {
 823        int page_insns = (TARGET_PAGE_SIZE - (tb->pc & TARGET_PAGE_MASK)) / 4;
 824        max_insns = tb->cflags & CF_COUNT_MASK;
 825        if (max_insns == 0) {
 826            max_insns = CF_COUNT_MASK;
 827        }
 828        if (max_insns > page_insns) {
 829            max_insns = page_insns;
 830        }
 831        if (max_insns > TCG_MAX_INSNS) {
 832            max_insns = TCG_MAX_INSNS;
 833        }
 834    }
 835
 836    gen_tb_start(tb);
 837    do {
 838        tcg_gen_insn_start(dc->pc);
 839        num_insns++;
 840
 841        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
 842            gen_exception(dc, EXCP_DEBUG);
 843            /* The address covered by the breakpoint must be included in
 844               [tb->pc, tb->pc + tb->size) in order to for it to be
 845               properly cleared -- thus we increment the PC here so that
 846               the logic setting tb->size below does the right thing.  */
 847            dc->pc += 4;
 848            break;
 849        }
 850
 851        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
 852            gen_io_start();
 853        }
 854
 855        /* Decode an instruction */
 856        handle_instruction(dc, env);
 857
 858        dc->pc += 4;
 859
 860        /* Translation stops when a conditional branch is encountered.
 861         * Otherwise the subsequent code could get translated several times.
 862         * Also stop translation when a page boundary is reached.  This
 863         * ensures prefetch aborts occur at the right place.  */
 864    } while (!dc->is_jmp &&
 865             !tcg_op_buf_full() &&
 866             num_insns < max_insns);
 867
 868    if (tb->cflags & CF_LAST_IO) {
 869        gen_io_end();
 870    }
 871
 872    /* Indicate where the next block should start */
 873    switch (dc->is_jmp) {
 874    case DISAS_NEXT:
 875        /* Save the current PC back into the CPU register */
 876        tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
 877        tcg_gen_exit_tb(0);
 878        break;
 879
 880    default:
 881    case DISAS_JUMP:
 882    case DISAS_UPDATE:
 883        /* The jump will already have updated the PC register */
 884        tcg_gen_exit_tb(0);
 885        break;
 886
 887    case DISAS_TB_JUMP:
 888        /* nothing more to generate */
 889        break;
 890    }
 891
 892    /* End off the block */
 893    gen_tb_end(tb, num_insns);
 894
 895    /* Mark instruction starts for the final generated instruction */
 896    tb->size = dc->pc - tb->pc;
 897    tb->icount = num_insns;
 898
 899#ifdef DEBUG_DISAS
 900    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
 901        && qemu_log_in_addr_range(tb->pc)) {
 902        qemu_log_lock();
 903        qemu_log("IN: %s\n", lookup_symbol(tb->pc));
 904        log_target_disas(cs, tb->pc, dc->pc - tb->pc, 0);
 905        qemu_log("\n");
 906        qemu_log_unlock();
 907    }
 908#endif
 909}
 910
 911void nios2_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
 912                          int flags)
 913{
 914    Nios2CPU *cpu = NIOS2_CPU(cs);
 915    CPUNios2State *env = &cpu->env;
 916    int i;
 917
 918    if (!env || !f) {
 919        return;
 920    }
 921
 922    cpu_fprintf(f, "IN: PC=%x %s\n",
 923                env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
 924
 925    for (i = 0; i < NUM_CORE_REGS; i++) {
 926        cpu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
 927        if ((i + 1) % 4 == 0) {
 928            cpu_fprintf(f, "\n");
 929        }
 930    }
 931#if !defined(CONFIG_USER_ONLY)
 932    cpu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
 933                env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
 934                (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
 935                env->mmu.tlbacc_wr);
 936#endif
 937    cpu_fprintf(f, "\n\n");
 938}
 939
 940void nios2_tcg_init(void)
 941{
 942    int i;
 943
 944    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 945
 946    for (i = 0; i < NUM_CORE_REGS; i++) {
 947        cpu_R[i] = tcg_global_mem_new(cpu_env,
 948                                      offsetof(CPUNios2State, regs[i]),
 949                                      regnames[i]);
 950    }
 951}
 952
 953void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
 954                          target_ulong *data)
 955{
 956    env->regs[R_PC] = data[0];
 957}
 958