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