diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/ppc/cpu-models.c | 27 | ||||
-rw-r--r-- | target/ppc/cpu-models.h | 4 | ||||
-rw-r--r-- | target/ppc/cpu.h | 76 | ||||
-rw-r--r-- | target/ppc/cpu_init.c | 251 | ||||
-rw-r--r-- | target/ppc/excp_helper.c | 163 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 38 | ||||
-rw-r--r-- | target/ppc/helper.h | 38 | ||||
-rw-r--r-- | target/ppc/helper_regs.c | 45 | ||||
-rw-r--r-- | target/ppc/insn32.decode | 106 | ||||
-rw-r--r-- | target/ppc/tcg-excp_helper.c | 12 | ||||
-rw-r--r-- | target/ppc/translate.c | 35 | ||||
-rw-r--r-- | target/ppc/translate/fp-impl.c.inc | 291 | ||||
-rw-r--r-- | target/ppc/translate/fp-ops.c.inc | 30 | ||||
-rw-r--r-- | target/ppc/translate/ppe-impl.c.inc | 609 |
14 files changed, 1396 insertions, 329 deletions
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index ea86ea2..89ae763 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -32,17 +32,20 @@ /* PowerPC CPU definitions */ #define POWERPC_DEF_PREFIX(pvr, svr, type) \ glue(glue(glue(glue(pvr, _), svr), _), type) -#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ +#define POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, _deprecation_note) \ static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ (ObjectClass *oc, const void *data) \ { \ DeviceClass *dc = DEVICE_CLASS(oc); \ + CPUClass *cc = CPU_CLASS(oc); \ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ dc->desc = _desc; \ + \ + cc->deprecation_note = _deprecation_note; \ } \ \ static const TypeInfo \ @@ -63,6 +66,13 @@ type_init( \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) +#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ + POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, NULL) + +#define POWERPC_DEPRECATED_CPU(_name, _pvr, _type, _desc, _deprecation_note)\ + POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type, \ + _deprecation_note) + #define POWERPC_DEF(_name, _pvr, _type, _desc) \ POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) @@ -116,6 +126,13 @@ NULL) POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, NULL) + /* PPE42 Embedded Controllers */ + POWERPC_DEF("PPE42", CPU_POWERPC_PPE42, ppe42, + "Generic PPE 42") + POWERPC_DEF("PPE42X", CPU_POWERPC_PPE42X, ppe42x, + "Generic PPE 42X") + POWERPC_DEF("PPE42XM", CPU_POWERPC_PPE42XM, ppe42xm, + "Generic PPE 42XM") /* PowerPC 440 family */ #if defined(TODO_USER_ONLY) POWERPC_DEF("440", CPU_POWERPC_440, 440GP, @@ -722,12 +739,12 @@ "POWER7 v2.3") POWERPC_DEF("power7p_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, - "POWER8E v2.1") + POWERPC_DEPRECATED_CPU("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1", "CPU is unmaintained.") POWERPC_DEF("power8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, "POWER8 v2.0") - POWERPC_DEF("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8, - "POWER8NVL v1.0") + POWERPC_DEPRECATED_CPU("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8, + "POWER8NVL v1.0", "CPU is unmaintained.") POWERPC_DEF("power9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9, "POWER9 v2.0") POWERPC_DEF("power9_v2.2", CPU_POWERPC_POWER9_DD22, POWER9, diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index 72ad31b..c6cd27f 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -69,6 +69,10 @@ enum { /* Xilinx cores */ CPU_POWERPC_X2VP4 = 0x20010820, CPU_POWERPC_X2VP20 = 0x20010860, + /* IBM PPE42 Family */ + CPU_POWERPC_PPE42 = 0x42000000, + CPU_POWERPC_PPE42X = 0x42100000, + CPU_POWERPC_PPE42XM = 0x42200000, /* PowerPC 440 family */ /* Generic PowerPC 440 */ #define CPU_POWERPC_440 CPU_POWERPC_440GXf diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 0e26e43..787020f 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -220,6 +220,8 @@ typedef enum powerpc_excp_t { POWERPC_EXCP_POWER10, /* POWER11 exception model */ POWERPC_EXCP_POWER11, + /* PPE42 exception model */ + POWERPC_EXCP_PPE42, } powerpc_excp_t; /*****************************************************************************/ @@ -282,6 +284,8 @@ typedef enum powerpc_input_t { PPC_FLAGS_INPUT_POWER9, /* Freescale RCPU bus */ PPC_FLAGS_INPUT_RCPU, + /* PPE42 bus */ + PPC_FLAGS_INPUT_PPE42, } powerpc_input_t; #define PPC_INPUT(env) ((env)->bus_model) @@ -433,39 +437,64 @@ typedef enum { #define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */ #define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */ #define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */ +#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */ +#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */ +#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */ #define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */ +#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */ +#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */ #define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */ #define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */ #define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */ +#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */ +#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */ #define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */ +#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */ #define MSR_S PPC_BIT_NR(41) /* Secure state */ +#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */ +#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */ +#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */ +#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */ #define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */ #define MSR_POW PPC_BIT_NR(45) /* Power management */ #define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */ +#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */ #define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */ #define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */ #define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */ +#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */ #define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */ #define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */ #define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */ #define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */ #define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */ +#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */ +#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */ #define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */ #define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */ #define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */ #define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */ #define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */ #define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */ +#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */ #define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */ +#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */ +#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */ #define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */ #define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */ #define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */ +#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */ +#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */ #define MSR_DR PPC_BIT_NR(59) /* Data relocate */ #define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */ #define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */ +#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */ +#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */ #define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */ #define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */ #define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */ +#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */ +#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */ #define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */ FIELD(MSR, SF, MSR_SF, 1) @@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1) FIELD(MSR, PMM, MSR_PMM, 1) FIELD(MSR, RI, MSR_RI, 1) FIELD(MSR, LE, MSR_LE, 1) +FIELD(MSR, SEM, MSR_SEM6, 7) +FIELD(MSR, SIBRC, MSR_SIBRC2, 3) +FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8) /* * FE0 and FE1 bits are not side-by-side @@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1) #define ESR_VLEMI PPC_BIT(58) /* VLE operation */ #define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */ +/* PPE42 Interrupt Status Register bits */ +#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */ +#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */ +#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */ +#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */ +#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */ +#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */ +#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */ +#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */ +#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */ +#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */ +#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */ +FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4) +FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3) + +/* PPE42 Machine Check Status field values */ +#define PPE42_ISR_MCS_INSTRUCTION 0 +#define PPE42_ISR_MCS_DATA_LOAD 1 +#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2 +#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3 +#define PPE42_ISR_MCS_PROGRAM 4 +#define PPE42_ISR_MCS_ISI 5 +#define PPE42_ISR_MCS_ALIGNMENT 6 +#define PPE42_ISR_MCS_DSI 7 + /* Transaction EXception And Summary Register bits */ #define TEXASR_FAILURE_PERSISTENT (63 - 7) #define TEXASR_DISALLOWED (63 - 8) @@ -785,6 +842,8 @@ enum { POWERPC_FLAG_SMT_1LPAR = 0x00800000, /* Has BHRB */ POWERPC_FLAG_BHRB = 0x01000000, + /* Use PPE42-specific behavior */ + POWERPC_FLAG_PPE42 = 0x02000000, }; /* @@ -1754,9 +1813,12 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_CSRR0 (0x03A) #define SPR_BOOKE_CSRR1 (0x03B) #define SPR_BOOKE_DEAR (0x03D) +#define SPR_PPE42_EDR (0x03D) #define SPR_IAMR (0x03D) #define SPR_BOOKE_ESR (0x03E) +#define SPR_PPE42_ISR (0x03E) #define SPR_BOOKE_IVPR (0x03F) +#define SPR_PPE42_IVPR (0x03F) #define SPR_MPC_EIE (0x050) #define SPR_MPC_EID (0x051) #define SPR_MPC_NRI (0x052) @@ -1822,6 +1884,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_TBU40 (0x11E) #define SPR_SVR (0x11E) #define SPR_BOOKE_PIR (0x11E) +#define SPR_PPE42_PIR (0x11E) #define SPR_PVR (0x11F) #define SPR_HSPRG0 (0x130) #define SPR_BOOKE_DBSR (0x130) @@ -1831,6 +1894,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_EPCR (0x133) #define SPR_SPURR (0x134) #define SPR_BOOKE_DBCR0 (0x134) +#define SPR_PPE42_DBCR (0x134) #define SPR_IBCR (0x135) #define SPR_PURR (0x135) #define SPR_BOOKE_DBCR1 (0x135) @@ -1848,6 +1912,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_HSRR1 (0x13B) #define SPR_BOOKE_IAC4 (0x13B) #define SPR_BOOKE_DAC1 (0x13C) +#define SPR_PPE42_DACR (0x13C) #define SPR_MMCRH (0x13C) #define SPR_DABR2 (0x13D) #define SPR_BOOKE_DAC2 (0x13D) @@ -1857,12 +1922,14 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_DVC2 (0x13F) #define SPR_LPIDR (0x13F) #define SPR_BOOKE_TSR (0x150) +#define SPR_PPE42_TSR (0x150) #define SPR_HMER (0x150) #define SPR_HMEER (0x151) #define SPR_PCR (0x152) #define SPR_HEIR (0x153) #define SPR_BOOKE_LPIDR (0x152) #define SPR_BOOKE_TCR (0x154) +#define SPR_PPE42_TCR (0x154) #define SPR_BOOKE_TLB0PS (0x158) #define SPR_BOOKE_TLB1PS (0x159) #define SPR_BOOKE_TLB2PS (0x15A) @@ -2532,6 +2599,12 @@ enum { PPC2_MEM_LWSYNC = 0x0000000000200000ULL, /* ISA 2.06 BCD assist instructions */ PPC2_BCDA_ISA206 = 0x0000000000400000ULL, + /* PPE42 instructions */ + PPC2_PPE42 = 0x0000000000800000ULL, + /* PPE42X instructions */ + PPC2_PPE42X = 0x0000000001000000ULL, + /* PPE42XM instructions */ + PPC2_PPE42XM = 0x0000000002000000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2541,7 +2614,8 @@ enum { PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \ PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \ - PPC2_BCDA_ISA206) + PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \ + PPC2_PPE42XM) }; /*****************************************************************************/ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index db841f1..3aa3aef 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -1653,6 +1653,47 @@ static void register_8xx_sprs(CPUPPCState *env) * ... and more (thermal management, performance counters, ...) */ +static void register_ppe42_sprs(CPUPPCState *env) +{ + spr_register(env, SPR_PPE42_EDR, "EDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_PPE42_ISR, "ISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_PPE42_IVPR, "IVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0xfff80000); + spr_register(env, SPR_PPE42_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + spr_register(env, SPR_PPE42_DBCR, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_40x_dbcr0, + 0x00000000); + spr_register(env, SPR_PPE42_DACR, "DACR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + spr_register(env, SPR_PPE42_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + spr_register(env, SPR_BOOKE_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); +} + /*****************************************************************************/ /* Exception vectors models */ static void init_excp_4xx(CPUPPCState *env) @@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env) #endif } +static void init_excp_ppe42(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + /* Machine Check vector changed after version 0 */ + if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) { + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000; + } else { + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020; + } + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140; + env->ivpr_mask = 0xFFFFFE00UL; + /* Hardware reset vector */ + env->hreset_vector = 0x00000040UL; +#endif +} + static void init_excp_MPC5xx(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } +static void init_proc_ppe42(CPUPPCState *env) +{ + register_ppe42_sprs(env); + + init_excp_ppe42(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env_archcpu(env)); + + SET_FIT_PERIOD(8, 12, 16, 20); + SET_WDT_PERIOD(16, 20, 24, 28); +} + +static void ppe42_class_common_init(PowerPCCPUClass *pcc) +{ + pcc->init_proc = init_proc_ppe42; + pcc->check_pow = check_pow_nocheck; + pcc->check_attn = check_attn_none; + pcc->insns_flags = PPC_INSNS_BASE | + PPC_WRTEE | + PPC_CACHE | + PPC_CACHE_DCBZ | + PPC_MEM_SYNC; + pcc->msr_mask = R_MSR_SEM_MASK | + (1ull << MSR_IS0) | + R_MSR_SIBRC_MASK | + (1ull << MSR_LP) | + (1ull << MSR_WE) | + (1ull << MSR_IS1) | + (1ull << MSR_UIE) | + (1ull << MSR_EE) | + (1ull << MSR_ME) | + (1ull << MSR_IS2) | + (1ull << MSR_IS3) | + (1ull << MSR_IPE) | + R_MSR_SIBRCA_MASK; + pcc->mmu_model = POWERPC_MMU_REAL; + pcc->excp_model = POWERPC_EXCP_PPE42; + pcc->bus_model = PPC_FLAGS_INPUT_PPE42; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK; +} + +POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42"; + pcc->insns_flags2 = PPC2_PPE42; + ppe42_class_common_init(pcc); +} + +POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42X"; + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X; + ppe42_class_common_init(pcc); +} + +POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42XM"; + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM; + ppe42_class_common_init(pcc); +} + static void init_proc_440EP(CPUPPCState *env) { register_BookE_sprs(env, 0x000000000000FFFFULL); @@ -6802,53 +6941,64 @@ static void init_ppc_proc(PowerPCCPU *cpu) /* MSR bits & flags consistency checks */ if (env->msr_mask & (1 << 25)) { - switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_SPE: case POWERPC_FLAG_VRE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n"); + "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n"); + "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 17)) { - switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_TGPR: case POWERPC_FLAG_CE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n"); + "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n"); + "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 10)) { switch (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | - POWERPC_FLAG_UBLE)) { + POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_SE: case POWERPC_FLAG_DWE: case POWERPC_FLAG_UBLE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" "Should define POWERPC_FLAG_SE or POWERPC_FLAG_DWE or " - "POWERPC_FLAG_UBLE\n"); + "POWERPC_FLAG_UBLE or POWERPC_FLAG_PPE42\n"); exit(1); } } else if (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | - POWERPC_FLAG_UBLE)) { + POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" "Should not define POWERPC_FLAG_SE nor POWERPC_FLAG_DWE nor " - "POWERPC_FLAG_UBLE\n"); + "POWERPC_FLAG_UBLE nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 9)) { @@ -6867,18 +7017,23 @@ static void init_ppc_proc(PowerPCCPU *cpu) exit(1); } if (env->msr_mask & (1 << 2)) { - switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_PX: case POWERPC_FLAG_PMM: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n"); + "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n"); + "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if ((env->flags & POWERPC_FLAG_BUS_CLK) == 0) { @@ -7143,6 +7298,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); DeviceClass *family = DEVICE_CLASS(ppc_cpu_get_family_class(pcc)); const char *typename = object_class_get_name(oc); char *name; @@ -7153,7 +7309,11 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) } name = cpu_model_from_type(typename); - qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr); + if (cc->deprecation_note) { + qemu_printf(" %-16s PVR %08x (deprecated)\n", name, pcc->pvr); + } else { + qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr); + } for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); @@ -7243,39 +7403,40 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) } msr = (target_ulong)0; - msr |= (target_ulong)MSR_HVB; - msr |= (target_ulong)1 << MSR_EP; + if (!(env->flags & POWERPC_FLAG_PPE42)) { + msr |= (target_ulong)MSR_HVB; + msr |= (target_ulong)1 << MSR_EP; #if defined(DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr |= (target_ulong)1 << MSR_SE; - msr |= (target_ulong)1 << MSR_BE; + /* Single step trace mode */ + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; #endif #if defined(CONFIG_USER_ONLY) - msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ - msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */ - msr |= (target_ulong)1 << MSR_FE1; - msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ - msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ - msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ - msr |= (target_ulong)1 << MSR_PR; + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */ + msr |= (target_ulong)1 << MSR_FE1; + msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ + msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ + msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ + msr |= (target_ulong)1 << MSR_PR; #if defined(TARGET_PPC64) - msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */ + msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */ #endif #if !TARGET_BIG_ENDIAN - msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ - if (!((env->msr_mask >> MSR_LE) & 1)) { - fprintf(stderr, "Selected CPU does not support little-endian.\n"); - exit(1); - } + msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ + if (!((env->msr_mask >> MSR_LE) & 1)) { + fprintf(stderr, "Selected CPU does not support little-endian.\n"); + exit(1); + } #endif #endif #if defined(TARGET_PPC64) - if (mmu_is_64bit(env->mmu_model)) { - msr |= (1ULL << MSR_SF); - } + if (mmu_is_64bit(env->mmu_model)) { + msr |= (1ULL << MSR_SF); + } #endif - + } hreg_store_msr(env, msr, 1); #if !defined(CONFIG_USER_ONLY) @@ -7725,6 +7886,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) * they can be read with "p $ivor0", "p $ivor1", etc. */ break; + case POWERPC_EXCP_PPE42: + qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_SRR0], env->spr[SPR_SRR1]); + + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx + " ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n", + env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR], + env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]); + + qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n", + env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]); + break; case POWERPC_EXCP_40x: qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 1efdc40..d8bca19 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) powerpc_set_excp_state(cpu, vector, new_msr); } +static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp) +{ + CPUPPCState *env = &cpu->env; + target_ulong msr, new_msr, vector; + target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION; + bool promote_unmaskable; + + msr = env->msr; + + /* + * New interrupt handler msr preserves SIBRC and ME unless explicitly + * overridden by the exception. All other MSR bits are zeroed out. + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK); + + /* HV emu assistance interrupt only exists on server arch 2.05 or later */ + if (excp == POWERPC_EXCP_HV_EMU) { + excp = POWERPC_EXCP_PROGRAM; + } + + /* + * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to + * machine check if MSR_UIE is 0. + */ + promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE)); + + + switch (excp) { + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]); + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_DSI; + } + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_ISI; + } + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_ALIGNMENT; + } + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_PROGRAM; + } + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR); + break; + case POWERPC_EXCP_TRAP: + env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR); + break; + default: + /* Should never occur */ + cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } +#ifdef CONFIG_TCG + env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip); +#endif + break; + case POWERPC_EXCP_DECR: /* Decrementer exception */ + break; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + trace_ppc_excp_print("FIT"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + trace_ppc_excp_print("WDT"); + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + /* reset exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + break; + default: + cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n", + excp); + break; + } + + env->spr[SPR_SRR0] = env->nip; + env->spr[SPR_SRR1] = msr; + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(env_cpu(env), + "Raised an exception without defined vector %d\n", excp); + } + vector |= env->spr[SPR_PPE42_IVPR]; + + if (excp == POWERPC_EXCP_MCHECK) { + /* Also set the Machine Check Status (MCS) */ + env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK; + env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK); + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE); + + /* Machine checks halt execution if MSR_ME is 0 */ + powerpc_mcheck_checkstop(env); + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + } + + powerpc_set_excp_state(cpu, vector, new_msr); +} + static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) { CPUPPCState *env = &cpu->env; @@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_POWER11: powerpc_excp_books(cpu, excp); break; + case POWERPC_EXCP_PPE42: + powerpc_excp_ppe42(cpu, excp); + break; default: g_assert_not_reached(); } @@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env, } #endif /* TARGET_PPC64 */ +static int ppe42_next_unmasked_interrupt(CPUPPCState *env) +{ + bool async_deliver; + + /* External reset */ + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + async_deliver = FIELD_EX64(env->msr, MSR, EE); + + if (async_deliver != 0) { + /* Watchdog timer */ + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; + } + /* External Interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + return PPC_INTERRUPT_EXT; + } + /* Fixed interval timer */ + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; + } + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + } + + return 0; +} + static int ppc_next_unmasked_interrupt(CPUPPCState *env) { uint32_t pending_interrupts = env->pending_interrupts; @@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } #endif + if (env->excp_model == POWERPC_EXCP_PPE42) { + return ppe42_next_unmasked_interrupt(env); + } + /* External reset */ if (pending_interrupts & PPC_INTERRUPT_RESET) { return PPC_INTERRUPT_RESET; diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 07b782f..850aca6 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -562,14 +562,14 @@ uint64_t helper_##op(CPUPPCState *env, float64 arg) \ return ret; \ } -FPU_FCTI(fctiw, int32, 0x80000000U) -FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) -FPU_FCTI(fctiwu, uint32, 0x00000000U) -FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U) -FPU_FCTI(fctid, int64, 0x8000000000000000ULL) -FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL) -FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL) -FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL) +FPU_FCTI(FCTIW, int32, 0x80000000U) +FPU_FCTI(FCTIWZ, int32_round_to_zero, 0x80000000U) +FPU_FCTI(FCTIWU, uint32, 0x00000000U) +FPU_FCTI(FCTIWUZ, uint32_round_to_zero, 0x00000000U) +FPU_FCTI(FCTID, int64, 0x8000000000000000ULL) +FPU_FCTI(FCTIDZ, int64_round_to_zero, 0x8000000000000000ULL) +FPU_FCTI(FCTIDU, uint64, 0x0000000000000000ULL) +FPU_FCTI(FCTIDUZ, uint64_round_to_zero, 0x0000000000000000ULL) #define FPU_FCFI(op, cvtr, is_single) \ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ @@ -586,10 +586,10 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ return farg.ll; \ } -FPU_FCFI(fcfid, int64_to_float64, 0) -FPU_FCFI(fcfids, int64_to_float32, 1) -FPU_FCFI(fcfidu, uint64_to_float64, 0) -FPU_FCFI(fcfidus, uint64_to_float32, 1) +FPU_FCFI(FCFID, int64_to_float64, 0) +FPU_FCFI(FCFIDS, int64_to_float32, 1) +FPU_FCFI(FCFIDU, uint64_to_float64, 0) +FPU_FCFI(FCFIDUS, uint64_to_float32, 1) static uint64_t do_fri(CPUPPCState *env, uint64_t arg, FloatRoundMode rounding_mode) @@ -613,22 +613,22 @@ static uint64_t do_fri(CPUPPCState *env, uint64_t arg, return arg; } -uint64_t helper_frin(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIN(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_ties_away); } -uint64_t helper_friz(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIZ(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_to_zero); } -uint64_t helper_frip(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIP(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_up); } -uint64_t helper_frim(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIM(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_down); } @@ -697,7 +697,7 @@ static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr) return helper_todouble(f32); } -uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRSP(CPUPPCState *env, uint64_t arg) { return do_frsp(env, arg, GETPC()); } @@ -871,7 +871,7 @@ uint32_t helper_FTSQRT(uint64_t frb) return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); } -void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, +void helper_FCMPU(CPUPPCState *env, uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; @@ -902,7 +902,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, } } -void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, +void helper_FCMPO(CPUPPCState *env, uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index ca414f2..e99c8c8 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -94,26 +94,26 @@ DEF_HELPER_2(fpscr_setbit, void, env, i32) DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32) DEF_HELPER_FLAGS_1(tosingle, TCG_CALL_NO_RWG_SE, i32, i64) -DEF_HELPER_4(fcmpo, void, env, i64, i64, i32) -DEF_HELPER_4(fcmpu, void, env, i64, i64, i32) +DEF_HELPER_4(FCMPO, void, env, i64, i64, i32) +DEF_HELPER_4(FCMPU, void, env, i64, i64, i32) -DEF_HELPER_2(fctiw, i64, env, i64) -DEF_HELPER_2(fctiwu, i64, env, i64) -DEF_HELPER_2(fctiwz, i64, env, i64) -DEF_HELPER_2(fctiwuz, i64, env, i64) -DEF_HELPER_2(fcfid, i64, env, i64) -DEF_HELPER_2(fcfidu, i64, env, i64) -DEF_HELPER_2(fcfids, i64, env, i64) -DEF_HELPER_2(fcfidus, i64, env, i64) -DEF_HELPER_2(fctid, i64, env, i64) -DEF_HELPER_2(fctidu, i64, env, i64) -DEF_HELPER_2(fctidz, i64, env, i64) -DEF_HELPER_2(fctiduz, i64, env, i64) -DEF_HELPER_2(frsp, i64, env, i64) -DEF_HELPER_2(frin, i64, env, i64) -DEF_HELPER_2(friz, i64, env, i64) -DEF_HELPER_2(frip, i64, env, i64) -DEF_HELPER_2(frim, i64, env, i64) +DEF_HELPER_2(FCTIW, i64, env, i64) +DEF_HELPER_2(FCTIWU, i64, env, i64) +DEF_HELPER_2(FCTIWZ, i64, env, i64) +DEF_HELPER_2(FCTIWUZ, i64, env, i64) +DEF_HELPER_2(FCFID, i64, env, i64) +DEF_HELPER_2(FCFIDU, i64, env, i64) +DEF_HELPER_2(FCFIDS, i64, env, i64) +DEF_HELPER_2(FCFIDUS, i64, env, i64) +DEF_HELPER_2(FCTID, i64, env, i64) +DEF_HELPER_2(FCTIDU, i64, env, i64) +DEF_HELPER_2(FCTIDZ, i64, env, i64) +DEF_HELPER_2(FCTIDUZ, i64, env, i64) +DEF_HELPER_2(FRSP, i64, env, i64) +DEF_HELPER_2(FRIN, i64, env, i64) +DEF_HELPER_2(FRIZ, i64, env, i64) +DEF_HELPER_2(FRIP, i64, env, i64) +DEF_HELPER_2(FRIM, i64, env, i64) DEF_HELPER_3(FADD, f64, env, f64, f64) DEF_HELPER_3(FADDS, f64, env, f64, f64) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 5f21739..a07e6a7 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->spr[SPR_LPCR] & LPCR_HR) { hflags |= 1 << HFLAGS_HR; } + if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) { + /* PPE42 has a single address space and no problem state */ + msr = 0; + } #ifndef CONFIG_USER_ONLY if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { @@ -308,9 +312,6 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) value &= ~(1 << MSR_ME); value |= env->msr & (1 << MSR_ME); } - if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { - cpu_interrupt_exittb(cs); - } if ((env->mmu_model == POWERPC_MMU_BOOKE || env->mmu_model == POWERPC_MMU_BOOKE206) && ((value ^ env->msr) & R_MSR_GS_MASK)) { @@ -321,8 +322,14 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) /* Swap temporary saved registers with GPRs */ hreg_swap_gpr_tgpr(env); } - if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { - env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; + /* PPE42 uses IR, DR and EP MSR bits for other purposes */ + if (likely(!(env->flags & POWERPC_FLAG_PPE42))) { + if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { + cpu_interrupt_exittb(cs); + } + if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { + env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; + } } /* * If PR=1 then EE, IR and DR must be 1 @@ -464,6 +471,23 @@ void register_generic_sprs(PowerPCCPU *cpu) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + spr_register(env, SPR_PVR, "PVR", + /* Linux permits userspace to read PVR */ +#if defined(CONFIG_LINUX_USER) + &spr_read_generic, +#else + SPR_NOACCESS, +#endif + SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + pcc->pvr); + + /* PPE42 doesn't support SPRG1-3, SVR or TB regs */ + if (env->insns_flags2 & PPC2_PPE42) { + return; + } + spr_register(env, SPR_SPRG1, "SPRG1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -477,17 +501,6 @@ void register_generic_sprs(PowerPCCPU *cpu) &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_PVR, "PVR", - /* Linux permits userspace to read PVR */ -#if defined(CONFIG_LINUX_USER) - &spr_read_generic, -#else - SPR_NOACCESS, -#endif - SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - pcc->pvr); - /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ if (pcc->svr != POWERPC_SVR_NONE) { if (pcc->svr & POWERPC_SVR_E500) { diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index e53fd28..0e9c68f 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -58,6 +58,10 @@ %ds_rtp 22:4 !function=times_2 @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si +%dd_si 3:s13 +&DD rt ra si:int64_t +@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si + &DX_b vrt b %dx_b 6:10 16:5 0:1 @DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b @@ -66,6 +70,11 @@ %dx_d 6:s10 16:5 0:1 @DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d +%md_sh 1:1 11:5 +%md_mb 5:1 6:5 +&MD rs ra sh mb rc +@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb + &VA vrt vra vrb rc @VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA @@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X LQ 111000 ..... ..... ............ ---- @DQ_rtp +LVD 000101 ..... ..... ................ @D +LVDU 001001 ..... ..... ................ @D +LVDX 011111 ..... ..... ..... 0000010001 - @X +LSKU 111010 ..... ..... ............. 0 11 @DD +LCXU 111010 ..... ..... ............. 1 11 @DD + + ### Fixed-Point Store Instructions STB 100110 ..... ..... ................ @D @@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X STQ 111110 ..... ..... ..............10 @DS_rtp +STVDU 010110 ..... ..... ................ @D +STVDX 011111 ..... ..... ..... 0010010001 - @X +STSKU 111110 ..... ..... ............. 0 11 @DD +STCXU 111110 ..... ..... ............. 1 11 @DD + ### Fixed-Point Compare Instructions CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl @@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa BPERMD 011111 ..... ..... ..... 0011111100 - @X CFUGED 011111 ..... ..... ..... 0011011100 - @X -CNTLZDM 011111 ..... ..... ..... 0000111011 - @X -CNTTZDM 011111 ..... ..... ..... 1000111011 - @X +{ + SLVD 011111 ..... ..... ..... 0000111011 . @X_rc + CNTLZDM 011111 ..... ..... ..... 0000111011 - @X +} +{ + SRVD 011111 ..... ..... ..... 1000111011 . @X_rc + CNTTZDM 011111 ..... ..... ..... 1000111011 - @X +} PDEPD 011111 ..... ..... ..... 0010011100 - @X PEXTD 011111 ..... ..... ..... 0010111100 - @X @@ -503,6 +530,17 @@ STFDU 110111 ..... ...... ............... @D STFDX 011111 ..... ...... .... 1011010111 - @X STFDUX 011111 ..... ...... .... 1011110111 - @X +### Floating-Point Move Instructions + +FMR 111111 ..... ----- ..... 0001001000 . @X_tb_rc +FNEG 111111 ..... ----- ..... 0000101000 . @X_tb_rc +FABS 111111 ..... ----- ..... 0100001000 . @X_tb_rc +FNABS 111111 ..... ----- ..... 0010001000 . @X_tb_rc + +FCPSGN 111111 ..... ..... ..... 0000001000 . @X_rc +FMRGEW 111111 ..... ..... ..... 1111000110 - @X +FMRGOW 111111 ..... ..... ..... 1101000110 - @X + ### Floating-Point Arithmetic Instructions FADD 111111 ..... ..... ..... ----- 10101 . @A_tab @@ -541,6 +579,35 @@ FNMADDS 111011 ..... ..... ..... ..... 11111 . @A FNMSUB 111111 ..... ..... ..... ..... 11110 . @A FNMSUBS 111011 ..... ..... ..... ..... 11110 . @A +### Floating-Point Rounding and Conversion Instructions + +FRSP 111111 ..... ----- ..... 0000001100 . @X_tb_rc + +FRIN 111111 ..... ----- ..... 0110001000 . @X_tb_rc +FRIZ 111111 ..... ----- ..... 0110101000 . @X_tb_rc +FRIP 111111 ..... ----- ..... 0111001000 . @X_tb_rc +FRIM 111111 ..... ----- ..... 0111101000 . @X_tb_rc + +FCTIW 111111 ..... ----- ..... 0000001110 . @X_tb_rc +FCTIWU 111111 ..... ----- ..... 0010001110 . @X_tb_rc +FCTIWZ 111111 ..... ----- ..... 0000001111 . @X_tb_rc +FCTIWUZ 111111 ..... ----- ..... 0010001111 . @X_tb_rc + +FCTID 111111 ..... ----- ..... 1100101110 . @X_tb_rc +FCTIDU 111111 ..... ----- ..... 1110101110 . @X_tb_rc +FCTIDZ 111111 ..... ----- ..... 1100101111 . @X_tb_rc +FCTIDUZ 111111 ..... ----- ..... 1110101111 . @X_tb_rc + +FCFID 111111 ..... ----- ..... 1101001110 . @X_tb_rc +FCFIDS 111011 ..... ----- ..... 1101001110 . @X_tb_rc +FCFIDU 111111 ..... ----- ..... 1111001110 . @X_tb_rc +FCFIDUS 111011 ..... ----- ..... 1111001110 . @X_tb_rc + +### Floating-Point Compare Instructions + +FCMPU 111111 ... -- ..... ..... 0000000000 - @X_bf +FCMPO 111111 ... -- ..... ..... 0000100000 - @X_bf + ### Floating-Point Select Instruction FSEL 111111 ..... ..... ..... ..... 10111 . @A @@ -981,8 +1048,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS STXSSP 111101 ..... ..... .............. 11 @DS LXV 111101 ..... ..... ............ . 001 @DQ_TSX STXV 111101 ..... ..... ............ . 101 @DQ_TSX -LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP -STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP + +# STVD PPE instruction overlaps with the LXVP and STXVP instructions +{ + STVD 000110 ..... ..... ................ @D + [ + LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP + STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP + ] +} + LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP @@ -1300,3 +1375,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 - ## Misc POWER instructions ATTN 000000 00000 00000 00000 0100000000 0 + +# Fused compare-branch instructions for PPE only +%fcb_bdx 1:s10 !function=times_4 +&FCB px:bool ra rb:uint64_t bdx lk:bool +@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx +&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool +@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx + +CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix +CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix +CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix +BNBWI 000001 11 . 00 ..... ..... .......... . @FCB +BNBW 000001 11 . 01 ..... ..... .......... . @FCB +CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB +CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB + +# Data Cache Block Query for PPE only +DCBQ 011111 ..... ..... ..... 0110010110 - @X + +# Rotate Doubleword Instructions for PPE only +RLDICL 011110 ..... ..... ..... ...... 000 . . @MD +RLDICR 011110 ..... ..... ..... ...... 001 . . @MD +RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c index f835be5..edecfb8 100644 --- a/target/ppc/tcg-excp_helper.c +++ b/target/ppc/tcg-excp_helper.c @@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, case POWERPC_MMU_BOOKE206: env->spr[SPR_BOOKE_DEAR] = vaddr; break; + case POWERPC_MMU_REAL: + if (env->flags & POWERPC_FLAG_PPE42) { + env->spr[SPR_PPE42_EDR] = vaddr; + if (access_type == MMU_DATA_STORE) { + env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST; + } else { + env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST; + } + } else { + env->spr[SPR_DAR] = vaddr; + } + break; default: env->spr[SPR_DAR] = vaddr; break; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 27f90c3..d422789 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -209,6 +209,11 @@ struct DisasContext { #define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */ #define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */ +static inline bool is_ppe(const DisasContext *ctx) +{ + return !!(ctx->flags & POWERPC_FLAG_PPE42); +} + /* Return true iff byteswap is needed in a scalar memop */ static inline bool need_byteswap(const DisasContext *ctx) { @@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn) #endif -/* SPR common to all PowerPC */ -/* XER */ -void spr_read_xer(DisasContext *ctx, int gprn, int sprn) +static void gen_get_xer(DisasContext *ctx, TCGv dst) { - TCGv dst = cpu_gpr[gprn]; TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); @@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn) } } -void spr_write_xer(DisasContext *ctx, int sprn, int gprn) +/* SPR common to all PowerPC */ +/* XER */ +void spr_read_xer(DisasContext *ctx, int gprn, int sprn) +{ + TCGv dst = cpu_gpr[gprn]; + gen_get_xer(ctx, dst); +} + +static void gen_set_xer(DisasContext *ctx, TCGv src) { - TCGv src = cpu_gpr[gprn]; /* Write all flags, while reading back check for isa300 */ tcg_gen_andi_tl(cpu_xer, src, ~((1u << XER_SO) | @@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn) tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1); } +void spr_write_xer(DisasContext *ctx, int sprn, int gprn) +{ + TCGv src = cpu_gpr[gprn]; + gen_set_xer(ctx, src); +} + /* LR */ void spr_read_lr(DisasContext *ctx, int gprn, int sprn) { @@ -4264,8 +4279,10 @@ static void gen_mtmsr(DisasContext *ctx) /* L=1 form only updates EE and RI */ mask &= (1ULL << MSR_RI) | (1ULL << MSR_EE); } else { - /* mtmsr does not alter S, ME, or LE */ - mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S)); + if (likely(!(ctx->insns_flags2 & PPC2_PPE42))) { + /* mtmsr does not alter S, ME, or LE */ + mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S)); + } /* * XXX: we need to update nip before the store if we enter @@ -5753,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) #include "translate/bhrb-impl.c.inc" +#include "translate/ppe-impl.c.inc" + /* Handles lfdp */ static void gen_dform39(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index a66b833..464fb1d 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -98,28 +98,26 @@ static bool do_helper_ac(DisasContext *ctx, arg_A_tac *a, return true; } -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0; \ - TCGv_i64 t1; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - t0 = tcg_temp_new_i64(); \ - t1 = tcg_temp_new_i64(); \ - gen_reset_fpstatus(); \ - get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, tcg_env, t0); \ - set_fpr(rD(ctx->opcode), t1); \ - if (set_fprf) { \ - gen_helper_compute_fprf_float64(tcg_env, t1); \ - } \ - gen_helper_float_check_status(tcg_env); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ +static bool do_round_convert(DisasContext *ctx, arg_X_tb_rc *a, + void (*helper)(TCGv_i64, TCGv_env, TCGv_i64), + bool set_fprf) +{ + TCGv_i64 t0, t1; + REQUIRE_FPU(ctx); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + gen_reset_fpstatus(); + get_fpr(t0, a->rb); + helper(t1, tcg_env, t0); + set_fpr(a->rt, t1); + if (set_fprf) { + gen_helper_compute_fprf_float64(tcg_env, t1); + } + gen_helper_float_check_status(tcg_env); + if (unlikely(a->rc)) { + gen_set_cr1_from_fpscr(ctx); + } + return true; } static bool do_helper_bs(DisasContext *ctx, arg_A_tb *a, @@ -213,41 +211,26 @@ TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); /*** Floating-Point round & convert ***/ -/* fctiw */ -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); -/* fctiwu */ -GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206); -/* fctiwz */ -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); -/* fctiwuz */ -GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); -/* frsp */ -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); -/* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); -/* fcfids */ -GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); -/* fcfidu */ -GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fcfidus */ -GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); -/* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); - -/* frin */ -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); -/* friz */ -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); -/* frip */ -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); -/* frim */ -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); +TRANS_FLAGS(FLOAT, FRSP, do_round_convert, gen_helper_FRSP, true); +TRANS_FLAGS(FLOAT_EXT, FRIN, do_round_convert, gen_helper_FRIN, true); +TRANS_FLAGS(FLOAT_EXT, FRIZ, do_round_convert, gen_helper_FRIZ, true); +TRANS_FLAGS(FLOAT_EXT, FRIP, do_round_convert, gen_helper_FRIP, true); +TRANS_FLAGS(FLOAT_EXT, FRIM, do_round_convert, gen_helper_FRIM, true); + +TRANS_FLAGS(FLOAT, FCTIW, do_round_convert, gen_helper_FCTIW, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIWU, do_round_convert, gen_helper_FCTIWU, false); +TRANS_FLAGS(FLOAT, FCTIWZ, do_round_convert, gen_helper_FCTIWZ, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIWUZ, do_round_convert, gen_helper_FCTIWUZ, false); + +TRANS_FLAGS2(FP_CVT_S64, FCTID, do_round_convert, gen_helper_FCTID, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIDU, do_round_convert, gen_helper_FCTIDU, false); +TRANS_FLAGS2(FP_CVT_S64, FCTIDZ, do_round_convert, gen_helper_FCTIDZ, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIDUZ, do_round_convert, gen_helper_FCTIDUZ, false); + +TRANS_FLAGS2(FP_CVT_S64, FCFID, do_round_convert, gen_helper_FCFID, true); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDS, do_round_convert, gen_helper_FCFIDS, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDU, do_round_convert, gen_helper_FCFIDU, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDUS, do_round_convert, gen_helper_FCFIDUS, false); static bool trans_FTDIV(DisasContext *ctx, arg_X_bf *a) { @@ -274,183 +257,117 @@ static bool trans_FTSQRT(DisasContext *ctx, arg_X_bf_b *a) } /*** Floating-Point compare ***/ - -/* fcmpo */ -static void gen_fcmpo(DisasContext *ctx) +static bool do_helper_cmp(DisasContext *ctx, arg_X_bf *a, + void (*helper)(TCGv_env, TCGv_i64, TCGv_i64, + TCGv_i32)) { TCGv_i32 crf; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); - crf = tcg_constant_i32(crfD(ctx->opcode)); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpo(tcg_env, t0, t1, crf); + crf = tcg_constant_i32(a->bf); + get_fpr(t0, a->ra); + get_fpr(t1, a->rb); + helper(tcg_env, t0, t1, crf); gen_helper_float_check_status(tcg_env); + return true; } -/* fcmpu */ -static void gen_fcmpu(DisasContext *ctx) -{ - TCGv_i32 crf; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - crf = tcg_constant_i32(crfD(ctx->opcode)); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpu(tcg_env, t0, t1, crf); - gen_helper_float_check_status(tcg_env); -} +TRANS(FCMPU, do_helper_cmp, gen_helper_FCMPU); +TRANS(FCMPO, do_helper_cmp, gen_helper_FCMPO); /*** Floating-point move ***/ -/* fabs */ -/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ -static void gen_fabs(DisasContext *ctx) -{ - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_andi_i64(t1, t0, ~(1ULL << 63)); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} /* fmr - fmr. */ /* XXX: beware that fmr never checks for NaNs nor update FPSCR */ -static void gen_fmr(DisasContext *ctx) +static bool trans_FMR(DisasContext *ctx, arg_FMR *a) { TCGv_i64 t0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - set_fpr(rD(ctx->opcode), t0); - if (unlikely(Rc(ctx->opcode))) { + get_fpr(t0, a->rb); + set_fpr(a->rt, t0); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -/* fnabs */ -/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ -static void gen_fnabs(DisasContext *ctx) +/* XXX: beware that f{neg, abs, nabs} never checks for NaNs nor update FPSCR */ +static bool do_move_b(DisasContext *ctx, arg_X_tb_rc *a, int64_t val, + void (*tcg_op)(TCGv_i64, TCGv_i64, int64_t)) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_ori_i64(t1, t0, 1ULL << 63); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { + get_fpr(t0, a->rb); + tcg_op(t1, t0, val); + set_fpr(a->rt, t1); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -/* fneg */ -/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ -static void gen_fneg(DisasContext *ctx) -{ - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_xori_i64(t1, t0, 1ULL << 63); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} +TRANS(FNEG, do_move_b, 1ULL << 63, tcg_gen_xori_i64); +TRANS(FABS, do_move_b, ~(1ULL << 63), tcg_gen_andi_i64); +TRANS(FNABS, do_move_b, 1ULL << 63, tcg_gen_ori_i64); /* fcpsgn: PowerPC 2.05 specification */ /* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ -static void gen_fcpsgn(DisasContext *ctx) +static bool trans_FCPSGN(DisasContext *ctx, arg_FCPSGN *a) { - TCGv_i64 t0; - TCGv_i64 t1; - TCGv_i64 t2; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, ISA205); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); + get_fpr(t0, a->ra); + get_fpr(t1, a->rb); tcg_gen_deposit_i64(t2, t0, t1, 0, 63); - set_fpr(rD(ctx->opcode), t2); - if (unlikely(Rc(ctx->opcode))) { + set_fpr(a->rt, t2); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -static void gen_fmrgew(DisasContext *ctx) +static bool trans_FMRGEW(DisasContext *ctx, arg_FMRGEW *a) { - TCGv_i64 b0; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - b0 = tcg_temp_new_i64(); + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_shri_i64(b0, t0, 32); - get_fpr(t0, rA(ctx->opcode)); - tcg_gen_deposit_i64(t1, t0, b0, 0, 32); - set_fpr(rD(ctx->opcode), t1); + t2 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_shri_i64(t0, t1, 32); + get_fpr(t1, a->ra); + tcg_gen_deposit_i64(t2, t1, t0, 0, 32); + set_fpr(a->rt, t2); + return true; } -static void gen_fmrgow(DisasContext *ctx) +static bool trans_FMRGOW(DisasContext *ctx, arg_FMRGOW *a) { - TCGv_i64 t0; - TCGv_i64 t1; - TCGv_i64 t2; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - get_fpr(t1, rA(ctx->opcode)); + get_fpr(t0, a->rb); + get_fpr(t1, a->ra); tcg_gen_deposit_i64(t2, t0, t1, 32, 32); - set_fpr(rD(ctx->opcode), t2); + set_fpr(a->rt, t2); + return true; } /*** Floating-Point status & ctrl register ***/ @@ -479,7 +396,7 @@ static void gen_mcrfs(DisasContext *ctx) tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); /* Only the exception bits (including FX) should be cleared if read */ tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, - ~((0xF << shift) & FP_EX_CLEAR_BITS)); + ~(MAKE_64BIT_MASK(shift, 4) & FP_EX_CLEAR_BITS)); /* FEX and VX need to be updated, so don't set fpscr directly */ tmask = tcg_constant_i32(1 << nibble); gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask); @@ -1051,8 +968,6 @@ TRANS(STFDX, do_lsfp_X, false, true, false) TRANS(STFDUX, do_lsfp_X, true, true, false) TRANS(PSTFD, do_lsfp_PLS_D, false, true, false) -#undef GEN_FLOAT_B - #undef GEN_LDF #undef GEN_LDUF #undef GEN_LDUXF diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index cef4b5d..9bc9c3a 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -1,24 +1,3 @@ -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) - -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT), -GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), - GEN_HANDLER_E(lfdepx, 0x1F, 0x1F, 0x12, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), @@ -31,15 +10,6 @@ GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), -GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT), -GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc new file mode 100644 index 0000000..0a05903 --- /dev/null +++ b/target/ppc/translate/ppe-impl.c.inc @@ -0,0 +1,609 @@ +/* + * IBM PPE Instructions + * + * Copyright (c) 2025, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +static bool vdr_is_valid(uint32_t vdr) +{ + const uint32_t valid_bitmap = 0xf00003ff; + return !!((1ul << (vdr & 0x1f)) & valid_bitmap); +} + +static bool ppe_gpr_is_valid(uint32_t reg) +{ + const uint32_t valid_bitmap = 0xf00027ff; + return !!((1ul << (reg & 0x1f)) & valid_bitmap); +} + +#define CHECK_VDR(CTX, VDR) \ + do { \ + if (unlikely(!vdr_is_valid(VDR))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +#define CHECK_PPE_GPR(CTX, REG) \ + do { \ + if (unlikely(!ppe_gpr_is_valid(REG))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f) + +#define CHECK_PPE_LEVEL(CTX, LVL) \ + do { \ + if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a) +{ + int i; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + const uint8_t vd_list[] = {9, 7, 5, 3, 0}; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + + tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8); + gen_store_spr(SPR_PPE42_EDR, base); + + t8 = tcg_temp_new_i64(); + + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8); + + lo = tcg_temp_new(); + hi = tcg_temp_new(); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + gen_store_spr(SPR_SRR0, hi); + gen_store_spr(SPR_SRR1, lo); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + gen_set_xer(ctx, hi); + tcg_gen_mov_tl(cpu_ctr, lo); + + for (i = 0; i < sizeof(vd_list); i++) { + int vd = vd_list[i]; + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8); + } + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + tcg_gen_shri_tl(hi, hi, 28); + tcg_gen_trunc_tl_i32(cpu_crf[0], hi); + gen_store_spr(SPR_SPRG0, lo); + + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], base); + return true; +} + +static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a) +{ + int64_t n; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || + (a->si & PPC_BIT(0)) || (a->si == 0))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + gen_addr_register(ctx, base); + + + tcg_gen_addi_tl(base, base, a->si * 8); + gen_store_spr(SPR_PPE42_EDR, base); + + n = a->si - 1; + t8 = tcg_temp_new_i64(); + if (n > 0) { + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + hi = cpu_gpr[30]; + lo = cpu_gpr[31]; + tcg_gen_extr_i64_tl(lo, hi, t8); + } + if (n > 1) { + tcg_gen_addi_tl(EA, base, -16); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + hi = cpu_gpr[28]; + lo = cpu_gpr[29]; + tcg_gen_extr_i64_tl(lo, hi, t8); + } + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], base); + return true; +} + +static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a) +{ + TCGv EA; + TCGv lo, hi; + TCGv_i64 t8; + int i; + const uint8_t vd_list[] = {9, 7, 5, 3, 0}; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4); + tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + + gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]); + + t8 = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]); + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + lo = tcg_temp_new(); + hi = tcg_temp_new(); + + gen_load_spr(hi, SPR_SRR0); + gen_load_spr(lo, SPR_SRR1); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + gen_get_xer(ctx, hi); + tcg_gen_mov_tl(lo, cpu_ctr); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + for (i = 0; i < sizeof(vd_list); i++) { + int vd = vd_list[i]; + tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + + gen_load_spr(lo, SPR_SPRG0); + tcg_gen_extu_i32_tl(hi, cpu_crf[0]); + tcg_gen_shli_tl(hi, hi, 28); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8); + tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) | + MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], EA); + return true; +} + +static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a) +{ + int64_t n; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + gen_addr_register(ctx, base); + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + + gen_store_spr(SPR_PPE42_EDR, base); + + n = ~(a->si); + + t8 = tcg_temp_new_i64(); + if (n > 0) { + hi = cpu_gpr[30]; + lo = cpu_gpr[31]; + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + if (n > 1) { + hi = cpu_gpr[28]; + lo = cpu_gpr[29]; + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, base, -16); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + + tcg_gen_addi_tl(EA, base, a->si * 8); + tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) | + MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], EA); + return true; +} + +static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv disp, + bool update, bool store) +{ + TCGv ea; + int rt_lo; + TCGv_i64 t8; + + CHECK_VDR(ctx, rt); + CHECK_PPE_GPR(ctx, ra); + rt_lo = VDR_PAIR_REG(rt); + if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) { + gen_invalid(ctx); + return true; + } + gen_set_access_type(ctx, ACCESS_INT); + + ea = do_ea_calc(ctx, ra, disp); + t8 = tcg_temp_new_i64(); + if (store) { + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]); + tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64)); + } else { + tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64)); + tcg_gen_extr_i64_tl(cpu_gpr[rt_lo], cpu_gpr[rt], t8); + } + if (update) { + tcg_gen_mov_tl(cpu_gpr[ra], ea); + } + return true; +} + +static bool do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, + store); +} + +static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->rb); + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store); +} + +TRANS(LVD, do_ppe_ldst_D, false, false) +TRANS(LVDU, do_ppe_ldst_D, true, false) +TRANS(STVD, do_ppe_ldst_D, false, true) +TRANS(STVDU, do_ppe_ldst_D, true, true) +TRANS(LVDX, do_ppe_ldst_X, false) +TRANS(STVDX, do_ppe_ldst_X, true) + + +static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix, + int32_t bdx, bool s, bool px, bool lk) +{ + TCGCond cond; + uint32_t mask; + TCGLabel *no_branch; + target_ulong dest; + + /* Update CR0 */ + gen_op_cmp32(ra_val, rb_val, s, 0); + + if (lk) { + gen_setlr(ctx, ctx->base.pc_next); + } + + + mask = PPC_BIT32(28 + bix); + cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE; + no_branch = gen_new_label(); + dest = ctx->cia + bdx; + + /* Do the branch if CR0[bix] == PX */ + tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch); + gen_goto_tb(ctx, 0, dest); + gen_set_label(no_branch); + gen_goto_tb(ctx, 1, ctx->base.pc_next); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s, + bool rb_is_gpr) +{ + TCGv old_ra; + TCGv rb_val; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->ra); + if (rb_is_gpr) { + CHECK_PPE_GPR(ctx, a->rb); + rb_val = cpu_gpr[a->rb]; + } else { + rb_val = tcg_constant_tl(a->rb); + } + if (a->bix == 3) { + old_ra = tcg_temp_new(); + tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]); + tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val); + return do_fcb(ctx, old_ra, rb_val, 2, + a->bdx, s, a->px, a->lk); + } else { + return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix, + a->bdx, s, a->px, a->lk); + } +} + +TRANS(CMPWBC, do_cmp_branch, true, true) +TRANS(CMPLWBC, do_cmp_branch, false, true) +TRANS(CMPWIBC, do_cmp_branch, true, false) + +static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert, + bool update, bool rb_is_gpr) +{ + TCGv r; + TCGv mask, shift; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->ra); + if (rb_is_gpr) { + CHECK_PPE_GPR(ctx, a->rb); + mask = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f); + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift); + } else { + mask = tcg_constant_tl(PPC_BIT32(a->rb)); + } + if (invert) { + tcg_gen_not_tl(mask, mask); + } + + /* apply mask to ra */ + r = tcg_temp_new(); + tcg_gen_and_tl(r, cpu_gpr[a->ra], mask); + if (update) { + tcg_gen_mov_tl(cpu_gpr[a->ra], r); + } + return do_fcb(ctx, r, tcg_constant_tl(0), 2, + a->bdx, false, a->px, a->lk); +} + +TRANS(BNBWI, do_mask_branch, false, false, false) +TRANS(BNBW, do_mask_branch, false, false, true) +TRANS(CLRBWIBC, do_mask_branch, true, true, false) +TRANS(CLRBWBC, do_mask_branch, true, true, true) + +static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_movi_i64(t0, CRF_EQ); + tcg_gen_movi_i64(t1, CRF_LT); + tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0); + tcg_gen_movi_i64(t1, CRF_GT); + tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0); + tcg_gen_extrl_i64_i32(t, t0); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t); +} + +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left) +{ + int rt_lo, ra_lo; + TCGv_i64 t0, t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rt); + CHECK_VDR(ctx, a->ra); + CHECK_PPE_GPR(ctx, a->rb); + rt_lo = VDR_PAIR_REG(a->rt); + ra_lo = VDR_PAIR_REG(a->ra); + t8 = tcg_temp_new_i64(); + + /* AND rt with a mask that is 0 when rb >= 0x40 */ + t0 = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]); + tcg_gen_shli_i64(t0, t0, 0x39); + tcg_gen_sari_i64(t0, t0, 0x3f); + + /* form 64bit value from two 32bit regs */ + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]); + + /* apply mask */ + tcg_gen_andc_i64(t8, t8, t0); + + /* do the shift */ + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]); + tcg_gen_andi_i64(t0, t0, 0x3f); + if (left) { + tcg_gen_shl_i64(t8, t8, t0); + } else { + tcg_gen_shr_i64(t8, t8, t0); + } + + /* split the 64bit word back into two 32bit regs */ + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8); + + /* update CR0 if requested */ + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t8); + } + return true; +} + +TRANS(SRVD, do_shift64, false) +TRANS(SLVD, do_shift64, true) + +static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ * a) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_GPR(ctx, a->rt); + CHECK_PPE_GPR(ctx, a->ra); + CHECK_PPE_GPR(ctx, a->rb); + + /* No cache exists, so just set RT to 0 */ + tcg_gen_movi_tl(cpu_gpr[a->rt], 0); + return true; +} + +static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a) +{ + TCGv_i64 t_rs, t_ra; + int ra_lo, rs_lo; + uint32_t sh = a->sh; + uint32_t mb = a->mb; + uint32_t me = 63 - sh; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rs); + CHECK_VDR(ctx, a->ra); + + rs_lo = VDR_PAIR_REG(a->rs); + ra_lo = VDR_PAIR_REG(a->ra); + + t_rs = tcg_temp_new_i64(); + t_ra = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]); + tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]); + + if (mb <= me) { + tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1); + } else { + uint64_t mask = mask_u64(mb, me); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_rotli_i64(t1, t_rs, sh); + tcg_gen_andi_i64(t1, t1, mask); + tcg_gen_andi_i64(t_ra, t_ra, ~mask); + tcg_gen_or_i64(t_ra, t_ra, t1); + } + + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra); + + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t_ra); + } + return true; +} + + +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh) +{ + int len = me - mb + 1; + int rsh = (64 - sh) & 63; + int ra_lo, rs_lo; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rs); + CHECK_VDR(ctx, a->ra); + + rs_lo = VDR_PAIR_REG(a->rs); + ra_lo = VDR_PAIR_REG(a->ra); + t8 = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]); + if (sh != 0 && len > 0 && me == (63 - sh)) { + tcg_gen_deposit_z_i64(t8, t8, sh, len); + } else if (me == 63 && rsh + len <= 64) { + tcg_gen_extract_i64(t8, t8, rsh, len); + } else { + tcg_gen_rotli_i64(t8, t8, sh); + tcg_gen_andi_i64(t8, t8, mask_u64(mb, me)); + } + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8); + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t8); + } + return true; +} + +TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh) +TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh) |