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    if (unlikely(instr.c == R_ZERO)) {
 451        return;
 452    }
 453
 454    switch (instr.imm5 + CR_BASE) {
 455    case CR_IPENDING:
 456        /*
 457         * The value of the ipending register is synthetic.
 458         * In hw, this is the AND of a set of hardware irq lines
 459         * with the ienable register.  In qemu, we re-use the space
 460         * of CR_IPENDING to store the set of irq lines, and so we
 461         * must perform the AND here, and anywhere else we need the
 462         * guest value of ipending.
 463         */
 464        tcg_gen_and_tl(cpu_R[instr.c], cpu_R[CR_IPENDING], cpu_R[CR_IENABLE]);
 465        break;
 466    default:
 467        tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
 468        break;
 469    }
 470}
 471
 472/* ctlN <- rA */
 473static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 474{
 475    gen_check_supervisor(dc);
 476
 477#ifndef CONFIG_USER_ONLY
 478    R_TYPE(instr, code);
 479    TCGv v = load_gpr(dc, instr.a);
 480
 481    switch (instr.imm5 + CR_BASE) {
 482    case CR_PTEADDR:
 483        gen_helper_mmu_write_pteaddr(cpu_env, v);
 484        break;
 485    case CR_TLBACC:
 486        gen_helper_mmu_write_tlbacc(cpu_env, v);
 487        break;
 488    case CR_TLBMISC:
 489        gen_helper_mmu_write_tlbmisc(cpu_env, v);
 490        break;
 491    case CR_IPENDING:
 492        /* ipending is read only, writes ignored. */
 493        break;
 494    case CR_STATUS:
 495    case CR_IENABLE:
 496        /* If interrupts were enabled using WRCTL, trigger them. */
 497        dc->base.is_jmp = DISAS_UPDATE;
 498        /* fall through */
 499    default:
 500        tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], v);
 501        break;
 502    }
 503#endif
 504}
 505
 506/* Comparison instructions */
 507static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 508{
 509    R_TYPE(instr, code);
 510    if (likely(instr.c != R_ZERO)) {
 511        tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a],
 512                           cpu_R[instr.b]);
 513    }
 514}
 515
 516/* Math/logic instructions */
 517#define gen_r_math_logic(fname, insn, op3)                                 \
 518static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 519{                                                                          \
 520    R_TYPE(instr, (code));                                                 \
 521    if (likely(instr.c != R_ZERO)) {                                       \
 522        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3));    \
 523    }                                                                      \
 524}
 525
 526gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
 527gen_r_math_logic(sub,  sub_tl,   load_gpr(dc, instr.b))
 528gen_r_math_logic(mul,  mul_tl,   load_gpr(dc, instr.b))
 529
 530gen_r_math_logic(and,  and_tl,   load_gpr(dc, instr.b))
 531gen_r_math_logic(or,   or_tl,    load_gpr(dc, instr.b))
 532gen_r_math_logic(xor,  xor_tl,   load_gpr(dc, instr.b))
 533gen_r_math_logic(nor,  nor_tl,   load_gpr(dc, instr.b))
 534
 535gen_r_math_logic(srai, sari_tl,  instr.imm5)
 536gen_r_math_logic(srli, shri_tl,  instr.imm5)
 537gen_r_math_logic(slli, shli_tl,  instr.imm5)
 538gen_r_math_logic(roli, rotli_tl, instr.imm5)
 539
 540#define gen_r_mul(fname, insn)                                         \
 541static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
 542{                                                                      \
 543    R_TYPE(instr, (code));                                             \
 544    if (likely(instr.c != R_ZERO)) {                                   \
 545        TCGv t0 = tcg_temp_new();                                      \
 546        tcg_gen_##insn(t0, cpu_R[instr.c],                             \
 547                       load_gpr(dc, instr.a), load_gpr(dc, instr.b));  \
 548        tcg_temp_free(t0);                                             \
 549    }                                                                  \
 550}
 551
 552gen_r_mul(mulxss, muls2_tl)
 553gen_r_mul(mulxuu, mulu2_tl)
 554gen_r_mul(mulxsu, mulsu2_tl)
 555
 556#define gen_r_shift_s(fname, insn)                                         \
 557static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 558{                                                                          \
 559    R_TYPE(instr, (code));                                                 \
 560    if (likely(instr.c != R_ZERO)) {                                       \
 561        TCGv t0 = tcg_temp_new();                                          \
 562        tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
 563        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0);       \
 564        tcg_temp_free(t0);                                                 \
 565    }                                                                      \
 566}
 567
 568gen_r_shift_s(sra, sar_tl)
 569gen_r_shift_s(srl, shr_tl)
 570gen_r_shift_s(sll, shl_tl)
 571gen_r_shift_s(rol, rotl_tl)
 572gen_r_shift_s(ror, rotr_tl)
 573
 574static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 575{
 576    R_TYPE(instr, (code));
 577
 578    /* Stores into R_ZERO are ignored */
 579    if (unlikely(instr.c == R_ZERO)) {
 580        return;
 581    }
 582
 583    TCGv t0 = tcg_temp_new();
 584    TCGv t1 = tcg_temp_new();
 585    TCGv t2 = tcg_temp_new();
 586    TCGv t3 = tcg_temp_new();
 587
 588    tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
 589    tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
 590    tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
 591    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
 592    tcg_gen_and_tl(t2, t2, t3);
 593    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
 594    tcg_gen_or_tl(t2, t2, t3);
 595    tcg_gen_movi_tl(t3, 0);
 596    tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
 597    tcg_gen_div_tl(cpu_R[instr.c], t0, t1);
 598    tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
 599
 600    tcg_temp_free(t3);
 601    tcg_temp_free(t2);
 602    tcg_temp_free(t1);
 603    tcg_temp_free(t0);
 604}
 605
 606static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 607{
 608    R_TYPE(instr, (code));
 609
 610    /* Stores into R_ZERO are ignored */
 611    if (unlikely(instr.c == R_ZERO)) {
 612        return;
 613    }
 614
 615    TCGv t0 = tcg_temp_new();
 616    TCGv t1 = tcg_temp_new();
 617    TCGv t2 = tcg_const_tl(0);
 618    TCGv t3 = tcg_const_tl(1);
 619
 620    tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
 621    tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
 622    tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
 623    tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
 624    tcg_gen_ext32s_tl(cpu_R[instr.c], 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 trap(DisasContext *dc, uint32_t code, uint32_t flags)
 633{
 634#ifdef CONFIG_USER_ONLY
 635    /*
 636     * The imm5 field is not stored anywhere on real hw; the kernel
 637     * has to load the insn and extract the field.  But we can make
 638     * things easier for cpu_loop if we pop this into env->error_code.
 639     */
 640    R_TYPE(instr, code);
 641    tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env,
 642                   offsetof(CPUNios2State, error_code));
 643#endif
 644    t_gen_helper_raise_exception(dc, EXCP_TRAP);
 645}
 646
 647static const Nios2Instruction r_type_instructions[] = {
 648    INSTRUCTION_ILLEGAL(),
 649    INSTRUCTION(eret),                                /* eret */
 650    INSTRUCTION(roli),                                /* roli */
 651    INSTRUCTION(rol),                                 /* rol */
 652    INSTRUCTION_NOP(),                                /* flushp */
 653    INSTRUCTION(ret),                                 /* ret */
 654    INSTRUCTION(nor),                                 /* nor */
 655    INSTRUCTION(mulxuu),                              /* mulxuu */
 656    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
 657    INSTRUCTION(bret),                                /* bret */
 658    INSTRUCTION_ILLEGAL(),
 659    INSTRUCTION(ror),                                 /* ror */
 660    INSTRUCTION_NOP(),                                /* flushi */
 661    INSTRUCTION(jmp),                                 /* jmp */
 662    INSTRUCTION(and),                                 /* and */
 663    INSTRUCTION_ILLEGAL(),
 664    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
 665    INSTRUCTION_ILLEGAL(),
 666    INSTRUCTION(slli),                                /* slli */
 667    INSTRUCTION(sll),                                 /* sll */
 668    INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
 669    INSTRUCTION_ILLEGAL(),
 670    INSTRUCTION(or),                                  /* or */
 671    INSTRUCTION(mulxsu),                              /* mulxsu */
 672    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
 673    INSTRUCTION_ILLEGAL(),
 674    INSTRUCTION(srli),                                /* srli */
 675    INSTRUCTION(srl),                                 /* srl */
 676    INSTRUCTION(nextpc),                              /* nextpc */
 677    INSTRUCTION(callr),                               /* callr */
 678    INSTRUCTION(xor),                                 /* xor */
 679    INSTRUCTION(mulxss),                              /* mulxss */
 680    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
 681    INSTRUCTION_ILLEGAL(),
 682    INSTRUCTION_ILLEGAL(),
 683    INSTRUCTION_ILLEGAL(),
 684    INSTRUCTION(divu),                                /* divu */
 685    INSTRUCTION(divs),                                /* div */
 686    INSTRUCTION(rdctl),                               /* rdctl */
 687    INSTRUCTION(mul),                                 /* mul */
 688    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
 689    INSTRUCTION_NOP(),                                /* initi */
 690    INSTRUCTION_ILLEGAL(),
 691    INSTRUCTION_ILLEGAL(),
 692    INSTRUCTION_ILLEGAL(),
 693    INSTRUCTION(trap),                                /* trap */
 694    INSTRUCTION(wrctl),                               /* wrctl */
 695    INSTRUCTION_ILLEGAL(),
 696    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
 697    INSTRUCTION(add),                                 /* add */
 698    INSTRUCTION_ILLEGAL(),
 699    INSTRUCTION_ILLEGAL(),
 700    INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
 701    INSTRUCTION_ILLEGAL(),
 702    INSTRUCTION(nop),                                 /* nop */
 703    INSTRUCTION_ILLEGAL(),
 704    INSTRUCTION_ILLEGAL(),
 705    INSTRUCTION(sub),                                 /* sub */
 706    INSTRUCTION(srai),                                /* srai */
 707    INSTRUCTION(sra),                                 /* sra */
 708    INSTRUCTION_ILLEGAL(),
 709    INSTRUCTION_ILLEGAL(),
 710    INSTRUCTION_ILLEGAL(),
 711    INSTRUCTION_ILLEGAL(),
 712};
 713
 714static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
 715{
 716    uint8_t opx;
 717    const Nios2Instruction *instr;
 718
 719    opx = get_opxcode(code);
 720    if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
 721        goto illegal_op;
 722    }
 723
 724    instr = &r_type_instructions[opx];
 725    instr->handler(dc, code, instr->flags);
 726
 727    return;
 728
 729illegal_op:
 730    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 731}
 732
 733static const char * const regnames[] = {
 734    "zero",       "at",         "r2",         "r3",
 735    "r4",         "r5",         "r6",         "r7",
 736    "r8",         "r9",         "r10",        "r11",
 737    "r12",        "r13",        "r14",        "r15",
 738    "r16",        "r17",        "r18",        "r19",
 739    "r20",        "r21",        "r22",        "r23",
 740    "et",         "bt",         "gp",         "sp",
 741    "fp",         "ea",         "ba",         "ra",
 742    "status",     "estatus",    "bstatus",    "ienable",
 743    "ipending",   "cpuid",      "reserved0",  "exception",
 744    "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
 745    "badaddr",    "config",     "mpubase",    "mpuacc",
 746    "reserved2",  "reserved3",  "reserved4",  "reserved5",
 747    "reserved6",  "reserved7",  "reserved8",  "reserved9",
 748    "reserved10", "reserved11", "reserved12", "reserved13",
 749    "reserved14", "reserved15", "reserved16", "reserved17",
 750    "rpc"
 751};
 752
 753#include "exec/gen-icount.h"
 754
 755/* generate intermediate code for basic block 'tb'.  */
 756static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 757{
 758    DisasContext *dc = container_of(dcbase, DisasContext, base);
 759    CPUNios2State *env = cs->env_ptr;
 760    int page_insns;
 761
 762    dc->mem_idx = cpu_mmu_index(env, false);
 763
 764    /* Bound the number of insns to execute to those left on the page.  */
 765    page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
 766    dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
 767}
 768
 769static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
 770{
 771}
 772
 773static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
 774{
 775    tcg_gen_insn_start(dcbase->pc_next);
 776}
 777
 778static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 779{
 780    DisasContext *dc = container_of(dcbase, DisasContext, base);
 781    CPUNios2State *env = cs->env_ptr;
 782    const Nios2Instruction *instr;
 783    uint32_t code, pc;
 784    uint8_t op;
 785
 786    pc = dc->base.pc_next;
 787    dc->pc = pc;
 788    dc->base.pc_next = pc + 4;
 789
 790    /* Decode an instruction */
 791    code = cpu_ldl_code(env, pc);
 792    op = get_opcode(code);
 793
 794    if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
 795        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 796        return;
 797    }
 798
 799    dc->zero = NULL;
 800
 801    instr = &i_type_instructions[op];
 802    instr->handler(dc, code, instr->flags);
 803
 804    if (dc->zero) {
 805        tcg_temp_free(dc->zero);
 806    }
 807}
 808
 809static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
 810{
 811    DisasContext *dc = container_of(dcbase, DisasContext, base);
 812
 813    /* Indicate where the next block should start */
 814    switch (dc->base.is_jmp) {
 815    case DISAS_TOO_MANY:
 816    case DISAS_UPDATE:
 817        /* Save the current PC back into the CPU register */
 818        tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next);
 819        tcg_gen_exit_tb(NULL, 0);
 820        break;
 821
 822    case DISAS_JUMP:
 823        /* The jump will already have updated the PC register */
 824        tcg_gen_exit_tb(NULL, 0);
 825        break;
 826
 827    case DISAS_NORETURN:
 828        /* nothing more to generate */
 829        break;
 830
 831    default:
 832        g_assert_not_reached();
 833    }
 834}
 835
 836static void nios2_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
 837{
 838    qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
 839    log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
 840}
 841
 842static const TranslatorOps nios2_tr_ops = {
 843    .init_disas_context = nios2_tr_init_disas_context,
 844    .tb_start           = nios2_tr_tb_start,
 845    .insn_start         = nios2_tr_insn_start,
 846    .translate_insn     = nios2_tr_translate_insn,
 847    .tb_stop            = nios2_tr_tb_stop,
 848    .disas_log          = nios2_tr_disas_log,
 849};
 850
 851void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
 852{
 853    DisasContext dc;
 854    translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns);
 855}
 856
 857void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 858{
 859    Nios2CPU *cpu = NIOS2_CPU(cs);
 860    CPUNios2State *env = &cpu->env;
 861    int i;
 862
 863    if (!env) {
 864        return;
 865    }
 866
 867    qemu_fprintf(f, "IN: PC=%x %s\n",
 868                 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
 869
 870    for (i = 0; i < NUM_CORE_REGS; i++) {
 871        qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
 872        if ((i + 1) % 4 == 0) {
 873            qemu_fprintf(f, "\n");
 874        }
 875    }
 876#if !defined(CONFIG_USER_ONLY)
 877    qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
 878                 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
 879                 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
 880                 env->mmu.tlbacc_wr);
 881#endif
 882    qemu_fprintf(f, "\n\n");
 883}
 884
 885void nios2_tcg_init(void)
 886{
 887    int i;
 888
 889    for (i = 0; i < NUM_CORE_REGS; i++) {
 890        cpu_R[i] = tcg_global_mem_new(cpu_env,
 891                                      offsetof(CPUNios2State, regs[i]),
 892                                      regnames[i]);
 893    }
 894}
 895
 896void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
 897                          target_ulong *data)
 898{
 899    env->regs[R_PC] = data[0];
 900}
 901