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