sparc64 fixes (Blue Swirl)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1514 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2005-07-23 14:27:54 +00:00
parent b7c7b18129
commit 8346901560
15 changed files with 1053 additions and 284 deletions

View file

@ -6,9 +6,11 @@
#if !defined(TARGET_SPARC64)
#define TARGET_LONG_BITS 32
#define TARGET_FPREGS 32
#define TARGET_PAGE_BITS 12 /* 4k */
#else
#define TARGET_LONG_BITS 64
#define TARGET_FPREGS 64
#define TARGET_PAGE_BITS 12 /* XXX */
#endif
#define TARGET_FPREG_T float
@ -35,6 +37,7 @@
#define TT_TRAP 0x80
#else
#define TT_TFAULT 0x08
#define TT_TMISS 0x09
#define TT_ILL_INSN 0x10
#define TT_PRIV_INSN 0x11
#define TT_NFPU_INSN 0x20
@ -42,6 +45,9 @@
#define TT_CLRWIN 0x24
#define TT_DIV_ZERO 0x28
#define TT_DFAULT 0x30
#define TT_DMISS 0x31
#define TT_DPROT 0x32
#define TT_PRIV_ACT 0x37
#define TT_EXTINT 0x40
#define TT_SPILL 0x80
#define TT_FILL 0xc0
@ -65,10 +71,14 @@
#define TBR_BASE_MASK 0xfffff000
#if defined(TARGET_SPARC64)
#define PS_IG (1<<11)
#define PS_MG (1<<10)
#define PS_RED (1<<5)
#define PS_PEF (1<<4)
#define PS_AM (1<<3)
#define PS_PRIV (1<<2)
#define PS_IE (1<<1)
#define PS_AG (1<<0)
#endif
/* Fcc */
@ -166,7 +176,7 @@ typedef struct CPUSPARCState {
context) */
unsigned long mem_write_pc; /* host pc at which the memory was
written */
unsigned long mem_write_vaddr; /* target virtual addr at which the
target_ulong mem_write_vaddr; /* target virtual addr at which the
memory was written */
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
@ -201,11 +211,13 @@ typedef struct CPUSPARCState {
uint32_t pstate;
uint32_t tl;
uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
target_ulong agregs[8]; /* alternate general registers */
target_ulong igregs[8]; /* interrupt general registers */
target_ulong mgregs[8]; /* mmu general registers */
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 version;
uint64_t fprs;
uint64_t tick_cmpr, stick_cmpr;
#endif
#if !defined(TARGET_SPARC64) && !defined(reg_T2)
target_ulong t2;
@ -275,7 +287,6 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
struct siginfo;
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
#define TARGET_PAGE_BITS 12 /* 4k */
#include "cpu-all.h"
#endif

View file

@ -65,6 +65,9 @@ void do_fcmpd_fcc2(void);
void do_fcmps_fcc3(void);
void do_fcmpd_fcc3(void);
void do_popc();
void do_wrpstate();
void do_done();
void do_retry();
#endif
void do_ldd_kernel(target_ulong addr);
void do_ldd_user(target_ulong addr);

View file

@ -1,7 +1,7 @@
/*
* sparc helpers
*
* Copyright (c) 2003 Fabrice Bellard
* 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
@ -28,7 +28,6 @@
#include "cpu.h"
#include "exec-all.h"
//#define DEBUG_PCALL
//#define DEBUG_MMU
/* Sparc MMU emulation */
@ -62,6 +61,9 @@ int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
#else
#ifndef TARGET_SPARC64
/*
* Sparc V8 Reference MMU (SRMMU)
*/
static const int access_table[8][8] = {
{ 0, 0, 0, 0, 2, 0, 3, 3 },
{ 0, 0, 0, 0, 2, 0, 0, 0 },
@ -229,6 +231,9 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
}
}
#else
/*
* UltraSparc IIi I/DMMUs
*/
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
int *access_index, target_ulong address, int rw,
int is_user)
@ -237,46 +242,55 @@ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical
unsigned int i;
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
*physical = address & 0xffffffff;
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
return 0;
}
for (i = 0; i < 64; i++) {
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
switch (env->dtlb_tte[i] >> 60) {
default:
case 0x4: // 8k
mask = 0xffffffffffffe000ULL;
break;
case 0x5: // 64k
mask = 0xffffffffffff0000ULL;
break;
case 0x6: // 512k
mask = 0xfffffffffff80000ULL;
break;
case 0x7: // 4M
mask = 0xffffffffffc00000ULL;
break;
}
// ctx match, vaddr match?
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
// access ok?
if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) ||
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
env->exception_index = TT_DFAULT;
return 1;
}
*physical = env->dtlb_tte[i] & 0xffffe000;
*prot = PAGE_READ;
if (env->dtlb_tte[i] & 0x2)
*prot |= PAGE_WRITE;
return 0;
switch ((env->dtlb_tte[i] >> 61) & 3) {
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;
}
// ctx match, vaddr match?
if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
(address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
// valid, access ok?
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
((env->dtlb_tte[i] & 0x4) && is_user) ||
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
if (env->dmmuregs[3]) /* Fault status register */
env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
env->dmmuregs[4] = address; /* Fault address register */
env->exception_index = TT_DFAULT;
#ifdef DEBUG_MMU
printf("DFAULT at 0x%llx\n", address);
#endif
return 1;
}
*physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
*prot = PAGE_READ;
if (env->dtlb_tte[i] & 0x2)
*prot |= PAGE_WRITE;
return 0;
}
}
env->exception_index = TT_DFAULT;
#ifdef DEBUG_MMU
printf("DMISS at 0x%llx\n", address);
#endif
env->exception_index = TT_DMISS;
return 1;
}
@ -288,42 +302,51 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical
unsigned int i;
if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
*physical = address & 0xffffffff;
*physical = address;
*prot = PAGE_READ;
return 0;
}
for (i = 0; i < 64; i++) {
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
switch (env->itlb_tte[i] >> 60) {
default:
case 0x4: // 8k
mask = 0xffffffffffffe000ULL;
break;
case 0x5: // 64k
mask = 0xffffffffffff0000ULL;
break;
case 0x6: // 512k
mask = 0xfffffffffff80000ULL;
break;
case 0x7: // 4M
mask = 0xffffffffffc00000ULL;
switch ((env->itlb_tte[i] >> 61) & 3) {
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;
}
// ctx match, vaddr match?
if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
// valid, access ok?
if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
((env->itlb_tte[i] & 0x4) && is_user)) {
if (env->immuregs[3]) /* Fault status register */
env->immuregs[3] = 2; /* overflow (not read before another fault) */
env->immuregs[3] |= (is_user << 3) | 1;
env->exception_index = TT_TFAULT;
#ifdef DEBUG_MMU
printf("TFAULT at 0x%llx\n", address);
#endif
return 1;
}
// ctx match, vaddr match?
if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
(address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
// access ok?
if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) {
env->exception_index = TT_TFAULT;
return 1;
}
*physical = env->itlb_tte[i] & 0xffffe000;
*prot = PAGE_READ;
return 0;
}
*physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
*prot = PAGE_READ;
return 0;
}
}
env->exception_index = TT_TFAULT;
#ifdef DEBUG_MMU
printf("TMISS at 0x%llx\n", address);
#endif
env->exception_index = TT_TMISS;
return 1;
}
@ -341,15 +364,17 @@ int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
target_ulong virt_addr;
target_ulong virt_addr, vaddr;
target_phys_addr_t paddr;
unsigned long vaddr;
int error_code = 0, prot, ret = 0, access_index;
error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
if (error_code == 0) {
virt_addr = address & TARGET_PAGE_MASK;
vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
#ifdef DEBUG_MMU
printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
#endif
ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
return ret;
}
@ -471,4 +496,77 @@ void dump_mmu(CPUState *env)
printf("MMU dump ends\n");
}
#endif
#else
#ifdef DEBUG_MMU
void dump_mmu(CPUState *env)
{
unsigned int i;
const char *mask;
printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]);
if ((env->lsu & DMMU_E) == 0) {
printf("DMMU disabled\n");
} else {
printf("DMMU dump:\n");
for (i = 0; i < 64; i++) {
switch ((env->dtlb_tte[i] >> 61) & 3) {
default:
case 0x0:
mask = " 8k";
break;
case 0x1:
mask = " 64k";
break;
case 0x2:
mask = "512k";
break;
case 0x3:
mask = " 4M";
break;
}
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n",
env->dtlb_tag[i] & ~0x1fffULL,
env->dtlb_tte[i] & 0x1ffffffe000ULL,
mask,
env->dtlb_tte[i] & 0x4? "priv": "user",
env->dtlb_tte[i] & 0x2? "RW": "RO",
env->dtlb_tte[i] & 0x40? "locked": "unlocked",
env->dtlb_tag[i] & 0x1fffULL);
}
}
}
if ((env->lsu & IMMU_E) == 0) {
printf("IMMU disabled\n");
} else {
printf("IMMU dump:\n");
for (i = 0; i < 64; i++) {
switch ((env->itlb_tte[i] >> 61) & 3) {
default:
case 0x0:
mask = " 8k";
break;
case 0x1:
mask = " 64k";
break;
case 0x2:
mask = "512k";
break;
case 0x3:
mask = " 4M";
break;
}
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n",
env->itlb_tag[i] & ~0x1fffULL,
env->itlb_tte[i] & 0x1ffffffe000ULL,
mask,
env->itlb_tte[i] & 0x4? "priv": "user",
env->itlb_tte[i] & 0x40? "locked": "unlocked",
env->itlb_tag[i] & 0x1fffULL);
}
}
}
}
#endif
#endif

View file

@ -267,15 +267,6 @@
#endif
#ifdef TARGET_SPARC64
#undef JUMP_TB
#define JUMP_TB(opname, tbparam, n, eip) \
do { \
GOTO_TB(opname, tbparam, n); \
T0 = (long)(tbparam) + (n); \
env->pc = (eip) & 0xffffffff; \
EXIT_TB(); \
} while (0)
#ifdef WORDS_BIGENDIAN
typedef union UREG64 {
struct { uint16_t v3, v2, v1, v0; } w;
@ -388,7 +379,7 @@ void OPPROTO op_add_T1_T0_cc(void)
env->psr |= PSR_ZERO;
if ((int32_t) T0 < 0)
env->psr |= PSR_NEG;
if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
env->psr |= PSR_CARRY;
if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@ -433,7 +424,7 @@ void OPPROTO op_addx_T1_T0_cc(void)
env->psr |= PSR_ZERO;
if ((int32_t) T0 < 0)
env->psr |= PSR_NEG;
if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
env->psr |= PSR_CARRY;
if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@ -478,7 +469,7 @@ void OPPROTO op_sub_T1_T0_cc(void)
env->psr |= PSR_ZERO;
if ((int32_t) T0 < 0)
env->psr |= PSR_NEG;
if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
env->psr |= PSR_CARRY;
if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@ -523,7 +514,7 @@ void OPPROTO op_subx_T1_T0_cc(void)
env->psr |= PSR_ZERO;
if ((int32_t) T0 < 0)
env->psr |= PSR_NEG;
if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
env->psr |= PSR_CARRY;
if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@ -585,7 +576,11 @@ void OPPROTO op_umul_T1_T0(void)
{
uint64_t res;
res = (uint64_t) T0 * (uint64_t) T1;
#ifdef TARGET_SPARC64
T0 = res;
#else
T0 = res & 0xffffffff;
#endif
env->y = res >> 32;
}
@ -593,7 +588,11 @@ void OPPROTO op_smul_T1_T0(void)
{
uint64_t res;
res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
#ifdef TARGET_SPARC64
T0 = res;
#else
T0 = res & 0xffffffff;
#endif
env->y = res >> 32;
}
@ -902,7 +901,7 @@ void OPPROTO op_rdpstate(void)
void OPPROTO op_wrpstate(void)
{
env->pstate = T0 & 0x1f;
do_wrpstate();
}
// CWP handling is reversed in V9, but we still use the V8 register
@ -1201,12 +1200,12 @@ void OPPROTO op_eval_xbvc(void)
#ifdef TARGET_SPARC64
void OPPROTO op_eval_brz(void)
{
T2 = T0;
T2 = (T0 == 0);
}
void OPPROTO op_eval_brnz(void)
{
T2 = !T0;
T2 = (T0 != 0);
}
void OPPROTO op_eval_brlz(void)
@ -1266,43 +1265,32 @@ void OPPROTO op_next_insn(void)
env->npc = env->npc + 4;
}
void OPPROTO op_branch(void)
void OPPROTO op_goto_tb0(void)
{
env->npc = (uint32_t)PARAM3; /* XXX: optimize */
JUMP_TB(op_branch, PARAM1, 0, PARAM2);
GOTO_TB(op_goto_tb0, PARAM1, 0);
}
void OPPROTO op_branch2(void)
void OPPROTO op_goto_tb1(void)
{
if (T2) {
env->npc = (uint32_t)PARAM2 + 4;
JUMP_TB(op_branch2, PARAM1, 0, PARAM2);
} else {
env->npc = (uint32_t)PARAM3 + 4;
JUMP_TB(op_branch2, PARAM1, 1, PARAM3);
}
GOTO_TB(op_goto_tb1, PARAM1, 1);
}
void OPPROTO op_jmp_label(void)
{
GOTO_LABEL_PARAM(1);
}
void OPPROTO op_jnz_T2_label(void)
{
if (T2)
GOTO_LABEL_PARAM(1);
FORCE_RET();
}
void OPPROTO op_branch_a(void)
void OPPROTO op_jz_T2_label(void)
{
if (T2) {
env->npc = (uint32_t)PARAM2; /* XXX: optimize */
JUMP_TB(op_branch_a, PARAM1, 0, PARAM3);
} else {
env->npc = (uint32_t)PARAM3 + 8; /* XXX: optimize */
JUMP_TB(op_branch_a, PARAM1, 1, PARAM3 + 4);
}
FORCE_RET();
}
void OPPROTO op_generic_branch(void)
{
if (T2) {
env->npc = (uint32_t)PARAM1;
} else {
env->npc = (uint32_t)PARAM2;
}
if (!T2)
GOTO_LABEL_PARAM(1);
FORCE_RET();
}
@ -1547,18 +1535,12 @@ void OPPROTO op_popc(void)
void OPPROTO op_done(void)
{
env->pc = env->tnpc[env->tl];
env->npc = env->tnpc[env->tl] + 4;
env->pstate = env->tstate[env->tl];
env->tl--;
do_done();
}
void OPPROTO op_retry(void)
{
env->pc = env->tpc[env->tl];
env->npc = env->tnpc[env->tl];
env->pstate = env->tstate[env->tl];
env->tl--;
do_retry();
}
void OPPROTO op_sir(void)

View file

@ -1,5 +1,6 @@
#include "exec.h"
//#define DEBUG_PCALL
//#define DEBUG_MMU
void raise_exception(int tt)
@ -223,7 +224,7 @@ void do_fcmpd_fcc3 (void)
#ifndef TARGET_SPARC64
void helper_ld_asi(int asi, int size, int sign)
{
uint32_t ret;
uint32_t ret = 0;
switch (asi) {
case 3: /* MMU probe */
@ -299,7 +300,8 @@ void helper_st_asi(int asi, int size, int sign)
}
case 4: /* write MMU regs */
{
int reg = (T0 >> 8) & 0xf, oldreg;
int reg = (T0 >> 8) & 0xf;
uint32_t oldreg;
oldreg = env->mmuregs[reg];
switch(reg) {
@ -339,7 +341,7 @@ void helper_st_asi(int asi, int size, int sign)
// value (T1) = src
// address (T0) = dst
// copy 32 bytes
int src = T1, dst = T0;
uint32_t src = T1, dst = T0;
uint8_t temp[32];
tswap32s(&src);
@ -353,7 +355,8 @@ void helper_st_asi(int asi, int size, int sign)
// value (T1, T2)
// address (T0) = dst
// fill 32 bytes
int i, dst = T0;
int i;
uint32_t dst = T0;
uint64_t val;
val = (((uint64_t)T1) << 32) | T2;
@ -366,7 +369,7 @@ void helper_st_asi(int asi, int size, int sign)
return;
case 0x20 ... 0x2f: /* MMU passthrough */
{
int temp = T1;
uint32_t temp = T1;
if (size == 4)
tswap32s(&temp);
else if (size == 2)
@ -383,10 +386,10 @@ void helper_st_asi(int asi, int size, int sign)
void helper_ld_asi(int asi, int size, int sign)
{
uint64_t ret;
uint64_t ret = 0;
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
raise_exception(TT_PRIV_INSN);
raise_exception(TT_PRIV_ACT);
switch (asi) {
case 0x14: // Bypass
@ -401,8 +404,23 @@ void helper_ld_asi(int asi, int size, int sign)
tswap16s((uint16_t *)&ret);
break;
}
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
case 0x10: // As if user primary
case 0x11: // As if user secondary
case 0x18: // As if user primary LE
case 0x19: // As if user secondary LE
case 0x1c: // Bypass LE
case 0x1d: // Bypass, non-cacheable LE
case 0x24: // Nucleus quad LDD 128 bit atomic
case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
case 0x82: // Primary no-fault
case 0x83: // Secondary no-fault
case 0x88: // Primary LE
case 0x89: // Secondary LE
case 0x8a: // Primary no-fault LE
case 0x8b: // Secondary no-fault LE
// XXX
break;
case 0x45: // LSU
@ -418,8 +436,22 @@ void helper_ld_asi(int asi, int size, int sign)
case 0x51: // I-MMU 8k TSB pointer
case 0x52: // I-MMU 64k TSB pointer
case 0x55: // I-MMU data access
case 0x56: // I-MMU tag read
// XXX
break;
case 0x56: // I-MMU tag read
{
unsigned int i;
for (i = 0; i < 64; i++) {
// Valid, ctx match, vaddr match
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
env->itlb_tag[i] == T0) {
ret = env->itlb_tag[i];
break;
}
}
break;
}
case 0x58: // D-MMU regs
{
int reg = (T0 >> 3) & 0xf;
@ -427,16 +459,34 @@ void helper_ld_asi(int asi, int size, int sign)
ret = env->dmmuregs[reg];
break;
}
case 0x5e: // D-MMU tag read
{
unsigned int i;
for (i = 0; i < 64; i++) {
// Valid, ctx match, vaddr match
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
env->dtlb_tag[i] == T0) {
ret = env->dtlb_tag[i];
break;
}
}
break;
}
case 0x59: // D-MMU 8k TSB pointer
case 0x5a: // D-MMU 64k TSB pointer
case 0x5b: // D-MMU data pointer
case 0x5d: // D-MMU data access
case 0x5e: // D-MMU tag read
case 0x48: // Interrupt dispatch, RO
case 0x49: // Interrupt data receive
case 0x7f: // Incoming interrupt vector, RO
// XXX
break;
case 0x54: // I-MMU data in, WO
case 0x57: // I-MMU demap, WO
case 0x5c: // D-MMU data in, WO
case 0x5f: // D-MMU demap, WO
case 0x77: // Interrupt vector, WO
default:
ret = 0;
break;
@ -447,7 +497,7 @@ void helper_ld_asi(int asi, int size, int sign)
void helper_st_asi(int asi, int size, int sign)
{
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
raise_exception(TT_PRIV_INSN);
raise_exception(TT_PRIV_ACT);
switch(asi) {
case 0x14: // Bypass
@ -463,8 +513,19 @@ void helper_st_asi(int asi, int size, int sign)
cpu_physical_memory_write(T0, (void *) &temp, size);
}
return;
case 0x04: // Nucleus
case 0x0c: // Nucleus Little Endian (LE)
case 0x10: // As if user primary
case 0x11: // As if user secondary
case 0x18: // As if user primary LE
case 0x19: // As if user secondary LE
case 0x1c: // Bypass LE
case 0x1d: // Bypass, non-cacheable LE
case 0x24: // Nucleus quad LDD 128 bit atomic
case 0x2c: // Nucleus quad LDD 128 bit atomic
case 0x4a: // UPA config
case 0x88: // Primary LE
case 0x89: // Secondary LE
// XXX
return;
case 0x45: // LSU
@ -475,8 +536,13 @@ void helper_st_asi(int asi, int size, int sign)
env->lsu = T1 & (DMMU_E | IMMU_E);
// Mappings generated during D/I MMU disabled mode are
// invalid in normal mode
if (oldreg != env->lsu)
if (oldreg != env->lsu) {
#ifdef DEBUG_MMU
printf("LSU change: 0x%llx -> 0x%llx\n", oldreg, env->lsu);
dump_mmu(env);
#endif
tlb_flush(env, 1);
}
return;
}
case 0x50: // I-MMU regs
@ -506,7 +572,7 @@ void helper_st_asi(int asi, int size, int sign)
env->immuregs[reg] = T1;
#ifdef DEBUG_MMU
if (oldreg != env->immuregs[reg]) {
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]);
printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->immuregs[reg]);
}
dump_mmu(env);
#endif
@ -544,6 +610,7 @@ void helper_st_asi(int asi, int size, int sign)
return;
}
case 0x57: // I-MMU demap
// XXX
return;
case 0x58: // D-MMU regs
{
@ -574,7 +641,7 @@ void helper_st_asi(int asi, int size, int sign)
env->dmmuregs[reg] = T1;
#ifdef DEBUG_MMU
if (oldreg != env->dmmuregs[reg]) {
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]);
printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->dmmuregs[reg]);
}
dump_mmu(env);
#endif
@ -612,6 +679,8 @@ void helper_st_asi(int asi, int size, int sign)
return;
}
case 0x5f: // D-MMU demap
case 0x49: // Interrupt data receive
// XXX
return;
case 0x51: // I-MMU 8k TSB pointer, RO
case 0x52: // I-MMU 64k TSB pointer, RO
@ -620,6 +689,12 @@ void helper_st_asi(int asi, int size, int sign)
case 0x5a: // D-MMU 64k TSB pointer, RO
case 0x5b: // D-MMU data pointer, RO
case 0x5e: // D-MMU tag read, RO
case 0x48: // Interrupt dispatch, RO
case 0x7f: // Incoming interrupt vector, RO
case 0x82: // Primary no-fault, RO
case 0x83: // Secondary no-fault, RO
case 0x8a: // Primary no-fault LE, RO
case 0x8b: // Secondary no-fault LE, RO
default:
return;
}
@ -704,6 +779,61 @@ void do_popc()
T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
}
static inline uint64_t *get_gregset(uint64_t pstate)
{
switch (pstate) {
default:
case 0:
return env->bgregs;
case PS_AG:
return env->agregs;
case PS_MG:
return env->mgregs;
case PS_IG:
return env->igregs;
}
}
void do_wrpstate()
{
uint64_t new_pstate, pstate_regs, new_pstate_regs;
uint64_t *src, *dst;
new_pstate = T0 & 0xf3f;
pstate_regs = env->pstate & 0xc01;
new_pstate_regs = new_pstate & 0xc01;
if (new_pstate_regs != pstate_regs) {
// Switch global register bank
src = get_gregset(new_pstate_regs);
dst = get_gregset(pstate_regs);
memcpy32(dst, env->gregs);
memcpy32(env->gregs, src);
}
env->pstate = new_pstate;
}
void do_done(void)
{
env->tl--;
env->pc = env->tnpc[env->tl];
env->npc = env->tnpc[env->tl] + 4;
PUT_CCR(env, env->tstate[env->tl] >> 32);
env->asi = (env->tstate[env->tl] >> 24) & 0xff;
env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
set_cwp(env->tstate[env->tl] & 0xff);
}
void do_retry(void)
{
env->tl--;
env->pc = env->tpc[env->tl];
env->npc = env->tnpc[env->tl];
PUT_CCR(env, env->tstate[env->tl] >> 32);
env->asi = (env->tstate[env->tl] >> 24) & 0xff;
env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
set_cwp(env->tstate[env->tl] & 0xff);
}
#endif
void set_cwp(int new_cwp)
@ -744,7 +874,7 @@ void do_interrupt(int intno)
#ifdef DEBUG_PCALL
if (loglevel & CPU_LOG_INT) {
static int count;
fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
fprintf(logfile, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n",
count, intno,
env->pc,
env->npc, env->regwptr[6]);
@ -766,8 +896,8 @@ void do_interrupt(int intno)
}
#endif
#if !defined(CONFIG_USER_ONLY)
if (env->pstate & PS_IE) {
cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
if (env->tl == MAXTL) {
cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
return;
}
#endif
@ -776,8 +906,16 @@ void do_interrupt(int intno)
env->tpc[env->tl] = env->pc;
env->tnpc[env->tl] = env->npc;
env->tt[env->tl] = intno;
env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4);
env->tl++;
env->pstate = PS_PEF | PS_PRIV | PS_AG;
env->tbr &= ~0x7fffULL;
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
if (env->tl < MAXTL - 1) {
env->tl++;
} else {
env->pstate |= PS_RED;
if (env->tl != MAXTL)
env->tl++;
}
env->pc = env->tbr;
env->npc = env->pc + 4;
env->exception_index = 0;

View file

@ -105,20 +105,10 @@ void OPPROTO glue(op_casx, MEMSUFFIX)(void)
void OPPROTO glue(op_ldsw, MEMSUFFIX)(void)
{
T1 = (int64_t)glue(ldl, MEMSUFFIX)(T0);
T1 = (int64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff);
}
void OPPROTO glue(op_ldx, MEMSUFFIX)(void)
{
// XXX
T1 = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
T1 |= glue(ldl, MEMSUFFIX)(T0);
}
void OPPROTO glue(op_stx, MEMSUFFIX)(void)
{
glue(stl, MEMSUFFIX)(T0, T1 >> 32);
glue(stl, MEMSUFFIX)(T0, T1 & 0xffffffff);
}
SPARC_LD_OP(ldx, ldq);
SPARC_ST_OP(stx, stq);
#endif
#undef MEMSUFFIX

View file

@ -86,6 +86,12 @@ enum {
#define DFPREG(r) (r)
#endif
#ifdef USE_DIRECT_JUMP
#define TBPARAM(x)
#else
#define TBPARAM(x) (long)(x)
#endif
static int sign_extend(int x, int len)
{
len = 32 - len;
@ -462,7 +468,7 @@ OP_LD_TABLE(casx);
static inline void gen_movl_imm_TN(int reg, uint32_t imm)
{
gen_op_movl_TN_im[reg] (imm);
gen_op_movl_TN_im[reg](imm);
}
static inline void gen_movl_imm_T1(uint32_t val)
@ -529,15 +535,6 @@ static inline void gen_movl_T1_reg(int reg)
gen_movl_TN_reg(reg, 1);
}
/* call this function before using T2 as it may have been set for a jump */
static inline void flush_T2(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
dc->npc = DYNAMIC_PC;
}
}
static inline void gen_jmp_im(target_ulong pc)
{
#ifdef TARGET_SPARC64
@ -564,10 +561,88 @@ static inline void gen_movl_npc_im(target_ulong npc)
#endif
}
static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
{
int l1;
l1 = gen_new_label();
gen_op_jz_T2_label(l1);
gen_op_goto_tb0(TBPARAM(tb));
gen_jmp_im(pc1);
gen_movl_npc_im(pc1 + 4);
gen_op_movl_T0_im((long)tb + 0);
gen_op_exit_tb();
gen_set_label(l1);
gen_op_goto_tb1(TBPARAM(tb));
gen_jmp_im(pc2);
gen_movl_npc_im(pc2 + 4);
gen_op_movl_T0_im((long)tb + 1);
gen_op_exit_tb();
}
static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
{
int l1;
l1 = gen_new_label();
gen_op_jz_T2_label(l1);
gen_op_goto_tb0(TBPARAM(tb));
gen_jmp_im(pc2);
gen_movl_npc_im(pc1);
gen_op_movl_T0_im((long)tb + 0);
gen_op_exit_tb();
gen_set_label(l1);
gen_op_goto_tb1(TBPARAM(tb));
gen_jmp_im(pc2 + 4);
gen_movl_npc_im(pc2 + 8);
gen_op_movl_T0_im((long)tb + 1);
gen_op_exit_tb();
}
static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc)
{
gen_op_goto_tb0(TBPARAM(tb));
gen_jmp_im(pc);
gen_movl_npc_im(npc);
gen_op_movl_T0_im((long)tb + 0);
gen_op_exit_tb();
}
static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2)
{
int l1, l2;
l1 = gen_new_label();
l2 = gen_new_label();
gen_op_jz_T2_label(l1);
gen_movl_npc_im(npc1);
gen_op_jmp_label(l2);
gen_set_label(l1);
gen_movl_npc_im(npc2);
gen_set_label(l2);
}
/* call this function before using T2 as it may have been set for a jump */
static inline void flush_T2(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
dc->npc = DYNAMIC_PC;
}
}
static inline void save_npc(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
dc->npc = DYNAMIC_PC;
} else if (dc->npc != DYNAMIC_PC) {
gen_movl_npc_im(dc->npc);
@ -583,7 +658,7 @@ static inline void save_state(DisasContext * dc)
static inline void gen_mov_pc_npc(DisasContext * dc)
{
if (dc->npc == JUMP_PC) {
gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
gen_op_mov_pc_npc();
dc->pc = DYNAMIC_PC;
} else if (dc->npc == DYNAMIC_PC) {
@ -769,7 +844,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
flush_T2(dc);
gen_cond[cc][cond]();
if (a) {
gen_op_branch_a((long)dc->tb, target, dc->npc);
gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@ -808,7 +883,7 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
flush_T2(dc);
gen_fcond[cc][cond]();
if (a) {
gen_op_branch_a((long)dc->tb, target, dc->npc);
gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@ -829,7 +904,7 @@ static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn)
flush_T2(dc);
gen_cond_reg(cond);
if (a) {
gen_op_branch_a((long)dc->tb, target, dc->npc);
gen_branch_a(dc, (long)dc->tb, target, dc->npc);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@ -893,7 +968,7 @@ static void disas_sparc_insn(DisasContext * dc)
target <<= 2;
target = sign_extend(target, 16);
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_T0_reg(rs1);
gen_movl_reg_T0(rs1);
do_branch_reg(dc, target, insn);
goto jmp_insn;
}
@ -952,7 +1027,15 @@ static void disas_sparc_insn(DisasContext * dc)
/*CALL*/ {
target_long target = GET_FIELDs(insn, 2, 31) << 2;
#ifdef TARGET_SPARC64
if (dc->pc == (uint32_t)dc->pc) {
gen_op_movl_T0_im(dc->pc);
} else {
gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
}
#else
gen_op_movl_T0_im(dc->pc);
#endif
gen_movl_T0_reg(15);
target += dc->pc;
gen_mov_pc_npc(dc);
@ -1039,6 +1122,25 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
gen_movl_T0_reg(rd);
break;
case 0x17: /* Tick compare */
gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr));
gen_movl_T0_reg(rd);
break;
case 0x18: /* System tick */
gen_op_rdtick(); // XXX
gen_movl_T0_reg(rd);
break;
case 0x19: /* System tick compare */
gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr));
gen_movl_T0_reg(rd);
break;
case 0x10: /* Performance Control */
case 0x11: /* Performance Instrumentation Counter */
case 0x12: /* Dispatch Control */
case 0x13: /* Graphics Status */
case 0x14: /* Softint set, WO */
case 0x15: /* Softint clear, WO */
case 0x16: /* Softint write */
#endif
default:
goto illegal_insn;
@ -1548,6 +1650,50 @@ static void disas_sparc_insn(DisasContext * dc)
}
gen_movl_T0_reg(rd);
}
#endif
#ifdef TARGET_SPARC64
} else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 20, 31);
gen_movl_simm_T1(rs2);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
gen_op_sll();
gen_movl_T0_reg(rd);
} else if (xop == 0x26) { /* srl, V9 srlx */
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 20, 31);
gen_movl_simm_T1(rs2);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
if (insn & (1 << 12))
gen_op_srlx();
else
gen_op_srl();
gen_movl_T0_reg(rd);
} else if (xop == 0x27) { /* sra, V9 srax */
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 20, 31);
gen_movl_simm_T1(rs2);
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
if (insn & (1 << 12))
gen_op_srax();
else
gen_op_sra();
gen_movl_T0_reg(rd);
#endif
} else if (xop < 0x38) {
rs1 = GET_FIELD(insn, 13, 17);
@ -1660,32 +1806,20 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_mulscc_T1_T0();
gen_movl_T0_reg(rd);
break;
case 0x25: /* sll, V9 sllx ( == sll) */
#ifndef TARGET_SPARC64
case 0x25: /* sll */
gen_op_sll();
gen_movl_T0_reg(rd);
break;
case 0x26: /* srl, V9 srlx */
#ifdef TARGET_SPARC64
if (insn & (1 << 12))
gen_op_srlx();
else
gen_op_srl();
#else
case 0x26: /* srl */
gen_op_srl();
#endif
gen_movl_T0_reg(rd);
break;
case 0x27: /* sra, V9 srax */
#ifdef TARGET_SPARC64
if (insn & (1 << 12))
gen_op_srax();
else
gen_op_sra();
#else
case 0x27: /* sra */
gen_op_sra();
#endif
gen_movl_T0_reg(rd);
break;
#endif
case 0x30:
{
switch(rd) {
@ -1709,7 +1843,28 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_sir();
#endif
break;
case 0x17: /* Tick compare */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
break;
case 0x18: /* System tick */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
break;
case 0x19: /* System tick compare */
#if !defined(CONFIG_USER_ONLY)
if (!supervisor(dc))
goto illegal_insn;
#endif
gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
break;
case 0x10: /* Performance Control */
case 0x11: /* Performance Instrumentation Counter */
case 0x12: /* Dispatch Control */
@ -1717,9 +1872,7 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x14: /* Softint set */
case 0x15: /* Softint clear */
case 0x16: /* Softint write */
case 0x17: /* Tick compare */
case 0x18: /* System tick */
case 0x19: /* System tick compare */
#endif
default:
goto illegal_insn;
}
@ -1770,7 +1923,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_wrtick();
break;
case 5: // tba
gen_op_movl_env_T0(offsetof(CPUSPARCState, tbr));
gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
break;
case 6: // pstate
gen_op_wrpstate();
@ -1896,7 +2049,6 @@ static void disas_sparc_insn(DisasContext * dc)
}
#ifdef TARGET_SPARC64
} else if (xop == 0x39) { /* V9 return */
gen_op_restore();
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
@ -1920,6 +2072,7 @@ static void disas_sparc_insn(DisasContext * dc)
}
#endif
}
gen_op_restore();
gen_mov_pc_npc(dc);
gen_op_movl_npc_T0();
dc->npc = DYNAMIC_PC;
@ -1993,13 +2146,17 @@ static void disas_sparc_insn(DisasContext * dc)
case 0:
if (!supervisor(dc))
goto priv_insn;
dc->npc = DYNAMIC_PC;
dc->pc = DYNAMIC_PC;
gen_op_done();
break;
goto jmp_insn;
case 1:
if (!supervisor(dc))
goto priv_insn;
dc->npc = DYNAMIC_PC;
dc->pc = DYNAMIC_PC;
gen_op_retry();
break;
goto jmp_insn;
default:
goto illegal_insn;
}
@ -2317,7 +2474,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_next_insn();
} else if (dc->npc == JUMP_PC) {
/* we can do a static jump */
gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
dc->is_br = 1;
} else {
dc->pc = dc->npc;
@ -2365,6 +2522,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
nb_gen_labels = 0;
do {
if (env->nb_breakpoints > 0) {
@ -2421,7 +2579,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
if (dc->pc != DYNAMIC_PC &&
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
/* static PC and NPC: we can use direct chaining */
gen_op_branch((long)tb, dc->pc, dc->npc);
gen_branch(dc, (long)tb, dc->pc, dc->npc);
} else {
if (dc->pc != DYNAMIC_PC)
gen_jmp_im(dc->pc);
@ -2487,15 +2645,16 @@ void cpu_reset(CPUSPARCState *env)
#else
env->psrs = 1;
env->psrps = 1;
env->pc = 0xffd00000;
env->gregs[1] = ram_size;
env->npc = env->pc + 4;
#ifdef TARGET_SPARC64
env->pstate = PS_AM | PS_PRIV; // XXX: Force AM
env->pstate = PS_PRIV;
env->version = GET_VER(env);
env->pc = 0x1fff0000000ULL;
#else
env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
env->pc = 0xffd00000;
#endif
env->npc = env->pc + 4;
#endif
}