aboutsummaryrefslogtreecommitdiff
path: root/target-sparc
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-12-19 23:18:01 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-12-19 23:18:01 +0000
commite80cfcfc8884400e826328b772971913a14d0f44 (patch)
treef9bbe461ff5dd6f13fbdbd781053309564c0b872 /target-sparc
parent9772c73bbc9f24a66bf060e16c0625a258b1bb41 (diff)
downloadqemu-e80cfcfc8884400e826328b772971913a14d0f44.zip
qemu-e80cfcfc8884400e826328b772971913a14d0f44.tar.gz
qemu-e80cfcfc8884400e826328b772971913a14d0f44.tar.bz2
SPARC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/cpu.h28
-rw-r--r--target-sparc/exec.h3
-rw-r--r--target-sparc/fop_template.h12
-rw-r--r--target-sparc/helper.c255
-rw-r--r--target-sparc/op.c29
-rw-r--r--target-sparc/op_helper.c176
-rw-r--r--target-sparc/op_mem.h4
-rw-r--r--target-sparc/translate.c396
8 files changed, 667 insertions, 236 deletions
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index adf8df2..a66d2e3 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -10,23 +10,42 @@
/* trap definitions */
#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_FP_EXCP 0x08
#define TT_DIV_ZERO 0x2a
#define TT_TRAP 0x80
+#define TT_EXTINT 0x10
#define PSR_NEG (1<<23)
#define PSR_ZERO (1<<22)
#define PSR_OVF (1<<21)
#define PSR_CARRY (1<<20)
#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
+#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
/* Fake impl 0, version 4 */
-#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp)
+#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \
+ (env->psref? PSR_EF : 0) | \
+ (env->psrpil << 8) | \
+ (env->psrs? PSR_S : 0) | \
+ (env->psrs? PSR_PS : 0) | \
+ (env->psret? PSR_ET : 0) | env->cwp)
+
+#define PUT_PSR(env, val) do { int _tmp = val; \
+ env->psr = _tmp & ~PSR_ICC; \
+ env->psref = (_tmp & PSR_EF)? 1 : 0; \
+ env->psrpil = (_tmp & PSR_PIL) >> 8; \
+ env->psrs = (_tmp & PSR_S)? 1 : 0; \
+ env->psrps = (_tmp & PSR_PS)? 1 : 0; \
+ env->psret = (_tmp & PSR_ET)? 1 : 0; \
+ set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1)); \
+ } while (0)
/* Trap base register */
#define TBR_BASE_MASK 0xfffff000
@@ -65,6 +84,9 @@
#define FSR_FTT1 (1<<15)
#define FSR_FTT0 (1<<14)
#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
+#define FSR_FTT_IEEE_EXCP (1 << 14)
+#define FSR_FTT_UNIMPFPOP (3 << 14)
+#define FSR_FTT_INVAL_FPR (6 << 14)
#define FSR_FCC1 (1<<11)
#define FSR_FCC0 (1<<10)
@@ -106,6 +128,8 @@ typedef struct CPUSPARCState {
int psrs; /* supervisor mode (extracted from PSR) */
int psrps; /* previous supervisor mode */
int psret; /* enable traps */
+ int psrpil; /* interrupt level */
+ int psref; /* enable fpu */
jmp_buf jmp_env;
int user_mode_only;
int exception_index;
@@ -144,6 +168,8 @@ typedef struct CPUSPARCState {
CPUSPARCState *cpu_sparc_init(void);
int cpu_sparc_exec(CPUSPARCState *s);
int cpu_sparc_close(CPUSPARCState *s);
+void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f);
+double cpu_put_fp64(uint64_t mant, uint16_t exp);
struct siginfo;
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 1b3d9a0..f8edc17 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -40,6 +40,9 @@ void do_interrupt(int intno, int is_int, int error_code,
void raise_exception_err(int exception_index, int error_code);
void raise_exception(int tt);
void memcpy32(uint32_t *dst, const uint32_t *src);
+uint32_t mmu_probe(uint32_t address, int mmulev);
+void dump_mmu(void);
+void helper_debug();
/* XXX: move that to a generic header */
#if !defined(CONFIG_USER_ONLY)
diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h
index 2987b68..eb1e1e3 100644
--- a/target-sparc/fop_template.h
+++ b/target-sparc/fop_template.h
@@ -51,18 +51,6 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void)
}
/* double floating point registers moves */
-#if 0
-#define CPU_DOUBLE_U_DEF
-typedef union {
- double d;
- struct {
- uint32_t lower;
- uint32_t upper;
- } l;
- uint64_t ll;
-} CPU_DoubleU;
-#endif /* CPU_DOUBLE_U_DEF */
-
void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
{
CPU_DoubleU u;
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 93ef930..76ad643 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -19,7 +19,8 @@
*/
#include "exec.h"
-#define DEBUG_PCALL
+//#define DEBUG_PCALL
+//#define DEBUG_MMU
/* Sparc MMU emulation */
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
@@ -108,80 +109,71 @@ static const int rw_table[2][8] = {
{ 0, 1, 0, 1, 0, 0, 0, 0 }
};
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int is_user, int is_softmmu)
+int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
+ int *access_index, uint32_t address, int rw,
+ int is_user)
{
- int exception = 0;
- int access_perms = 0, access_index = 0;
- uint8_t *pde_ptr;
+ int access_perms = 0;
+ target_phys_addr_t pde_ptr;
uint32_t pde, virt_addr;
- int error_code = 0, is_dirty, prot, ret = 0;
- unsigned long paddr, vaddr, page_offset;
-
- if (env->user_mode_only) {
- /* user mode only emulation */
- ret = -2;
- goto do_fault;
- }
+ int error_code = 0, is_dirty;
+ unsigned long page_offset;
virt_addr = address & TARGET_PAGE_MASK;
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
- paddr = address;
- page_offset = address & (TARGET_PAGE_SIZE - 1);
- prot = PAGE_READ | PAGE_WRITE;
- goto do_mapping;
+ *physical = address;
+ *prot = PAGE_READ | PAGE_WRITE;
+ return 0;
}
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
/* Context base + context number */
- pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
- pde = ldl_raw(pde_ptr);
+ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
/* Ctx pde */
switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
case 0: /* Invalid */
- error_code = 1;
- goto do_fault;
- case 2: /* PTE, maybe should not happen? */
+ return 1;
+ case 2: /* L0 PTE, maybe should not happen? */
case 3: /* Reserved */
- error_code = 4;
- goto do_fault;
- case 1: /* L1 PDE */
- pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_raw(pde_ptr);
+ return 4;
+ case 1: /* L0 PDE */
+ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
case 0: /* Invalid */
- error_code = 1;
- goto do_fault;
+ return 1;
case 3: /* Reserved */
- error_code = 4;
- goto do_fault;
- case 1: /* L2 PDE */
- pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_raw(pde_ptr);
+ return 4;
+ case 1: /* L1 PDE */
+ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
case 0: /* Invalid */
- error_code = 1;
- goto do_fault;
+ return 1;
case 3: /* Reserved */
- error_code = 4;
- goto do_fault;
- case 1: /* L3 PDE */
- pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_raw(pde_ptr);
+ return 4;
+ case 1: /* L2 PDE */
+ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
switch (pde & PTE_ENTRYTYPE_MASK) {
+ default:
case 0: /* Invalid */
- error_code = 1;
- goto do_fault;
+ return 1;
case 1: /* PDE, should not happen */
case 3: /* Reserved */
- error_code = 4;
- goto do_fault;
+ return 4;
case 2: /* L3 PTE */
virt_addr = address & TARGET_PAGE_MASK;
page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
@@ -201,40 +193,58 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
/* update page modified and dirty bits */
is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+ uint32_t tmppde;
pde |= PG_ACCESSED_MASK;
if (is_dirty)
pde |= PG_MODIFIED_MASK;
- stl_raw(pde_ptr, pde);
+ tmppde = bswap32(pde);
+ cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4);
}
-
/* check access */
- access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
+ *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
- error_code = access_table[access_index][access_perms];
+ error_code = access_table[*access_index][access_perms];
if (error_code)
- goto do_fault;
+ return error_code;
/* the page can be put in the TLB */
- prot = PAGE_READ;
+ *prot = PAGE_READ;
if (pde & PG_MODIFIED_MASK) {
/* only set write access if already dirty... otherwise wait
for dirty access */
if (rw_table[is_user][access_perms])
- prot |= PAGE_WRITE;
+ *prot |= PAGE_WRITE;
}
/* Even if large ptes, we map only one 4KB page in the cache to
avoid filling it too fast */
- virt_addr = address & TARGET_PAGE_MASK;
- paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+ *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+ return 0;
+}
+
+/* Perform address translation */
+int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+ int is_user, int is_softmmu)
+{
+ int exception = 0;
+ uint32_t virt_addr, paddr;
+ unsigned long vaddr;
+ int error_code = 0, prot, ret = 0, access_index;
- do_mapping:
- vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
+ if (env->user_mode_only) {
+ /* user mode only emulation */
+ error_code = -2;
+ goto do_fault_user;
+ }
- ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
- return ret;
+ 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));
+ ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+ return ret;
+ }
- do_fault:
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) | 2;
@@ -242,7 +252,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault
return 0;
-
+ do_fault_user:
env->exception_index = exception;
env->error_code = error_code;
return error_code;
@@ -289,13 +299,14 @@ void do_interrupt(int intno, int is_int, int error_code,
count, intno, error_code, is_int,
env->pc,
env->npc, env->regwptr[6]);
-#if 0
+#if 1
cpu_dump_state(env, logfile, fprintf, 0);
{
int i;
uint8_t *ptr;
+
fprintf(logfile, " code=");
- ptr = env->pc;
+ ptr = (uint8_t *)env->pc;
for(i = 0; i < 16; i++) {
fprintf(logfile, " %02x", ldub(ptr + i));
}
@@ -305,11 +316,18 @@ void do_interrupt(int intno, int is_int, int error_code,
count++;
}
#endif
+#if !defined(CONFIG_USER_ONLY)
+ if (env->psret == 0) {
+ fprintf(logfile, "Trap while interrupts disabled, Error state!\n");
+ qemu_system_shutdown_request();
+ return;
+ }
+#endif
env->psret = 0;
cwp = (env->cwp - 1) & (NWINDOWS - 1);
set_cwp(cwp);
- env->regwptr[9] = env->pc;
- env->regwptr[10] = env->npc;
+ env->regwptr[9] = env->pc - 4; // XXX?
+ env->regwptr[10] = env->pc;
env->psrps = env->psrs;
env->psrs = 1;
env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
@@ -322,3 +340,106 @@ void raise_exception_err(int exception_index, int error_code)
{
raise_exception(exception_index);
}
+
+uint32_t mmu_probe(uint32_t address, int mmulev)
+{
+ target_phys_addr_t pde_ptr;
+ uint32_t pde;
+
+ /* Context base + context number */
+ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
+ 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);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
+
+ 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);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
+
+ 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);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
+
+ 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(void)
+{
+#ifdef DEBUG_MMU
+ uint32_t pa, va, va1, va2;
+ int n, m, o;
+ target_phys_addr_t pde_ptr;
+ uint32_t pde;
+
+ printf("MMU dump:\n");
+ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
+ cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
+ bswap32s(&pde);
+ printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
+ for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
+ pde_ptr = mmu_probe(va, 2);
+ if (pde_ptr) {
+ pa = cpu_get_phys_page_debug(env, va);
+ printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr);
+ for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
+ pde_ptr = mmu_probe(va1, 1);
+ if (pde_ptr) {
+ pa = cpu_get_phys_page_debug(env, va1);
+ printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr);
+ for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
+ pde_ptr = mmu_probe(va2, 0);
+ if (pde_ptr) {
+ pa = cpu_get_phys_page_debug(env, va2);
+ printf(" VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr);
+ }
+ }
+ }
+ }
+ }
+ }
+ printf("MMU dump ends\n");
+#endif
+}
diff --git a/target-sparc/op.c b/target-sparc/op.c
index 2cf4ed8..f8cf2f8 100644
--- a/target-sparc/op.c
+++ b/target-sparc/op.c
@@ -524,13 +524,7 @@ void OPPROTO op_rdpsr(void)
void OPPROTO op_wrpsr(void)
{
- int cwp;
- env->psr = T0 & ~PSR_ICC;
- env->psrs = (T0 & PSR_S)? 1 : 0;
- env->psrps = (T0 & PSR_PS)? 1 : 0;
- env->psret = (T0 & PSR_ET)? 1 : 0;
- cwp = (T0 & PSR_CWP) & (NWINDOWS - 1);
- set_cwp(cwp);
+ PUT_PSR(env,T0);
FORCE_RET();
}
@@ -602,10 +596,27 @@ void OPPROTO op_trapcc_T0(void)
FORCE_RET();
}
-void OPPROTO op_debug(void)
+void OPPROTO op_trap_ifnofpu(void)
+{
+ if (!env->psref) {
+ env->exception_index = TT_NFPU_INSN;
+ cpu_loop_exit();
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_fpexception_im(void)
{
- env->exception_index = EXCP_DEBUG;
+ env->exception_index = TT_FP_EXCP;
+ env->fsr &= ~FSR_FTT_MASK;
+ env->fsr |= PARAM1;
cpu_loop_exit();
+ FORCE_RET();
+}
+
+void OPPROTO op_debug(void)
+{
+ helper_debug();
}
void OPPROTO op_exit_tb(void)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 3a6de7c..6dead66 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -2,6 +2,8 @@
#include <fenv.h>
#include "exec.h"
+//#define DEBUG_MMU
+
#ifdef USE_INT_TO_FLOAT_HELPERS
void do_fitos(void)
{
@@ -33,6 +35,13 @@ void do_fcmps (void)
{
if (isnan(FT0) || isnan(FT1)) {
T0 = FSR_FCC1 | FSR_FCC0;
+ env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
+ env->fsr |= T0;
+ if (env->fsr & FSR_NVM) {
+ raise_exception(TT_FP_EXCP);
+ } else {
+ env->fsr |= FSR_NVA;
+ }
} else if (FT0 < FT1) {
T0 = FSR_FCC0;
} else if (FT0 > FT1) {
@@ -47,6 +56,13 @@ void do_fcmpd (void)
{
if (isnan(DT0) || isnan(DT1)) {
T0 = FSR_FCC1 | FSR_FCC0;
+ env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
+ env->fsr |= T0;
+ if (env->fsr & FSR_NVM) {
+ raise_exception(TT_FP_EXCP);
+ } else {
+ env->fsr |= FSR_NVA;
+ }
} else if (DT0 < DT1) {
T0 = FSR_FCC0;
} else if (DT0 > DT1) {
@@ -59,55 +75,131 @@ void do_fcmpd (void)
void helper_ld_asi(int asi, int size, int sign)
{
- switch(asi) {
+ uint32_t ret;
+
+ switch (asi) {
case 3: /* MMU probe */
- T1 = 0;
- return;
+ {
+ int mmulev;
+
+ mmulev = (T0 >> 8) & 15;
+ if (mmulev > 4)
+ ret = 0;
+ else {
+ ret = mmu_probe(T0, mmulev);
+ //bswap32s(&ret);
+ }
+#ifdef DEBUG_MMU
+ printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
+#endif
+ }
+ break;
case 4: /* read MMU regs */
{
- int temp, reg = (T0 >> 8) & 0xf;
+ int reg = (T0 >> 8) & 0xf;
- temp = env->mmuregs[reg];
+ ret = env->mmuregs[reg];
if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/
- env->mmuregs[reg] = 0;
- T1 = temp;
+ env->mmuregs[4] = 0;
}
- return;
+ break;
case 0x20 ... 0x2f: /* MMU passthrough */
- {
- int temp;
-
- cpu_physical_memory_read(T0, (void *) &temp, size);
- bswap32s(&temp);
- T1 = temp;
- }
- return;
+ cpu_physical_memory_read(T0, (void *) &ret, size);
+ if (size == 4)
+ bswap32s(&ret);
+ else if (size == 2)
+ bswap16s(&ret);
+ break;
default:
- T1 = 0;
- return;
+ ret = 0;
+ break;
}
+ T1 = ret;
}
void helper_st_asi(int asi, int size, int sign)
{
switch(asi) {
case 3: /* MMU flush */
- return;
+ {
+ int mmulev;
+
+ mmulev = (T0 >> 8) & 15;
+ switch (mmulev) {
+ case 0: // flush page
+ tlb_flush_page(cpu_single_env, T0 & 0xfffff000);
+ break;
+ case 1: // flush segment (256k)
+ case 2: // flush region (16M)
+ case 3: // flush context (4G)
+ case 4: // flush entire
+ tlb_flush(cpu_single_env, 1);
+ break;
+ default:
+ break;
+ }
+ dump_mmu();
+ return;
+ }
case 4: /* write MMU regs */
{
- int reg = (T0 >> 8) & 0xf;
+ int reg = (T0 >> 8) & 0xf, oldreg;
+
+ oldreg = env->mmuregs[reg];
if (reg == 0) {
env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
} else
env->mmuregs[reg] = T1;
+ if (oldreg != env->mmuregs[reg]) {
+#if 0
+ // XXX: Only if MMU mapping change, we may need to flush?
+ tlb_flush(cpu_single_env, 1);
+ cpu_loop_exit();
+ FORCE_RET();
+#endif
+ }
+ dump_mmu();
return;
}
+ case 0x17: /* Block copy, sta access */
+ {
+ // value (T1) = src
+ // address (T0) = dst
+ // copy 32 bytes
+ int src = T1, dst = T0;
+ uint8_t temp[32];
+
+ bswap32s(&src);
+
+ cpu_physical_memory_read(src, (void *) &temp, 32);
+ cpu_physical_memory_write(dst, (void *) &temp, 32);
+ }
+ return;
+ case 0x1f: /* Block fill, stda access */
+ {
+ // value (T1, T2)
+ // address (T0) = dst
+ // fill 32 bytes
+ int i, dst = T0;
+ uint64_t val;
+
+ val = (((uint64_t)T1) << 32) | T2;
+ bswap64s(&val);
+
+ for (i = 0; i < 32; i += 8, dst += 8) {
+ cpu_physical_memory_write(dst, (void *) &val, 8);
+ }
+ }
+ return;
case 0x20 ... 0x2f: /* MMU passthrough */
{
int temp = T1;
-
- bswap32s(&temp);
+ if (size == 4)
+ bswap32s(&temp);
+ else if (size == 2)
+ bswap16s(&temp);
+
cpu_physical_memory_write(T0, (void *) &temp, size);
}
return;
@@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign)
}
}
-#if 0
-void do_ldd_raw(uint32_t addr)
-{
- T1 = ldl_raw((void *) addr);
- T0 = ldl_raw((void *) (addr + 4));
-}
-
-#if !defined(CONFIG_USER_ONLY)
-void do_ldd_user(uint32_t addr)
-{
- T1 = ldl_user((void *) addr);
- T0 = ldl_user((void *) (addr + 4));
-}
-void do_ldd_kernel(uint32_t addr)
-{
- T1 = ldl_kernel((void *) addr);
- T0 = ldl_kernel((void *) (addr + 4));
-}
-#endif
-#endif
-
void helper_rett()
{
int cwp;
@@ -166,3 +237,22 @@ void helper_ldfsr(void)
break;
}
}
+
+void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f)
+{
+ int exptemp;
+
+ *pmant = ldexp(frexp(f, &exptemp), 53);
+ *pexp = exptemp;
+}
+
+double cpu_put_fp64(uint64_t mant, uint16_t exp)
+{
+ return ldexp((double) mant, exp - 53);
+}
+
+void helper_debug()
+{
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit();
+}
diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h
index 2ae74f2..9c839a0 100644
--- a/target-sparc/op_mem.h
+++ b/target-sparc/op_mem.h
@@ -43,12 +43,8 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void)
void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
{
-#if 1
T1 = glue(ldl, MEMSUFFIX)((void *) T0);
T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4));
-#else
- glue(do_ldd, MEMSUFFIX)(T0);
-#endif
}
/*** Floating-point store ***/
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2440c0d..2f06795 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -646,6 +646,7 @@ static void disas_sparc_insn(DisasContext * dc)
switch (xop) {
case 0x0:
case 0x1: /* UNIMPL */
+ case 0x5: /*CBN+x */
default:
goto illegal_insn;
case 0x2: /* BN+x */
@@ -657,16 +658,24 @@ static void disas_sparc_insn(DisasContext * dc)
}
case 0x6: /* FBN+x */
{
+#if !defined(CONFIG_USER_ONLY)
+ gen_op_trap_ifnofpu();
+#endif
target <<= 2;
target = sign_extend(target, 22);
do_fbranch(dc, target, insn);
goto jmp_insn;
}
case 0x4: /* SETHI */
- gen_movl_imm_T0(target << 10);
- gen_movl_T0_reg(rd);
- break;
- case 0x5: /*CBN+x */
+#define OPTIM
+#if defined(OPTIM)
+ if (rd) { // nop
+#endif
+ gen_movl_imm_T0(target << 10);
+ gen_movl_T0_reg(rd);
+#if defined(OPTIM)
+ }
+#endif
break;
}
break;
@@ -691,14 +700,24 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_reg_T0(rs1);
if (IS_IMM) {
rs2 = GET_FIELD(insn, 25, 31);
+#if defined(OPTIM)
if (rs2 != 0) {
- gen_movl_imm_T1(rs2);
- gen_op_add_T1_T0();
+#endif
+ gen_movl_imm_T1(rs2);
+ gen_op_add_T1_T0();
+#if defined(OPTIM)
}
+#endif
} else {
rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
+#if defined(OPTIM)
+ if (rs2 != 0) {
+#endif
+ gen_movl_reg_T1(rs2);
+ gen_op_add_T1_T0();
+#if defined(OPTIM)
+ }
+#endif
}
save_state(dc);
cond = GET_FIELD(insn, 3, 6);
@@ -707,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc)
dc->is_br = 1;
goto jmp_insn;
} else {
+ gen_cond(cond);
gen_op_trapcc_T0();
}
} else if (xop == 0x28) {
@@ -741,7 +761,10 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_T0_reg(rd);
break;
#endif
- } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
+ } else if (xop == 0x34) { /* FPU Operations */
+#if !defined(CONFIG_USER_ONLY)
+ gen_op_trap_ifnofpu();
+#endif
rs1 = GET_FIELD(insn, 13, 17);
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
@@ -770,6 +793,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fsqrtd();
gen_op_store_DT0_fpr(rd);
break;
+ case 0x2b: /* fsqrtq */
+ goto nfpu_insn;
case 0x41:
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
@@ -782,6 +807,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_faddd();
gen_op_store_DT0_fpr(rd);
break;
+ case 0x43: /* faddq */
+ goto nfpu_insn;
case 0x45:
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
@@ -794,6 +821,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fsubd();
gen_op_store_DT0_fpr(rd);
break;
+ case 0x47: /* fsubq */
+ goto nfpu_insn;
case 0x49:
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
@@ -806,6 +835,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fmuld();
gen_op_store_DT0_fpr(rd);
break;
+ case 0x4b: /* fmulq */
+ goto nfpu_insn;
case 0x4d:
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
@@ -818,32 +849,16 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fdivd();
gen_op_store_DT0_fpr(rd);
break;
- case 0x51:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fcmps();
- break;
- case 0x52:
- gen_op_load_fpr_DT0(rs1);
- gen_op_load_fpr_DT1(rs2);
- gen_op_fcmpd();
- break;
- case 0x55: /* fcmpes */
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fcmps(); /* XXX */
- break;
- case 0x56: /* fcmped */
- gen_op_load_fpr_DT0(rs1);
- gen_op_load_fpr_DT1(rs2);
- gen_op_fcmpd(); /* XXX */
- break;
+ case 0x4f: /* fdivq */
+ goto nfpu_insn;
case 0x69:
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
gen_op_fsmuld();
gen_op_store_DT0_fpr(rd);
break;
+ case 0x6e: /* fdmulq */
+ goto nfpu_insn;
case 0xc4:
gen_op_load_fpr_FT1(rs2);
gen_op_fitos();
@@ -854,6 +869,8 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fdtos();
gen_op_store_FT0_fpr(rd);
break;
+ case 0xc7: /* fqtos */
+ goto nfpu_insn;
case 0xc8:
gen_op_load_fpr_FT1(rs2);
gen_op_fitod();
@@ -864,6 +881,14 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fstod();
gen_op_store_DT0_fpr(rd);
break;
+ case 0xcb: /* fqtod */
+ goto nfpu_insn;
+ case 0xcc: /* fitoq */
+ goto nfpu_insn;
+ case 0xcd: /* fstoq */
+ goto nfpu_insn;
+ case 0xce: /* fdtoq */
+ goto nfpu_insn;
case 0xd1:
gen_op_load_fpr_FT1(rs2);
gen_op_fstoi();
@@ -874,13 +899,85 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_fdtoi();
gen_op_store_FT0_fpr(rd);
break;
+ case 0xd3: /* fqtoi */
+ goto nfpu_insn;
default:
goto illegal_insn;
}
- } else {
+ } else if (xop == 0x35) { /* FPU Operations */
+#if !defined(CONFIG_USER_ONLY)
+ gen_op_trap_ifnofpu();
+#endif
rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELD(insn, 27, 31);
+ xop = GET_FIELD(insn, 18, 26);
+ switch (xop) {
+ case 0x51:
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fcmps();
+ break;
+ case 0x52:
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpd();
+ break;
+ case 0x53: /* fcmpq */
+ goto nfpu_insn;
+ case 0x55: /* fcmpes */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
+ break;
+ case 0x56: /* fcmped */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
+ break;
+ case 0x57: /* fcmpeq */
+ goto nfpu_insn;
+ default:
+ goto illegal_insn;
+ }
+#if defined(OPTIM)
+ } else if (xop == 0x2) {
+ // clr/mov shortcut
+
+ rs1 = GET_FIELD(insn, 13, 17);
+ if (rs1 == 0) {
+ // or %g0, x, y -> mov T1, x; mov y, T1
+ if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELDs(insn, 19, 31);
+ gen_movl_imm_T1(rs2);
+ } else { /* register */
+ rs2 = GET_FIELD(insn, 27, 31);
+ gen_movl_reg_T1(rs2);
+ }
+ gen_movl_T1_reg(rd);
+ } else {
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
+ // or x, #0, y -> mov T1, x; mov y, T1
+ rs2 = GET_FIELDs(insn, 19, 31);
+ if (rs2 != 0) {
+ gen_movl_imm_T1(rs2);
+ gen_op_or_T1_T0();
+ }
+ } else { /* register */
+ // or x, %g0, y -> mov T1, x; mov y, T1
+ rs2 = GET_FIELD(insn, 27, 31);
+ if (rs2 != 0) {
+ gen_movl_reg_T1(rs2);
+ gen_op_or_T1_T0();
+ }
+ }
+ gen_movl_T0_reg(rd);
+ }
+#endif
+ } else if (xop < 0x38) {
+ rs1 = GET_FIELD(insn, 13, 17);
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 19, 31);
gen_movl_imm_T1(rs2);
} else { /* register */
@@ -901,10 +998,10 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_logic_T0_cc();
break;
case 0x2:
- gen_op_or_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
+ gen_op_or_T1_T0();
+ if (xop & 0x10)
+ gen_op_logic_T0_cc();
+ break;
case 0x3:
gen_op_xor_T1_T0();
if (xop & 0x10)
@@ -964,9 +1061,14 @@ static void disas_sparc_insn(DisasContext * dc)
default:
goto illegal_insn;
}
- gen_movl_T0_reg(rd);
+ gen_movl_T0_reg(rd);
} else {
switch (xop) {
+ case 0x20: /* taddcc */
+ case 0x21: /* tsubcc */
+ case 0x22: /* taddcctv */
+ case 0x23: /* tsubcctv */
+ goto illegal_insn;
case 0x24: /* mulscc */
gen_op_mulscc_T1_T0();
gen_movl_T0_reg(rd);
@@ -1021,56 +1123,72 @@ static void disas_sparc_insn(DisasContext * dc)
}
break;
#endif
- case 0x38: /* jmpl */
- {
- gen_op_add_T1_T0();
- gen_op_movl_npc_T0();
- if (rd != 0) {
- gen_op_movl_T0_im((long) (dc->pc));
- gen_movl_T0_reg(rd);
- }
- dc->pc = dc->npc;
- dc->npc = DYNAMIC_PC;
- }
- goto jmp_insn;
-#if !defined(CONFIG_USER_ONLY)
- case 0x39: /* rett */
- {
- if (!supervisor(dc))
- goto priv_insn;
- gen_op_add_T1_T0();
- gen_op_movl_npc_T0();
- gen_op_rett();
-#if 0
- dc->pc = dc->npc;
- dc->npc = DYNAMIC_PC;
+ default:
+ goto illegal_insn;
+ }
+ }
+ } else {
+ rs1 = GET_FIELD(insn, 13, 17);
+ gen_movl_reg_T0(rs1);
+ if (IS_IMM) { /* immediate */
+ rs2 = GET_FIELDs(insn, 19, 31);
+#if defined(OPTIM)
+ if (rs2) {
#endif
- }
-#if 0
- goto jmp_insn;
+ gen_movl_imm_T1(rs2);
+ gen_op_add_T1_T0();
+#if defined(OPTIM)
+ }
#endif
- break;
+ } else { /* register */
+ rs2 = GET_FIELD(insn, 27, 31);
+#if defined(OPTIM)
+ if (rs2) {
+#endif
+ gen_movl_reg_T1(rs2);
+ gen_op_add_T1_T0();
+#if defined(OPTIM)
+ }
#endif
- case 0x3b: /* flush */
- gen_op_add_T1_T0();
- gen_op_flush_T0();
- break;
- case 0x3c: /* save */
- save_state(dc);
- gen_op_add_T1_T0();
- gen_op_save();
- gen_movl_T0_reg(rd);
- break;
- case 0x3d: /* restore */
- save_state(dc);
- gen_op_add_T1_T0();
- gen_op_restore();
- gen_movl_T0_reg(rd);
- break;
- default:
- goto illegal_insn;
- }
}
+ switch (xop) {
+ case 0x38: /* jmpl */
+ {
+ gen_op_movl_npc_T0();
+ if (rd != 0) {
+ gen_op_movl_T0_im((long) (dc->pc));
+ gen_movl_T0_reg(rd);
+ }
+ dc->pc = dc->npc;
+ dc->npc = DYNAMIC_PC;
+ }
+ goto jmp_insn;
+#if !defined(CONFIG_USER_ONLY)
+ case 0x39: /* rett */
+ {
+ if (!supervisor(dc))
+ goto priv_insn;
+ gen_op_movl_npc_T0();
+ gen_op_rett();
+ }
+ break;
+#endif
+ case 0x3b: /* flush */
+ gen_op_flush_T0();
+ break;
+ case 0x3c: /* save */
+ save_state(dc);
+ gen_op_save();
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x3d: /* restore */
+ save_state(dc);
+ gen_op_restore();
+ gen_movl_T0_reg(rd);
+ break;
+ default:
+ goto illegal_insn;
+ }
}
break;
}
@@ -1081,14 +1199,24 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 19, 31);
+#if defined(OPTIM)
if (rs2 != 0) {
+#endif
gen_movl_imm_T1(rs2);
gen_op_add_T1_T0();
+#if defined(OPTIM)
}
+#endif
} else { /* register */
rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
+#if defined(OPTIM)
+ if (rs2 != 0) {
+#endif
+ gen_movl_reg_T1(rs2);
+ gen_op_add_T1_T0();
+#if defined(OPTIM)
+ }
+#endif
}
if (xop < 4 || (xop > 7 && xop < 0x14) || \
(xop > 0x17 && xop < 0x20)) {
@@ -1116,8 +1244,10 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_ldst(ldstub);
break;
case 0x0f: /* swap register with memory. Also atomically */
+ gen_movl_reg_T1(rd);
gen_op_ldst(swap);
break;
+#if !defined(CONFIG_USER_ONLY)
case 0x10: /* load word alternate */
if (!supervisor(dc))
goto priv_insn;
@@ -1157,11 +1287,18 @@ static void disas_sparc_insn(DisasContext * dc)
case 0x1f: /* swap reg with alt. memory. Also atomically */
if (!supervisor(dc))
goto priv_insn;
+ gen_movl_reg_T1(rd);
gen_op_swapa(insn, 1, 4, 0);
break;
+#endif
+ default:
+ goto illegal_insn;
}
gen_movl_T1_reg(rd);
} else if (xop >= 0x20 && xop < 0x24) {
+#if !defined(CONFIG_USER_ONLY)
+ gen_op_trap_ifnofpu();
+#endif
switch (xop) {
case 0x20: /* load fpreg */
gen_op_ldst(ldf);
@@ -1169,11 +1306,14 @@ static void disas_sparc_insn(DisasContext * dc)
break;
case 0x21: /* load fsr */
gen_op_ldfsr();
+ gen_op_store_FT0_fpr(rd);
break;
case 0x23: /* load double fpreg */
gen_op_ldst(lddf);
gen_op_store_DT0_fpr(rd);
break;
+ default:
+ goto illegal_insn;
}
} else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) {
gen_movl_reg_T1(rd);
@@ -1192,6 +1332,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_reg_T2(rd + 1);
gen_op_ldst(std);
break;
+#if !defined(CONFIG_USER_ONLY)
case 0x14:
if (!supervisor(dc))
goto priv_insn;
@@ -1214,24 +1355,37 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_reg_T2(rd + 1);
gen_op_stda(insn, 0, 8, 0);
break;
+#endif
+ default:
+ goto illegal_insn;
}
} else if (xop > 0x23 && xop < 0x28) {
+#if !defined(CONFIG_USER_ONLY)
+ gen_op_trap_ifnofpu();
+#endif
switch (xop) {
case 0x24:
gen_op_load_fpr_FT0(rd);
gen_op_ldst(stf);
break;
case 0x25:
+ gen_op_load_fpr_FT0(rd);
gen_op_stfsr();
break;
case 0x27:
gen_op_load_fpr_DT0(rd);
gen_op_ldst(stdf);
break;
+ case 0x26: /* stdfq */
+ default:
+ goto illegal_insn;
}
} else if (xop > 0x33 && xop < 0x38) {
/* Co-processor */
+ goto illegal_insn;
}
+ else
+ goto illegal_insn;
}
}
/* default case for non jump instructions */
@@ -1246,17 +1400,24 @@ static void disas_sparc_insn(DisasContext * dc)
dc->pc = dc->npc;
dc->npc = dc->npc + 4;
}
- jmp_insn:;
+ jmp_insn:
return;
illegal_insn:
save_state(dc);
gen_op_exception(TT_ILL_INSN);
dc->is_br = 1;
return;
+#if !defined(CONFIG_USER_ONLY)
priv_insn:
save_state(dc);
gen_op_exception(TT_PRIV_INSN);
dc->is_br = 1;
+ return;
+#endif
+ nfpu_insn:
+ save_state(dc);
+ gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
+ dc->is_br = 1;
}
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
@@ -1271,6 +1432,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
dc->tb = tb;
pc_start = tb->pc;
dc->pc = pc_start;
+ last_pc = dc->pc;
dc->npc = (target_ulong) tb->cs_base;
#if defined(CONFIG_USER_ONLY)
dc->mem_idx = 0;
@@ -1285,8 +1447,13 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
if (env->breakpoints[j] == dc->pc) {
- gen_debug(dc, dc->pc);
- break;
+ if (dc->pc != pc_start)
+ save_state(dc);
+ gen_op_debug();
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ dc->is_br = 1;
+ goto exit_gen_loop;
}
}
}
@@ -1310,8 +1477,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
/* if the next PC is different, we abort now */
if (dc->pc != (last_pc + 4))
break;
+ /* if single step mode, we generate only one instruction and
+ generate an exception */
+ if (env->singlestep_enabled) {
+ gen_op_jmp_im(dc->pc);
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ break;
+ }
} while ((gen_opc_ptr < gen_opc_end) &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+
+ exit_gen_loop:
if (!dc->is_br) {
if (dc->pc != DYNAMIC_PC &&
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
@@ -1338,7 +1515,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
}
#endif
} else {
- tb->size = dc->npc - pc_start;
+ tb->size = last_pc + 4 - pc_start;
}
#ifdef DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
@@ -1366,14 +1543,10 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
return gen_intermediate_code_internal(tb, 1, env);
}
-CPUSPARCState *cpu_sparc_init(void)
-{
- CPUSPARCState *env;
-
- cpu_exec_init();
+extern int ram_size;
- if (!(env = malloc(sizeof(CPUSPARCState))))
- return (NULL);
+void cpu_reset(CPUSPARCState *env)
+{
memset(env, 0, sizeof(*env));
env->cwp = 0;
env->wim = 1;
@@ -1381,14 +1554,24 @@ CPUSPARCState *cpu_sparc_init(void)
#if defined(CONFIG_USER_ONLY)
env->user_mode_only = 1;
#else
- /* Emulate Prom */
env->psrs = 1;
- env->pc = 0x4000;
+ env->pc = 0xffd00000;
+ env->gregs[1] = ram_size;
+ env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
env->npc = env->pc + 4;
- env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */
- env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */
#endif
+}
+
+CPUSPARCState *cpu_sparc_init(void)
+{
+ CPUSPARCState *env;
+
+ cpu_exec_init();
+
+ if (!(env = malloc(sizeof(CPUSPARCState))))
+ return (NULL);
cpu_single_env = env;
+ cpu_reset(env);
return (env);
}
@@ -1436,11 +1619,24 @@ void cpu_dump_state(CPUState *env, FILE *f,
cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr);
}
+#if defined(CONFIG_USER_ONLY)
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
+#else
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ uint32_t phys_addr;
+ int prot, access_index;
+
+ if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0)
+ return -1;
+ return phys_addr;
+}
+#endif
+
void helper_flush(target_ulong addr)
{
addr &= ~7;