import
This commit is contained in:
8
qemu/target-sparc/Makefile.objs
Normal file
8
qemu/target-sparc/Makefile.objs
Normal 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
88
qemu/target-sparc/TODO
Normal 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
|
||||
485
qemu/target-sparc/cc_helper.c
Normal file
485
qemu/target-sparc/cc_helper.c
Normal 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;
|
||||
}
|
||||
88
qemu/target-sparc/cpu-qom.h
Normal file
88
qemu/target-sparc/cpu-qom.h
Normal 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
872
qemu/target-sparc/cpu.c
Normal 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
759
qemu/target-sparc/cpu.h
Normal 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
|
||||
467
qemu/target-sparc/fop_helper.c
Normal file
467
qemu/target-sparc/fop_helper.c
Normal 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
208
qemu/target-sparc/gdbstub.c
Normal 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
255
qemu/target-sparc/helper.c
Normal 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
177
qemu/target-sparc/helper.h
Normal 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)
|
||||
95
qemu/target-sparc/int32_helper.c
Normal file
95
qemu/target-sparc/int32_helper.c
Normal 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
|
||||
128
qemu/target-sparc/int64_helper.c
Normal file
128
qemu/target-sparc/int64_helper.c
Normal 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);
|
||||
}
|
||||
}
|
||||
2455
qemu/target-sparc/ldst_helper.c
Normal file
2455
qemu/target-sparc/ldst_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
218
qemu/target-sparc/machine.c
Normal file
218
qemu/target-sparc/machine.c
Normal 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;
|
||||
}
|
||||
867
qemu/target-sparc/mmu_helper.c
Normal file
867
qemu/target-sparc/mmu_helper.c
Normal 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
|
||||
5699
qemu/target-sparc/translate.c
Normal file
5699
qemu/target-sparc/translate.c
Normal file
File diff suppressed because it is too large
Load Diff
107
qemu/target-sparc/unicorn.c
Normal file
107
qemu/target-sparc/unicorn.c
Normal 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);
|
||||
}
|
||||
16
qemu/target-sparc/unicorn.h
Normal file
16
qemu/target-sparc/unicorn.h
Normal 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
|
||||
87
qemu/target-sparc/unicorn64.c
Normal file
87
qemu/target-sparc/unicorn64.c
Normal 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;
|
||||
}
|
||||
489
qemu/target-sparc/vis_helper.c
Normal file
489
qemu/target-sparc/vis_helper.c
Normal 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;
|
||||
}
|
||||
392
qemu/target-sparc/win_helper.c
Normal file
392
qemu/target-sparc/win_helper.c
Normal 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
|
||||
Reference in New Issue
Block a user