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