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