This commit is contained in:
Nguyen Anh Quynh
2015-08-21 15:04:50 +08:00
commit 344d016104
499 changed files with 266445 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
#obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += translate.o helper.o cpu.o
obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
obj-$(TARGET_SPARC) += int32_helper.o
obj-$(TARGET_SPARC64) += int64_helper.o
obj-$(TARGET_SPARC64) += vis_helper.o
obj-$(TARGET_SPARC) += unicorn.o
obj-$(TARGET_SPARC64) += unicorn64.o

88
qemu/target-sparc/TODO Normal file
View File

@@ -0,0 +1,88 @@
TODO-list:
CPU common:
- Unimplemented features/bugs:
- Delay slot handling may fail sometimes (branch end of page, delay
slot next page)
- Atomical instructions
- CPU features should match real CPUs (also ASI selection)
- Optimizations/improvements:
- Condition code/branch handling like x86, also for FPU?
- Remove remaining explicit alignment checks
- Global register for regwptr, so that windowed registers can be
accessed directly
- Improve Sparc32plus addressing
- NPC/PC static optimisations (use JUMP_TB when possible)? (Is this
obsolete?)
- Synthetic instructions
- MMU model dependent on CPU model
- Select ASI helper at translation time (on V9 only if known)
- KQemu/KVM support for VM only
- Hardware breakpoint/watchpoint support
- Cache emulation mode
- Reverse-endian pages
- Faster FPU emulation
- Busy loop detection
Sparc32 CPUs:
- Unimplemented features/bugs:
- Sun4/Sun4c MMUs
- Some V8 ASIs
Sparc64 CPUs:
- Unimplemented features/bugs:
- Interrupt handling
- Secondary address space, other MMU functions
- Many V9/UA2005/UA2007 ASIs
- Rest of V9 instructions, missing VIS instructions
- IG/MG/AG vs. UA2007 globals
- Full hypervisor support
- SMP/CMT
- Sun4v CPUs
Sun4:
- To be added
Sun4c:
- A lot of unimplemented features
- Maybe split from Sun4m
Sun4m:
- Unimplemented features/bugs:
- Hardware devices do not match real boards
- Floppy does not work
- CS4231: merge with cs4231a, add DMA
- Add cg6, bwtwo
- Arbitrary resolution support
- PCI for MicroSparc-IIe
- JavaStation machines
- SBus slot probing, FCode ROM support
- SMP probing support
- Interrupt routing does not match real HW
- SuSE 7.3 keyboard sometimes unresponsive
- Gentoo 2004.1 SMP does not work
- SS600MP ledma -> lebuffer
- Type 5 keyboard
- Less fixed hardware choices
- DBRI audio (Am7930)
- BPP parallel
- Diagnostic switch
- ESP PIO mode
Sun4d:
- A lot of unimplemented features:
- SBI
- IO-unit
- Maybe split from Sun4m
Sun4u:
- Unimplemented features/bugs:
- Interrupt controller
- PCI/IOMMU support (Simba, JIO, Tomatillo, Psycho, Schizo, Safari...)
- SMP
- Happy Meal Ethernet, flash, I2C, GPIO
- A lot of real machine types
Sun4v:
- A lot of unimplemented features
- A lot of real machine types

View File

@@ -0,0 +1,485 @@
/*
* Helpers for lazy condition code handling
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/helper-proto.h"
static uint32_t compute_all_flags(CPUSPARCState *env)
{
return env->psr & PSR_ICC;
}
static uint32_t compute_C_flags(CPUSPARCState *env)
{
return env->psr & PSR_CARRY;
}
static inline uint32_t get_NZ_icc(int32_t dst)
{
uint32_t ret = 0;
if (dst == 0) {
ret = PSR_ZERO;
} else if (dst < 0) {
ret = PSR_NEG;
}
return ret;
}
#ifdef TARGET_SPARC64
static uint32_t compute_all_flags_xcc(CPUSPARCState *env)
{
return env->xcc & PSR_ICC;
}
static uint32_t compute_C_flags_xcc(CPUSPARCState *env)
{
return env->xcc & PSR_CARRY;
}
static inline uint32_t get_NZ_xcc(target_long dst)
{
uint32_t ret = 0;
if (!dst) {
ret = PSR_ZERO;
} else if (dst < 0) {
ret = PSR_NEG;
}
return ret;
}
#endif
static inline uint32_t get_V_div_icc(target_ulong src2)
{
uint32_t ret = 0;
if (src2 != 0) {
ret = PSR_OVF;
}
return ret;
}
static uint32_t compute_all_div(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_V_div_icc(CC_SRC2);
return ret;
}
static uint32_t compute_C_div(CPUSPARCState *env)
{
return 0;
}
static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
{
uint32_t ret = 0;
if (dst < src1) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
uint32_t src2)
{
uint32_t ret = 0;
if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
uint32_t src2)
{
uint32_t ret = 0;
if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
ret = PSR_OVF;
}
return ret;
}
#ifdef TARGET_SPARC64
static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
{
uint32_t ret = 0;
if (dst < src1) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
target_ulong src2)
{
uint32_t ret = 0;
if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
target_ulong src2)
{
uint32_t ret = 0;
if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
ret = PSR_OVF;
}
return ret;
}
static uint32_t compute_all_add_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_xcc(CC_DST);
ret |= get_C_add_xcc(CC_DST, CC_SRC);
ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_add_xcc(CPUSPARCState *env)
{
return get_C_add_xcc(CC_DST, CC_SRC);
}
#endif
static uint32_t compute_all_add(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_add_icc(CC_DST, CC_SRC);
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_add(CPUSPARCState *env)
{
return get_C_add_icc(CC_DST, CC_SRC);
}
#ifdef TARGET_SPARC64
static uint32_t compute_all_addx_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_xcc(CC_DST);
ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_addx_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
#endif
static uint32_t compute_all_addx(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_addx(CPUSPARCState *env)
{
uint32_t ret;
ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
{
uint32_t ret = 0;
if ((src1 | src2) & 0x3) {
ret = PSR_OVF;
}
return ret;
}
static uint32_t compute_all_tadd(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_add_icc(CC_DST, CC_SRC);
ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_all_taddtv(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_add_icc(CC_DST, CC_SRC);
return ret;
}
static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
{
uint32_t ret = 0;
if (src1 < src2) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
uint32_t src2)
{
uint32_t ret = 0;
if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
uint32_t src2)
{
uint32_t ret = 0;
if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
ret = PSR_OVF;
}
return ret;
}
#ifdef TARGET_SPARC64
static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
{
uint32_t ret = 0;
if (src1 < src2) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
target_ulong src2)
{
uint32_t ret = 0;
if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
ret = PSR_CARRY;
}
return ret;
}
static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
target_ulong src2)
{
uint32_t ret = 0;
if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
ret = PSR_OVF;
}
return ret;
}
static uint32_t compute_all_sub_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_xcc(CC_DST);
ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_sub_xcc(CPUSPARCState *env)
{
return get_C_sub_xcc(CC_SRC, CC_SRC2);
}
#endif
static uint32_t compute_all_sub(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_sub(CPUSPARCState *env)
{
return get_C_sub_icc(CC_SRC, CC_SRC2);
}
#ifdef TARGET_SPARC64
static uint32_t compute_all_subx_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_xcc(CC_DST);
ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_subx_xcc(CPUSPARCState *env)
{
uint32_t ret;
ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
#endif
static uint32_t compute_all_subx(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_C_subx(CPUSPARCState *env)
{
uint32_t ret;
ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_all_tsub(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_all_tsubtv(CPUSPARCState *env)
{
uint32_t ret;
ret = get_NZ_icc(CC_DST);
ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
return ret;
}
static uint32_t compute_all_logic(CPUSPARCState *env)
{
return get_NZ_icc(CC_DST);
}
static uint32_t compute_C_logic(CPUSPARCState *env)
{
return 0;
}
#ifdef TARGET_SPARC64
static uint32_t compute_all_logic_xcc(CPUSPARCState *env)
{
return get_NZ_xcc(CC_DST);
}
#endif
typedef struct CCTable {
uint32_t (*compute_all)(CPUSPARCState *env); /* return all the flags */
uint32_t (*compute_c)(CPUSPARCState *env); /* return the C flag */
} CCTable;
static const CCTable icc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
[CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
[CC_OP_DIV] = { compute_all_div, compute_C_div },
[CC_OP_ADD] = { compute_all_add, compute_C_add },
[CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
[CC_OP_TADD] = { compute_all_tadd, compute_C_add },
[CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
[CC_OP_SUB] = { compute_all_sub, compute_C_sub },
[CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
[CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
[CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
[CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
};
#ifdef TARGET_SPARC64
static const CCTable xcc_table[CC_OP_NB] = {
/* CC_OP_DYNAMIC should never happen */
[CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
[CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
[CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
[CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
[CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
[CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
[CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
[CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
[CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
};
#endif
void helper_compute_psr(CPUSPARCState *env)
{
uint32_t new_psr;
new_psr = icc_table[CC_OP].compute_all(env);
env->psr = new_psr;
#ifdef TARGET_SPARC64
new_psr = xcc_table[CC_OP].compute_all(env);
env->xcc = new_psr;
#endif
CC_OP = CC_OP_FLAGS;
}
uint32_t helper_compute_C_icc(CPUSPARCState *env)
{
uint32_t ret;
ret = icc_table[CC_OP].compute_c(env) >> PSR_CARRY_SHIFT;
return ret;
}

View File

@@ -0,0 +1,88 @@
/*
* QEMU SPARC CPU
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* 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>
*/
#ifndef QEMU_SPARC_CPU_QOM_H
#define QEMU_SPARC_CPU_QOM_H
#include "qom/cpu.h"
#include "cpu.h"
#ifdef TARGET_SPARC64
#define TYPE_SPARC_CPU "sparc64-cpu"
#else
#define TYPE_SPARC_CPU "sparc-cpu"
#endif
#define SPARC_CPU_CLASS(uc, klass) \
OBJECT_CLASS_CHECK(uc, SPARCCPUClass, (klass), TYPE_SPARC_CPU)
#define SPARC_CPU(uc, obj) \
OBJECT_CHECK(uc, SPARCCPU, (obj), TYPE_SPARC_CPU)
#define SPARC_CPU_GET_CLASS(uc, obj) \
OBJECT_GET_CLASS(uc, SPARCCPUClass, (obj), TYPE_SPARC_CPU)
/**
* SPARCCPUClass:
* @parent_realize: The parent class' realize handler.
* @parent_reset: The parent class' reset handler.
*
* A SPARC CPU model.
*/
typedef struct SPARCCPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
} SPARCCPUClass;
/**
* SPARCCPU:
* @env: #CPUSPARCState
*
* A SPARC CPU.
*/
typedef struct SPARCCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUSPARCState env;
} SPARCCPU;
static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env)
{
return container_of(env, SPARCCPU, env);
}
#define ENV_GET_CPU(e) CPU(sparc_env_get_cpu(e))
#define ENV_OFFSET offsetof(SPARCCPU, env)
void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
fprintf_function cpu_fprintf, int flags);
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu,
vaddr addr, int is_write,
int is_user, uintptr_t retaddr);
#endif

872
qemu/target-sparc/cpu.c Normal file
View File

@@ -0,0 +1,872 @@
/*
* Sparc CPU init helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "hw/sparc/sparc.h"
//#define DEBUG_FEATURES
static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
/* CPUClass::reset() */
static void sparc_cpu_reset(CPUState *s)
{
SPARCCPU *cpu = SPARC_CPU(s->uc, s);
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(s->uc, cpu);
CPUSPARCState *env = &cpu->env;
scc->parent_reset(s);
memset(env, 0, offsetof(CPUSPARCState, version));
tlb_flush(s, 1);
env->cwp = 0;
#ifndef TARGET_SPARC64
env->wim = 1;
#endif
env->regwptr = env->regbase + (env->cwp * 16);
CC_OP = CC_OP_FLAGS;
#if defined(CONFIG_USER_ONLY)
#ifdef TARGET_SPARC64
env->cleanwin = env->nwindows - 2;
env->cansave = env->nwindows - 2;
env->pstate = PS_RMO | PS_PEF | PS_IE;
env->asi = 0x82; /* Primary no-fault */
#endif
#else
#if !defined(TARGET_SPARC64)
env->psret = 0;
env->psrs = 1;
env->psrps = 1;
#endif
#ifdef TARGET_SPARC64
env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
env->tl = env->maxtl;
cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
env->lsu = 0;
#else
env->mmuregs[0] &= ~(MMU_E | MMU_NF);
env->mmuregs[0] |= env->def->mmu_bm;
#endif
env->pc = 0;
env->npc = env->pc + 4;
#endif
env->cache_control = 0;
}
static bool sparc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
if (interrupt_request & CPU_INTERRUPT_HARD) {
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
if (cpu_interrupts_enabled(env) && env->interrupt_index > 0) {
int pil = env->interrupt_index & 0xf;
int type = env->interrupt_index & 0xf0;
if (type != TT_EXTINT || cpu_pil_allowed(env, pil)) {
cs->exception_index = env->interrupt_index;
sparc_cpu_do_interrupt(cs);
return true;
}
}
}
return false;
}
static int cpu_sparc_register(struct uc_struct *uc, SPARCCPU *cpu, const char *cpu_model)
{
CPUClass *cc = CPU_GET_CLASS(uc, cpu);
CPUSPARCState *env = &cpu->env;
char *s = g_strdup(cpu_model);
char *featurestr, *name = strtok(s, ",");
sparc_def_t def1, *def = &def1;
Error *err = NULL;
if (cpu_sparc_find_by_name(def, name) < 0) {
g_free(s);
return -1;
}
env->def = g_new0(sparc_def_t, 1);
memcpy(env->def, def, sizeof(*def));
featurestr = strtok(NULL, ",");
cc->parse_features(CPU(cpu), featurestr, &err);
g_free(s);
if (err) {
//error_report("%s", error_get_pretty(err));
error_free(err);
return -1;
}
env->version = def->iu_version;
env->fsr = def->fpu_version;
env->nwindows = def->nwindows;
#if !defined(TARGET_SPARC64)
env->mmuregs[0] |= def->mmu_version;
cpu_sparc_set_id(env, 0);
env->mxccregs[7] |= def->mxcc_version;
#else
env->mmu_version = def->mmu_version;
env->maxtl = def->maxtl;
env->version |= def->maxtl << 8;
env->version |= def->nwindows - 1;
#endif
return 0;
}
SPARCCPU *cpu_sparc_init(struct uc_struct *uc, const char *cpu_model)
{
SPARCCPU *cpu;
cpu = SPARC_CPU(uc, object_new(uc, TYPE_SPARC_CPU));
if (cpu_sparc_register(uc, cpu, cpu_model) < 0) {
object_unref(uc, OBJECT(cpu));
return NULL;
}
object_property_set_bool(uc, OBJECT(cpu), true, "realized", NULL);
return cpu;
}
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
{
#if !defined(TARGET_SPARC64)
env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
#endif
}
static const sparc_def_t sparc_defs[] = {
#ifdef TARGET_SPARC64
{
.name = "Fujitsu Sparc64",
.iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 4,
.maxtl = 4,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Fujitsu Sparc64 III",
.iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 5,
.maxtl = 4,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Fujitsu Sparc64 IV",
.iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Fujitsu Sparc64 V",
.iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI UltraSparc I",
.iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI UltraSparc II",
.iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI UltraSparc IIi",
.iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI UltraSparc IIe",
.iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc III",
.iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc III Cu",
.iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_3,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc IIIi",
.iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc IV",
.iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_4,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc IV+",
.iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
},
{
.name = "Sun UltraSparc IIIi+",
.iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_3,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Sun UltraSparc T1",
/* defined in sparc_ifu_fdp.v and ctu.h */
.iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_sun4v,
.nwindows = 8,
.maxtl = 6,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
| CPU_FEATURE_GL,
},
{
.name = "Sun UltraSparc T2",
/* defined in tlu_asi_ctl.v and n2_revid_cust.v */
.iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_sun4v,
.nwindows = 8,
.maxtl = 6,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
| CPU_FEATURE_GL,
},
{
.name = "NEC UltraSparc I",
.iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
#else
{
.name = "Fujitsu MB86904",
.iu_version = 0x04 << 24, /* Impl 0, ver 4 */
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0x00ffffc0,
.mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0x00016fff,
.mmu_trcr_mask = 0x00ffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "Fujitsu MB86907",
.iu_version = 0x05 << 24, /* Impl 0, ver 5 */
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0x00016fff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI MicroSparc I",
.iu_version = 0x41000000,
.fpu_version = 4 << 17,
.mmu_version = 0x41000000,
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0x007ffff0,
.mmu_cxr_mask = 0x0000003f,
.mmu_sfsr_mask = 0x00016fff,
.mmu_trcr_mask = 0x0000003f,
.nwindows = 7,
.features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
CPU_FEATURE_FMUL,
},
{
.name = "TI MicroSparc II",
.iu_version = 0x42000000,
.fpu_version = 4 << 17,
.mmu_version = 0x02000000,
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0x00ffffc0,
.mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0x00016fff,
.mmu_trcr_mask = 0x00ffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI MicroSparc IIep",
.iu_version = 0x42000000,
.fpu_version = 4 << 17,
.mmu_version = 0x04000000,
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0x00ffffc0,
.mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0x00016bff,
.mmu_trcr_mask = 0x00ffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc 40", /* STP1020NPGA */
.iu_version = 0x41000000, /* SuperSPARC 2.x */
.fpu_version = 0 << 17,
.mmu_version = 0x00000800, /* SuperSPARC 2.x, no MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc 50", /* STP1020PGA */
.iu_version = 0x40000000, /* SuperSPARC 3.x */
.fpu_version = 0 << 17,
.mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc 51",
.iu_version = 0x40000000, /* SuperSPARC 3.x */
.fpu_version = 0 << 17,
.mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.mxcc_version = 0x00000104,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc 60", /* STP1020APGA */
.iu_version = 0x40000000, /* SuperSPARC 3.x */
.fpu_version = 0 << 17,
.mmu_version = 0x01000800, /* SuperSPARC 3.x, no MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc 61",
.iu_version = 0x44000000, /* SuperSPARC 3.x */
.fpu_version = 0 << 17,
.mmu_version = 0x01000000, /* SuperSPARC 3.x, MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.mxcc_version = 0x00000104,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "TI SuperSparc II",
.iu_version = 0x40000000, /* SuperSPARC II 1.x */
.fpu_version = 0 << 17,
.mmu_version = 0x08000000, /* SuperSPARC II 1.x, MXCC */
.mmu_bm = 0x00002000,
.mmu_ctpr_mask = 0xffffffc0,
.mmu_cxr_mask = 0x0000ffff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.mxcc_version = 0x00000104,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "LEON2",
.iu_version = 0xf2000000,
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0xf2000000,
.mmu_bm = 0x00004000,
.mmu_ctpr_mask = 0x007ffff0,
.mmu_cxr_mask = 0x0000003f,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
},
{
.name = "LEON3",
.iu_version = 0xf3000000,
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
.mmu_version = 0xf3000000,
.mmu_bm = 0x00000000,
.mmu_ctpr_mask = 0xfffffffc,
.mmu_cxr_mask = 0x000000ff,
.mmu_sfsr_mask = 0xffffffff,
.mmu_trcr_mask = 0xffffffff,
.nwindows = 8,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN |
CPU_FEATURE_CASA,
},
#endif
};
static const char * const feature_name[] = {
"float",
"float128",
"swap",
"mul",
"div",
"flush",
"fsqrt",
"fmul",
"vis1",
"vis2",
"fsmuld",
"hypv",
"cmt",
"gl",
};
#if 0
static void print_features(FILE *f, fprintf_function cpu_fprintf,
uint32_t features, const char *prefix)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
if (feature_name[i] && (features & (1 << i))) {
if (prefix) {
(*cpu_fprintf)(f, "%s", prefix);
}
(*cpu_fprintf)(f, "%s ", feature_name[i]);
}
}
}
#endif
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(feature_name); i++) {
if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
*features |= 1 << i;
return;
}
}
//error_report("CPU feature %s not found", flagname);
}
static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *name)
{
unsigned int i;
const sparc_def_t *def = NULL;
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
if (strcasecmp(name, sparc_defs[i].name) == 0) {
def = &sparc_defs[i];
}
}
if (!def) {
return -1;
}
memcpy(cpu_def, def, sizeof(*def));
return 0;
}
static void sparc_cpu_parse_features(CPUState *cs, char *features,
Error **errp)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
sparc_def_t *cpu_def = cpu->env.def;
char *featurestr;
uint32_t plus_features = 0;
uint32_t minus_features = 0;
uint64_t iu_version;
uint32_t fpu_version, mmu_version, nwindows;
featurestr = features ? strtok(features, ",") : NULL;
while (featurestr) {
char *val;
if (featurestr[0] == '+') {
add_flagname_to_bitmaps(featurestr + 1, &plus_features);
} else if (featurestr[0] == '-') {
add_flagname_to_bitmaps(featurestr + 1, &minus_features);
} else if ((val = strchr(featurestr, '='))) {
*val = 0; val++;
if (!strcmp(featurestr, "iu_version")) {
char *err;
iu_version = strtoll(val, &err, 0);
if (!*val || *err) {
error_setg(errp, "bad numerical value %s", val);
return;
}
cpu_def->iu_version = iu_version;
#ifdef DEBUG_FEATURES
fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
#endif
} else if (!strcmp(featurestr, "fpu_version")) {
char *err;
fpu_version = strtol(val, &err, 0);
if (!*val || *err) {
error_setg(errp, "bad numerical value %s", val);
return;
}
cpu_def->fpu_version = fpu_version;
#ifdef DEBUG_FEATURES
fprintf(stderr, "fpu_version %x\n", fpu_version);
#endif
} else if (!strcmp(featurestr, "mmu_version")) {
char *err;
mmu_version = strtol(val, &err, 0);
if (!*val || *err) {
error_setg(errp, "bad numerical value %s", val);
return;
}
cpu_def->mmu_version = mmu_version;
#ifdef DEBUG_FEATURES
fprintf(stderr, "mmu_version %x\n", mmu_version);
#endif
} else if (!strcmp(featurestr, "nwindows")) {
char *err;
nwindows = strtol(val, &err, 0);
if (!*val || *err || nwindows > MAX_NWINDOWS ||
nwindows < MIN_NWINDOWS) {
error_setg(errp, "bad numerical value %s", val);
return;
}
cpu_def->nwindows = nwindows;
#ifdef DEBUG_FEATURES
fprintf(stderr, "nwindows %d\n", nwindows);
#endif
} else {
error_setg(errp, "unrecognized feature %s", featurestr);
return;
}
} else {
error_setg(errp, "feature string `%s' not in format "
"(+feature|-feature|feature=xyz)", featurestr);
return;
}
featurestr = strtok(NULL, ",");
}
cpu_def->features |= plus_features;
cpu_def->features &= ~minus_features;
#ifdef DEBUG_FEATURES
print_features(stderr, fprintf, cpu_def->features, NULL);
#endif
}
#if 0
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
(*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx
" FPU %08x MMU %08x NWINS %d ",
sparc_defs[i].name,
sparc_defs[i].iu_version,
sparc_defs[i].fpu_version,
sparc_defs[i].mmu_version,
sparc_defs[i].nwindows);
print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
~sparc_defs[i].features, "-");
print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
sparc_defs[i].features, "+");
(*cpu_fprintf)(f, "\n");
}
(*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
(*cpu_fprintf)(f, "\n");
(*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
(*cpu_fprintf)(f, "\n");
(*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
"fpu_version mmu_version nwindows\n");
}
static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
uint32_t cc)
{
cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG ? 'N' : '-',
cc & PSR_ZERO ? 'Z' : '-', cc & PSR_OVF ? 'V' : '-',
cc & PSR_CARRY ? 'C' : '-');
}
#ifdef TARGET_SPARC64
#define REGS_PER_LINE 4
#else
#define REGS_PER_LINE 8
#endif
void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
int i, x;
cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
env->npc);
for (i = 0; i < 8; i++) {
if (i % REGS_PER_LINE == 0) {
cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
}
cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
cpu_fprintf(f, "\n");
}
}
for (x = 0; x < 3; x++) {
for (i = 0; i < 8; i++) {
if (i % REGS_PER_LINE == 0) {
cpu_fprintf(f, "%%%c%d-%d: ",
x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
i, i + REGS_PER_LINE - 1);
}
cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
cpu_fprintf(f, "\n");
}
}
}
for (i = 0; i < TARGET_DPREGS; i++) {
if ((i & 3) == 0) {
cpu_fprintf(f, "%%f%02d: ", i * 2);
}
cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll);
if ((i & 3) == 3) {
cpu_fprintf(f, "\n");
}
}
#ifdef TARGET_SPARC64
cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
(unsigned)cpu_get_ccr(env));
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
cpu_fprintf(f, " xcc: ");
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
env->psrpil);
cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
"cleanwin: %d cwp: %d\n",
env->cansave, env->canrestore, env->otherwin, env->wstate,
env->cleanwin, env->nwindows - 1 - env->cwp);
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
#else
cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs ? 'S' : '-',
env->psrps ? 'P' : '-', env->psret ? 'E' : '-',
env->wim);
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
env->fsr, env->y);
#endif
cpu_fprintf(f, "\n");
}
#endif
static void sparc_cpu_set_pc(CPUState *cs, vaddr value)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
cpu->env.pc = value;
cpu->env.npc = value + 4;
}
static void sparc_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
cpu->env.pc = tb->pc;
cpu->env.npc = tb->cs_base;
}
static bool sparc_cpu_has_work(CPUState *cs)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
cpu_interrupts_enabled(env);
}
static void sparc_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **errp)
{
SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(uc, dev);
#if defined(CONFIG_USER_ONLY)
SPARCCPU *cpu = SPARC_CPU(uc, dev);
CPUSPARCState *env = &cpu->env;
if ((env->def->features & CPU_FEATURE_FLOAT)) {
env->def->features |= CPU_FEATURE_FLOAT128;
}
#endif
qemu_init_vcpu(CPU(dev));
scc->parent_realize(uc, dev, errp);
}
static void sparc_cpu_initfn(struct uc_struct *uc, Object *obj, void *opaque)
{
CPUState *cs = CPU(obj);
SPARCCPU *cpu = SPARC_CPU(uc, obj);
CPUSPARCState *env = &cpu->env;
cs->env_ptr = env;
cpu_exec_init(env, opaque);
if (tcg_enabled(uc)) {
gen_intermediate_code_init(env);
}
}
static void sparc_cpu_uninitfn(struct uc_struct *uc, Object *obj, void *opaque)
{
SPARCCPU *cpu = SPARC_CPU(uc, obj);
CPUSPARCState *env = &cpu->env;
g_free(env->def);
}
static void sparc_cpu_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
{
SPARCCPUClass *scc = SPARC_CPU_CLASS(uc, oc);
CPUClass *cc = CPU_CLASS(uc, oc);
DeviceClass *dc = DEVICE_CLASS(uc, oc);
scc->parent_realize = dc->realize;
dc->realize = sparc_cpu_realizefn;
scc->parent_reset = cc->reset;
cc->reset = sparc_cpu_reset;
cc->parse_features = sparc_cpu_parse_features;
cc->has_work = sparc_cpu_has_work;
cc->do_interrupt = sparc_cpu_do_interrupt;
cc->cpu_exec_interrupt = sparc_cpu_exec_interrupt;
//cc->dump_state = sparc_cpu_dump_state;
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
cc->memory_rw_debug = sparc_cpu_memory_rw_debug;
#endif
cc->set_pc = sparc_cpu_set_pc;
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
#ifdef CONFIG_USER_ONLY
cc->handle_mmu_fault = sparc_cpu_handle_mmu_fault;
#else
cc->do_unassigned_access = sparc_cpu_unassigned_access;
cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
#endif
}
void sparc_cpu_register_types(void *opaque)
{
TypeInfo sparc_cpu_type_info = {
.name = TYPE_SPARC_CPU,
.parent = TYPE_CPU,
.instance_userdata = opaque,
.instance_size = sizeof(SPARCCPU),
.instance_init = sparc_cpu_initfn,
.instance_finalize = sparc_cpu_uninitfn,
.abstract = false,
.class_size = sizeof(SPARCCPUClass),
.class_init = sparc_cpu_class_init,
};
//printf(">>> sparc_cpu_register_types\n");
type_register_static(opaque, &sparc_cpu_type_info);
}

759
qemu/target-sparc/cpu.h Normal file
View File

@@ -0,0 +1,759 @@
#ifndef CPU_SPARC_H
#define CPU_SPARC_H
#include "config.h"
#include "qemu-common.h"
#include "qemu/bswap.h"
#define ALIGNED_ONLY
#if !defined(TARGET_SPARC64)
#define TARGET_LONG_BITS 32
#define TARGET_DPREGS 16
#define TARGET_PAGE_BITS 12 /* 4k */
#define TARGET_PHYS_ADDR_SPACE_BITS 36
#define TARGET_VIRT_ADDR_SPACE_BITS 32
#else
#define TARGET_LONG_BITS 64
#define TARGET_DPREGS 32
#define TARGET_PAGE_BITS 13 /* 8k */
#define TARGET_PHYS_ADDR_SPACE_BITS 41
# ifdef TARGET_ABI32
# define TARGET_VIRT_ADDR_SPACE_BITS 32
# else
# define TARGET_VIRT_ADDR_SPACE_BITS 44
# endif
#endif
#define CPUArchState struct CPUSPARCState
#include "exec/cpu-defs.h"
#include "fpu/softfloat.h"
#define TARGET_HAS_ICE 1
#if !defined(TARGET_SPARC64)
#define ELF_MACHINE EM_SPARC
#else
#define ELF_MACHINE EM_SPARCV9
#endif
/*#define EXCP_INTERRUPT 0x100*/
/* trap definitions */
#ifndef TARGET_SPARC64
#define TT_TFAULT 0x01
#define TT_ILL_INSN 0x02
#define TT_PRIV_INSN 0x03
#define TT_NFPU_INSN 0x04
#define TT_WIN_OVF 0x05
#define TT_WIN_UNF 0x06
#define TT_UNALIGNED 0x07
#define TT_FP_EXCP 0x08
#define TT_DFAULT 0x09
#define TT_TOVF 0x0a
#define TT_EXTINT 0x10
#define TT_CODE_ACCESS 0x21
#define TT_UNIMP_FLUSH 0x25
#define TT_DATA_ACCESS 0x29
#define TT_DIV_ZERO 0x2a
#define TT_NCP_INSN 0x24
#define TT_TRAP 0x80
#else
#define TT_POWER_ON_RESET 0x01
#define TT_TFAULT 0x08
#define TT_CODE_ACCESS 0x0a
#define TT_ILL_INSN 0x10
#define TT_UNIMP_FLUSH TT_ILL_INSN
#define TT_PRIV_INSN 0x11
#define TT_NFPU_INSN 0x20
#define TT_FP_EXCP 0x21
#define TT_TOVF 0x23
#define TT_CLRWIN 0x24
#define TT_DIV_ZERO 0x28
#define TT_DFAULT 0x30
#define TT_DATA_ACCESS 0x32
#define TT_UNALIGNED 0x34
#define TT_PRIV_ACT 0x37
#define TT_EXTINT 0x40
#define TT_IVEC 0x60
#define TT_TMISS 0x64
#define TT_DMISS 0x68
#define TT_DPROT 0x6c
#define TT_SPILL 0x80
#define TT_FILL 0xc0
#define TT_WOTHER (1 << 5)
#define TT_TRAP 0x100
#endif
#define PSR_NEG_SHIFT 23
#define PSR_NEG (1 << PSR_NEG_SHIFT)
#define PSR_ZERO_SHIFT 22
#define PSR_ZERO (1 << PSR_ZERO_SHIFT)
#define PSR_OVF_SHIFT 21
#define PSR_OVF (1 << PSR_OVF_SHIFT)
#define PSR_CARRY_SHIFT 20
#define PSR_CARRY (1 << PSR_CARRY_SHIFT)
#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
#if !defined(TARGET_SPARC64)
#define PSR_EF (1<<12)
#define PSR_PIL 0xf00
#define PSR_S (1<<7)
#define PSR_PS (1<<6)
#define PSR_ET (1<<5)
#define PSR_CWP 0x1f
#endif
#define CC_SRC (env->cc_src)
#define CC_SRC2 (env->cc_src2)
#define CC_DST (env->cc_dst)
#define CC_OP (env->cc_op)
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
CC_OP_FLAGS, /* all cc are back in status register */
CC_OP_DIV, /* modify N, Z and V, C = 0*/
CC_OP_ADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_ADDX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TADD, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TADDTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
CC_OP_SUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_SUBX, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TSUB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
CC_OP_TSUBTV, /* modify all flags except V, CC_DST = res, CC_SRC = src1 */
CC_OP_LOGIC, /* modify N and Z, C = V = 0, CC_DST = res */
CC_OP_NB,
};
/* Trap base register */
#define TBR_BASE_MASK 0xfffff000
#if defined(TARGET_SPARC64)
#define PS_TCT (1<<12) /* UA2007, impl.dep. trap on control transfer */
#define PS_IG (1<<11) /* v9, zero on UA2007 */
#define PS_MG (1<<10) /* v9, zero on UA2007 */
#define PS_CLE (1<<9) /* UA2007 */
#define PS_TLE (1<<8) /* UA2007 */
#define PS_RMO (1<<7)
#define PS_RED (1<<5) /* v9, zero on UA2007 */
#define PS_PEF (1<<4) /* enable fpu */
#define PS_AM (1<<3) /* address mask */
#define PS_PRIV (1<<2)
#define PS_IE (1<<1)
#define PS_AG (1<<0) /* v9, zero on UA2007 */
#define FPRS_FEF (1<<2)
#define HS_PRIV (1<<2)
#endif
/* Fcc */
#define FSR_RD1 (1ULL << 31)
#define FSR_RD0 (1ULL << 30)
#define FSR_RD_MASK (FSR_RD1 | FSR_RD0)
#define FSR_RD_NEAREST 0
#define FSR_RD_ZERO FSR_RD0
#define FSR_RD_POS FSR_RD1
#define FSR_RD_NEG (FSR_RD1 | FSR_RD0)
#define FSR_NVM (1ULL << 27)
#define FSR_OFM (1ULL << 26)
#define FSR_UFM (1ULL << 25)
#define FSR_DZM (1ULL << 24)
#define FSR_NXM (1ULL << 23)
#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM)
#define FSR_NVA (1ULL << 9)
#define FSR_OFA (1ULL << 8)
#define FSR_UFA (1ULL << 7)
#define FSR_DZA (1ULL << 6)
#define FSR_NXA (1ULL << 5)
#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
#define FSR_NVC (1ULL << 4)
#define FSR_OFC (1ULL << 3)
#define FSR_UFC (1ULL << 2)
#define FSR_DZC (1ULL << 1)
#define FSR_NXC (1ULL << 0)
#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC)
#define FSR_FTT2 (1ULL << 16)
#define FSR_FTT1 (1ULL << 15)
#define FSR_FTT0 (1ULL << 14)
//gcc warns about constant overflow for ~FSR_FTT_MASK
//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
#ifdef TARGET_SPARC64
#define FSR_FTT_NMASK 0xfffffffffffe3fffULL
#define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL
#define FSR_LDFSR_OLDMASK 0x0000003f000fc000ULL
#define FSR_LDXFSR_MASK 0x0000003fcfc00fffULL
#define FSR_LDXFSR_OLDMASK 0x00000000000fc000ULL
#else
#define FSR_FTT_NMASK 0xfffe3fffULL
#define FSR_FTT_CEXC_NMASK 0xfffe3fe0ULL
#define FSR_LDFSR_OLDMASK 0x000fc000ULL
#endif
#define FSR_LDFSR_MASK 0xcfc00fffULL
#define FSR_FTT_IEEE_EXCP (1ULL << 14)
#define FSR_FTT_UNIMPFPOP (3ULL << 14)
#define FSR_FTT_SEQ_ERROR (4ULL << 14)
#define FSR_FTT_INVAL_FPR (6ULL << 14)
#define FSR_FCC1_SHIFT 11
#define FSR_FCC1 (1ULL << FSR_FCC1_SHIFT)
#define FSR_FCC0_SHIFT 10
#define FSR_FCC0 (1ULL << FSR_FCC0_SHIFT)
/* MMU */
#define MMU_E (1<<0)
#define MMU_NF (1<<1)
#define PTE_ENTRYTYPE_MASK 3
#define PTE_ACCESS_MASK 0x1c
#define PTE_ACCESS_SHIFT 2
#define PTE_PPN_SHIFT 7
#define PTE_ADDR_MASK 0xffffff00
#define PG_ACCESSED_BIT 5
#define PG_MODIFIED_BIT 6
#define PG_CACHE_BIT 7
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT)
#define PG_CACHE_MASK (1 << PG_CACHE_BIT)
/* 3 <= NWINDOWS <= 32. */
#define MIN_NWINDOWS 3
#define MAX_NWINDOWS 32
#if !defined(TARGET_SPARC64)
#define NB_MMU_MODES 2
#else
#define NB_MMU_MODES 6
typedef struct trap_state {
uint64_t tpc;
uint64_t tnpc;
uint64_t tstate;
uint32_t tt;
} trap_state;
#endif
typedef struct sparc_def_t {
const char *name;
target_ulong iu_version;
uint32_t fpu_version;
uint32_t mmu_version;
uint32_t mmu_bm;
uint32_t mmu_ctpr_mask;
uint32_t mmu_cxr_mask;
uint32_t mmu_sfsr_mask;
uint32_t mmu_trcr_mask;
uint32_t mxcc_version;
uint32_t features;
uint32_t nwindows;
uint32_t maxtl;
} sparc_def_t;
#define CPU_FEATURE_FLOAT (1 << 0)
#define CPU_FEATURE_FLOAT128 (1 << 1)
#define CPU_FEATURE_SWAP (1 << 2)
#define CPU_FEATURE_MUL (1 << 3)
#define CPU_FEATURE_DIV (1 << 4)
#define CPU_FEATURE_FLUSH (1 << 5)
#define CPU_FEATURE_FSQRT (1 << 6)
#define CPU_FEATURE_FMUL (1 << 7)
#define CPU_FEATURE_VIS1 (1 << 8)
#define CPU_FEATURE_VIS2 (1 << 9)
#define CPU_FEATURE_FSMULD (1 << 10)
#define CPU_FEATURE_HYPV (1 << 11)
#define CPU_FEATURE_CMT (1 << 12)
#define CPU_FEATURE_GL (1 << 13)
#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
#define CPU_FEATURE_ASR17 (1 << 15)
#define CPU_FEATURE_CACHE_CTRL (1 << 16)
#define CPU_FEATURE_POWERDOWN (1 << 17)
#define CPU_FEATURE_CASA (1 << 18)
#ifndef TARGET_SPARC64
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
CPU_FEATURE_FMUL | CPU_FEATURE_FSMULD)
#else
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 | \
CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD | \
CPU_FEATURE_CASA)
enum {
mmu_us_12, // Ultrasparc < III (64 entry TLB)
mmu_us_3, // Ultrasparc III (512 entry TLB)
mmu_us_4, // Ultrasparc IV (several TLBs, 32 and 256MB pages)
mmu_sun4v, // T1, T2
};
#endif
#define TTE_VALID_BIT (1ULL << 63)
#define TTE_NFO_BIT (1ULL << 60)
#define TTE_USED_BIT (1ULL << 41)
#define TTE_LOCKED_BIT (1ULL << 6)
#define TTE_SIDEEFFECT_BIT (1ULL << 3)
#define TTE_PRIV_BIT (1ULL << 2)
#define TTE_W_OK_BIT (1ULL << 1)
#define TTE_GLOBAL_BIT (1ULL << 0)
#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT)
#define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT)
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT)
#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
#define TTE_IS_PRIV(tte) ((tte) & TTE_PRIV_BIT)
#define TTE_IS_W_OK(tte) ((tte) & TTE_W_OK_BIT)
#define TTE_IS_GLOBAL(tte) ((tte) & TTE_GLOBAL_BIT)
#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT)
#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
#define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL)
#define TTE_PA(tte) ((tte) & 0x1ffffffe000ULL)
#define SFSR_NF_BIT (1ULL << 24) /* JPS1 NoFault */
#define SFSR_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */
#define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */
#define SFSR_FT_VA_DMMU_BIT (1ULL << 12) /* USIIi VA out of range (DMMU) */
#define SFSR_FT_NFO_BIT (1ULL << 11) /* NFO page access */
#define SFSR_FT_ILL_BIT (1ULL << 10) /* illegal LDA/STA ASI */
#define SFSR_FT_ATOMIC_BIT (1ULL << 9) /* atomic op on noncacheable area */
#define SFSR_FT_NF_E_BIT (1ULL << 8) /* NF access on side effect area */
#define SFSR_FT_PRIV_BIT (1ULL << 7) /* privilege violation */
#define SFSR_PR_BIT (1ULL << 3) /* privilege mode */
#define SFSR_WRITE_BIT (1ULL << 2) /* write access mode */
#define SFSR_OW_BIT (1ULL << 1) /* status overwritten */
#define SFSR_VALID_BIT (1ULL << 0) /* status valid */
#define SFSR_ASI_SHIFT 16 /* 23:16 ASI value */
#define SFSR_ASI_MASK (0xffULL << SFSR_ASI_SHIFT)
#define SFSR_CT_PRIMARY (0ULL << 4) /* 5:4 context type */
#define SFSR_CT_SECONDARY (1ULL << 4)
#define SFSR_CT_NUCLEUS (2ULL << 4)
#define SFSR_CT_NOTRANS (3ULL << 4)
#define SFSR_CT_MASK (3ULL << 4)
/* Leon3 cache control */
/* Cache control: emulate the behavior of cache control registers but without
any effect on the emulated */
#define CACHE_STATE_MASK 0x3
#define CACHE_DISABLED 0x0
#define CACHE_FROZEN 0x1
#define CACHE_ENABLED 0x3
/* Cache Control register fields */
#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
typedef struct SparcTLBEntry {
uint64_t tag;
uint64_t tte;
} SparcTLBEntry;
struct CPUTimer
{
const char *name;
uint32_t frequency;
uint32_t disabled;
uint64_t disabled_mask;
int64_t clock_offset;
QEMUTimer *qtimer;
};
typedef struct CPUTimer CPUTimer;
struct QEMUFile;
void cpu_put_timer(struct QEMUFile *f, CPUTimer *s);
void cpu_get_timer(struct QEMUFile *f, CPUTimer *s);
typedef struct CPUSPARCState CPUSPARCState;
struct CPUSPARCState {
target_ulong gregs[8]; /* general registers */
target_ulong *regwptr; /* pointer to current register window */
target_ulong pc; /* program counter */
target_ulong npc; /* next program counter */
target_ulong y; /* multiply/divide register */
/* emulator internal flags handling */
target_ulong cc_src, cc_src2;
target_ulong cc_dst;
uint32_t cc_op;
target_ulong cond; /* conditional branch result (XXX: save it in a
temporary register when possible) */
uint32_t psr; /* processor state register */
target_ulong fsr; /* FPU state register */
CPU_DoubleU fpr[TARGET_DPREGS]; /* floating point registers */
uint32_t cwp; /* index of current register window (extracted
from PSR) */
#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
uint32_t wim; /* window invalid mask */
#endif
target_ulong tbr; /* trap base register */
#if !defined(TARGET_SPARC64)
int psrs; /* supervisor mode (extracted from PSR) */
int psrps; /* previous supervisor mode */
int psret; /* enable traps */
#endif
uint32_t psrpil; /* interrupt blocking level */
uint32_t pil_in; /* incoming interrupt level bitmap */
#if !defined(TARGET_SPARC64)
int psref; /* enable fpu */
#endif
int interrupt_index;
/* NOTE: we allow 8 more registers to handle wrapping */
target_ulong regbase[MAX_NWINDOWS * 16 + 8];
CPU_COMMON
/* Fields from here on are preserved across CPU reset. */
target_ulong version;
uint32_t nwindows;
/* MMU regs */
#if defined(TARGET_SPARC64)
uint64_t lsu;
#define DMMU_E 0x8
#define IMMU_E 0x4
//typedef struct SparcMMU
union {
uint64_t immuregs[16];
struct {
uint64_t tsb_tag_target;
uint64_t unused_mmu_primary_context; // use DMMU
uint64_t unused_mmu_secondary_context; // use DMMU
uint64_t sfsr;
uint64_t sfar;
uint64_t tsb;
uint64_t tag_access;
} immu;
};
union {
uint64_t dmmuregs[16];
struct {
uint64_t tsb_tag_target;
uint64_t mmu_primary_context;
uint64_t mmu_secondary_context;
uint64_t sfsr;
uint64_t sfar;
uint64_t tsb;
uint64_t tag_access;
} dmmu;
};
SparcTLBEntry itlb[64];
SparcTLBEntry dtlb[64];
uint32_t mmu_version;
#else
uint32_t mmuregs[32];
uint64_t mxccdata[4];
uint64_t mxccregs[8];
uint32_t mmubpctrv, mmubpctrc, mmubpctrs;
uint64_t mmubpaction;
uint64_t mmubpregs[4];
uint64_t prom_addr;
#endif
/* temporary float registers */
float128 qt0, qt1;
float_status fp_status;
#if defined(TARGET_SPARC64)
#define MAXTL_MAX 8
#define MAXTL_MASK (MAXTL_MAX - 1)
trap_state ts[MAXTL_MAX];
uint32_t xcc; /* Extended integer condition codes */
uint32_t asi;
uint32_t pstate;
uint32_t tl;
uint32_t maxtl;
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
uint64_t agregs[8]; /* alternate general registers */
uint64_t bgregs[8]; /* backup for normal global registers */
uint64_t igregs[8]; /* interrupt general registers */
uint64_t mgregs[8]; /* mmu general registers */
uint64_t fprs;
uint64_t tick_cmpr, stick_cmpr;
CPUTimer *tick, *stick;
#define TICK_NPT_MASK 0x8000000000000000ULL
#define TICK_INT_DIS 0x8000000000000000ULL
uint64_t gsr;
uint32_t gl; // UA2005
/* UA 2005 hyperprivileged registers */
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
CPUTimer *hstick; // UA 2005
/* Interrupt vector registers */
uint64_t ivec_status;
uint64_t ivec_data[3];
uint32_t softint;
#define SOFTINT_TIMER 1
#define SOFTINT_STIMER (1 << 16)
#define SOFTINT_INTRMASK (0xFFFE)
#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
#endif
sparc_def_t *def;
//void *irq_manager;
//void (*qemu_irq_ack)(CPUSPARCState *env, void *irq_manager, int intno);
/* Leon3 cache control */
uint32_t cache_control;
// Unicorn engine
struct uc_struct *uc;
};
#include "cpu-qom.h"
#ifndef NO_CPU_IO_DEFS
/* cpu_init.c */
SPARCCPU *cpu_sparc_init(struct uc_struct *uc, const char *cpu_model);
void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
/* mmu_helper.c */
int sparc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
int mmu_idx);
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env);
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
int sparc_cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
uint8_t *buf, int len, bool is_write);
#endif
/* translate.c */
void gen_intermediate_code_init(CPUSPARCState *env);
/* cpu-exec.c */
int cpu_sparc_exec(struct uc_struct *uc, CPUSPARCState *s);
/* win_helper.c */
target_ulong cpu_get_psr(CPUSPARCState *env1);
void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
#ifdef TARGET_SPARC64
target_ulong cpu_get_ccr(CPUSPARCState *env1);
void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
target_ulong cpu_get_cwp64(CPUSPARCState *env1);
void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
#endif
int cpu_cwp_inc(CPUSPARCState *env1, int cwp);
int cpu_cwp_dec(CPUSPARCState *env1, int cwp);
void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
/* int_helper.c */
void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno);
/* sun4m.c, sun4u.c */
void cpu_check_irqs(CPUSPARCState *env);
/* leon3.c */
void leon3_irq_ack(void *irq_manager, int intno);
#if defined (TARGET_SPARC64)
static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
{
return (x & mask) == (y & mask);
}
#define MMU_CONTEXT_BITS 13
#define MMU_CONTEXT_MASK ((1 << MMU_CONTEXT_BITS) - 1)
static inline int tlb_compare_context(const SparcTLBEntry *tlb,
uint64_t context)
{
return compare_masked(context, tlb->tag, MMU_CONTEXT_MASK);
}
#endif
#endif
/* cpu-exec.c */
#if !defined(CONFIG_USER_ONLY)
void sparc_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
bool is_write, bool is_exec, int is_asi,
unsigned size);
#if defined(TARGET_SPARC64)
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int mmu_idx);
#endif
#endif
int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
#ifndef NO_CPU_IO_DEFS
static inline CPUSPARCState *cpu_init(struct uc_struct *uc, const char *cpu_model)
{
SPARCCPU *cpu = cpu_sparc_init(uc, cpu_model);
if (cpu == NULL) {
return NULL;
}
return &cpu->env;
}
#endif
#define cpu_exec cpu_sparc_exec
#define cpu_gen_code cpu_sparc_gen_code
#define cpu_signal_handler cpu_sparc_signal_handler
#define cpu_list sparc_cpu_list
#define CPU_SAVE_VERSION 7
/* MMU modes definitions */
#if defined (TARGET_SPARC64)
#define MMU_USER_IDX 0
#define MMU_MODE0_SUFFIX _user
#define MMU_USER_SECONDARY_IDX 1
#define MMU_MODE1_SUFFIX _user_secondary
#define MMU_KERNEL_IDX 2
#define MMU_MODE2_SUFFIX _kernel
#define MMU_KERNEL_SECONDARY_IDX 3
#define MMU_MODE3_SUFFIX _kernel_secondary
#define MMU_NUCLEUS_IDX 4
#define MMU_MODE4_SUFFIX _nucleus
#define MMU_HYPV_IDX 5
#define MMU_MODE5_SUFFIX _hypv
#else
#define MMU_USER_IDX 0
#define MMU_MODE0_SUFFIX _user
#define MMU_KERNEL_IDX 1
#define MMU_MODE1_SUFFIX _kernel
#endif
#if defined (TARGET_SPARC64)
static inline int cpu_has_hypervisor(CPUSPARCState *env1)
{
return env1->def->features & CPU_FEATURE_HYPV;
}
static inline int cpu_hypervisor_mode(CPUSPARCState *env1)
{
return cpu_has_hypervisor(env1) && (env1->hpstate & HS_PRIV);
}
static inline int cpu_supervisor_mode(CPUSPARCState *env1)
{
return env1->pstate & PS_PRIV;
}
#endif
static inline int cpu_mmu_index(CPUSPARCState *env1)
{
#if defined(CONFIG_USER_ONLY)
return MMU_USER_IDX;
#elif !defined(TARGET_SPARC64)
return env1->psrs;
#else
if (env1->tl > 0) {
return MMU_NUCLEUS_IDX;
} else if (cpu_hypervisor_mode(env1)) {
return MMU_HYPV_IDX;
} else if (cpu_supervisor_mode(env1)) {
return MMU_KERNEL_IDX;
} else {
return MMU_USER_IDX;
}
#endif
}
static inline int cpu_interrupts_enabled(CPUSPARCState *env1)
{
#if !defined (TARGET_SPARC64)
if (env1->psret != 0)
return 1;
#else
if (env1->pstate & PS_IE)
return 1;
#endif
return 0;
}
static inline int cpu_pil_allowed(CPUSPARCState *env1, int pil)
{
#if !defined(TARGET_SPARC64)
/* level 15 is non-maskable on sparc v8 */
return pil == 15 || pil > env1->psrpil;
#else
return pil > env1->psrpil;
#endif
}
#include "exec/cpu-all.h"
#ifdef TARGET_SPARC64
/* sun4u.c */
void cpu_tick_set_count(CPUTimer *timer, uint64_t count);
uint64_t cpu_tick_get_count(CPUTimer *timer);
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
trap_state* cpu_tsptr(CPUSPARCState* env);
#endif
#define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5)
static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
*pc = env->pc;
*cs_base = env->npc;
#ifdef TARGET_SPARC64
// AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
*flags = (env->pstate & PS_PRIV) /* 2 */
| ((env->lsu & (DMMU_E | IMMU_E)) >> 2) /* 1, 0 */
| ((env->tl & 0xff) << 8)
| (env->dmmu.mmu_primary_context << 16); /* 16... */
if (env->pstate & PS_AM) {
*flags |= TB_FLAG_AM_ENABLED;
}
if ((env->def->features & CPU_FEATURE_FLOAT) && (env->pstate & PS_PEF)
&& (env->fprs & FPRS_FEF)) {
*flags |= TB_FLAG_FPU_ENABLED;
}
#else
// FPU enable . Supervisor
*flags = env->psrs;
if ((env->def->features & CPU_FEATURE_FLOAT) && env->psref) {
*flags |= TB_FLAG_FPU_ENABLED;
}
#endif
}
static inline bool tb_fpu_enabled(int tb_flags)
{
#if defined(CONFIG_USER_ONLY)
return true;
#else
return tb_flags & TB_FLAG_FPU_ENABLED;
#endif
}
static inline bool tb_am_enabled(int tb_flags)
{
#ifndef TARGET_SPARC64
return false;
#else
return tb_flags & TB_FLAG_AM_ENABLED;
#endif
}
#include "exec/exec-all.h"
#endif

View File

@@ -0,0 +1,467 @@
/*
* FPU op helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/helper-proto.h"
#define QT0 (env->qt0)
#define QT1 (env->qt1)
static void check_ieee_exceptions(CPUSPARCState *env)
{
target_ulong status;
status = get_float_exception_flags(&env->fp_status);
if (status) {
/* Copy IEEE 754 flags into FSR */
if (status & float_flag_invalid) {
env->fsr |= FSR_NVC;
}
if (status & float_flag_overflow) {
env->fsr |= FSR_OFC;
}
if (status & float_flag_underflow) {
env->fsr |= FSR_UFC;
}
if (status & float_flag_divbyzero) {
env->fsr |= FSR_DZC;
}
if (status & float_flag_inexact) {
env->fsr |= FSR_NXC;
}
if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
/* Unmasked exception, generate a trap */
env->fsr |= FSR_FTT_IEEE_EXCP;
helper_raise_exception(env, TT_FP_EXCP);
} else {
/* Accumulate exceptions */
env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
}
}
}
static inline void clear_float_exceptions(CPUSPARCState *env)
{
set_float_exception_flags(0, &env->fp_status);
}
#define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env)
#define F_BINOP(name) \
float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \
float32 src2) \
{ \
float32 ret; \
clear_float_exceptions(env); \
ret = float32_ ## name (src1, src2, &env->fp_status); \
check_ieee_exceptions(env); \
return ret; \
} \
float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\
float64 src2) \
{ \
float64 ret; \
clear_float_exceptions(env); \
ret = float64_ ## name (src1, src2, &env->fp_status); \
check_ieee_exceptions(env); \
return ret; \
} \
F_HELPER(name, q) \
{ \
clear_float_exceptions(env); \
QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
check_ieee_exceptions(env); \
}
F_BINOP(add);
F_BINOP(sub);
F_BINOP(mul);
F_BINOP(div);
#undef F_BINOP
float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
{
float64 ret;
clear_float_exceptions(env);
ret = float64_mul(float32_to_float64(src1, &env->fp_status),
float32_to_float64(src2, &env->fp_status),
&env->fp_status);
check_ieee_exceptions(env);
return ret;
}
void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
{
clear_float_exceptions(env);
QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
float64_to_float128(src2, &env->fp_status),
&env->fp_status);
check_ieee_exceptions(env);
}
float32 helper_fnegs(float32 src)
{
return float32_chs(src);
}
#ifdef TARGET_SPARC64
float64 helper_fnegd(float64 src)
{
return float64_chs(src);
}
F_HELPER(neg, q)
{
QT0 = float128_chs(QT1);
}
#endif
/* Integer to float conversion. */
float32 helper_fitos(CPUSPARCState *env, int32_t src)
{
/* Inexact error possible converting int to float. */
float32 ret;
clear_float_exceptions(env);
ret = int32_to_float32(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
float64 helper_fitod(CPUSPARCState *env, int32_t src)
{
/* No possible exceptions converting int to double. */
return int32_to_float64(src, &env->fp_status);
}
void helper_fitoq(CPUSPARCState *env, int32_t src)
{
/* No possible exceptions converting int to long double. */
QT0 = int32_to_float128(src, &env->fp_status);
}
#ifdef TARGET_SPARC64
float32 helper_fxtos(CPUSPARCState *env, int64_t src)
{
float32 ret;
clear_float_exceptions(env);
ret = int64_to_float32(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
float64 helper_fxtod(CPUSPARCState *env, int64_t src)
{
float64 ret;
clear_float_exceptions(env);
ret = int64_to_float64(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
void helper_fxtoq(CPUSPARCState *env, int64_t src)
{
/* No possible exceptions converting long long to long double. */
QT0 = int64_to_float128(src, &env->fp_status);
}
#endif
#undef F_HELPER
/* floating point conversion */
float32 helper_fdtos(CPUSPARCState *env, float64 src)
{
float32 ret;
clear_float_exceptions(env);
ret = float64_to_float32(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
float64 helper_fstod(CPUSPARCState *env, float32 src)
{
float64 ret;
clear_float_exceptions(env);
ret = float32_to_float64(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
float32 helper_fqtos(CPUSPARCState *env)
{
float32 ret;
clear_float_exceptions(env);
ret = float128_to_float32(QT1, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
void helper_fstoq(CPUSPARCState *env, float32 src)
{
clear_float_exceptions(env);
QT0 = float32_to_float128(src, &env->fp_status);
check_ieee_exceptions(env);
}
float64 helper_fqtod(CPUSPARCState *env)
{
float64 ret;
clear_float_exceptions(env);
ret = float128_to_float64(QT1, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
void helper_fdtoq(CPUSPARCState *env, float64 src)
{
clear_float_exceptions(env);
QT0 = float64_to_float128(src, &env->fp_status);
check_ieee_exceptions(env);
}
/* Float to integer conversion. */
int32_t helper_fstoi(CPUSPARCState *env, float32 src)
{
int32_t ret;
clear_float_exceptions(env);
ret = float32_to_int32_round_to_zero(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
{
int32_t ret;
clear_float_exceptions(env);
ret = float64_to_int32_round_to_zero(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
int32_t helper_fqtoi(CPUSPARCState *env)
{
int32_t ret;
clear_float_exceptions(env);
ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
#ifdef TARGET_SPARC64
int64_t helper_fstox(CPUSPARCState *env, float32 src)
{
int64_t ret;
clear_float_exceptions(env);
ret = float32_to_int64_round_to_zero(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
int64_t helper_fdtox(CPUSPARCState *env, float64 src)
{
int64_t ret;
clear_float_exceptions(env);
ret = float64_to_int64_round_to_zero(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
int64_t helper_fqtox(CPUSPARCState *env)
{
int64_t ret;
clear_float_exceptions(env);
ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
#endif
float32 helper_fabss(float32 src)
{
return float32_abs(src);
}
#ifdef TARGET_SPARC64
float64 helper_fabsd(float64 src)
{
return float64_abs(src);
}
void helper_fabsq(CPUSPARCState *env)
{
QT0 = float128_abs(QT1);
}
#endif
float32 helper_fsqrts(CPUSPARCState *env, float32 src)
{
float32 ret;
clear_float_exceptions(env);
ret = float32_sqrt(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
{
float64 ret;
clear_float_exceptions(env);
ret = float64_sqrt(src, &env->fp_status);
check_ieee_exceptions(env);
return ret;
}
void helper_fsqrtq(CPUSPARCState *env)
{
clear_float_exceptions(env);
QT0 = float128_sqrt(QT1, &env->fp_status);
check_ieee_exceptions(env);
}
#define GEN_FCMP(name, size, reg1, reg2, FS, E) \
void glue(helper_, name) (CPUSPARCState *env) \
{ \
int ret; \
clear_float_exceptions(env); \
if (E) { \
ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \
} else { \
ret = glue(size, _compare_quiet)(reg1, reg2, \
&env->fp_status); \
} \
check_ieee_exceptions(env); \
switch (ret) { \
case float_relation_unordered: \
env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
env->fsr |= FSR_NVA; \
break; \
case float_relation_less: \
env->fsr &= ~(FSR_FCC1) << FS; \
env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
env->fsr &= ~(FSR_FCC0) << FS; \
env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
break; \
} \
}
#define GEN_FCMP_T(name, size, FS, E) \
void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \
{ \
int ret; \
clear_float_exceptions(env); \
if (E) { \
ret = glue(size, _compare)(src1, src2, &env->fp_status); \
} else { \
ret = glue(size, _compare_quiet)(src1, src2, \
&env->fp_status); \
} \
check_ieee_exceptions(env); \
switch (ret) { \
case float_relation_unordered: \
env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
break; \
case float_relation_less: \
env->fsr &= ~(FSR_FCC1 << FS); \
env->fsr |= FSR_FCC0 << FS; \
break; \
case float_relation_greater: \
env->fsr &= ~(FSR_FCC0 << FS); \
env->fsr |= FSR_FCC1 << FS; \
break; \
default: \
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
break; \
} \
}
GEN_FCMP_T(fcmps, float32, 0, 0);
GEN_FCMP_T(fcmpd, float64, 0, 0);
GEN_FCMP_T(fcmpes, float32, 0, 1);
GEN_FCMP_T(fcmped, float64, 0, 1);
GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
#ifdef TARGET_SPARC64
GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
#endif
#undef GEN_FCMP_T
#undef GEN_FCMP
static inline void set_fsr(CPUSPARCState *env)
{
int rnd_mode;
switch (env->fsr & FSR_RD_MASK) {
case FSR_RD_NEAREST:
rnd_mode = float_round_nearest_even;
break;
default:
case FSR_RD_ZERO:
rnd_mode = float_round_to_zero;
break;
case FSR_RD_POS:
rnd_mode = float_round_up;
break;
case FSR_RD_NEG:
rnd_mode = float_round_down;
break;
}
set_float_rounding_mode(rnd_mode, &env->fp_status);
}
void helper_ldfsr(CPUSPARCState *env, uint32_t new_fsr)
{
env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
set_fsr(env);
}
#ifdef TARGET_SPARC64
void helper_ldxfsr(CPUSPARCState *env, uint64_t new_fsr)
{
env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
set_fsr(env);
}
#endif

208
qemu/target-sparc/gdbstub.c Normal file
View File

@@ -0,0 +1,208 @@
/*
* SPARC gdb server stub
*
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2013 SUSE LINUX Products GmbH
*
* 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 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/>.
*/
#include "config.h"
#include "qemu-common.h"
#include "exec/gdbstub.h"
#ifdef TARGET_ABI32
#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
#else
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
#endif
int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
if (n < 8) {
/* g0..g7 */
return gdb_get_rega(mem_buf, env->gregs[n]);
}
if (n < 32) {
/* register window */
return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
}
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
if (n < 64) {
/* fprs */
if (n & 1) {
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
} else {
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
}
}
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
switch (n) {
case 64:
return gdb_get_rega(mem_buf, env->y);
case 65:
return gdb_get_rega(mem_buf, cpu_get_psr(env));
case 66:
return gdb_get_rega(mem_buf, env->wim);
case 67:
return gdb_get_rega(mem_buf, env->tbr);
case 68:
return gdb_get_rega(mem_buf, env->pc);
case 69:
return gdb_get_rega(mem_buf, env->npc);
case 70:
return gdb_get_rega(mem_buf, env->fsr);
case 71:
return gdb_get_rega(mem_buf, 0); /* csr */
default:
return gdb_get_rega(mem_buf, 0);
}
#else
if (n < 64) {
/* f0-f31 */
if (n & 1) {
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
} else {
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
}
}
if (n < 80) {
/* f32-f62 (double width, even numbers only) */
return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll);
}
switch (n) {
case 80:
return gdb_get_regl(mem_buf, env->pc);
case 81:
return gdb_get_regl(mem_buf, env->npc);
case 82:
return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
((env->asi & 0xff) << 24) |
((env->pstate & 0xfff) << 8) |
cpu_get_cwp64(env));
case 83:
return gdb_get_regl(mem_buf, env->fsr);
case 84:
return gdb_get_regl(mem_buf, env->fprs);
case 85:
return gdb_get_regl(mem_buf, env->y);
}
#endif
return 0;
}
int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
#if defined(TARGET_ABI32)
abi_ulong tmp;
tmp = ldl_p(mem_buf);
#else
target_ulong tmp;
tmp = ldtul_p(mem_buf);
#endif
if (n < 8) {
/* g0..g7 */
env->gregs[n] = tmp;
} else if (n < 32) {
/* register window */
env->regwptr[n - 8] = tmp;
}
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
else if (n < 64) {
/* fprs */
/* f0-f31 */
if (n & 1) {
env->fpr[(n - 32) / 2].l.lower = tmp;
} else {
env->fpr[(n - 32) / 2].l.upper = tmp;
}
} else {
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
switch (n) {
case 64:
env->y = tmp;
break;
case 65:
cpu_put_psr(env, tmp);
break;
case 66:
env->wim = tmp;
break;
case 67:
env->tbr = tmp;
break;
case 68:
env->pc = tmp;
break;
case 69:
env->npc = tmp;
break;
case 70:
env->fsr = tmp;
break;
default:
return 0;
}
}
return 4;
#else
else if (n < 64) {
/* f0-f31 */
tmp = ldl_p(mem_buf);
if (n & 1) {
env->fpr[(n - 32) / 2].l.lower = tmp;
} else {
env->fpr[(n - 32) / 2].l.upper = tmp;
}
return 4;
} else if (n < 80) {
/* f32-f62 (double width, even numbers only) */
env->fpr[(n - 32) / 2].ll = tmp;
} else {
switch (n) {
case 80:
env->pc = tmp;
break;
case 81:
env->npc = tmp;
break;
case 82:
cpu_put_ccr(env, tmp >> 32);
env->asi = (tmp >> 24) & 0xff;
env->pstate = (tmp >> 8) & 0xfff;
cpu_put_cwp64(env, tmp & 0xff);
break;
case 83:
env->fsr = tmp;
break;
case 84:
env->fprs = tmp;
break;
case 85:
env->y = tmp;
break;
default:
return 0;
}
}
return 8;
#endif
}

255
qemu/target-sparc/helper.c Normal file
View File

@@ -0,0 +1,255 @@
/*
* Misc Sparc helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "sysemu/sysemu.h"
void helper_raise_exception(CPUSPARCState *env, int tt)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
cs->exception_index = tt;
cpu_loop_exit(cs);
}
void helper_debug(CPUSPARCState *env)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
cs->exception_index = EXCP_DEBUG;
cpu_loop_exit(cs);
}
#ifdef TARGET_SPARC64
target_ulong helper_popc(target_ulong val)
{
return ctpop64(val);
}
void helper_tick_set_count(void *opaque, uint64_t count)
{
#if !defined(CONFIG_USER_ONLY)
// cpu_tick_set_count(opaque, count);
#endif
}
uint64_t helper_tick_get_count(void *opaque)
{
#if !defined(CONFIG_USER_ONLY)
return 0; //cpu_tick_get_count(opaque);
#else
return 0;
#endif
}
void helper_tick_set_limit(void *opaque, uint64_t limit)
{
#if !defined(CONFIG_USER_ONLY)
// cpu_tick_set_limit(opaque, limit);
#endif
}
#endif
static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
target_ulong b, int cc)
{
SPARCCPU *cpu = sparc_env_get_cpu(env);
int overflow = 0;
uint64_t x0;
uint32_t x1;
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
x1 = (b & 0xffffffff);
if (x1 == 0) {
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_DIV_ZERO);
}
x0 = x0 / x1;
if (x0 > UINT32_MAX) {
x0 = UINT32_MAX;
overflow = 1;
}
if (cc) {
env->cc_dst = x0;
env->cc_src2 = overflow;
env->cc_op = CC_OP_DIV;
}
return x0;
}
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
{
return helper_udiv_common(env, a, b, 0);
}
target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
{
return helper_udiv_common(env, a, b, 1);
}
static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
target_ulong b, int cc)
{
SPARCCPU *cpu = sparc_env_get_cpu(env);
int overflow = 0;
int64_t x0;
int32_t x1;
x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
x1 = (b & 0xffffffff);
if (x1 == 0) {
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_DIV_ZERO);
} else if (x1 == -1 && x0 == INT64_MIN) {
x0 = INT32_MAX;
overflow = 1;
} else {
x0 = x0 / x1;
if ((int32_t) x0 != x0) {
x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
overflow = 1;
}
}
if (cc) {
env->cc_dst = x0;
env->cc_src2 = overflow;
env->cc_op = CC_OP_DIV;
}
return x0;
}
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
{
return helper_sdiv_common(env, a, b, 0);
}
target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
{
return helper_sdiv_common(env, a, b, 1);
}
#ifdef TARGET_SPARC64
int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
{
if (b == 0) {
/* Raise divide by zero trap. */
SPARCCPU *cpu = sparc_env_get_cpu(env);
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_DIV_ZERO);
} else if (b == -1) {
/* Avoid overflow trap with i386 divide insn. */
return -a;
} else {
return a / b;
}
}
uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
{
if (b == 0) {
/* Raise divide by zero trap. */
SPARCCPU *cpu = sparc_env_get_cpu(env);
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_DIV_ZERO);
}
return a / b;
}
#endif
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
target_ulong src2)
{
SPARCCPU *cpu = sparc_env_get_cpu(env);
target_ulong dst;
/* Tag overflow occurs if either input has bits 0 or 1 set. */
if ((src1 | src2) & 3) {
goto tag_overflow;
}
dst = src1 + src2;
/* Tag overflow occurs if the addition overflows. */
if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
goto tag_overflow;
}
/* Only modify the CC after any exceptions have been generated. */
env->cc_op = CC_OP_TADDTV;
env->cc_src = src1;
env->cc_src2 = src2;
env->cc_dst = dst;
return dst;
tag_overflow:
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_TOVF);
}
target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
target_ulong src2)
{
SPARCCPU *cpu = sparc_env_get_cpu(env);
target_ulong dst;
/* Tag overflow occurs if either input has bits 0 or 1 set. */
if ((src1 | src2) & 3) {
goto tag_overflow;
}
dst = src1 - src2;
/* Tag overflow occurs if the subtraction overflows. */
if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
goto tag_overflow;
}
/* Only modify the CC after any exceptions have been generated. */
env->cc_op = CC_OP_TSUBTV;
env->cc_src = src1;
env->cc_src2 = src2;
env->cc_dst = dst;
return dst;
tag_overflow:
cpu_restore_state(CPU(cpu), GETPC());
helper_raise_exception(env, TT_TOVF);
}
#ifndef TARGET_SPARC64
void helper_power_down(CPUSPARCState *env)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
cs->halted = 1;
cs->exception_index = EXCP_HLT;
env->pc = env->npc;
env->npc = env->pc + 4;
cpu_loop_exit(cs);
}
#endif

177
qemu/target-sparc/helper.h Normal file
View File

@@ -0,0 +1,177 @@
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
#ifndef TARGET_SPARC64
DEF_HELPER_1(rett, void, env)
DEF_HELPER_2(wrpsr, void, env, tl)
DEF_HELPER_1(rdpsr, tl, env)
DEF_HELPER_1(power_down, void, env)
#else
DEF_HELPER_2(wrpil, void, env, tl)
DEF_HELPER_2(wrpstate, void, env, tl)
DEF_HELPER_1(done, void, env)
DEF_HELPER_1(retry, void, env)
DEF_HELPER_1(flushw, void, env)
DEF_HELPER_1(saved, void, env)
DEF_HELPER_1(restored, void, env)
DEF_HELPER_1(rdccr, tl, env)
DEF_HELPER_2(wrccr, void, env, tl)
DEF_HELPER_1(rdcwp, tl, env)
DEF_HELPER_2(wrcwp, void, env, tl)
DEF_HELPER_FLAGS_2(array8, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_1(popc, tl, tl)
DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
DEF_HELPER_5(stf_asi, void, env, tl, int, int, int)
DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32)
DEF_HELPER_2(set_softint, void, env, i64)
DEF_HELPER_2(clear_softint, void, env, i64)
DEF_HELPER_2(write_softint, void, env, i64)
DEF_HELPER_2(tick_set_count, void, ptr, i64)
DEF_HELPER_1(tick_get_count, i64, ptr)
DEF_HELPER_2(tick_set_limit, void, ptr, i64)
#endif
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
#endif
DEF_HELPER_3(check_align, void, env, tl, i32)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_1(save, void, env)
DEF_HELPER_1(restore, void, env)
DEF_HELPER_3(udiv, tl, env, tl, tl)
DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
DEF_HELPER_3(sdiv, tl, env, tl, tl)
DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
DEF_HELPER_3(taddcctv, tl, env, tl, tl)
DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
#ifdef TARGET_SPARC64
DEF_HELPER_3(sdivx, s64, env, s64, s64)
DEF_HELPER_3(udivx, i64, env, i64, i64)
#endif
DEF_HELPER_3(ldqf, void, env, tl, int)
DEF_HELPER_3(stqf, void, env, tl, int)
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int)
DEF_HELPER_5(st_asi, void, env, tl, i64, int, int)
#endif
DEF_HELPER_2(ldfsr, void, env, i32)
DEF_HELPER_FLAGS_1(fabss, TCG_CALL_NO_RWG_SE, f32, f32)
DEF_HELPER_2(fsqrts, f32, env, f32)
DEF_HELPER_2(fsqrtd, f64, env, f64)
DEF_HELPER_3(fcmps, void, env, f32, f32)
DEF_HELPER_3(fcmpd, void, env, f64, f64)
DEF_HELPER_3(fcmpes, void, env, f32, f32)
DEF_HELPER_3(fcmped, void, env, f64, f64)
DEF_HELPER_1(fsqrtq, void, env)
DEF_HELPER_1(fcmpq, void, env)
DEF_HELPER_1(fcmpeq, void, env)
#ifdef TARGET_SPARC64
DEF_HELPER_2(ldxfsr, void, env, i64)
DEF_HELPER_FLAGS_1(fabsd, TCG_CALL_NO_RWG_SE, f64, f64)
DEF_HELPER_3(fcmps_fcc1, void, env, f32, f32)
DEF_HELPER_3(fcmps_fcc2, void, env, f32, f32)
DEF_HELPER_3(fcmps_fcc3, void, env, f32, f32)
DEF_HELPER_3(fcmpd_fcc1, void, env, f64, f64)
DEF_HELPER_3(fcmpd_fcc2, void, env, f64, f64)
DEF_HELPER_3(fcmpd_fcc3, void, env, f64, f64)
DEF_HELPER_3(fcmpes_fcc1, void, env, f32, f32)
DEF_HELPER_3(fcmpes_fcc2, void, env, f32, f32)
DEF_HELPER_3(fcmpes_fcc3, void, env, f32, f32)
DEF_HELPER_3(fcmped_fcc1, void, env, f64, f64)
DEF_HELPER_3(fcmped_fcc2, void, env, f64, f64)
DEF_HELPER_3(fcmped_fcc3, void, env, f64, f64)
DEF_HELPER_1(fabsq, void, env)
DEF_HELPER_1(fcmpq_fcc1, void, env)
DEF_HELPER_1(fcmpq_fcc2, void, env)
DEF_HELPER_1(fcmpq_fcc3, void, env)
DEF_HELPER_1(fcmpeq_fcc1, void, env)
DEF_HELPER_1(fcmpeq_fcc2, void, env)
DEF_HELPER_1(fcmpeq_fcc3, void, env)
#endif
DEF_HELPER_2(raise_exception, noreturn, env, int)
#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
DEF_HELPER_3(faddd, f64, env, f64, f64)
DEF_HELPER_3(fsubd, f64, env, f64, f64)
DEF_HELPER_3(fmuld, f64, env, f64, f64)
DEF_HELPER_3(fdivd, f64, env, f64, f64)
F_HELPER_0_1(addq)
F_HELPER_0_1(subq)
F_HELPER_0_1(mulq)
F_HELPER_0_1(divq)
DEF_HELPER_3(fadds, f32, env, f32, f32)
DEF_HELPER_3(fsubs, f32, env, f32, f32)
DEF_HELPER_3(fmuls, f32, env, f32, f32)
DEF_HELPER_3(fdivs, f32, env, f32, f32)
DEF_HELPER_3(fsmuld, f64, env, f32, f32)
DEF_HELPER_3(fdmulq, void, env, f64, f64)
DEF_HELPER_FLAGS_1(fnegs, TCG_CALL_NO_RWG_SE, f32, f32)
DEF_HELPER_2(fitod, f64, env, s32)
DEF_HELPER_2(fitoq, void, env, s32)
DEF_HELPER_2(fitos, f32, env, s32)
#ifdef TARGET_SPARC64
DEF_HELPER_FLAGS_1(fnegd, TCG_CALL_NO_RWG_SE, f64, f64)
DEF_HELPER_1(fnegq, void, env)
DEF_HELPER_2(fxtos, f32, env, s64)
DEF_HELPER_2(fxtod, f64, env, s64)
DEF_HELPER_2(fxtoq, void, env, s64)
#endif
DEF_HELPER_2(fdtos, f32, env, f64)
DEF_HELPER_2(fstod, f64, env, f32)
DEF_HELPER_1(fqtos, f32, env)
DEF_HELPER_2(fstoq, void, env, f32)
DEF_HELPER_1(fqtod, f64, env)
DEF_HELPER_2(fdtoq, void, env, f64)
DEF_HELPER_2(fstoi, s32, env, f32)
DEF_HELPER_2(fdtoi, s32, env, f64)
DEF_HELPER_1(fqtoi, s32, env)
#ifdef TARGET_SPARC64
DEF_HELPER_2(fstox, s64, env, f32)
DEF_HELPER_2(fdtox, s64, env, f64)
DEF_HELPER_1(fqtox, s64, env)
DEF_HELPER_FLAGS_2(fpmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmul8x16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_3(pdist, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
DEF_HELPER_FLAGS_2(fpack16, TCG_CALL_NO_RWG_SE, i32, i64, i64)
DEF_HELPER_FLAGS_3(fpack32, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
DEF_HELPER_FLAGS_2(fpackfix, TCG_CALL_NO_RWG_SE, i32, i64, i64)
DEF_HELPER_FLAGS_3(bshuffle, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
#define VIS_HELPER(name) \
DEF_HELPER_FLAGS_2(f ## name ## 16, TCG_CALL_NO_RWG_SE, \
i64, i64, i64) \
DEF_HELPER_FLAGS_2(f ## name ## 16s, TCG_CALL_NO_RWG_SE, \
i32, i32, i32) \
DEF_HELPER_FLAGS_2(f ## name ## 32, TCG_CALL_NO_RWG_SE, \
i64, i64, i64) \
DEF_HELPER_FLAGS_2(f ## name ## 32s, TCG_CALL_NO_RWG_SE, \
i32, i32, i32)
VIS_HELPER(padd)
VIS_HELPER(psub)
#define VIS_CMPHELPER(name) \
DEF_HELPER_FLAGS_2(f##name##16, TCG_CALL_NO_RWG_SE, \
i64, i64, i64) \
DEF_HELPER_FLAGS_2(f##name##32, TCG_CALL_NO_RWG_SE, \
i64, i64, i64)
VIS_CMPHELPER(cmpgt)
VIS_CMPHELPER(cmpeq)
VIS_CMPHELPER(cmple)
VIS_CMPHELPER(cmpne)
#endif
#undef F_HELPER_0_1
#undef VIS_HELPER
#undef VIS_CMPHELPER
DEF_HELPER_1(compute_psr, void, env)
DEF_HELPER_1(compute_C_icc, i32, env)

View File

@@ -0,0 +1,95 @@
/*
* Sparc32 interrupt helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "sysemu/sysemu.h"
void sparc_cpu_do_interrupt(CPUState *cs)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
int cwp, intno = cs->exception_index;
/* Compute PSR before exposing state. */
if (env->cc_op != CC_OP_FLAGS) {
cpu_get_psr(env);
}
#if !defined(CONFIG_USER_ONLY)
if (env->psret == 0) {
if (cs->exception_index == 0x80 &&
env->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
qemu_system_shutdown_request();
} else {
cpu_abort(cs, "Trap 0x%02x while interrupts disabled, Error state",
cs->exception_index);
}
return;
}
#endif
env->psret = 0;
cwp = cpu_cwp_dec(env, env->cwp - 1);
cpu_set_cwp(env, cwp);
env->regwptr[9] = env->pc;
env->regwptr[10] = env->npc;
env->psrps = env->psrs;
env->psrs = 1;
env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
env->pc = env->tbr;
env->npc = env->pc + 4;
cs->exception_index = -1;
}
#if !defined(CONFIG_USER_ONLY)
static void leon3_cache_control_int(CPUSPARCState *env)
{
uint32_t state = 0;
if (env->cache_control & CACHE_CTRL_IF) {
/* Instruction cache state */
state = env->cache_control & CACHE_STATE_MASK;
if (state == CACHE_ENABLED) {
state = CACHE_FROZEN;
//trace_int_helper_icache_freeze();
}
env->cache_control &= ~CACHE_STATE_MASK;
env->cache_control |= state;
}
if (env->cache_control & CACHE_CTRL_DF) {
/* Data cache state */
state = (env->cache_control >> 2) & CACHE_STATE_MASK;
if (state == CACHE_ENABLED) {
state = CACHE_FROZEN;
//trace_int_helper_dcache_freeze();
}
env->cache_control &= ~(CACHE_STATE_MASK << 2);
env->cache_control |= (state << 2);
}
}
void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno)
{
//leon3_irq_ack(irq_manager, intno);
leon3_cache_control_int(env);
}
#endif

View File

@@ -0,0 +1,128 @@
/*
* Sparc64 interrupt helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/helper-proto.h"
void sparc_cpu_do_interrupt(CPUState *cs)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
int intno = cs->exception_index;
trap_state *tsptr;
/* Compute PSR before exposing state. */
if (env->cc_op != CC_OP_FLAGS) {
cpu_get_psr(env);
}
#if !defined(CONFIG_USER_ONLY)
if (env->tl >= env->maxtl) {
cpu_abort(cs, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
" Error state", cs->exception_index, env->tl, env->maxtl);
return;
}
#endif
if (env->tl < env->maxtl - 1) {
env->tl++;
} else {
env->pstate |= PS_RED;
if (env->tl < env->maxtl) {
env->tl++;
}
}
tsptr = cpu_tsptr(env);
tsptr->tstate = (cpu_get_ccr(env) << 32) |
((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
cpu_get_cwp64(env);
tsptr->tpc = env->pc;
tsptr->tnpc = env->npc;
tsptr->tt = intno;
switch (intno) {
case TT_IVEC:
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
break;
case TT_TFAULT:
case TT_DFAULT:
case TT_TMISS ... TT_TMISS + 3:
case TT_DMISS ... TT_DMISS + 3:
case TT_DPROT ... TT_DPROT + 3:
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
break;
default:
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
break;
}
if (intno == TT_CLRWIN) {
cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
} else if ((intno & 0x1c0) == TT_SPILL) {
cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
} else if ((intno & 0x1c0) == TT_FILL) {
cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
}
env->tbr &= ~0x7fffULL;
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
env->pc = env->tbr;
env->npc = env->pc + 4;
cs->exception_index = -1;
}
trap_state *cpu_tsptr(CPUSPARCState* env)
{
return &env->ts[env->tl & MAXTL_MASK];
}
static bool do_modify_softint(CPUSPARCState *env, uint32_t value)
{
if (env->softint != value) {
env->softint = value;
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
//cpu_check_irqs(env);
}
#endif
return true;
}
return false;
}
void helper_set_softint(CPUSPARCState *env, uint64_t value)
{
if (do_modify_softint(env, env->softint | (uint32_t)value)) {
//trace_int_helper_set_softint(env->softint);
}
}
void helper_clear_softint(CPUSPARCState *env, uint64_t value)
{
if (do_modify_softint(env, env->softint & (uint32_t)~value)) {
//trace_int_helper_clear_softint(env->softint);
}
}
void helper_write_softint(CPUSPARCState *env, uint64_t value)
{
if (do_modify_softint(env, (uint32_t)value)) {
//trace_int_helper_write_softint(env->softint);
}
}

File diff suppressed because it is too large Load Diff

218
qemu/target-sparc/machine.c Normal file
View File

@@ -0,0 +1,218 @@
#include "hw/hw.h"
#include "hw/boards.h"
#include "qemu/timer.h"
#include "cpu.h"
void cpu_save(QEMUFile *f, void *opaque)
{
CPUSPARCState *env = opaque;
int i;
uint32_t tmp;
// if env->cwp == env->nwindows - 1, this will set the ins of the last
// window as the outs of the first window
cpu_set_cwp(env, env->cwp);
for(i = 0; i < 8; i++)
qemu_put_betls(f, &env->gregs[i]);
qemu_put_be32s(f, &env->nwindows);
for(i = 0; i < env->nwindows * 16; i++)
qemu_put_betls(f, &env->regbase[i]);
/* FPU */
for (i = 0; i < TARGET_DPREGS; i++) {
qemu_put_be32(f, env->fpr[i].l.upper);
qemu_put_be32(f, env->fpr[i].l.lower);
}
qemu_put_betls(f, &env->pc);
qemu_put_betls(f, &env->npc);
qemu_put_betls(f, &env->y);
tmp = cpu_get_psr(env);
qemu_put_be32(f, tmp);
qemu_put_betls(f, &env->fsr);
qemu_put_betls(f, &env->tbr);
tmp = env->interrupt_index;
qemu_put_be32(f, tmp);
qemu_put_be32s(f, &env->pil_in);
#ifndef TARGET_SPARC64
qemu_put_be32s(f, &env->wim);
/* MMU */
for (i = 0; i < 32; i++)
qemu_put_be32s(f, &env->mmuregs[i]);
for (i = 0; i < 4; i++) {
qemu_put_be64s(f, &env->mxccdata[i]);
}
for (i = 0; i < 8; i++) {
qemu_put_be64s(f, &env->mxccregs[i]);
}
qemu_put_be32s(f, &env->mmubpctrv);
qemu_put_be32s(f, &env->mmubpctrc);
qemu_put_be32s(f, &env->mmubpctrs);
qemu_put_be64s(f, &env->mmubpaction);
for (i = 0; i < 4; i++) {
qemu_put_be64s(f, &env->mmubpregs[i]);
}
#else
qemu_put_be64s(f, &env->lsu);
for (i = 0; i < 16; i++) {
qemu_put_be64s(f, &env->immuregs[i]);
qemu_put_be64s(f, &env->dmmuregs[i]);
}
for (i = 0; i < 64; i++) {
qemu_put_be64s(f, &env->itlb[i].tag);
qemu_put_be64s(f, &env->itlb[i].tte);
qemu_put_be64s(f, &env->dtlb[i].tag);
qemu_put_be64s(f, &env->dtlb[i].tte);
}
qemu_put_be32s(f, &env->mmu_version);
for (i = 0; i < MAXTL_MAX; i++) {
qemu_put_be64s(f, &env->ts[i].tpc);
qemu_put_be64s(f, &env->ts[i].tnpc);
qemu_put_be64s(f, &env->ts[i].tstate);
qemu_put_be32s(f, &env->ts[i].tt);
}
qemu_put_be32s(f, &env->xcc);
qemu_put_be32s(f, &env->asi);
qemu_put_be32s(f, &env->pstate);
qemu_put_be32s(f, &env->tl);
qemu_put_be32s(f, &env->cansave);
qemu_put_be32s(f, &env->canrestore);
qemu_put_be32s(f, &env->otherwin);
qemu_put_be32s(f, &env->wstate);
qemu_put_be32s(f, &env->cleanwin);
for (i = 0; i < 8; i++)
qemu_put_be64s(f, &env->agregs[i]);
for (i = 0; i < 8; i++)
qemu_put_be64s(f, &env->bgregs[i]);
for (i = 0; i < 8; i++)
qemu_put_be64s(f, &env->igregs[i]);
for (i = 0; i < 8; i++)
qemu_put_be64s(f, &env->mgregs[i]);
qemu_put_be64s(f, &env->fprs);
qemu_put_be64s(f, &env->tick_cmpr);
qemu_put_be64s(f, &env->stick_cmpr);
cpu_put_timer(f, env->tick);
cpu_put_timer(f, env->stick);
qemu_put_be64s(f, &env->gsr);
qemu_put_be32s(f, &env->gl);
qemu_put_be64s(f, &env->hpstate);
for (i = 0; i < MAXTL_MAX; i++)
qemu_put_be64s(f, &env->htstate[i]);
qemu_put_be64s(f, &env->hintp);
qemu_put_be64s(f, &env->htba);
qemu_put_be64s(f, &env->hver);
qemu_put_be64s(f, &env->hstick_cmpr);
qemu_put_be64s(f, &env->ssr);
cpu_put_timer(f, env->hstick);
#endif
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
CPUSPARCState *env = opaque;
SPARCCPU *cpu = sparc_env_get_cpu(env);
int i;
uint32_t tmp;
if (version_id < 6)
return -EINVAL;
for(i = 0; i < 8; i++)
qemu_get_betls(f, &env->gregs[i]);
qemu_get_be32s(f, &env->nwindows);
for(i = 0; i < env->nwindows * 16; i++)
qemu_get_betls(f, &env->regbase[i]);
/* FPU */
for (i = 0; i < TARGET_DPREGS; i++) {
env->fpr[i].l.upper = qemu_get_be32(f);
env->fpr[i].l.lower = qemu_get_be32(f);
}
qemu_get_betls(f, &env->pc);
qemu_get_betls(f, &env->npc);
qemu_get_betls(f, &env->y);
tmp = qemu_get_be32(f);
env->cwp = 0; /* needed to ensure that the wrapping registers are
correctly updated */
cpu_put_psr(env, tmp);
qemu_get_betls(f, &env->fsr);
qemu_get_betls(f, &env->tbr);
tmp = qemu_get_be32(f);
env->interrupt_index = tmp;
qemu_get_be32s(f, &env->pil_in);
#ifndef TARGET_SPARC64
qemu_get_be32s(f, &env->wim);
/* MMU */
for (i = 0; i < 32; i++)
qemu_get_be32s(f, &env->mmuregs[i]);
for (i = 0; i < 4; i++) {
qemu_get_be64s(f, &env->mxccdata[i]);
}
for (i = 0; i < 8; i++) {
qemu_get_be64s(f, &env->mxccregs[i]);
}
qemu_get_be32s(f, &env->mmubpctrv);
qemu_get_be32s(f, &env->mmubpctrc);
qemu_get_be32s(f, &env->mmubpctrs);
qemu_get_be64s(f, &env->mmubpaction);
for (i = 0; i < 4; i++) {
qemu_get_be64s(f, &env->mmubpregs[i]);
}
#else
qemu_get_be64s(f, &env->lsu);
for (i = 0; i < 16; i++) {
qemu_get_be64s(f, &env->immuregs[i]);
qemu_get_be64s(f, &env->dmmuregs[i]);
}
for (i = 0; i < 64; i++) {
qemu_get_be64s(f, &env->itlb[i].tag);
qemu_get_be64s(f, &env->itlb[i].tte);
qemu_get_be64s(f, &env->dtlb[i].tag);
qemu_get_be64s(f, &env->dtlb[i].tte);
}
qemu_get_be32s(f, &env->mmu_version);
for (i = 0; i < MAXTL_MAX; i++) {
qemu_get_be64s(f, &env->ts[i].tpc);
qemu_get_be64s(f, &env->ts[i].tnpc);
qemu_get_be64s(f, &env->ts[i].tstate);
qemu_get_be32s(f, &env->ts[i].tt);
}
qemu_get_be32s(f, &env->xcc);
qemu_get_be32s(f, &env->asi);
qemu_get_be32s(f, &env->pstate);
qemu_get_be32s(f, &env->tl);
qemu_get_be32s(f, &env->cansave);
qemu_get_be32s(f, &env->canrestore);
qemu_get_be32s(f, &env->otherwin);
qemu_get_be32s(f, &env->wstate);
qemu_get_be32s(f, &env->cleanwin);
for (i = 0; i < 8; i++)
qemu_get_be64s(f, &env->agregs[i]);
for (i = 0; i < 8; i++)
qemu_get_be64s(f, &env->bgregs[i]);
for (i = 0; i < 8; i++)
qemu_get_be64s(f, &env->igregs[i]);
for (i = 0; i < 8; i++)
qemu_get_be64s(f, &env->mgregs[i]);
qemu_get_be64s(f, &env->fprs);
qemu_get_be64s(f, &env->tick_cmpr);
qemu_get_be64s(f, &env->stick_cmpr);
cpu_get_timer(f, env->tick);
cpu_get_timer(f, env->stick);
qemu_get_be64s(f, &env->gsr);
qemu_get_be32s(f, &env->gl);
qemu_get_be64s(f, &env->hpstate);
for (i = 0; i < MAXTL_MAX; i++)
qemu_get_be64s(f, &env->htstate[i]);
qemu_get_be64s(f, &env->hintp);
qemu_get_be64s(f, &env->htba);
qemu_get_be64s(f, &env->hver);
qemu_get_be64s(f, &env->hstick_cmpr);
qemu_get_be64s(f, &env->ssr);
cpu_get_timer(f, env->hstick);
#endif
tlb_flush(CPU(cpu), 1);
return 0;
}

View File

@@ -0,0 +1,867 @@
/*
* Sparc MMU helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/address-spaces.h"
/* Sparc MMU emulation */
#if defined(CONFIG_USER_ONLY)
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
int mmu_idx)
{
if (rw & 2) {
cs->exception_index = TT_TFAULT;
} else {
cs->exception_index = TT_DFAULT;
}
return 1;
}
#else
#ifndef TARGET_SPARC64
/*
* Sparc V8 Reference MMU (SRMMU)
*/
static const int access_table[8][8] = {
{ 0, 0, 0, 0, 8, 0, 12, 12 },
{ 0, 0, 0, 0, 8, 0, 0, 0 },
{ 8, 8, 0, 0, 0, 8, 12, 12 },
{ 8, 8, 0, 0, 0, 8, 0, 0 },
{ 8, 0, 8, 0, 8, 8, 12, 12 },
{ 8, 0, 8, 0, 8, 0, 8, 0 },
{ 8, 8, 8, 0, 8, 8, 12, 12 },
{ 8, 8, 8, 0, 8, 8, 8, 0 }
};
static const int perm_table[2][8] = {
{
PAGE_READ,
PAGE_READ | PAGE_WRITE,
PAGE_READ | PAGE_EXEC,
PAGE_READ | PAGE_WRITE | PAGE_EXEC,
PAGE_EXEC,
PAGE_READ | PAGE_WRITE,
PAGE_READ | PAGE_EXEC,
PAGE_READ | PAGE_WRITE | PAGE_EXEC
},
{
PAGE_READ,
PAGE_READ | PAGE_WRITE,
PAGE_READ | PAGE_EXEC,
PAGE_READ | PAGE_WRITE | PAGE_EXEC,
PAGE_EXEC,
PAGE_READ,
0,
0,
}
};
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
int *prot, int *access_index,
target_ulong address, int rw, int mmu_idx,
target_ulong *page_size)
{
int access_perms = 0;
hwaddr pde_ptr;
uint32_t pde;
int error_code = 0, is_dirty, is_user;
unsigned long page_offset;
CPUState *cs = CPU(sparc_env_get_cpu(env));
is_user = mmu_idx == MMU_USER_IDX;
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
*page_size = TARGET_PAGE_SIZE;
/* Boot mode: instruction fetches are taken from PROM */
if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
*physical = env->prom_addr | (address & 0x7ffffULL);
*prot = PAGE_READ | PAGE_EXEC;
return 0;
}
*physical = address;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return 0;
}
*access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
*physical = 0xffffffffffff0000ULL;
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
/* Context base + context number */
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
pde = ldl_phys(cs->as, pde_ptr);
/* Ctx pde */
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
return 1 << 2;
case 2: /* L0 PTE, maybe should not happen? */
case 3: /* Reserved */
return 4 << 2;
case 1: /* L0 PDE */
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
return (1 << 8) | (1 << 2);
case 3: /* Reserved */
return (1 << 8) | (4 << 2);
case 1: /* L1 PDE */
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
return (2 << 8) | (1 << 2);
case 3: /* Reserved */
return (2 << 8) | (4 << 2);
case 1: /* L2 PDE */
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
return (3 << 8) | (1 << 2);
case 1: /* PDE, should not happen */
case 3: /* Reserved */
return (3 << 8) | (4 << 2);
case 2: /* L3 PTE */
page_offset = 0;
}
*page_size = TARGET_PAGE_SIZE;
break;
case 2: /* L2 PTE */
page_offset = address & 0x3f000;
*page_size = 0x40000;
}
break;
case 2: /* L1 PTE */
page_offset = address & 0xfff000;
*page_size = 0x1000000;
}
}
/* check access */
access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
error_code = access_table[*access_index][access_perms];
if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
return error_code;
}
/* update page modified and dirty bits */
is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
pde |= PG_ACCESSED_MASK;
if (is_dirty) {
pde |= PG_MODIFIED_MASK;
}
stl_phys_notdirty(cs->as, pde_ptr, pde);
}
/* the page can be put in the TLB */
*prot = perm_table[is_user][access_perms];
if (!(pde & PG_MODIFIED_MASK)) {
/* only set write access if already dirty... otherwise wait
for dirty access */
*prot &= ~PAGE_WRITE;
}
/* Even if large ptes, we map only one 4KB page in the cache to
avoid filling it too fast */
*physical = ((hwaddr)(pde & PTE_ADDR_MASK) << 4) + page_offset;
return error_code;
}
/* Perform address translation */
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
int mmu_idx)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
hwaddr paddr;
target_ulong vaddr;
target_ulong page_size;
int error_code = 0, prot, access_index;
address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
vaddr = address;
if (error_code == 0) {
#ifdef DEBUG_MMU
printf("Translate at %" VADDR_PRIx " -> " TARGET_FMT_plx ", vaddr "
TARGET_FMT_lx "\n", address, paddr, vaddr);
#endif
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
return 0;
}
if (env->mmuregs[3]) { /* Fault status register */
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
}
env->mmuregs[3] |= (access_index << 5) | error_code | 2;
env->mmuregs[4] = address; /* Fault address register */
if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
/* No fault mode: if a mapping is available, just override
permissions. If no mapping is available, redirect accesses to
neverland. Fake/overridden mappings will be flushed when
switching to normal mode. */
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
} else {
if (rw & 2) {
cs->exception_index = TT_TFAULT;
} else {
cs->exception_index = TT_DFAULT;
}
return 1;
}
}
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
hwaddr pde_ptr;
uint32_t pde;
/* Context base + context number */
pde_ptr = (hwaddr)(env->mmuregs[1] << 4) +
(env->mmuregs[2] << 2);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
case 2: /* PTE, maybe should not happen? */
case 3: /* Reserved */
return 0;
case 1: /* L1 PDE */
if (mmulev == 3) {
return pde;
}
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
case 3: /* Reserved */
return 0;
case 2: /* L1 PTE */
return pde;
case 1: /* L2 PDE */
if (mmulev == 2) {
return pde;
}
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
case 3: /* Reserved */
return 0;
case 2: /* L2 PTE */
return pde;
case 1: /* L3 PDE */
if (mmulev == 1) {
return pde;
}
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
pde = ldl_phys(cs->as, pde_ptr);
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
case 0: /* Invalid */
case 1: /* PDE, should not happen */
case 3: /* Reserved */
return 0;
case 2: /* L3 PTE */
return pde;
}
}
}
}
return 0;
}
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
target_ulong va, va1, va2;
unsigned int n, m, o;
hwaddr pde_ptr, pa;
uint32_t pde;
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
pde = ldl_phys(cs->as, pde_ptr);
(*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
(hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]);
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
pde = mmu_probe(env, va, 2);
if (pde) {
pa = cpu_get_phys_page_debug(cs, va);
(*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
" PDE: " TARGET_FMT_lx "\n", va, pa, pde);
for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
pde = mmu_probe(env, va1, 1);
if (pde) {
pa = cpu_get_phys_page_debug(cs, va1);
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
va1, pa, pde);
for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
pde = mmu_probe(env, va2, 0);
if (pde) {
pa = cpu_get_phys_page_debug(cs, va2);
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
TARGET_FMT_plx " PTE: "
TARGET_FMT_lx "\n",
va2, pa, pde);
}
}
}
}
}
}
}
/* Gdb expects all registers windows to be flushed in ram. This function handles
* reads (and only reads) in stack frames as if windows were flushed. We assume
* that the sparc ABI is followed.
*/
int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address,
uint8_t *buf, int len, bool is_write)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
target_ulong addr = address;
int i;
int len1;
int cwp = env->cwp;
if (!is_write) {
for (i = 0; i < env->nwindows; i++) {
int off;
target_ulong fp = env->regbase[cwp * 16 + 22];
/* Assume fp == 0 means end of frame. */
if (fp == 0) {
break;
}
cwp = cpu_cwp_inc(env, cwp + 1);
/* Invalid window ? */
if (env->wim & (1 << cwp)) {
break;
}
/* According to the ABI, the stack is growing downward. */
if (addr + len < fp) {
break;
}
/* Not in this frame. */
if (addr > fp + 64) {
continue;
}
/* Handle access before this window. */
if (addr < fp) {
len1 = fp - addr;
if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) {
return -1;
}
addr += len1;
len -= len1;
buf += len1;
}
/* Access byte per byte to registers. Not very efficient but speed
* is not critical.
*/
off = addr - fp;
len1 = 64 - off;
if (len1 > len) {
len1 = len;
}
for (; len1; len1--) {
int reg = cwp * 16 + 8 + (off >> 2);
union {
uint32_t v;
uint8_t c[4];
} u;
u.v = cpu_to_be32(env->regbase[reg]);
*buf++ = u.c[off & 3];
addr++;
len--;
off++;
}
if (len == 0) {
return 0;
}
}
}
return cpu_memory_rw_debug(cs, addr, buf, len, is_write);
}
#else /* !TARGET_SPARC64 */
/* 41 bit physical address space */
static inline hwaddr ultrasparc_truncate_physical(uint64_t x)
{
return x & 0x1ffffffffffULL;
}
/*
* UltraSparc IIi I/DMMUs
*/
/* Returns true if TTE tag is valid and matches virtual address value
in context requires virtual address mask value calculated from TTE
entry size */
static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
uint64_t address, uint64_t context,
hwaddr *physical)
{
uint64_t mask;
switch (TTE_PGSIZE(tlb->tte)) {
default:
case 0x0: /* 8k */
mask = 0xffffffffffffe000ULL;
break;
case 0x1: /* 64k */
mask = 0xffffffffffff0000ULL;
break;
case 0x2: /* 512k */
mask = 0xfffffffffff80000ULL;
break;
case 0x3: /* 4M */
mask = 0xffffffffffc00000ULL;
break;
}
/* valid, context match, virtual address match? */
if (TTE_IS_VALID(tlb->tte) &&
(TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
&& compare_masked(address, tlb->tag, mask)) {
/* decode physical address */
*physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
return 1;
}
return 0;
}
static int get_physical_address_data(CPUSPARCState *env,
hwaddr *physical, int *prot,
target_ulong address, int rw, int mmu_idx)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
unsigned int i;
uint64_t context;
uint64_t sfsr = 0;
int is_user = (mmu_idx == MMU_USER_IDX ||
mmu_idx == MMU_USER_SECONDARY_IDX);
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
*physical = ultrasparc_truncate_physical(address);
*prot = PAGE_READ | PAGE_WRITE;
return 0;
}
switch (mmu_idx) {
case MMU_USER_IDX:
case MMU_KERNEL_IDX:
context = env->dmmu.mmu_primary_context & 0x1fff;
sfsr |= SFSR_CT_PRIMARY;
break;
case MMU_USER_SECONDARY_IDX:
case MMU_KERNEL_SECONDARY_IDX:
context = env->dmmu.mmu_secondary_context & 0x1fff;
sfsr |= SFSR_CT_SECONDARY;
break;
case MMU_NUCLEUS_IDX:
sfsr |= SFSR_CT_NUCLEUS;
/* FALLTHRU */
default:
context = 0;
break;
}
if (rw == 1) {
sfsr |= SFSR_WRITE_BIT;
} else if (rw == 4) {
sfsr |= SFSR_NF_BIT;
}
for (i = 0; i < 64; i++) {
/* ctx match, vaddr match, valid? */
if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
int do_fault = 0;
/* access ok? */
/* multiple bits in SFSR.FT may be set on TT_DFAULT */
if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
do_fault = 1;
sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
//trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
}
if (rw == 4) {
if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
do_fault = 1;
sfsr |= SFSR_FT_NF_E_BIT;
}
} else {
if (TTE_IS_NFO(env->dtlb[i].tte)) {
do_fault = 1;
sfsr |= SFSR_FT_NFO_BIT;
}
}
if (do_fault) {
/* faults above are reported with TT_DFAULT. */
cs->exception_index = TT_DFAULT;
} else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
do_fault = 1;
cs->exception_index = TT_DPROT;
//trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
}
if (!do_fault) {
*prot = PAGE_READ;
if (TTE_IS_W_OK(env->dtlb[i].tte)) {
*prot |= PAGE_WRITE;
}
TTE_SET_USED(env->dtlb[i].tte);
return 0;
}
if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
sfsr |= SFSR_OW_BIT; /* overflow (not read before
another fault) */
}
if (env->pstate & PS_PRIV) {
sfsr |= SFSR_PR_BIT;
}
/* FIXME: ASI field in SFSR must be set */
env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
env->dmmu.sfar = address; /* Fault address register */
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
return 1;
}
}
//trace_mmu_helper_dmiss(address, context);
/*
* On MMU misses:
* - UltraSPARC IIi: SFSR and SFAR unmodified
* - JPS1: SFAR updated and some fields of SFSR updated
*/
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
cs->exception_index = TT_DMISS;
return 1;
}
static int get_physical_address_code(CPUSPARCState *env,
hwaddr *physical, int *prot,
target_ulong address, int mmu_idx)
{
CPUState *cs = CPU(sparc_env_get_cpu(env));
unsigned int i;
uint64_t context;
int is_user = (mmu_idx == MMU_USER_IDX ||
mmu_idx == MMU_USER_SECONDARY_IDX);
if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
/* IMMU disabled */
*physical = ultrasparc_truncate_physical(address);
*prot = PAGE_EXEC;
return 0;
}
if (env->tl == 0) {
/* PRIMARY context */
context = env->dmmu.mmu_primary_context & 0x1fff;
} else {
/* NUCLEUS context */
context = 0;
}
for (i = 0; i < 64; i++) {
/* ctx match, vaddr match, valid? */
if (ultrasparc_tag_match(&env->itlb[i],
address, context, physical)) {
/* access ok? */
if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
/* Fault status register */
if (env->immu.sfsr & SFSR_VALID_BIT) {
env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
another fault) */
} else {
env->immu.sfsr = 0;
}
if (env->pstate & PS_PRIV) {
env->immu.sfsr |= SFSR_PR_BIT;
}
if (env->tl > 0) {
env->immu.sfsr |= SFSR_CT_NUCLEUS;
}
/* FIXME: ASI field in SFSR must be set */
env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
cs->exception_index = TT_TFAULT;
env->immu.tag_access = (address & ~0x1fffULL) | context;
//trace_mmu_helper_tfault(address, context);
return 1;
}
*prot = PAGE_EXEC;
TTE_SET_USED(env->itlb[i].tte);
return 0;
}
}
//trace_mmu_helper_tmiss(address, context);
/* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
env->immu.tag_access = (address & ~0x1fffULL) | context;
cs->exception_index = TT_TMISS;
return 1;
}
static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
int *prot, int *access_index,
target_ulong address, int rw, int mmu_idx,
target_ulong *page_size)
{
/* ??? We treat everything as a small page, then explicitly flush
everything when an entry is evicted. */
*page_size = TARGET_PAGE_SIZE;
/* safety net to catch wrong softmmu index use from dynamic code */
if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
if (rw == 2) {
//trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
// env->dmmu.mmu_primary_context,
// env->dmmu.mmu_secondary_context,
// address);
} else {
//trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
// env->dmmu.mmu_primary_context,
// env->dmmu.mmu_secondary_context,
// address);
}
}
if (rw == 2) {
return get_physical_address_code(env, physical, prot, address,
mmu_idx);
} else {
return get_physical_address_data(env, physical, prot, address, rw,
mmu_idx);
}
}
/* Perform address translation */
int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
int mmu_idx)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
target_ulong vaddr;
hwaddr paddr;
target_ulong page_size;
int error_code = 0, prot, access_index;
address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
if (error_code == 0) {
vaddr = address;
//trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
// env->dmmu.mmu_primary_context,
// env->dmmu.mmu_secondary_context);
tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size);
return 0;
}
/* XXX */
return 1;
}
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
{
unsigned int i;
const char *mask;
(*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
PRId64 "\n",
env->dmmu.mmu_primary_context,
env->dmmu.mmu_secondary_context);
if ((env->lsu & DMMU_E) == 0) {
(*cpu_fprintf)(f, "DMMU disabled\n");
} else {
(*cpu_fprintf)(f, "DMMU dump\n");
for (i = 0; i < 64; i++) {
switch (TTE_PGSIZE(env->dtlb[i].tte)) {
default:
case 0x0:
mask = " 8k";
break;
case 0x1:
mask = " 64k";
break;
case 0x2:
mask = "512k";
break;
case 0x3:
mask = " 4M";
break;
}
if (TTE_IS_VALID(env->dtlb[i].tte)) {
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
i,
env->dtlb[i].tag & (uint64_t)~0x1fffULL,
TTE_PA(env->dtlb[i].tte),
mask,
TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
TTE_IS_LOCKED(env->dtlb[i].tte) ?
"locked" : "unlocked",
env->dtlb[i].tag & (uint64_t)0x1fffULL,
TTE_IS_GLOBAL(env->dtlb[i].tte) ?
"global" : "local");
}
}
}
if ((env->lsu & IMMU_E) == 0) {
(*cpu_fprintf)(f, "IMMU disabled\n");
} else {
(*cpu_fprintf)(f, "IMMU dump\n");
for (i = 0; i < 64; i++) {
switch (TTE_PGSIZE(env->itlb[i].tte)) {
default:
case 0x0:
mask = " 8k";
break;
case 0x1:
mask = " 64k";
break;
case 0x2:
mask = "512k";
break;
case 0x3:
mask = " 4M";
break;
}
if (TTE_IS_VALID(env->itlb[i].tte)) {
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
", %s, %s, %s, ctx %" PRId64 " %s\n",
i,
env->itlb[i].tag & (uint64_t)~0x1fffULL,
TTE_PA(env->itlb[i].tte),
mask,
TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
TTE_IS_LOCKED(env->itlb[i].tte) ?
"locked" : "unlocked",
env->itlb[i].tag & (uint64_t)0x1fffULL,
TTE_IS_GLOBAL(env->itlb[i].tte) ?
"global" : "local");
}
}
}
}
#endif /* TARGET_SPARC64 */
static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys,
target_ulong addr, int rw, int mmu_idx)
{
target_ulong page_size;
int prot, access_index;
return get_physical_address(env, phys, &prot, &access_index, addr, rw,
mmu_idx, &page_size);
}
#if defined(TARGET_SPARC64)
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int mmu_idx)
{
hwaddr phys_addr;
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
return -1;
}
return phys_addr;
}
#endif
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
SPARCCPU *cpu = SPARC_CPU(cs->uc, cs);
CPUSPARCState *env = &cpu->env;
hwaddr phys_addr;
int mmu_idx = cpu_mmu_index(env);
MemoryRegionSection section;
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
return -1;
}
}
section = memory_region_find(get_system_memory(cs->uc), phys_addr, 1);
memory_region_unref(section.mr);
if (!int128_nz(section.size)) {
return -1;
}
return phys_addr;
}
#endif

File diff suppressed because it is too large Load Diff

107
qemu/target-sparc/unicorn.c Normal file
View File

@@ -0,0 +1,107 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
#include "hw/boards.h"
#include "hw/sparc/sparc.h"
#include "sysemu/cpus.h"
#include "unicorn.h"
#include "cpu.h"
#include "unicorn_common.h"
#define READ_QWORD(x) ((uint64)x)
#define READ_DWORD(x) (x & 0xffffffff)
#define READ_WORD(x) (x & 0xffff)
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
#define READ_BYTE_L(x) (x & 0xff)
static bool sparc_stop_interrupt(int intno)
{
switch(intno) {
default:
return false;
case TT_ILL_INSN:
return true;
}
}
static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUSPARCState *)uc->current_cpu->env_ptr)->pc = address;
((CPUSPARCState *)uc->current_cpu->env_ptr)->npc = address + 4;
}
void sparc_reg_reset(uch handle)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUArchState *env;
env = first_cpu->env_ptr;
memset(env->gregs, 0, sizeof(env->gregs));
memset(env->fpr, 0, sizeof(env->fpr));
memset(env->regbase, 0, sizeof(env->regbase));
env->pc = 0;
env->npc = 0;
}
int sparc_reg_read(uch handle, unsigned int regid, void *value)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUState *mycpu = first_cpu;
if (regid >= SPARC_REG_G0 && regid <= SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - SPARC_REG_G0];
else {
switch(regid) {
default: break;
case SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
}
}
return 0;
}
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
int sparc_reg_write(uch handle, unsigned int regid, void *value)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUState *mycpu = first_cpu;
if (regid >= SPARC_REG_G0 && regid <= SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - SPARC_REG_G0] = *(int32_t *)value;
else {
switch(regid) {
default: break;
case SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
break;
}
}
return 0;
}
__attribute__ ((visibility ("default")))
void sparc_uc_init(struct uc_struct* uc)
{
register_accel_types(uc);
sparc_cpu_register_types(uc);
leon3_machine_init(uc);
uc->reg_read = sparc_reg_read;
uc->reg_write = sparc_reg_write;
uc->reg_reset = sparc_reg_reset;
uc->set_pc = sparc_set_pc;
uc->stop_interrupt = sparc_stop_interrupt;
uc_common_init(uc);
}

View File

@@ -0,0 +1,16 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
#ifndef UC_QEMU_TARGET_SPARC_H
#define UC_QEMU_TARGET_SPARC_H
// functions to read & write registers
int sparc_reg_read(uch handle, unsigned int regid, void *value);
int sparc_reg_write(uch handle, unsigned int regid, void *value);
void sparc_reg_reset(uch handle);
void sparc_uc_init(struct uc_struct* uc);
void sparc64_uc_init(struct uc_struct* uc);
#endif

View File

@@ -0,0 +1,87 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
#include "hw/boards.h"
#include "hw/sparc/sparc.h"
#include "sysemu/cpus.h"
#include "unicorn.h"
#include "cpu.h"
#define READ_QWORD(x) ((uint64)x)
#define READ_DWORD(x) (x & 0xffffffff)
#define READ_WORD(x) (x & 0xffff)
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
#define READ_BYTE_L(x) (x & 0xff)
void sparc_reg_reset(uch handle)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUArchState *env;
env = first_cpu->env_ptr;
memset(env->gregs, 0, sizeof(env->gregs));
memset(env->fpr, 0, sizeof(env->fpr));
memset(env->regbase, 0, sizeof(env->regbase));
env->pc = 0;
env->npc = 0;
}
int sparc_reg_read(uch handle, unsigned int regid, void *value)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUState *mycpu = first_cpu;
if (regid >= SPARC_REG_G0 && regid <= SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - SPARC_REG_G0];
else {
switch(regid) {
default: break;
case SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
}
}
return 0;
}
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
int sparc_reg_write(uch handle, unsigned int regid, void *value)
{
struct uc_struct *uc = (struct uc_struct *) handle;
CPUState *mycpu = first_cpu;
if (regid >= SPARC_REG_G0 && regid <= SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - SPARC_REG_G0] = *(int32_t *)value;
else {
switch(regid) {
default: break;
case SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
break;
}
}
return 0;
}
__attribute__ ((visibility ("default")))
void sparc64_uc_init(struct uc_struct* uc)
{
register_accel_types(uc);
sparc_cpu_register_types(uc);
sun4u_machine_init(uc);
uc->reg_read = sparc_reg_read;
uc->reg_write = sparc_reg_write;
uc->reg_reset = sparc_reg_reset;
}

View File

@@ -0,0 +1,489 @@
/*
* VIS op helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/helper-proto.h"
/* This function uses non-native bit order */
#define GET_FIELD(X, FROM, TO) \
((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
/* This function uses the order in the manuals, i.e. bit 0 is 2^0 */
#define GET_FIELD_SP(X, FROM, TO) \
GET_FIELD(X, 63 - (TO), 63 - (FROM))
target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
{
return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
(GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
(GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
(GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
(GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
(GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
(((pixel_addr >> 55) & 1) << 4) |
(GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
GET_FIELD_SP(pixel_addr, 11, 12);
}
#ifdef HOST_WORDS_BIGENDIAN
#define VIS_B64(n) b[7 - (n)]
#define VIS_W64(n) w[3 - (n)]
#define VIS_SW64(n) sw[3 - (n)]
#define VIS_L64(n) l[1 - (n)]
#define VIS_B32(n) b[3 - (n)]
#define VIS_W32(n) w[1 - (n)]
#else
#define VIS_B64(n) b[n]
#define VIS_W64(n) w[n]
#define VIS_SW64(n) sw[n]
#define VIS_L64(n) l[n]
#define VIS_B32(n) b[n]
#define VIS_W32(n) w[n]
#endif
typedef union {
uint8_t b[8];
uint16_t w[4];
int16_t sw[4];
uint32_t l[2];
uint64_t ll;
float64 d;
} VIS64;
typedef union {
uint8_t b[4];
uint16_t w[2];
uint32_t l;
float32 f;
} VIS32;
uint64_t helper_fpmerge(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
s.ll = src1;
d.ll = src2;
/* Reverse calculation order to handle overlap */
d.VIS_B64(7) = s.VIS_B64(3);
d.VIS_B64(6) = d.VIS_B64(3);
d.VIS_B64(5) = s.VIS_B64(2);
d.VIS_B64(4) = d.VIS_B64(2);
d.VIS_B64(3) = s.VIS_B64(1);
d.VIS_B64(2) = d.VIS_B64(1);
d.VIS_B64(1) = s.VIS_B64(0);
/* d.VIS_B64(0) = d.VIS_B64(0); */
return d.ll;
}
uint64_t helper_fmul8x16(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_W64(r) = tmp >> 8;
PMUL(0);
PMUL(1);
PMUL(2);
PMUL(3);
#undef PMUL
return d.ll;
}
uint64_t helper_fmul8x16al(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_W64(r) = tmp >> 8;
PMUL(0);
PMUL(1);
PMUL(2);
PMUL(3);
#undef PMUL
return d.ll;
}
uint64_t helper_fmul8x16au(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_W64(r) = tmp >> 8;
PMUL(0);
PMUL(1);
PMUL(2);
PMUL(3);
#undef PMUL
return d.ll;
}
uint64_t helper_fmul8sux16(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_W64(r) = tmp >> 8;
PMUL(0);
PMUL(1);
PMUL(2);
PMUL(3);
#undef PMUL
return d.ll;
}
uint64_t helper_fmul8ulx16(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_W64(r) = tmp >> 8;
PMUL(0);
PMUL(1);
PMUL(2);
PMUL(3);
#undef PMUL
return d.ll;
}
uint64_t helper_fmuld8sux16(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_L64(r) = tmp;
/* Reverse calculation order to handle overlap */
PMUL(1);
PMUL(0);
#undef PMUL
return d.ll;
}
uint64_t helper_fmuld8ulx16(uint64_t src1, uint64_t src2)
{
VIS64 s, d;
uint32_t tmp;
s.ll = src1;
d.ll = src2;
#define PMUL(r) \
tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
if ((tmp & 0xff) > 0x7f) { \
tmp += 0x100; \
} \
d.VIS_L64(r) = tmp;
/* Reverse calculation order to handle overlap */
PMUL(1);
PMUL(0);
#undef PMUL
return d.ll;
}
uint64_t helper_fexpand(uint64_t src1, uint64_t src2)
{
VIS32 s;
VIS64 d;
s.l = (uint32_t)src1;
d.ll = src2;
d.VIS_W64(0) = s.VIS_B32(0) << 4;
d.VIS_W64(1) = s.VIS_B32(1) << 4;
d.VIS_W64(2) = s.VIS_B32(2) << 4;
d.VIS_W64(3) = s.VIS_B32(3) << 4;
return d.ll;
}
#define VIS_HELPER(name, F) \
uint64_t name##16(uint64_t src1, uint64_t src2) \
{ \
VIS64 s, d; \
\
s.ll = src1; \
d.ll = src2; \
\
d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
\
return d.ll; \
} \
\
uint32_t name##16s(uint32_t src1, uint32_t src2) \
{ \
VIS32 s, d; \
\
s.l = src1; \
d.l = src2; \
\
d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
\
return d.l; \
} \
\
uint64_t name##32(uint64_t src1, uint64_t src2) \
{ \
VIS64 s, d; \
\
s.ll = src1; \
d.ll = src2; \
\
d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
\
return d.ll; \
} \
\
uint32_t name##32s(uint32_t src1, uint32_t src2) \
{ \
VIS32 s, d; \
\
s.l = src1; \
d.l = src2; \
\
d.l = F(d.l, s.l); \
\
return d.l; \
}
#define FADD(a, b) ((a) + (b))
#define FSUB(a, b) ((a) - (b))
VIS_HELPER(helper_fpadd, FADD)
VIS_HELPER(helper_fpsub, FSUB)
#define VIS_CMPHELPER(name, F) \
uint64_t name##16(uint64_t src1, uint64_t src2) \
{ \
VIS64 s, d; \
\
s.ll = src1; \
d.ll = src2; \
\
d.VIS_W64(0) = F(s.VIS_W64(0), d.VIS_W64(0)) ? 1 : 0; \
d.VIS_W64(0) |= F(s.VIS_W64(1), d.VIS_W64(1)) ? 2 : 0; \
d.VIS_W64(0) |= F(s.VIS_W64(2), d.VIS_W64(2)) ? 4 : 0; \
d.VIS_W64(0) |= F(s.VIS_W64(3), d.VIS_W64(3)) ? 8 : 0; \
d.VIS_W64(1) = d.VIS_W64(2) = d.VIS_W64(3) = 0; \
\
return d.ll; \
} \
\
uint64_t name##32(uint64_t src1, uint64_t src2) \
{ \
VIS64 s, d; \
\
s.ll = src1; \
d.ll = src2; \
\
d.VIS_L64(0) = F(s.VIS_L64(0), d.VIS_L64(0)) ? 1 : 0; \
d.VIS_L64(0) |= F(s.VIS_L64(1), d.VIS_L64(1)) ? 2 : 0; \
d.VIS_L64(1) = 0; \
\
return d.ll; \
}
#define FCMPGT(a, b) ((a) > (b))
#define FCMPEQ(a, b) ((a) == (b))
#define FCMPLE(a, b) ((a) <= (b))
#define FCMPNE(a, b) ((a) != (b))
VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
VIS_CMPHELPER(helper_fcmple, FCMPLE)
VIS_CMPHELPER(helper_fcmpne, FCMPNE)
uint64_t helper_pdist(uint64_t sum, uint64_t src1, uint64_t src2)
{
int i;
for (i = 0; i < 8; i++) {
int s1, s2;
s1 = (src1 >> (56 - (i * 8))) & 0xff;
s2 = (src2 >> (56 - (i * 8))) & 0xff;
/* Absolute value of difference. */
s1 -= s2;
if (s1 < 0) {
s1 = -s1;
}
sum += s1;
}
return sum;
}
uint32_t helper_fpack16(uint64_t gsr, uint64_t rs2)
{
int scale = (gsr >> 3) & 0xf;
uint32_t ret = 0;
int byte;
for (byte = 0; byte < 4; byte++) {
uint32_t val;
int16_t src = rs2 >> (byte * 16);
int32_t scaled = src << scale;
int32_t from_fixed = scaled >> 7;
val = (from_fixed < 0 ? 0 :
from_fixed > 255 ? 255 : from_fixed);
ret |= val << (8 * byte);
}
return ret;
}
uint64_t helper_fpack32(uint64_t gsr, uint64_t rs1, uint64_t rs2)
{
int scale = (gsr >> 3) & 0x1f;
uint64_t ret = 0;
int word;
ret = (rs1 << 8) & ~(0x000000ff000000ffULL);
for (word = 0; word < 2; word++) {
uint64_t val;
int32_t src = rs2 >> (word * 32);
int64_t scaled = (int64_t)src << scale;
int64_t from_fixed = scaled >> 23;
val = (from_fixed < 0 ? 0 :
(from_fixed > 255) ? 255 : from_fixed);
ret |= val << (32 * word);
}
return ret;
}
uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
{
int scale = (gsr >> 3) & 0x1f;
uint32_t ret = 0;
int word;
for (word = 0; word < 2; word++) {
uint32_t val;
int32_t src = rs2 >> (word * 32);
int64_t scaled = src << scale;
int64_t from_fixed = scaled >> 16;
val = (from_fixed < -32768 ? -32768 :
from_fixed > 32767 ? 32767 : from_fixed);
ret |= (val & 0xffff) << (word * 16);
}
return ret;
}
uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
{
union {
uint64_t ll[2];
uint8_t b[16];
} s;
VIS64 r;
uint32_t i, mask, host;
/* Set up S such that we can index across all of the bytes. */
#ifdef HOST_WORDS_BIGENDIAN
s.ll[0] = src1;
s.ll[1] = src2;
host = 0;
#else
s.ll[1] = src1;
s.ll[0] = src2;
host = 15;
#endif
mask = gsr >> 32;
for (i = 0; i < 8; ++i) {
unsigned e = (mask >> (28 - i*4)) & 0xf;
r.VIS_B64(i) = s.b[e ^ host];
}
return r.ll;
}

View File

@@ -0,0 +1,392 @@
/*
* Helpers for CWP and PSTATE handling
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* 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 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/>.
*/
#include "cpu.h"
#include "exec/helper-proto.h"
static inline void memcpy32(target_ulong *dst, const target_ulong *src)
{
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[4];
dst[5] = src[5];
dst[6] = src[6];
dst[7] = src[7];
}
void cpu_set_cwp(CPUSPARCState *env, int new_cwp)
{
/* put the modified wrap registers at their proper location */
if (env->cwp == env->nwindows - 1) {
memcpy32(env->regbase, env->regbase + env->nwindows * 16);
}
env->cwp = new_cwp;
/* put the wrap registers at their temporary location */
if (new_cwp == env->nwindows - 1) {
memcpy32(env->regbase + env->nwindows * 16, env->regbase);
}
env->regwptr = env->regbase + (new_cwp * 16);
}
target_ulong cpu_get_psr(CPUSPARCState *env)
{
helper_compute_psr(env);
#if !defined(TARGET_SPARC64)
return env->version | (env->psr & PSR_ICC) |
(env->psref ? PSR_EF : 0) |
(env->psrpil << 8) |
(env->psrs ? PSR_S : 0) |
(env->psrps ? PSR_PS : 0) |
(env->psret ? PSR_ET : 0) | env->cwp;
#else
return env->psr & PSR_ICC;
#endif
}
void cpu_put_psr(CPUSPARCState *env, target_ulong val)
{
env->psr = val & PSR_ICC;
#if !defined(TARGET_SPARC64)
env->psref = (val & PSR_EF) ? 1 : 0;
env->psrpil = (val & PSR_PIL) >> 8;
#endif
#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
//cpu_check_irqs(env);
#endif
#if !defined(TARGET_SPARC64)
env->psrs = (val & PSR_S) ? 1 : 0;
env->psrps = (val & PSR_PS) ? 1 : 0;
env->psret = (val & PSR_ET) ? 1 : 0;
cpu_set_cwp(env, val & PSR_CWP);
#endif
env->cc_op = CC_OP_FLAGS;
}
int cpu_cwp_inc(CPUSPARCState *env, int cwp)
{
if (unlikely(cwp >= env->nwindows)) {
cwp -= env->nwindows;
}
return cwp;
}
int cpu_cwp_dec(CPUSPARCState *env, int cwp)
{
if (unlikely(cwp < 0)) {
cwp += env->nwindows;
}
return cwp;
}
#ifndef TARGET_SPARC64
void helper_rett(CPUSPARCState *env)
{
unsigned int cwp;
if (env->psret == 1) {
helper_raise_exception(env, TT_ILL_INSN);
}
env->psret = 1;
cwp = cpu_cwp_inc(env, env->cwp + 1) ;
if (env->wim & (1 << cwp)) {
helper_raise_exception(env, TT_WIN_UNF);
}
cpu_set_cwp(env, cwp);
env->psrs = env->psrps;
}
/* XXX: use another pointer for %iN registers to avoid slow wrapping
handling ? */
void helper_save(CPUSPARCState *env)
{
uint32_t cwp;
cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->wim & (1 << cwp)) {
helper_raise_exception(env, TT_WIN_OVF);
}
cpu_set_cwp(env, cwp);
}
void helper_restore(CPUSPARCState *env)
{
uint32_t cwp;
cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->wim & (1 << cwp)) {
helper_raise_exception(env, TT_WIN_UNF);
}
cpu_set_cwp(env, cwp);
}
void helper_wrpsr(CPUSPARCState *env, target_ulong new_psr)
{
if ((new_psr & PSR_CWP) >= env->nwindows) {
helper_raise_exception(env, TT_ILL_INSN);
} else {
cpu_put_psr(env, new_psr);
}
}
target_ulong helper_rdpsr(CPUSPARCState *env)
{
return cpu_get_psr(env);
}
#else
/* XXX: use another pointer for %iN registers to avoid slow wrapping
handling ? */
void helper_save(CPUSPARCState *env)
{
uint32_t cwp;
cwp = cpu_cwp_dec(env, env->cwp - 1);
if (env->cansave == 0) {
helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
(TT_WOTHER |
((env->wstate & 0x38) >> 1)) :
((env->wstate & 0x7) << 2)));
} else {
if (env->cleanwin - env->canrestore == 0) {
/* XXX Clean windows without trap */
helper_raise_exception(env, TT_CLRWIN);
} else {
env->cansave--;
env->canrestore++;
cpu_set_cwp(env, cwp);
}
}
}
void helper_restore(CPUSPARCState *env)
{
uint32_t cwp;
cwp = cpu_cwp_inc(env, env->cwp + 1);
if (env->canrestore == 0) {
helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
(TT_WOTHER |
((env->wstate & 0x38) >> 1)) :
((env->wstate & 0x7) << 2)));
} else {
env->cansave++;
env->canrestore--;
cpu_set_cwp(env, cwp);
}
}
void helper_flushw(CPUSPARCState *env)
{
if (env->cansave != env->nwindows - 2) {
helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
(TT_WOTHER |
((env->wstate & 0x38) >> 1)) :
((env->wstate & 0x7) << 2)));
}
}
void helper_saved(CPUSPARCState *env)
{
env->cansave++;
if (env->otherwin == 0) {
env->canrestore--;
} else {
env->otherwin--;
}
}
void helper_restored(CPUSPARCState *env)
{
env->canrestore++;
if (env->cleanwin < env->nwindows - 1) {
env->cleanwin++;
}
if (env->otherwin == 0) {
env->cansave--;
} else {
env->otherwin--;
}
}
target_ulong cpu_get_ccr(CPUSPARCState *env)
{
target_ulong psr;
psr = cpu_get_psr(env);
return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
}
void cpu_put_ccr(CPUSPARCState *env, target_ulong val)
{
env->xcc = (val >> 4) << 20;
env->psr = (val & 0xf) << 20;
CC_OP = CC_OP_FLAGS;
}
target_ulong cpu_get_cwp64(CPUSPARCState *env)
{
return env->nwindows - 1 - env->cwp;
}
void cpu_put_cwp64(CPUSPARCState *env, int cwp)
{
if (unlikely(cwp >= env->nwindows || cwp < 0)) {
cwp %= env->nwindows;
}
cpu_set_cwp(env, env->nwindows - 1 - cwp);
}
target_ulong helper_rdccr(CPUSPARCState *env)
{
return cpu_get_ccr(env);
}
void helper_wrccr(CPUSPARCState *env, target_ulong new_ccr)
{
cpu_put_ccr(env, new_ccr);
}
/* CWP handling is reversed in V9, but we still use the V8 register
order. */
target_ulong helper_rdcwp(CPUSPARCState *env)
{
return cpu_get_cwp64(env);
}
void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp)
{
cpu_put_cwp64(env, new_cwp);
}
static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
{
switch (pstate) {
default:
//trace_win_helper_gregset_error(pstate);
/* pass through to normal set of global registers */
case 0:
return env->bgregs;
case PS_AG:
return env->agregs;
case PS_MG:
return env->mgregs;
case PS_IG:
return env->igregs;
}
}
void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate)
{
uint32_t pstate_regs, new_pstate_regs;
uint64_t *src, *dst;
if (env->def->features & CPU_FEATURE_GL) {
/* PS_AG is not implemented in this case */
new_pstate &= ~PS_AG;
}
pstate_regs = env->pstate & 0xc01;
new_pstate_regs = new_pstate & 0xc01;
if (new_pstate_regs != pstate_regs) {
//trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs);
/* Switch global register bank */
src = get_gregset(env, new_pstate_regs);
dst = get_gregset(env, pstate_regs);
memcpy32(dst, env->gregs);
memcpy32(env->gregs, src);
} else {
//trace_win_helper_no_switch_pstate(new_pstate_regs);
}
env->pstate = new_pstate;
}
void helper_wrpstate(CPUSPARCState *env, target_ulong new_state)
{
cpu_change_pstate(env, new_state & 0xf3f);
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
// cpu_check_irqs(env);
}
#endif
}
void helper_wrpil(CPUSPARCState *env, target_ulong new_pil)
{
#if !defined(CONFIG_USER_ONLY)
//trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil);
env->psrpil = new_pil;
if (cpu_interrupts_enabled(env)) {
// cpu_check_irqs(env);
}
#endif
}
void helper_done(CPUSPARCState *env)
{
trap_state *tsptr = cpu_tsptr(env);
env->pc = tsptr->tnpc;
env->npc = tsptr->tnpc + 4;
cpu_put_ccr(env, tsptr->tstate >> 32);
env->asi = (tsptr->tstate >> 24) & 0xff;
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
cpu_put_cwp64(env, tsptr->tstate & 0xff);
env->tl--;
//trace_win_helper_done(env->tl);
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
// cpu_check_irqs(env);
}
#endif
}
void helper_retry(CPUSPARCState *env)
{
trap_state *tsptr = cpu_tsptr(env);
env->pc = tsptr->tpc;
env->npc = tsptr->tnpc;
cpu_put_ccr(env, tsptr->tstate >> 32);
env->asi = (tsptr->tstate >> 24) & 0xff;
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
cpu_put_cwp64(env, tsptr->tstate & 0xff);
env->tl--;
//trace_win_helper_retry(env->tl);
#if !defined(CONFIG_USER_ONLY)
if (cpu_interrupts_enabled(env)) {
// cpu_check_irqs(env);
}
#endif
}
#endif