The hook is now unused, with breakpoints checked outside translation. Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
		
			
				
	
	
		
			902 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			902 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Altera Nios II emulation for qemu: main translation routines.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
 | 
						|
 * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com>
 | 
						|
 * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
 | 
						|
 *  (Portions of this file that were originally from nios2sim-ng.)
 | 
						|
 *
 | 
						|
 * This library is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Lesser General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2.1 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This library is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public
 | 
						|
 * License along with this library; if not, see
 | 
						|
 * <http://www.gnu.org/licenses/lgpl-2.1.html>
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "cpu.h"
 | 
						|
#include "tcg/tcg-op.h"
 | 
						|
#include "exec/exec-all.h"
 | 
						|
#include "disas/disas.h"
 | 
						|
#include "exec/helper-proto.h"
 | 
						|
#include "exec/helper-gen.h"
 | 
						|
#include "exec/log.h"
 | 
						|
#include "exec/cpu_ldst.h"
 | 
						|
#include "exec/translator.h"
 | 
						|
#include "qemu/qemu-print.h"
 | 
						|
#include "exec/gen-icount.h"
 | 
						|
 | 
						|
/* is_jmp field values */
 | 
						|
#define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
 | 
						|
#define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
 | 
						|
 | 
						|
#define INSTRUCTION_FLG(func, flags) { (func), (flags) }
 | 
						|
#define INSTRUCTION(func)                  \
 | 
						|
        INSTRUCTION_FLG(func, 0)
 | 
						|
#define INSTRUCTION_NOP()                  \
 | 
						|
        INSTRUCTION_FLG(nop, 0)
 | 
						|
#define INSTRUCTION_UNIMPLEMENTED()        \
 | 
						|
        INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL)
 | 
						|
#define INSTRUCTION_ILLEGAL()              \
 | 
						|
        INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL)
 | 
						|
 | 
						|
/* Special R-Type instruction opcode */
 | 
						|
#define INSN_R_TYPE 0x3A
 | 
						|
 | 
						|
/* I-Type instruction parsing */
 | 
						|
#define I_TYPE(instr, code)                \
 | 
						|
    struct {                               \
 | 
						|
        uint8_t op;                        \
 | 
						|
        union {                            \
 | 
						|
            uint16_t u;                    \
 | 
						|
            int16_t s;                     \
 | 
						|
        } imm16;                           \
 | 
						|
        uint8_t b;                         \
 | 
						|
        uint8_t a;                         \
 | 
						|
    } (instr) = {                          \
 | 
						|
        .op    = extract32((code), 0, 6),  \
 | 
						|
        .imm16.u = extract32((code), 6, 16), \
 | 
						|
        .b     = extract32((code), 22, 5), \
 | 
						|
        .a     = extract32((code), 27, 5), \
 | 
						|
    }
 | 
						|
 | 
						|
/* R-Type instruction parsing */
 | 
						|
#define R_TYPE(instr, code)                \
 | 
						|
    struct {                               \
 | 
						|
        uint8_t op;                        \
 | 
						|
        uint8_t imm5;                      \
 | 
						|
        uint8_t opx;                       \
 | 
						|
        uint8_t c;                         \
 | 
						|
        uint8_t b;                         \
 | 
						|
        uint8_t a;                         \
 | 
						|
    } (instr) = {                          \
 | 
						|
        .op    = extract32((code), 0, 6),  \
 | 
						|
        .imm5  = extract32((code), 6, 5),  \
 | 
						|
        .opx   = extract32((code), 11, 6), \
 | 
						|
        .c     = extract32((code), 17, 5), \
 | 
						|
        .b     = extract32((code), 22, 5), \
 | 
						|
        .a     = extract32((code), 27, 5), \
 | 
						|
    }
 | 
						|
 | 
						|
/* J-Type instruction parsing */
 | 
						|
#define J_TYPE(instr, code)                \
 | 
						|
    struct {                               \
 | 
						|
        uint8_t op;                        \
 | 
						|
        uint32_t imm26;                    \
 | 
						|
    } (instr) = {                          \
 | 
						|
        .op    = extract32((code), 0, 6),  \
 | 
						|
        .imm26 = extract32((code), 6, 26), \
 | 
						|
    }
 | 
						|
 | 
						|
typedef struct DisasContext {
 | 
						|
    DisasContextBase  base;
 | 
						|
    TCGv_i32          zero;
 | 
						|
    target_ulong      pc;
 | 
						|
    int               mem_idx;
 | 
						|
} DisasContext;
 | 
						|
 | 
						|
static TCGv cpu_R[NUM_CORE_REGS];
 | 
						|
 | 
						|
typedef struct Nios2Instruction {
 | 
						|
    void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
 | 
						|
    uint32_t  flags;
 | 
						|
} Nios2Instruction;
 | 
						|
 | 
						|
static uint8_t get_opcode(uint32_t code)
 | 
						|
{
 | 
						|
    I_TYPE(instr, code);
 | 
						|
    return instr.op;
 | 
						|
}
 | 
						|
 | 
						|
static uint8_t get_opxcode(uint32_t code)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
    return instr.opx;
 | 
						|
}
 | 
						|
 | 
						|
static TCGv load_zero(DisasContext *dc)
 | 
						|
{
 | 
						|
    if (!dc->zero) {
 | 
						|
        dc->zero = tcg_const_i32(0);
 | 
						|
    }
 | 
						|
    return dc->zero;
 | 
						|
}
 | 
						|
 | 
						|
static TCGv load_gpr(DisasContext *dc, uint8_t reg)
 | 
						|
{
 | 
						|
    if (likely(reg != R_ZERO)) {
 | 
						|
        return cpu_R[reg];
 | 
						|
    } else {
 | 
						|
        return load_zero(dc);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void t_gen_helper_raise_exception(DisasContext *dc,
 | 
						|
                                         uint32_t index)
 | 
						|
{
 | 
						|
    TCGv_i32 tmp = tcg_const_i32(index);
 | 
						|
 | 
						|
    tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
 | 
						|
    gen_helper_raise_exception(cpu_env, tmp);
 | 
						|
    tcg_temp_free_i32(tmp);
 | 
						|
    dc->base.is_jmp = DISAS_NORETURN;
 | 
						|
}
 | 
						|
 | 
						|
static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
 | 
						|
{
 | 
						|
    const TranslationBlock *tb = dc->base.tb;
 | 
						|
 | 
						|
    if (translator_use_goto_tb(&dc->base, dest)) {
 | 
						|
        tcg_gen_goto_tb(n);
 | 
						|
        tcg_gen_movi_tl(cpu_R[R_PC], dest);
 | 
						|
        tcg_gen_exit_tb(tb, n);
 | 
						|
    } else {
 | 
						|
        tcg_gen_movi_tl(cpu_R[R_PC], dest);
 | 
						|
        tcg_gen_exit_tb(NULL, 0);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    t_gen_helper_raise_exception(dc, flags);
 | 
						|
}
 | 
						|
 | 
						|
static void gen_check_supervisor(DisasContext *dc)
 | 
						|
{
 | 
						|
    if (dc->base.tb->flags & CR_STATUS_U) {
 | 
						|
        /* CPU in user mode, privileged instruction called, stop. */
 | 
						|
        t_gen_helper_raise_exception(dc, EXCP_SUPERI);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Used as a placeholder for all instructions which do not have
 | 
						|
 * an effect on the simulator (e.g. flush, sync)
 | 
						|
 */
 | 
						|
static void nop(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    /* Nothing to do here */
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * J-Type instructions
 | 
						|
 */
 | 
						|
static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    J_TYPE(instr, code);
 | 
						|
    gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2));
 | 
						|
    dc->base.is_jmp = DISAS_NORETURN;
 | 
						|
}
 | 
						|
 | 
						|
static void call(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
 | 
						|
    jmpi(dc, code, flags);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * I-Type instructions
 | 
						|
 */
 | 
						|
/* Load instructions */
 | 
						|
static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    I_TYPE(instr, code);
 | 
						|
 | 
						|
    TCGv addr = tcg_temp_new();
 | 
						|
    TCGv data;
 | 
						|
 | 
						|
    /*
 | 
						|
     * WARNING: Loads into R_ZERO are ignored, but we must generate the
 | 
						|
     *          memory access itself to emulate the CPU precisely. Load
 | 
						|
     *          from a protected page to R_ZERO will cause SIGSEGV on
 | 
						|
     *          the Nios2 CPU.
 | 
						|
     */
 | 
						|
    if (likely(instr.b != R_ZERO)) {
 | 
						|
        data = cpu_R[instr.b];
 | 
						|
    } else {
 | 
						|
        data = tcg_temp_new();
 | 
						|
    }
 | 
						|
 | 
						|
    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 | 
						|
    tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
 | 
						|
 | 
						|
    if (unlikely(instr.b == R_ZERO)) {
 | 
						|
        tcg_temp_free(data);
 | 
						|
    }
 | 
						|
 | 
						|
    tcg_temp_free(addr);
 | 
						|
}
 | 
						|
 | 
						|
/* Store instructions */
 | 
						|
static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    I_TYPE(instr, code);
 | 
						|
    TCGv val = load_gpr(dc, instr.b);
 | 
						|
 | 
						|
    TCGv addr = tcg_temp_new();
 | 
						|
    tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
 | 
						|
    tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags);
 | 
						|
    tcg_temp_free(addr);
 | 
						|
}
 | 
						|
 | 
						|
/* Branch instructions */
 | 
						|
static void br(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    I_TYPE(instr, code);
 | 
						|
 | 
						|
    gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4));
 | 
						|
    dc->base.is_jmp = DISAS_NORETURN;
 | 
						|
}
 | 
						|
 | 
						|
static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    I_TYPE(instr, code);
 | 
						|
 | 
						|
    TCGLabel *l1 = gen_new_label();
 | 
						|
    tcg_gen_brcond_tl(flags, cpu_R[instr.a], cpu_R[instr.b], l1);
 | 
						|
    gen_goto_tb(dc, 0, dc->base.pc_next);
 | 
						|
    gen_set_label(l1);
 | 
						|
    gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
 | 
						|
    dc->base.is_jmp = DISAS_NORETURN;
 | 
						|
}
 | 
						|
 | 
						|
/* Comparison instructions */
 | 
						|
#define gen_i_cmpxx(fname, op3)                                              \
 | 
						|
static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)         \
 | 
						|
{                                                                            \
 | 
						|
    I_TYPE(instr, (code));                                                   \
 | 
						|
    tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3));       \
 | 
						|
}
 | 
						|
 | 
						|
gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
 | 
						|
gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
 | 
						|
 | 
						|
/* Math/logic instructions */
 | 
						|
#define gen_i_math_logic(fname, insn, resimm, op3)                          \
 | 
						|
static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)        \
 | 
						|
{                                                                           \
 | 
						|
    I_TYPE(instr, (code));                                                  \
 | 
						|
    if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */     \
 | 
						|
        return;                                                             \
 | 
						|
    } else if (instr.a == R_ZERO) { /* MOVxI optimizations */               \
 | 
						|
        tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0);              \
 | 
						|
    } else {                                                                \
 | 
						|
        tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3));         \
 | 
						|
    }                                                                       \
 | 
						|
}
 | 
						|
 | 
						|
gen_i_math_logic(addi,  addi, 1, instr.imm16.s)
 | 
						|
gen_i_math_logic(muli,  muli, 0, instr.imm16.s)
 | 
						|
 | 
						|
gen_i_math_logic(andi,  andi, 0, instr.imm16.u)
 | 
						|
gen_i_math_logic(ori,   ori,  1, instr.imm16.u)
 | 
						|
gen_i_math_logic(xori,  xori, 1, instr.imm16.u)
 | 
						|
 | 
						|
gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
 | 
						|
gen_i_math_logic(orhi , ori,  1, instr.imm16.u << 16)
 | 
						|
gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
 | 
						|
 | 
						|
/* Prototype only, defined below */
 | 
						|
static void handle_r_type_instr(DisasContext *dc, uint32_t code,
 | 
						|
                                uint32_t flags);
 | 
						|
 | 
						|
static const Nios2Instruction i_type_instructions[] = {
 | 
						|
    INSTRUCTION(call),                                /* call */
 | 
						|
    INSTRUCTION(jmpi),                                /* jmpi */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbu */
 | 
						|
    INSTRUCTION(addi),                                /* addi */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stb */
 | 
						|
    INSTRUCTION(br),                                  /* br */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldb */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE),        /* cmpgei */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhu */
 | 
						|
    INSTRUCTION(andi),                                /* andi */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sth */
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_GE),            /* bge */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldh */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT),        /* cmplti */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_NOP(),                                /* initda */
 | 
						|
    INSTRUCTION(ori),                                 /* ori */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_UL),                  /* stw */
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_LT),            /* blt */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldw */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE),        /* cmpnei */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_NOP(),                                /* flushda */
 | 
						|
    INSTRUCTION(xori),                                /* xori */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_NE),            /* bne */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ),        /* cmpeqi */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UB),                  /* ldbuio */
 | 
						|
    INSTRUCTION(muli),                                /* muli */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_UB),                  /* stbio */
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ),            /* beq */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_SB),                  /* ldbio */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU),       /* cmpgeui */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UW),                  /* ldhuio */
 | 
						|
    INSTRUCTION(andhi),                               /* andhi */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_UW),                  /* sthio */
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU),           /* bgeu */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_SW),                  /* ldhio */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU),       /* cmpltui */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_UNIMPLEMENTED(),                      /* custom */
 | 
						|
    INSTRUCTION_NOP(),                                /* initd */
 | 
						|
    INSTRUCTION(orhi),                                /* orhi */
 | 
						|
    INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
 | 
						|
    INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
 | 
						|
    INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
 | 
						|
    INSTRUCTION_UNIMPLEMENTED(),                      /* rdprs */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
 | 
						|
    INSTRUCTION_NOP(),                                /* flushd */
 | 
						|
    INSTRUCTION(xorhi),                               /* xorhi */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * R-Type instructions
 | 
						|
 */
 | 
						|
/*
 | 
						|
 * status <- estatus
 | 
						|
 * PC <- ea
 | 
						|
 */
 | 
						|
static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
 | 
						|
    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]);
 | 
						|
 | 
						|
    dc->base.is_jmp = DISAS_JUMP;
 | 
						|
}
 | 
						|
 | 
						|
/* PC <- ra */
 | 
						|
static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_RA]);
 | 
						|
 | 
						|
    dc->base.is_jmp = DISAS_JUMP;
 | 
						|
}
 | 
						|
 | 
						|
/* PC <- ba */
 | 
						|
static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_BA]);
 | 
						|
 | 
						|
    dc->base.is_jmp = DISAS_JUMP;
 | 
						|
}
 | 
						|
 | 
						|
/* PC <- rA */
 | 
						|
static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
 | 
						|
    tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
 | 
						|
 | 
						|
    dc->base.is_jmp = DISAS_JUMP;
 | 
						|
}
 | 
						|
 | 
						|
/* rC <- PC + 4 */
 | 
						|
static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
 | 
						|
    if (likely(instr.c != R_ZERO)) {
 | 
						|
        tcg_gen_movi_tl(cpu_R[instr.c], dc->base.pc_next);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * ra <- PC + 4
 | 
						|
 * PC <- rA
 | 
						|
 */
 | 
						|
static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
 | 
						|
    tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
 | 
						|
    tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
 | 
						|
 | 
						|
    dc->base.is_jmp = DISAS_JUMP;
 | 
						|
}
 | 
						|
 | 
						|
/* rC <- ctlN */
 | 
						|
static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
 | 
						|
    gen_check_supervisor(dc);
 | 
						|
 | 
						|
    switch (instr.imm5 + CR_BASE) {
 | 
						|
    case CR_PTEADDR:
 | 
						|
    case CR_TLBACC:
 | 
						|
    case CR_TLBMISC:
 | 
						|
    {
 | 
						|
#if !defined(CONFIG_USER_ONLY)
 | 
						|
        if (likely(instr.c != R_ZERO)) {
 | 
						|
            tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
 | 
						|
#ifdef DEBUG_MMU
 | 
						|
            TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
 | 
						|
            gen_helper_mmu_read_debug(cpu_R[instr.c], cpu_env, tmp);
 | 
						|
            tcg_temp_free_i32(tmp);
 | 
						|
#endif
 | 
						|
        }
 | 
						|
#endif
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    default:
 | 
						|
        if (likely(instr.c != R_ZERO)) {
 | 
						|
            tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* ctlN <- rA */
 | 
						|
static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
 | 
						|
    gen_check_supervisor(dc);
 | 
						|
 | 
						|
    switch (instr.imm5 + CR_BASE) {
 | 
						|
    case CR_PTEADDR:
 | 
						|
    case CR_TLBACC:
 | 
						|
    case CR_TLBMISC:
 | 
						|
    {
 | 
						|
#if !defined(CONFIG_USER_ONLY)
 | 
						|
        TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE);
 | 
						|
        gen_helper_mmu_write(cpu_env, tmp, load_gpr(dc, instr.a));
 | 
						|
        tcg_temp_free_i32(tmp);
 | 
						|
#endif
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    default:
 | 
						|
        tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a));
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    /* If interrupts were enabled using WRCTL, trigger them. */
 | 
						|
#if !defined(CONFIG_USER_ONLY)
 | 
						|
    if ((instr.imm5 + CR_BASE) == CR_STATUS) {
 | 
						|
        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
 | 
						|
            gen_io_start();
 | 
						|
        }
 | 
						|
        gen_helper_check_interrupts(cpu_env);
 | 
						|
        dc->base.is_jmp = DISAS_UPDATE;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* Comparison instructions */
 | 
						|
static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, code);
 | 
						|
    if (likely(instr.c != R_ZERO)) {
 | 
						|
        tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a],
 | 
						|
                           cpu_R[instr.b]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Math/logic instructions */
 | 
						|
#define gen_r_math_logic(fname, insn, op3)                                 \
 | 
						|
static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 | 
						|
{                                                                          \
 | 
						|
    R_TYPE(instr, (code));                                                 \
 | 
						|
    if (likely(instr.c != R_ZERO)) {                                       \
 | 
						|
        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3));    \
 | 
						|
    }                                                                      \
 | 
						|
}
 | 
						|
 | 
						|
gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
 | 
						|
gen_r_math_logic(sub,  sub_tl,   load_gpr(dc, instr.b))
 | 
						|
gen_r_math_logic(mul,  mul_tl,   load_gpr(dc, instr.b))
 | 
						|
 | 
						|
gen_r_math_logic(and,  and_tl,   load_gpr(dc, instr.b))
 | 
						|
gen_r_math_logic(or,   or_tl,    load_gpr(dc, instr.b))
 | 
						|
gen_r_math_logic(xor,  xor_tl,   load_gpr(dc, instr.b))
 | 
						|
gen_r_math_logic(nor,  nor_tl,   load_gpr(dc, instr.b))
 | 
						|
 | 
						|
gen_r_math_logic(srai, sari_tl,  instr.imm5)
 | 
						|
gen_r_math_logic(srli, shri_tl,  instr.imm5)
 | 
						|
gen_r_math_logic(slli, shli_tl,  instr.imm5)
 | 
						|
gen_r_math_logic(roli, rotli_tl, instr.imm5)
 | 
						|
 | 
						|
#define gen_r_mul(fname, insn)                                         \
 | 
						|
static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
 | 
						|
{                                                                      \
 | 
						|
    R_TYPE(instr, (code));                                             \
 | 
						|
    if (likely(instr.c != R_ZERO)) {                                   \
 | 
						|
        TCGv t0 = tcg_temp_new();                                      \
 | 
						|
        tcg_gen_##insn(t0, cpu_R[instr.c],                             \
 | 
						|
                       load_gpr(dc, instr.a), load_gpr(dc, instr.b));  \
 | 
						|
        tcg_temp_free(t0);                                             \
 | 
						|
    }                                                                  \
 | 
						|
}
 | 
						|
 | 
						|
gen_r_mul(mulxss, muls2_tl)
 | 
						|
gen_r_mul(mulxuu, mulu2_tl)
 | 
						|
gen_r_mul(mulxsu, mulsu2_tl)
 | 
						|
 | 
						|
#define gen_r_shift_s(fname, insn)                                         \
 | 
						|
static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 | 
						|
{                                                                          \
 | 
						|
    R_TYPE(instr, (code));                                                 \
 | 
						|
    if (likely(instr.c != R_ZERO)) {                                       \
 | 
						|
        TCGv t0 = tcg_temp_new();                                          \
 | 
						|
        tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
 | 
						|
        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0);       \
 | 
						|
        tcg_temp_free(t0);                                                 \
 | 
						|
    }                                                                      \
 | 
						|
}
 | 
						|
 | 
						|
gen_r_shift_s(sra, sar_tl)
 | 
						|
gen_r_shift_s(srl, shr_tl)
 | 
						|
gen_r_shift_s(sll, shl_tl)
 | 
						|
gen_r_shift_s(rol, rotl_tl)
 | 
						|
gen_r_shift_s(ror, rotr_tl)
 | 
						|
 | 
						|
static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, (code));
 | 
						|
 | 
						|
    /* Stores into R_ZERO are ignored */
 | 
						|
    if (unlikely(instr.c == R_ZERO)) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    TCGv t0 = tcg_temp_new();
 | 
						|
    TCGv t1 = tcg_temp_new();
 | 
						|
    TCGv t2 = tcg_temp_new();
 | 
						|
    TCGv t3 = tcg_temp_new();
 | 
						|
 | 
						|
    tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a));
 | 
						|
    tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b));
 | 
						|
    tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
 | 
						|
    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
 | 
						|
    tcg_gen_and_tl(t2, t2, t3);
 | 
						|
    tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
 | 
						|
    tcg_gen_or_tl(t2, t2, t3);
 | 
						|
    tcg_gen_movi_tl(t3, 0);
 | 
						|
    tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
 | 
						|
    tcg_gen_div_tl(cpu_R[instr.c], t0, t1);
 | 
						|
    tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
 | 
						|
 | 
						|
    tcg_temp_free(t3);
 | 
						|
    tcg_temp_free(t2);
 | 
						|
    tcg_temp_free(t1);
 | 
						|
    tcg_temp_free(t0);
 | 
						|
}
 | 
						|
 | 
						|
static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    R_TYPE(instr, (code));
 | 
						|
 | 
						|
    /* Stores into R_ZERO are ignored */
 | 
						|
    if (unlikely(instr.c == R_ZERO)) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    TCGv t0 = tcg_temp_new();
 | 
						|
    TCGv t1 = tcg_temp_new();
 | 
						|
    TCGv t2 = tcg_const_tl(0);
 | 
						|
    TCGv t3 = tcg_const_tl(1);
 | 
						|
 | 
						|
    tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
 | 
						|
    tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
 | 
						|
    tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
 | 
						|
    tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
 | 
						|
    tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
 | 
						|
 | 
						|
    tcg_temp_free(t3);
 | 
						|
    tcg_temp_free(t2);
 | 
						|
    tcg_temp_free(t1);
 | 
						|
    tcg_temp_free(t0);
 | 
						|
}
 | 
						|
 | 
						|
static const Nios2Instruction r_type_instructions[] = {
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(eret),                                /* eret */
 | 
						|
    INSTRUCTION(roli),                                /* roli */
 | 
						|
    INSTRUCTION(rol),                                 /* rol */
 | 
						|
    INSTRUCTION_NOP(),                                /* flushp */
 | 
						|
    INSTRUCTION(ret),                                 /* ret */
 | 
						|
    INSTRUCTION(nor),                                 /* nor */
 | 
						|
    INSTRUCTION(mulxuu),                              /* mulxuu */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE),          /* cmpge */
 | 
						|
    INSTRUCTION(bret),                                /* bret */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(ror),                                 /* ror */
 | 
						|
    INSTRUCTION_NOP(),                                /* flushi */
 | 
						|
    INSTRUCTION(jmp),                                 /* jmp */
 | 
						|
    INSTRUCTION(and),                                 /* and */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT),          /* cmplt */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(slli),                                /* slli */
 | 
						|
    INSTRUCTION(sll),                                 /* sll */
 | 
						|
    INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(or),                                  /* or */
 | 
						|
    INSTRUCTION(mulxsu),                              /* mulxsu */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE),          /* cmpne */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(srli),                                /* srli */
 | 
						|
    INSTRUCTION(srl),                                 /* srl */
 | 
						|
    INSTRUCTION(nextpc),                              /* nextpc */
 | 
						|
    INSTRUCTION(callr),                               /* callr */
 | 
						|
    INSTRUCTION(xor),                                 /* xor */
 | 
						|
    INSTRUCTION(mulxss),                              /* mulxss */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ),          /* cmpeq */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(divu),                                /* divu */
 | 
						|
    INSTRUCTION(divs),                                /* div */
 | 
						|
    INSTRUCTION(rdctl),                               /* rdctl */
 | 
						|
    INSTRUCTION(mul),                                 /* mul */
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU),         /* cmpgeu */
 | 
						|
    INSTRUCTION_NOP(),                                /* initi */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_excp, EXCP_TRAP),             /* trap */
 | 
						|
    INSTRUCTION(wrctl),                               /* wrctl */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU),         /* cmpltu */
 | 
						|
    INSTRUCTION(add),                                 /* add */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(nop),                                 /* nop */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION(sub),                                 /* sub */
 | 
						|
    INSTRUCTION(srai),                                /* srai */
 | 
						|
    INSTRUCTION(sra),                                 /* sra */
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
    INSTRUCTION_ILLEGAL(),
 | 
						|
};
 | 
						|
 | 
						|
static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags)
 | 
						|
{
 | 
						|
    uint8_t opx;
 | 
						|
    const Nios2Instruction *instr;
 | 
						|
 | 
						|
    opx = get_opxcode(code);
 | 
						|
    if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) {
 | 
						|
        goto illegal_op;
 | 
						|
    }
 | 
						|
 | 
						|
    instr = &r_type_instructions[opx];
 | 
						|
    instr->handler(dc, code, instr->flags);
 | 
						|
 | 
						|
    return;
 | 
						|
 | 
						|
illegal_op:
 | 
						|
    t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 | 
						|
}
 | 
						|
 | 
						|
static const char * const regnames[] = {
 | 
						|
    "zero",       "at",         "r2",         "r3",
 | 
						|
    "r4",         "r5",         "r6",         "r7",
 | 
						|
    "r8",         "r9",         "r10",        "r11",
 | 
						|
    "r12",        "r13",        "r14",        "r15",
 | 
						|
    "r16",        "r17",        "r18",        "r19",
 | 
						|
    "r20",        "r21",        "r22",        "r23",
 | 
						|
    "et",         "bt",         "gp",         "sp",
 | 
						|
    "fp",         "ea",         "ba",         "ra",
 | 
						|
    "status",     "estatus",    "bstatus",    "ienable",
 | 
						|
    "ipending",   "cpuid",      "reserved0",  "exception",
 | 
						|
    "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
 | 
						|
    "badaddr",    "config",     "mpubase",    "mpuacc",
 | 
						|
    "reserved2",  "reserved3",  "reserved4",  "reserved5",
 | 
						|
    "reserved6",  "reserved7",  "reserved8",  "reserved9",
 | 
						|
    "reserved10", "reserved11", "reserved12", "reserved13",
 | 
						|
    "reserved14", "reserved15", "reserved16", "reserved17",
 | 
						|
    "rpc"
 | 
						|
};
 | 
						|
 | 
						|
#include "exec/gen-icount.h"
 | 
						|
 | 
						|
/* generate intermediate code for basic block 'tb'.  */
 | 
						|
static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 | 
						|
{
 | 
						|
    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
						|
    CPUNios2State *env = cs->env_ptr;
 | 
						|
    int page_insns;
 | 
						|
 | 
						|
    dc->mem_idx = cpu_mmu_index(env, false);
 | 
						|
 | 
						|
    /* Bound the number of insns to execute to those left on the page.  */
 | 
						|
    page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
 | 
						|
    dc->base.max_insns = MIN(page_insns, dc->base.max_insns);
 | 
						|
}
 | 
						|
 | 
						|
static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
 | 
						|
{
 | 
						|
    tcg_gen_insn_start(dcbase->pc_next);
 | 
						|
}
 | 
						|
 | 
						|
static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 | 
						|
{
 | 
						|
    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
						|
    CPUNios2State *env = cs->env_ptr;
 | 
						|
    const Nios2Instruction *instr;
 | 
						|
    uint32_t code, pc;
 | 
						|
    uint8_t op;
 | 
						|
 | 
						|
    pc = dc->base.pc_next;
 | 
						|
    dc->pc = pc;
 | 
						|
    dc->base.pc_next = pc + 4;
 | 
						|
 | 
						|
    /* Decode an instruction */
 | 
						|
 | 
						|
#if defined(CONFIG_USER_ONLY)
 | 
						|
    /* FIXME: Is this needed ? */
 | 
						|
    if (pc >= 0x1000 && pc < 0x2000) {
 | 
						|
        t_gen_helper_raise_exception(dc, 0xaa);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    code = cpu_ldl_code(env, pc);
 | 
						|
    op = get_opcode(code);
 | 
						|
 | 
						|
    if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) {
 | 
						|
        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    dc->zero = NULL;
 | 
						|
 | 
						|
    instr = &i_type_instructions[op];
 | 
						|
    instr->handler(dc, code, instr->flags);
 | 
						|
 | 
						|
    if (dc->zero) {
 | 
						|
        tcg_temp_free(dc->zero);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
 | 
						|
{
 | 
						|
    DisasContext *dc = container_of(dcbase, DisasContext, base);
 | 
						|
 | 
						|
    /* Indicate where the next block should start */
 | 
						|
    switch (dc->base.is_jmp) {
 | 
						|
    case DISAS_TOO_MANY:
 | 
						|
    case DISAS_UPDATE:
 | 
						|
        /* Save the current PC back into the CPU register */
 | 
						|
        tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next);
 | 
						|
        tcg_gen_exit_tb(NULL, 0);
 | 
						|
        break;
 | 
						|
 | 
						|
    case DISAS_JUMP:
 | 
						|
        /* The jump will already have updated the PC register */
 | 
						|
        tcg_gen_exit_tb(NULL, 0);
 | 
						|
        break;
 | 
						|
 | 
						|
    case DISAS_NORETURN:
 | 
						|
        /* nothing more to generate */
 | 
						|
        break;
 | 
						|
 | 
						|
    default:
 | 
						|
        g_assert_not_reached();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void nios2_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
 | 
						|
{
 | 
						|
    qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
 | 
						|
    log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
 | 
						|
}
 | 
						|
 | 
						|
static const TranslatorOps nios2_tr_ops = {
 | 
						|
    .init_disas_context = nios2_tr_init_disas_context,
 | 
						|
    .tb_start           = nios2_tr_tb_start,
 | 
						|
    .insn_start         = nios2_tr_insn_start,
 | 
						|
    .translate_insn     = nios2_tr_translate_insn,
 | 
						|
    .tb_stop            = nios2_tr_tb_stop,
 | 
						|
    .disas_log          = nios2_tr_disas_log,
 | 
						|
};
 | 
						|
 | 
						|
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
 | 
						|
{
 | 
						|
    DisasContext dc;
 | 
						|
    translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns);
 | 
						|
}
 | 
						|
 | 
						|
void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 | 
						|
{
 | 
						|
    Nios2CPU *cpu = NIOS2_CPU(cs);
 | 
						|
    CPUNios2State *env = &cpu->env;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (!env) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    qemu_fprintf(f, "IN: PC=%x %s\n",
 | 
						|
                 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
 | 
						|
 | 
						|
    for (i = 0; i < NUM_CORE_REGS; i++) {
 | 
						|
        qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
 | 
						|
        if ((i + 1) % 4 == 0) {
 | 
						|
            qemu_fprintf(f, "\n");
 | 
						|
        }
 | 
						|
    }
 | 
						|
#if !defined(CONFIG_USER_ONLY)
 | 
						|
    qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
 | 
						|
                 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
 | 
						|
                 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
 | 
						|
                 env->mmu.tlbacc_wr);
 | 
						|
#endif
 | 
						|
    qemu_fprintf(f, "\n\n");
 | 
						|
}
 | 
						|
 | 
						|
void nios2_tcg_init(void)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < NUM_CORE_REGS; i++) {
 | 
						|
        cpu_R[i] = tcg_global_mem_new(cpu_env,
 | 
						|
                                      offsetof(CPUNios2State, regs[i]),
 | 
						|
                                      regnames[i]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
 | 
						|
                          target_ulong *data)
 | 
						|
{
 | 
						|
    env->regs[R_PC] = data[0];
 | 
						|
}
 |