diff options
Diffstat (limited to 'target-sparc/helper.c')
-rw-r--r-- | target-sparc/helper.c | 527 |
1 files changed, 521 insertions, 6 deletions
diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 3437d13f66..a788ef633e 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -30,6 +30,22 @@ //#define DEBUG_MMU +typedef struct sparc_def_t sparc_def_t; + +struct sparc_def_t { + const unsigned 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; +}; + +static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name); + /* Sparc MMU emulation */ /* thread support */ @@ -98,9 +114,9 @@ static const int perm_table[2][8] = { } }; -int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int mmu_idx) +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx) { int access_perms = 0; target_phys_addr_t pde_ptr; @@ -483,9 +499,9 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical return 1; } -int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int mmu_idx) +static int get_physical_address(CPUState *env, target_phys_addr_t *physical, + int *prot, int *access_index, + target_ulong address, int rw, int mmu_idx) { int is_user = mmu_idx == MMU_USER_IDX; @@ -593,6 +609,30 @@ void dump_mmu(CPUState *env) #endif /* TARGET_SPARC64 */ #endif /* !CONFIG_USER_ONLY */ + +#if defined(CONFIG_USER_ONLY) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +#else +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + target_phys_addr_t phys_addr; + int prot, access_index; + + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, + MMU_KERNEL_IDX) != 0) + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, + 0, MMU_KERNEL_IDX) != 0) + return -1; + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) + return -1; + return phys_addr; +} +#endif + void memcpy32(target_ulong *dst, const target_ulong *src) { dst[0] = src[0]; @@ -605,6 +645,481 @@ void memcpy32(target_ulong *dst, const target_ulong *src) dst[7] = src[7]; } +void helper_flush(target_ulong addr) +{ + addr &= ~7; + tb_invalidate_page_range(addr, addr + 8); +} + +void cpu_reset(CPUSPARCState *env) +{ + tlb_flush(env, 1); + env->cwp = 0; + env->wim = 1; + env->regwptr = env->regbase + (env->cwp * 16); +#if defined(CONFIG_USER_ONLY) + env->user_mode_only = 1; +#ifdef TARGET_SPARC64 + env->cleanwin = NWINDOWS - 2; + env->cansave = NWINDOWS - 2; + env->pstate = PS_RMO | PS_PEF | PS_IE; + env->asi = 0x82; // Primary no-fault +#endif +#else + env->psret = 0; + env->psrs = 1; + env->psrps = 1; +#ifdef TARGET_SPARC64 + env->pstate = PS_PRIV; + env->hpstate = HS_PRIV; + env->pc = 0x1fff0000000ULL; + env->tsptr = &env->ts[env->tl]; +#else + env->pc = 0; + env->mmuregs[0] &= ~(MMU_E | MMU_NF); + env->mmuregs[0] |= env->mmu_bm; +#endif + env->npc = env->pc + 4; +#endif +} + +CPUSPARCState *cpu_sparc_init(const char *cpu_model) +{ + CPUSPARCState *env; + const sparc_def_t *def; + + def = cpu_sparc_find_by_name(cpu_model); + if (!def) + return NULL; + + env = qemu_mallocz(sizeof(CPUSPARCState)); + if (!env) + return NULL; + cpu_exec_init(env); + env->cpu_model_str = cpu_model; + env->version = def->iu_version; + env->fsr = def->fpu_version; +#if !defined(TARGET_SPARC64) + env->mmu_bm = def->mmu_bm; + env->mmu_ctpr_mask = def->mmu_ctpr_mask; + env->mmu_cxr_mask = def->mmu_cxr_mask; + env->mmu_sfsr_mask = def->mmu_sfsr_mask; + env->mmu_trcr_mask = def->mmu_trcr_mask; + env->mmuregs[0] |= def->mmu_version; + cpu_sparc_set_id(env, 0); +#endif + + gen_intermediate_code_init(env); + + cpu_reset(env); + + return env; +} + +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) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 III", + .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 IV", + .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 V", + .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc I", + .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc II", + .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc IIi", + .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc IIe", + .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc III", + .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc III Cu", + .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IIIi", + .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IV", + .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IV+", + .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IIIi+", + .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "NEC UltraSparc I", + .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, +#else + { + .name = "Fujitsu MB86900", + .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .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, + }, + { + .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, + }, + { + .name = "LSI L64811", + .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ + .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Cypress CY7C601", + .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Cypress CY7C611", + .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "TI SuperSparc II", + .iu_version = 0x40000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .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, + }, + { + .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, + }, + { + .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, + }, + { + .name = "TI SuperSparc 51", + .iu_version = 0x43000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "TI SuperSparc 61", + .iu_version = 0x44000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + .mmu_ctpr_mask = 0xffffffc0, + .mmu_cxr_mask = 0x0000ffff, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Ross RT625", + .iu_version = 0x1e000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1e000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Ross RT620", + .iu_version = 0x1f000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1f000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "BIT B5010", + .iu_version = 0x20000000, + .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ + .mmu_version = 0x20000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Matsushita MN10501", + .iu_version = 0x50000000, + .fpu_version = 0 << 17, + .mmu_version = 0x50000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .name = "Weitek W8601", + .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ + .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, + { + .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, + }, + { + .name = "LEON3", + .iu_version = 0xf3000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf3000000, + .mmu_bm = 0x00004000, + .mmu_ctpr_mask = 0x007ffff0, + .mmu_cxr_mask = 0x0000003f, + .mmu_sfsr_mask = 0xffffffff, + .mmu_trcr_mask = 0xffffffff, + }, +#endif +}; + +static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name) +{ + unsigned int i; + + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + if (strcasecmp(name, sparc_defs[i].name) == 0) { + return &sparc_defs[i]; + } + } + return NULL; +} + +void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x\n", + sparc_defs[i].name, + sparc_defs[i].iu_version, + sparc_defs[i].fpu_version, + sparc_defs[i].mmu_version); + } +} + +#define GET_FLAG(a,b) ((env->psr & a)?b:'-') + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i, x; + + cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); + cpu_fprintf(f, "General Registers:\n"); + for (i = 0; i < 4; i++) + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\n"); + for (; i < 8; i++) + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\nCurrent Register Window:\n"); + for (x = 0; x < 3; x++) { + for (i = 0; i < 4; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); + for (; i < 8; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) + cpu_fprintf(f, "%%f%02d:", i); + cpu_fprintf(f, " %016lf", env->fpr[i]); + if ((i & 3) == 3) + cpu_fprintf(f, "\n"); + } +#ifdef TARGET_SPARC64 + cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n", + env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); + 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, NWINDOWS - 1 - env->cwp); +#else + cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), + GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), + GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), + env->psrs?'S':'-', env->psrps?'P':'-', + env->psret?'E':'-', env->wim); +#endif + cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); +} + #ifdef TARGET_SPARC64 #if !defined(CONFIG_USER_ONLY) #include "qemu-common.h" |