diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2011-04-01 15:15:19 +1100 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2011-04-01 18:34:55 +0200 |
commit | fc1a7583576e6cd01f6e37967ed6cc9ac75567cb (patch) | |
tree | 421c8f64a44e93fcb48bfe922b2da67fdaed2da4 /target-ppc | |
parent | 6b62ac3632bb1cc4a01f5ae9406961383a9ab5b3 (diff) | |
download | qemu-fc1a7583576e6cd01f6e37967ed6cc9ac75567cb.tar.gz qemu-fc1a7583576e6cd01f6e37967ed6cc9ac75567cb.tar.bz2 qemu-fc1a7583576e6cd01f6e37967ed6cc9ac75567cb.zip |
Add POWER7 support for ppc
This adds emulation support for the recent POWER7 cpu to qemu. It's far
from perfect - it's missing a number of POWER7 features so far, including
any support for VSX or decimal floating point instructions. However, it's
close enough to boot a kernel with the POWER7 PVR.
Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 16 | ||||
-rw-r--r-- | target-ppc/helper.c | 6 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 107 |
3 files changed, 129 insertions, 0 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 10341b307f..25d0658c47 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -119,6 +119,8 @@ enum powerpc_mmu_t { POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, /* 620 variant (no segment exceptions) */ POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, + /* Architecture 2.06 variant */ + POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003, #endif /* defined(TARGET_PPC64) */ }; @@ -154,6 +156,8 @@ enum powerpc_excp_t { #if defined(TARGET_PPC64) /* PowerPC 970 exception model */ POWERPC_EXCP_970, + /* POWER7 exception model */ + POWERPC_EXCP_POWER7, #endif /* defined(TARGET_PPC64) */ }; @@ -289,6 +293,8 @@ enum powerpc_input_t { PPC_FLAGS_INPUT_405, /* PowerPC 970 bus */ PPC_FLAGS_INPUT_970, + /* PowerPC POWER7 bus */ + PPC_FLAGS_INPUT_POWER7, /* PowerPC 401 bus */ PPC_FLAGS_INPUT_401, /* Freescale RCPU bus */ @@ -1001,6 +1007,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #define SPR_HSPRG1 (0x131) #define SPR_HDSISR (0x132) #define SPR_HDAR (0x133) +#define SPR_SPURR (0x134) #define SPR_BOOKE_DBCR0 (0x134) #define SPR_IBCR (0x135) #define SPR_PURR (0x135) @@ -1625,6 +1632,15 @@ enum { PPC970_INPUT_THINT = 6, PPC970_INPUT_NB, }; + +enum { + /* POWER7 input pins */ + POWER7_INPUT_INT = 0, + /* POWER7 probably has other inputs, but we don't care about them + * for any existing machine. We can wire these up when we need + * them */ + POWER7_INPUT_NB, +}; #endif /* Hardware exceptions definitions */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6712fce8ac..278bee4f17 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1200,6 +1200,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; ctx->prot |= PAGE_WRITE; @@ -1277,6 +1278,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ @@ -1376,6 +1378,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; @@ -1485,6 +1488,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; @@ -1808,6 +1812,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); break; @@ -1875,6 +1880,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) #if defined(TARGET_PPC64) case POWERPC_MMU_620: case POWERPC_MMU_64B: + case POWERPC_MMU_2_06: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 63664248a4..e2a83c5a38 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -61,6 +61,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); PPC_IRQ_INIT_FN(40x); PPC_IRQ_INIT_FN(6xx); PPC_IRQ_INIT_FN(970); +PPC_IRQ_INIT_FN(POWER7); PPC_IRQ_INIT_FN(e500); /* Generic callbacks: @@ -3131,6 +3132,35 @@ static void init_excp_970 (CPUPPCState *env) env->hreset_vector = 0x0000000000000100ULL; #endif } + +static void init_excp_POWER7 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; + env->hreset_excp_prefix = 0; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif +} #endif /*****************************************************************************/ @@ -6312,6 +6342,78 @@ static void init_proc_970MP (CPUPPCState *env) vscr_init(env, 0x00010000); } +#if defined(TARGET_PPC64) +/* POWER7 */ +#define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_SEGMENT_64B | PPC_SLBI | \ + PPC_POPCNTB | PPC_POPCNTWD) +#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) +#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) +#define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) +#define POWERPC_INPUT_POWER7 (PPC_FLAGS_INPUT_POWER7) +#define POWERPC_BFDM_POWER7 (bfd_mach_ppc64) +#define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) +#define check_pow_POWER7 check_pow_nocheck + +static void init_proc_POWER7 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); +#if !defined(CONFIG_USER_ONLY) + /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ + spr_register(env, SPR_PURR, "PURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPURR, "SPURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + 0x00000000); +#endif /* !CONFIG_USER_ONLY */ + /* Memory management */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_CTRL, "SPR_CTRLT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x80800000); + spr_register(env, SPR_UCTRL, "SPR_CTRLF", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x80800000); + spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#if !defined(CONFIG_USER_ONLY) + env->slb_nr = 32; +#endif + init_excp_POWER7(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; + /* Allocate hardware IRQ controller */ + ppcPOWER7_irq_init(env); + /* Can't find information on what this should be on reset. This + * value is the one used by 74xx processors. */ + vscr_init(env, 0x00010000); +} +#endif /* TARGET_PPC64 */ + /* PowerPC 620 */ #define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -7034,6 +7136,8 @@ enum { CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, +#define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 + CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_970 = 0x00390202, #define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, @@ -8836,6 +8940,9 @@ static const ppc_def_t ppc_defs[] = { /* POWER6A */ POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), #endif + /* POWER7 */ + POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), + POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ |