diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-16 18:26:21 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-16 18:26:21 +0100 |
commit | af44da87e926ff64260b95f4350d338c4fc113ca (patch) | |
tree | 303a18d80e73641bb6e23218ac7b7df0666bcc6b /target-ppc | |
parent | f27701510cdce9f76cdad0aaf9fb0bbcb23d299a (diff) | |
parent | 9dbae97723e964692364fb43012c6fa5448a661f (diff) |
Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2014-06-16
This pull request brings a lot of fun things. Among others we have
- e500: u-boot firmware support
- sPAPR: magic page enablement
- sPAPR: add "compat" CPU option to support older guests
- sPAPR: refactorings in preparation for VFIO
- POWER8 live migration
- mac99: expose bus frequency
- little endian core dump, gdb and disas support
- new ppc64le-linux-user target
- DFP emulation
- bug fixes
# gpg: Signature made Mon 16 Jun 2014 12:28:32 BST using RSA key ID 03FEDC60
# gpg: Can't check signature: public key not found
* remotes/agraf/tags/signed-ppc-for-upstream: (156 commits)
spapr_pci: Advertise MSI quota
PPC: KVM: Make pv hcall endian agnostic
powerpc: use float64 for frsqrte
spapr: Add kvm-type property
spapr: Create SPAPRMachine struct
linux-user: Tell guest about big host page sizes
spapr_hcall: Add address-translation-mode-on-interrupt resource in H_SET_MODE
spapr_hcall: Split h_set_mode()
target-ppc: Enable DABRX SPR and limit it to <=POWER7
target-ppc: Enable PPR and VRSAVE SPRs migration
target-ppc: Add POWER8's Event Based Branch (EBB) control SPRs
KVM: target-ppc: Enable TM state migration
target-ppc: Add POWER8's TM SPRs
target-ppc: Add POWER8's MMCR2/MMCRS SPRs
target-ppc: Enable FSCR facility check for TAR
target-ppc: Add POWER8's FSCR SPR
target-ppc: Add POWER8's TIR SPR
target-ppc: Refactor class init for POWER7/8
target-ppc: Switch POWER7/8 classes to use correct PMU SPRs
target-ppc: Make use of gen_spr_power5p_lpar() for POWER7/8
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/Makefile.objs | 1 | ||||
-rw-r--r-- | target-ppc/arch_dump.c | 107 | ||||
-rw-r--r-- | target-ppc/cpu-models.c | 46 | ||||
-rw-r--r-- | target-ppc/cpu-models.h | 12 | ||||
-rw-r--r-- | target-ppc/cpu-qom.h | 22 | ||||
-rw-r--r-- | target-ppc/cpu.h | 163 | ||||
-rw-r--r-- | target-ppc/dfp_helper.c | 1317 | ||||
-rw-r--r-- | target-ppc/excp_helper.c | 12 | ||||
-rw-r--r-- | target-ppc/fpu_helper.c | 3 | ||||
-rw-r--r-- | target-ppc/gdbstub.c | 124 | ||||
-rw-r--r-- | target-ppc/helper.h | 59 | ||||
-rw-r--r-- | target-ppc/int_helper.c | 292 | ||||
-rw-r--r-- | target-ppc/kvm.c | 111 | ||||
-rw-r--r-- | target-ppc/kvm_ppc.h | 20 | ||||
-rw-r--r-- | target-ppc/machine.c | 43 | ||||
-rw-r--r-- | target-ppc/mem_helper.c | 26 | ||||
-rw-r--r-- | target-ppc/misc_helper.c | 39 | ||||
-rw-r--r-- | target-ppc/mmu_helper.c | 7 | ||||
-rw-r--r-- | target-ppc/translate.c | 1283 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 1956 |
20 files changed, 4150 insertions, 1493 deletions
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 3cb23e0f11..a7ae392cc0 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -6,6 +6,7 @@ obj-$(TARGET_PPC64) += mmu-hash64.o arch_dump.o endif obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o +obj-y += dfp_helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o diff --git a/target-ppc/arch_dump.c b/target-ppc/arch_dump.c index 9dccf1ae1f..5acafc68a4 100644 --- a/target-ppc/arch_dump.c +++ b/target-ppc/arch_dump.c @@ -79,94 +79,122 @@ typedef struct noteStruct { } contents; } QEMU_PACKED Note; +typedef struct NoteFuncArg { + Note note; + DumpState *state; +} NoteFuncArg; -static void ppc64_write_elf64_prstatus(Note *note, PowerPCCPU *cpu) +static void ppc64_write_elf64_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu) { int i; uint64_t cr; struct PPC64ElfPrstatus *prstatus; struct PPC64UserRegStruct *reg; + Note *note = &arg->note; + DumpState *s = arg->state; - note->hdr.n_type = cpu_to_be32(NT_PRSTATUS); + note->hdr.n_type = cpu_to_dump32(s, NT_PRSTATUS); prstatus = ¬e->contents.prstatus; memset(prstatus, 0, sizeof(*prstatus)); reg = &prstatus->pr_reg; for (i = 0; i < 32; i++) { - reg->gpr[i] = cpu_to_be64(cpu->env.gpr[i]); + reg->gpr[i] = cpu_to_dump64(s, cpu->env.gpr[i]); } - reg->nip = cpu_to_be64(cpu->env.nip); - reg->msr = cpu_to_be64(cpu->env.msr); - reg->ctr = cpu_to_be64(cpu->env.ctr); - reg->link = cpu_to_be64(cpu->env.lr); - reg->xer = cpu_to_be64(cpu_read_xer(&cpu->env)); + reg->nip = cpu_to_dump64(s, cpu->env.nip); + reg->msr = cpu_to_dump64(s, cpu->env.msr); + reg->ctr = cpu_to_dump64(s, cpu->env.ctr); + reg->link = cpu_to_dump64(s, cpu->env.lr); + reg->xer = cpu_to_dump64(s, cpu_read_xer(&cpu->env)); cr = 0; for (i = 0; i < 8; i++) { cr |= (cpu->env.crf[i] & 15) << (4 * (7 - i)); } - reg->ccr = cpu_to_be64(cr); + reg->ccr = cpu_to_dump64(s, cr); } -static void ppc64_write_elf64_fpregset(Note *note, PowerPCCPU *cpu) +static void ppc64_write_elf64_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu) { int i; struct PPC64ElfFpregset *fpregset; + Note *note = &arg->note; + DumpState *s = arg->state; - note->hdr.n_type = cpu_to_be32(NT_PRFPREG); + note->hdr.n_type = cpu_to_dump32(s, NT_PRFPREG); fpregset = ¬e->contents.fpregset; memset(fpregset, 0, sizeof(*fpregset)); for (i = 0; i < 32; i++) { - fpregset->fpr[i] = cpu_to_be64(cpu->env.fpr[i]); + fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]); } - fpregset->fpscr = cpu_to_be64(cpu->env.fpscr); + fpregset->fpscr = cpu_to_dump64(s, cpu->env.fpscr); } -static void ppc64_write_elf64_vmxregset(Note *note, PowerPCCPU *cpu) +static void ppc64_write_elf64_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu) { int i; struct PPC64ElfVmxregset *vmxregset; + Note *note = &arg->note; + DumpState *s = arg->state; - note->hdr.n_type = cpu_to_be32(NT_PPC_VMX); + note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VMX); vmxregset = ¬e->contents.vmxregset; memset(vmxregset, 0, sizeof(*vmxregset)); for (i = 0; i < 32; i++) { - vmxregset->avr[i].u64[0] = cpu_to_be64(cpu->env.avr[i].u64[0]); - vmxregset->avr[i].u64[1] = cpu_to_be64(cpu->env.avr[i].u64[1]); + bool needs_byteswap; + +#ifdef HOST_WORDS_BIGENDIAN + needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB; +#else + needs_byteswap = s->dump_info.d_endian == ELFDATA2MSB; +#endif + + if (needs_byteswap) { + vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]); + vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]); + } else { + vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0]; + vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1]; + } } - vmxregset->vscr.u32[3] = cpu_to_be32(cpu->env.vscr); + vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr); } -static void ppc64_write_elf64_vsxregset(Note *note, PowerPCCPU *cpu) +static void ppc64_write_elf64_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu) { int i; struct PPC64ElfVsxregset *vsxregset; + Note *note = &arg->note; + DumpState *s = arg->state; - note->hdr.n_type = cpu_to_be32(NT_PPC_VSX); + note->hdr.n_type = cpu_to_dump32(s, NT_PPC_VSX); vsxregset = ¬e->contents.vsxregset; memset(vsxregset, 0, sizeof(*vsxregset)); for (i = 0; i < 32; i++) { - vsxregset->vsr[i] = cpu_to_be64(cpu->env.vsr[i]); + vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]); } } -static void ppc64_write_elf64_speregset(Note *note, PowerPCCPU *cpu) +static void ppc64_write_elf64_speregset(NoteFuncArg *arg, PowerPCCPU *cpu) { struct PPC64ElfSperegset *speregset; - note->hdr.n_type = cpu_to_be32(NT_PPC_SPE); + Note *note = &arg->note; + DumpState *s = arg->state; + + note->hdr.n_type = cpu_to_dump32(s, NT_PPC_SPE); speregset = ¬e->contents.speregset; memset(speregset, 0, sizeof(*speregset)); - speregset->spe_acc = cpu_to_be64(cpu->env.spe_acc); - speregset->spe_fscr = cpu_to_be32(cpu->env.spe_fscr); + speregset->spe_acc = cpu_to_dump64(s, cpu->env.spe_acc); + speregset->spe_fscr = cpu_to_dump32(s, cpu->env.spe_fscr); } static const struct NoteFuncDescStruct { int contents_size; - void (*note_contents_func)(Note *note, PowerPCCPU *cpu); + void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu); } note_func[] = { {sizeof(((Note *)0)->contents.prstatus), ppc64_write_elf64_prstatus}, {sizeof(((Note *)0)->contents.fpregset), ppc64_write_elf64_fpregset}, @@ -181,12 +209,16 @@ typedef struct NoteFuncDescStruct NoteFuncDesc; int cpu_get_dump_info(ArchDumpInfo *info, const struct GuestPhysBlockList *guest_phys_blocks) { - /* - * Currently only handling PPC64 big endian. - */ + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + info->d_machine = EM_PPC64; - info->d_endian = ELFDATA2MSB; info->d_class = ELFCLASS64; + if ((*pcc->interrupts_big_endian)(cpu)) { + info->d_endian = ELFDATA2MSB; + } else { + info->d_endian = ELFDATA2LSB; + } return 0; } @@ -218,20 +250,21 @@ static int ppc64_write_all_elf64_notes(const char *note_name, PowerPCCPU *cpu, int id, void *opaque) { - Note note; + NoteFuncArg arg = { .state = opaque }; int ret = -1; int note_size; const NoteFuncDesc *nf; for (nf = note_func; nf->note_contents_func; nf++) { - note.hdr.n_namesz = cpu_to_be32(sizeof(note.name)); - note.hdr.n_descsz = cpu_to_be32(nf->contents_size); - strncpy(note.name, note_name, sizeof(note.name)); + arg.note.hdr.n_namesz = cpu_to_dump32(opaque, sizeof(arg.note.name)); + arg.note.hdr.n_descsz = cpu_to_dump32(opaque, nf->contents_size); + strncpy(arg.note.name, note_name, sizeof(arg.note.name)); - (*nf->note_contents_func)(¬e, cpu); + (*nf->note_contents_func)(&arg, cpu); - note_size = sizeof(note) - sizeof(note.contents) + nf->contents_size; - ret = f(¬e, note_size, opaque); + note_size = + sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size; + ret = f(&arg.note, note_size, opaque); if (ret < 0) { return -1; } diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index f6c9b3ab01..97a81d8660 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -671,20 +671,20 @@ POWERPC_DEF_SVR("MPC8379E", "MPC8379E", CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) /* e500 family */ - POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1, - "PowerPC e500 v1.0 core") - POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1, - "PowerPC e500 v2.0 core") - POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2, - "PowerPC e500v2 v1.0 core") - POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2, - "PowerPC e500v2 v2.0 core") - POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2, - "PowerPC e500v2 v2.1 core") - POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2, - "PowerPC e500v2 v2.2 core") - POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2, - "PowerPC e500v2 v3.0 core") + POWERPC_DEF_SVR("e500_v10", "PowerPC e500 v1.0 core", + CPU_POWERPC_e500v1_v10, POWERPC_SVR_E500, e500v1); + POWERPC_DEF_SVR("e500_v20", "PowerPC e500 v2.0 core", + CPU_POWERPC_e500v1_v20, POWERPC_SVR_E500, e500v1); + POWERPC_DEF_SVR("e500v2_v10", "PowerPC e500v2 v1.0 core", + CPU_POWERPC_e500v2_v10, POWERPC_SVR_E500, e500v2); + POWERPC_DEF_SVR("e500v2_v20", "PowerPC e500v2 v2.0 core", + CPU_POWERPC_e500v2_v20, POWERPC_SVR_E500, e500v2); + POWERPC_DEF_SVR("e500v2_v21", "PowerPC e500v2 v2.1 core", + CPU_POWERPC_e500v2_v21, POWERPC_SVR_E500, e500v2); + POWERPC_DEF_SVR("e500v2_v22", "PowerPC e500v2 v2.2 core", + CPU_POWERPC_e500v2_v22, POWERPC_SVR_E500, e500v2); + POWERPC_DEF_SVR("e500v2_v30", "PowerPC e500v2 v3.0 core", + CPU_POWERPC_e500v2_v30, POWERPC_SVR_E500, e500v2); POWERPC_DEF_SVR("e500mc", "e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) #ifdef TARGET_PPC64 @@ -1134,10 +1134,6 @@ POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6, "POWER6A") #endif - POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7, - "POWER7 v2.0") - POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7, - "POWER7 v2.1") POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, "POWER7 v2.3") POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P, @@ -1146,19 +1142,19 @@ "POWER8 v1.0") POWERPC_DEF("970", CPU_POWERPC_970, 970, "PowerPC 970") - POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX, + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970, "PowerPC 970FX v1.0 (G5)") - POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX, + POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970, "PowerPC 970FX v2.0 (G5)") - POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX, + POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970, "PowerPC 970FX v2.1 (G5)") - POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX, + POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970, "PowerPC 970FX v3.0 (G5)") - POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX, + POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970, "PowerPC 970FX v3.1 (G5)") - POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP, + POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970, "PowerPC 970MP v1.0") - POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP, + POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970, "PowerPC 970MP v1.1") #if defined(TODO) POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index 644a126459..db75896012 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -555,8 +555,6 @@ enum { CPU_POWERPC_POWER6A = 0x0F000002, CPU_POWERPC_POWER7_BASE = 0x003F0000, CPU_POWERPC_POWER7_MASK = 0xFFFF0000, - CPU_POWERPC_POWER7_v20 = 0x003F0200, - CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_POWER7P_BASE = 0x004A0000, CPU_POWERPC_POWER7P_MASK = 0xFFFF0000, @@ -597,6 +595,16 @@ enum { CPU_POWERPC_PA6T = 0x00900000, }; +/* Logical PVR definitions for sPAPR */ +enum { + CPU_POWERPC_LOGICAL_2_04 = 0x0F000001, + CPU_POWERPC_LOGICAL_2_05 = 0x0F000002, + CPU_POWERPC_LOGICAL_2_06 = 0x0F000003, + CPU_POWERPC_LOGICAL_2_06_PLUS = 0x0F100003, + CPU_POWERPC_LOGICAL_2_07 = 0x0F000004, + CPU_POWERPC_LOGICAL_2_08 = 0x0F000005, +}; + /* System version register (used on MPC 8xxx) */ enum { POWERPC_SVR_NONE = 0x00000000, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 47dc8e6fdf..13c7031265 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -57,6 +57,7 @@ typedef struct PowerPCCPUClass { uint32_t pvr; uint32_t pvr_mask; + uint64_t pcr_mask; uint32_t svr; uint64_t insns_flags; uint64_t insns_flags2; @@ -76,12 +77,15 @@ typedef struct PowerPCCPUClass { int (*handle_mmu_fault)(PowerPCCPU *cpu, target_ulong eaddr, int rwx, int mmu_idx); #endif + bool (*interrupts_big_endian)(PowerPCCPU *cpu); } PowerPCCPUClass; /** * PowerPCCPU: * @env: #CPUPPCState * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too + * @max_compat: Maximal supported logical PVR from the command line + * @cpu_version: Current logical PVR, zero if in "raw" mode * * A PowerPC CPU. */ @@ -92,6 +96,8 @@ struct PowerPCCPU { CPUPPCState env; int cpu_dt_id; + uint32_t max_compat; + uint32_t cpu_version; }; static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) @@ -120,6 +126,22 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); #ifndef CONFIG_USER_ONLY extern const struct VMStateDescription vmstate_ppc_cpu; + +typedef struct PPCTimebase { + uint64_t guest_timebase; + int64_t time_of_the_day_ns; +} PPCTimebase; + +extern const struct VMStateDescription vmstate_ppc_timebase; + +#define VMSTATE_PPC_TIMEBASE_V(_field, _state, _version) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .size = sizeof(PPCTimebase), \ + .vmsd = &vmstate_ppc_timebase, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, PPCTimebase), \ +} #endif #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 75ed5fa636..74407ee209 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -238,6 +238,7 @@ enum { POWERPC_EXCP_DTLBE = 93, /* Data TLB error */ /* VSX Unavailable (Power ISA 2.06 and later) */ POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */ + POWERPC_EXCP_FU = 95, /* Facility Unavailable */ /* EOL */ POWERPC_EXCP_NB = 96, /* QEMU exceptions: used internally during code translation */ @@ -426,6 +427,9 @@ struct ppc_slb_t { #define MSR_TAG 62 /* Tag-active mode (POWERx ?) */ #define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ #define MSR_SHV 60 /* hypervisor state hflags */ +#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */ +#define MSR_TS1 33 +#define MSR_TM 32 /* Transactional Memory Available (Book3s) */ #define MSR_CM 31 /* Computation mode for BookE hflags */ #define MSR_ICM 30 /* Interrupt computation mode for BookE */ #define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */ @@ -463,6 +467,8 @@ struct ppc_slb_t { #define MSR_LE 0 /* Little-endian mode 1 hflags */ #define LPCR_ILE (1 << (63-38)) +#define LPCR_AIL_SHIFT (63-40) /* Alternate interrupt location */ +#define LPCR_AIL (3 << LPCR_AIL_SHIFT) #define msr_sf ((env->msr >> MSR_SF) & 1) #define msr_isf ((env->msr >> MSR_ISF) & 1) @@ -502,6 +508,9 @@ struct ppc_slb_t { #define msr_pmm ((env->msr >> MSR_PMM) & 1) #define msr_ri ((env->msr >> MSR_RI) & 1) #define msr_le ((env->msr >> MSR_LE) & 1) +#define msr_ts ((env->msr >> MSR_TS1) & 3) +#define msr_tm ((env->msr >> MSR_TM) & 1) + /* Hypervisor bit is more specific */ #if defined(TARGET_PPC64) #define MSR_HVB (1ULL << MSR_SHV) @@ -516,6 +525,19 @@ struct ppc_slb_t { #endif #endif +/* Facility Status and Control (FSCR) bits */ +#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */ +#define FSCR_TAR (63 - 55) /* Target Address Register */ +/* Interrupt cause mask and position in FSCR. HFSCR has the same format */ +#define FSCR_IC_MASK (0xFFULL) +#define FSCR_IC_POS (63 - 7) +#define FSCR_IC_DSCR_SPR3 2 +#define FSCR_IC_PMU 3 +#define FSCR_IC_BHRB 4 +#define FSCR_IC_TM 5 +#define FSCR_IC_EBB 7 +#define FSCR_IC_TAR 8 + /* Exception state register bits definition */ #define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */ #define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */ @@ -908,10 +930,8 @@ struct CPUPPCState { */ /* general purpose registers */ target_ulong gpr[32]; -#if !defined(TARGET_PPC64) /* Storage for GPR MSB, used by the SPE extension */ target_ulong gprh[32]; -#endif /* LR */ target_ulong lr; /* CTR */ @@ -1081,6 +1101,20 @@ struct CPUPPCState { */ uint8_t fit_period[4]; uint8_t wdt_period[4]; + + /* Transactional memory state */ + target_ulong tm_gpr[32]; + ppc_avr_t tm_vsr[64]; + uint64_t tm_cr; + uint64_t tm_lr; + uint64_t tm_ctr; + uint64_t tm_fpscr; + uint64_t tm_amr; + uint64_t tm_ppr; + uint64_t tm_vrsave; + uint32_t tm_vscr; + uint64_t tm_dscr; + uint64_t tm_tar; }; #define SET_FIT_PERIOD(a_, b_, c_, d_) \ @@ -1104,6 +1138,7 @@ do { \ /*****************************************************************************/ PowerPCCPU *cpu_ppc_init(const char *cpu_model); void ppc_translate_init(void); +void gen_update_current_nip(void *opaque); int cpu_ppc_exec (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero @@ -1122,6 +1157,8 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); +int ppc_get_compat_smt_threads(PowerPCCPU *cpu); +int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version); /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS @@ -1162,7 +1199,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) uint64_t gprv; gprv = env->gpr[gprn]; -#if !defined(TARGET_PPC64) if (env->flags & POWERPC_FLAG_SPE) { /* If the CPU implements the SPE extension, we have to get the * high bits of the GPR from the gprh storage area @@ -1170,7 +1206,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) gprv &= 0xFFFFFFFFULL; gprv |= (uint64_t)env->gprh[gprn] << 32; } -#endif return gprv; } @@ -1258,6 +1293,10 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_MPC_EIE (0x050) #define SPR_MPC_EID (0x051) #define SPR_MPC_NRI (0x052) +#define SPR_TFHAR (0x080) +#define SPR_TFIAR (0x081) +#define SPR_TEXASR (0x082) +#define SPR_TEXASRU (0x083) #define SPR_UCTRL (0x088) #define SPR_MPC_CMPA (0x090) #define SPR_MPC_CMPB (0x091) @@ -1270,6 +1309,7 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_CTRL (0x098) #define SPR_MPC_CMPE (0x098) #define SPR_MPC_CMPF (0x099) +#define SPR_FSCR (0x099) #define SPR_MPC_CMPG (0x09A) #define SPR_MPC_CMPH (0x09B) #define SPR_MPC_LCTRL1 (0x09C) @@ -1338,6 +1378,7 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_LPCR (0x13E) #define SPR_BOOKE_DVC2 (0x13F) #define SPR_BOOKE_TSR (0x150) +#define SPR_PCR (0x152) #define SPR_BOOKE_TCR (0x154) #define SPR_BOOKE_TLB0PS (0x158) #define SPR_BOOKE_TLB1PS (0x159) @@ -1365,10 +1406,18 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_BOOKE_IVOR40 (0x1B2) #define SPR_BOOKE_IVOR41 (0x1B3) #define SPR_BOOKE_IVOR42 (0x1B4) +#define SPR_BOOKE_GIVOR2 (0x1B8) +#define SPR_BOOKE_GIVOR3 (0x1B9) +#define SPR_BOOKE_GIVOR4 (0x1BA) +#define SPR_BOOKE_GIVOR8 (0x1BB) +#define SPR_BOOKE_GIVOR13 (0x1BC) +#define SPR_BOOKE_GIVOR14 (0x1BD) +#define SPR_TIR (0x1BE) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) #define SPR_Exxx_L1CFG0 (0x203) +#define SPR_Exxx_L1CFG1 (0x204) #define SPR_Exxx_NPIDR (0x205) #define SPR_ATBL (0x20E) #define SPR_ATBU (0x20F) @@ -1453,62 +1502,96 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_MPC_MI_CTR (0x300) #define SPR_PERF1 (0x301) #define SPR_RCPU_MI_RBA1 (0x301) +#define SPR_POWER_UMMCR2 (0x301) #define SPR_PERF2 (0x302) #define SPR_RCPU_MI_RBA2 (0x302) #define SPR_MPC_MI_AP (0x302) -#define SPR_MMCRA (0x302) +#define SPR_POWER_UMMCRA (0x302) #define SPR_PERF3 (0x303) #define SPR_RCPU_MI_RBA3 (0x303) #define SPR_MPC_MI_EPN (0x303) +#define SPR_POWER_UPMC1 (0x303) #define SPR_PERF4 (0x304) +#define SPR_POWER_UPMC2 (0x304) #define SPR_PERF5 (0x305) #define SPR_MPC_MI_TWC (0x305) +#define SPR_POWER_UPMC3 (0x305) #define SPR_PERF6 (0x306) #define SPR_MPC_MI_RPN (0x306) +#define SPR_POWER_UPMC4 (0x306) #define SPR_PERF7 (0x307) +#define SPR_POWER_UPMC5 (0x307) #define SPR_PERF8 (0x308) #define SPR_RCPU_L2U_RBA0 (0x308) #define SPR_MPC_MD_CTR (0x308) +#define SPR_POWER_UPMC6 (0x308) #define SPR_PERF9 (0x309) #define SPR_RCPU_L2U_RBA1 (0x309) #define SPR_MPC_MD_CASID (0x309) +#define SPR_970_UPMC7 (0X309) #define SPR_PERFA (0x30A) #define SPR_RCPU_L2U_RBA2 (0x30A) #define SPR_MPC_MD_AP (0x30A) +#define SPR_970_UPMC8 (0X30A) #define SPR_PERFB (0x30B) #define SPR_RCPU_L2U_RBA3 (0x30B) #define SPR_MPC_MD_EPN (0x30B) +#define SPR_POWER_UMMCR0 (0X30B) #define SPR_PERFC (0x30C) #define SPR_MPC_MD_TWB (0x30C) +#define SPR_POWER_USIAR (0X30C) #define SPR_PERFD (0x30D) #define SPR_MPC_MD_TWC (0x30D) +#define SPR_POWER_USDAR (0X30D) #define SPR_PERFE (0x30E) #define SPR_MPC_MD_RPN (0x30E) +#define SPR_POWER_UMMCR1 (0X30E) #define SPR_PERFF (0x30F) #define SPR_MPC_MD_TW (0x30F) #define SPR_UPERF0 (0x310) #define SPR_UPERF1 (0x311) +#define SPR_POWER_MMCR2 (0x311) #define SPR_UPERF2 (0x312) +#define SPR_POWER_MMCRA (0X312) #define SPR_UPERF3 (0x313) +#define SPR_POWER_PMC1 (0X313) #define SPR_UPERF4 (0x314) +#define SPR_POWER_PMC2 (0X314) #define SPR_UPERF5 (0x315) +#define SPR_POWER_PMC3 (0X315) #define SPR_UPERF6 (0x316) +#define SPR_POWER_PMC4 (0X316) #define SPR_UPERF7 (0x317) +#define SPR_POWER_PMC5 (0X317) #define SPR_UPERF8 (0x318) +#define SPR_POWER_PMC6 (0X318) #define SPR_UPERF9 (0x319) +#define SPR_970_PMC7 (0X319) #define SPR_UPERFA (0x31A) +#define SPR_970_PMC8 (0X31A) #define SPR_UPERFB (0x31B) +#define SPR_POWER_MMCR0 (0X31B) #define SPR_UPERFC (0x31C) +#define SPR_POWER_SIAR (0X31C) #define SPR_UPERFD (0x31D) +#define SPR_POWER_SDAR (0X31D) #define SPR_UPERFE (0x31E) +#define SPR_POWER_MMCR1 (0X31E) #define SPR_UPERFF (0x31F) #define SPR_RCPU_MI_RA0 (0x320) #define SPR_MPC_MI_DBCAM (0x320) +#define SPR_BESCRS (0x320) #define SPR_RCPU_MI_RA1 (0x321) #define SPR_MPC_MI_DBRAM0 (0x321) +#define SPR_BESCRSU (0x321) #define SPR_RCPU_MI_RA2 (0x322) #define SPR_MPC_MI_DBRAM1 (0x322) +#define SPR_BESCRR (0x322) #define SPR_RCPU_MI_RA3 (0x323) +#define SPR_BESCRRU (0x323) +#define SPR_EBBHR (0x324) +#define SPR_EBBRR (0x325) +#define SPR_BESCR (0x326) #define SPR_RCPU_L2U_RA0 (0x328) #define SPR_MPC_MD_DBCAM (0x328) #define SPR_RCPU_L2U_RA1 (0x329) @@ -1527,6 +1610,7 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_440_ITV3 (0x377) #define SPR_440_CCR1 (0x378) #define SPR_DCRIPR (0x37B) +#define SPR_POWER_MMCRS (0x37E) #define SPR_PPR (0x380) #define SPR_750_GQR0 (0x390) #define SPR_440_DNV0 (0x390) @@ -1556,24 +1640,24 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_BOOKE_DCDBTRH (0x39D) #define SPR_BOOKE_ICDBTRL (0x39E) #define SPR_BOOKE_ICDBTRH (0x39F) -#define SPR_UMMCR2 (0x3A0) -#define SPR_UPMC5 (0x3A1) -#define SPR_UPMC6 (0x3A2) +#define SPR_74XX_UMMCR2 (0x3A0) +#define SPR_7XX_UPMC5 (0x3A1) +#define SPR_7XX_UPMC6 (0x3A2) #define SPR_UBAMR (0x3A7) -#define SPR_UMMCR0 (0x3A8) -#define SPR_UPMC1 (0x3A9) -#define SPR_UPMC2 (0x3AA) -#define SPR_USIAR (0x3AB) -#define SPR_UMMCR1 (0x3AC) -#define SPR_UPMC3 (0x3AD) -#define SPR_UPMC4 (0x3AE) +#define SPR_7XX_UMMCR0 (0x3A8) +#define SPR_7XX_UPMC1 (0x3A9) +#define SPR_7XX_UPMC2 (0x3AA) +#define SPR_7XX_USIAR (0x3AB) +#define SPR_7XX_UMMCR1 (0x3AC) +#define SPR_7XX_UPMC3 (0x3AD) +#define SPR_7XX_UPMC4 (0x3AE) #define SPR_USDA (0x3AF) #define SPR_40x_ZPR (0x3B0) #define SPR_BOOKE_MAS7 (0x3B0) -#define SPR_MMCR2 (0x3B0) -#define SPR_PMC5 (0x3B1) +#define SPR_74XX_MMCR2 (0x3B0) +#define SPR_7XX_PMC5 (0x3B1) #define SPR_40x_PID (0x3B1) -#define SPR_PMC6 (0x3B2) +#define SPR_7XX_PMC6 (0x3B2) #define SPR_440_MMUCR (0x3B2) #define SPR_4xx_CCR0 (0x3B3) #define SPR_BOOKE_EPLC (0x3B3) @@ -1583,19 +1667,19 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_405_DVC1 (0x3B6) #define SPR_405_DVC2 (0x3B7) #define SPR_BAMR (0x3B7) -#define SPR_MMCR0 (0x3B8) -#define SPR_PMC1 (0x3B9) +#define SPR_7XX_MMCR0 (0x3B8) +#define SPR_7XX_PMC1 (0x3B9) #define SPR_40x_SGR (0x3B9) -#define SPR_PMC2 (0x3BA) +#define SPR_7XX_PMC2 (0x3BA) #define SPR_40x_DCWR (0x3BA) -#define SPR_SIAR (0x3BB) +#define SPR_7XX_SIAR (0x3BB) #define SPR_405_SLER (0x3BB) -#define SPR_MMCR1 (0x3BC) +#define SPR_7XX_MMCR1 (0x3BC) #define SPR_405_SU0R (0x3BC) #define SPR_401_SKR (0x3BC) -#define SPR_PMC3 (0x3BD) +#define SPR_7XX_PMC3 (0x3BD) #define SPR_405_DBCR1 (0x3BD) -#define SPR_PMC4 (0x3BE) +#define SPR_7XX_PMC4 (0x3BE) #define SPR_SDA (0x3BF) #define SPR_403_VTBL (0x3CC) #define SPR_403_VTBU (0x3CD) @@ -1648,6 +1732,7 @@ static inline int cpu_mmu_index (CPUPPCState *env) #define SPR_750_TDCL (0x3F4) #define SPR_40x_IAC1 (0x3F4) #define SPR_MMUCSR0 (0x3F4) +#define SPR_970_HID4 (0x3F4) #define SPR_DABR (0x3F5) #define DABR_MASK (~(target_ulong)0x7) #define SPR_Exxx_BUCSR (0x3F5) @@ -1709,6 +1794,23 @@ static inline int cpu_mmu_index (CPUPPCState *env) /* External Input Interrupt Directed to Guest State */ #define EPCR_EXTGS (1 << 31) +#define L1CSR0_CPE 0x00010000 /* Data Cache Parity Enable */ +#define L1CSR0_CUL 0x00000400 /* (D-)Cache Unable to Lock */ +#define L1CSR0_DCLFR 0x00000100 /* D-Cache Lock Flash Reset */ +#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */ +#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */ + +#define L1CSR1_CPE 0x00010000 /* Instruction Cache Parity Enable */ +#define L1CSR1_ICUL 0x00000400 /* I-Cache Unable to Lock */ +#define L1CSR1_ICLFR 0x00000100 /* I-Cache Lock Flash Reset */ +#define L1CSR1_ICFI 0x00000002 /* Instruction Cache Flash Invalidate */ +#define L1CSR1_ICE 0x00000001 /* Instruction Cache Enable */ + +/* HID0 bits */ +#define HID0_DEEPNAP (1 << 24) +#define HID0_DOZE (1 << 23) +#define HID0_NAP (1 << 22) + /*****************************************************************************/ /* PowerPC Instructions types definitions */ enum { @@ -1910,7 +2012,7 @@ enum { PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ - PPC2_ALTIVEC_207) + PPC2_ALTIVEC_207 | PPC2_ISA207S) }; /*****************************************************************************/ @@ -2042,6 +2144,15 @@ enum { PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ }; +/* Processor Compatibility mask (PCR) */ +enum { + PCR_COMPAT_2_05 = 1ull << (63-62), + PCR_COMPAT_2_06 = 1ull << (63-61), + PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */ + PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */ + PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */ +}; + /*****************************************************************************/ static inline target_ulong cpu_read_xer(CPUPPCState *env) diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c new file mode 100644 index 0000000000..773803a285 --- /dev/null +++ b/target-ppc/dfp_helper.c @@ -0,0 +1,1317 @@ +/* + * PowerPC Decimal Floating Point (DPF) emulation helpers for QEMU. + * + * Copyright (c) 2014 IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "cpu.h" +#include "exec/helper-proto.h" + +#define DECNUMDIGITS 34 +#include "libdecnumber/decContext.h" +#include "libdecnumber/decNumber.h" +#include "libdecnumber/dpd/decimal32.h" +#include "libdecnumber/dpd/decimal64.h" +#include "libdecnumber/dpd/decimal128.h" + +#if defined(HOST_WORDS_BIGENDIAN) +#define HI_IDX 0 +#define LO_IDX 1 +#else +#define HI_IDX 1 +#define LO_IDX 0 +#endif + +struct PPC_DFP { + CPUPPCState *env; + uint64_t t64[2], a64[2], b64[2]; + decNumber t, a, b; + decContext context; + uint8_t crbf; +}; + +static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr) +{ + enum rounding rnd; + + switch ((fpscr >> 32) & 0x7) { + case 0: + rnd = DEC_ROUND_HALF_EVEN; + break; + case 1: + rnd = DEC_ROUND_DOWN; + break; + case 2: + rnd = DEC_ROUND_CEILING; + break; + case 3: + rnd = DEC_ROUND_FLOOR; + break; + case 4: + rnd = DEC_ROUND_HALF_UP; + break; + case 5: + rnd = DEC_ROUND_HALF_DOWN; + break; + case 6: + rnd = DEC_ROUND_UP; + break; + case 7: + rnd = DEC_ROUND_05UP; + break; + default: + g_assert_not_reached(); + } + + decContextSetRounding(context, rnd); +} + +static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc, + struct PPC_DFP *dfp) +{ + enum rounding rnd; + if (r == 0) { + switch (rmc & 3) { + case 0: + rnd = DEC_ROUND_HALF_EVEN; + break; + case 1: + rnd = DEC_ROUND_DOWN; + break; + case 2: + rnd = DEC_ROUND_HALF_UP; + break; + case 3: /* use FPSCR rounding mode */ + return; + default: + assert(0); /* cannot get here */ + } + } else { /* r == 1 */ + switch (rmc & 3) { + case 0: + rnd = DEC_ROUND_CEILING; + break; + case 1: + rnd = DEC_ROUND_FLOOR; + break; + case 2: + rnd = DEC_ROUND_UP; + break; + case 3: + rnd = DEC_ROUND_HALF_DOWN; + break; + default: + assert(0); /* cannot get here */ + } + } + decContextSetRounding(&dfp->context, rnd); +} + +static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, + uint64_t *b, CPUPPCState *env) +{ + decContextDefault(&dfp->context, DEC_INIT_DECIMAL64); + dfp_prepare_rounding_mode(&dfp->context, env->fpscr); + dfp->env = env; + + if (a) { + dfp->a64[0] = *a; + decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a); + } else { + dfp->a64[0] = 0; + decNumberZero(&dfp->a); + } + + if (b) { + dfp->b64[0] = *b; + decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b); + } else { + dfp->b64[0] = 0; + decNumberZero(&dfp->b); + } +} + +static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, + uint64_t *b, CPUPPCState *env) +{ + decContextDefault(&dfp->context, DEC_INIT_DECIMAL128); + dfp_prepare_rounding_mode(&dfp->context, env->fpscr); + dfp->env = env; + + if (a) { + dfp->a64[0] = a[HI_IDX]; + dfp->a64[1] = a[LO_IDX]; + decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a); + } else { + dfp->a64[0] = dfp->a64[1] = 0; + decNumberZero(&dfp->a); + } + + if (b) { + dfp->b64[0] = b[HI_IDX]; + dfp->b64[1] = b[LO_IDX]; + decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b); + } else { + dfp->b64[0] = dfp->b64[1] = 0; + decNumberZero(&dfp->b); + } +} + +#define FP_FX (1ull << FPSCR_FX) +#define FP_FEX (1ull << FPSCR_FEX) +#define FP_OX (1ull << FPSCR_OX) +#define FP_OE (1ull << FPSCR_OE) +#define FP_UX (1ull << FPSCR_UX) +#define FP_UE (1ull << FPSCR_UE) +#define FP_XX (1ull << FPSCR_XX) +#define FP_XE (1ull << FPSCR_XE) +#define FP_ZX (1ull << FPSCR_ZX) +#define FP_ZE (1ull << FPSCR_ZE) +#define FP_VX (1ull << FPSCR_VX) +#define FP_VXSNAN (1ull << FPSCR_VXSNAN) +#define FP_VXISI (1ull << FPSCR_VXISI) +#define FP_VXIMZ (1ull << FPSCR_VXIMZ) +#define FP_VXZDZ (1ull << FPSCR_VXZDZ) +#define FP_VXIDI (1ull << FPSCR_VXIDI) +#define FP_VXVC (1ull << FPSCR_VXVC) +#define FP_VXCVI (1ull << FPSCR_VXCVI) +#define FP_VE (1ull << FPSCR_VE) +#define FP_FI (1ull << FPSCR_FI) + +static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, + uint64_t enabled) +{ + dfp->env->fpscr |= (flag | FP_FX); + if (dfp->env->fpscr & enabled) { + dfp->env->fpscr |= FP_FEX; + } +} + +static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp, + decContext *context) +{ + uint64_t fprf = 0; + + /* construct FPRF */ + switch (decNumberClass(&dfp->t, context)) { + case DEC_CLASS_SNAN: + fprf = 0x01; + break; + case DEC_CLASS_QNAN: + fprf = 0x11; + break; + case DEC_CLASS_NEG_INF: + fprf = 0x09; + break; + case DEC_CLASS_NEG_NORMAL: + fprf = 0x08; + break; + case DEC_CLASS_NEG_SUBNORMAL: + fprf = 0x18; + break; + case DEC_CLASS_NEG_ZERO: + fprf = 0x12; + break; + case DEC_CLASS_POS_ZERO: + fprf = 0x02; + break; + case DEC_CLASS_POS_SUBNORMAL: + fprf = 0x14; + break; + case DEC_CLASS_POS_NORMAL: + fprf = 0x04; + break; + case DEC_CLASS_POS_INF: + fprf = 0x05; + break; + default: + assert(0); /* should never get here */ + } + dfp->env->fpscr &= ~(0x1F << 12); + dfp->env->fpscr |= (fprf << 12); +} + +static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT_with_context(dfp, &dfp->context); +} + +static void dfp_set_FPRF_from_FRT_short(struct PPC_DFP *dfp) +{ + decContext shortContext; + decContextDefault(&shortContext, DEC_INIT_DECIMAL32); + dfp_set_FPRF_from_FRT_with_context(dfp, &shortContext); +} + +static void dfp_set_FPRF_from_FRT_long(struct PPC_DFP *dfp) +{ + decContext longContext; + decContextDefault(&longContext, DEC_INIT_DECIMAL64); + dfp_set_FPRF_from_FRT_with_context(dfp, &longContext); +} + +static void dfp_check_for_OX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Overflow) { + dfp_set_FPSCR_flag(dfp, FP_OX, FP_OE); + } +} + +static void dfp_check_for_UX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Underflow) { + dfp_set_FPSCR_flag(dfp, FP_UX, FP_UE); + } +} + +static void dfp_check_for_XX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Inexact) { + dfp_set_FPSCR_flag(dfp, FP_XX | FP_FI, FP_XE); + } +} + +static void dfp_check_for_ZX(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Division_by_zero) { + dfp_set_FPSCR_flag(dfp, FP_ZX, FP_ZE); + } +} + +static void dfp_check_for_VXSNAN(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if (decNumberIsSNaN(&dfp->a) || decNumberIsSNaN(&dfp->b)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE); + } + } +} + +static void dfp_check_for_VXSNAN_and_convert_to_QNaN(struct PPC_DFP *dfp) +{ + if (decNumberIsSNaN(&dfp->t)) { + dfp->t.bits &= ~DECSNAN; + dfp->t.bits |= DECNAN; + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE); + } +} + +static void dfp_check_for_VXISI(struct PPC_DFP *dfp, int testForSameSign) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) { + int same = decNumberClass(&dfp->a, &dfp->context) == + decNumberClass(&dfp->b, &dfp->context); + if ((same && testForSameSign) || (!same && !testForSameSign)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXISI, FP_VE); + } + } + } +} + +static void dfp_check_for_VXISI_add(struct PPC_DFP *dfp) +{ + dfp_check_for_VXISI(dfp, 0); +} + +static void dfp_check_for_VXISI_subtract(struct PPC_DFP *dfp) +{ + dfp_check_for_VXISI(dfp, 1); +} + +static void dfp_check_for_VXIMZ(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if ((decNumberIsInfinite(&dfp->a) && decNumberIsZero(&dfp->b)) || + (decNumberIsInfinite(&dfp->b) && decNumberIsZero(&dfp->a))) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXIMZ, FP_VE); + } + } +} + +static void dfp_check_for_VXZDZ(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Division_undefined) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXZDZ, FP_VE); + } +} + +static void dfp_check_for_VXIDI(struct PPC_DFP *dfp) +{ + if (dfp->context.status & DEC_Invalid_operation) { + if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXIDI, FP_VE); + } + } +} + +static void dfp_check_for_VXVC(struct PPC_DFP *dfp) +{ + if (decNumberIsNaN(&dfp->a) || decNumberIsNaN(&dfp->b)) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXVC, FP_VE); + } +} + +static void dfp_check_for_VXCVI(struct PPC_DFP *dfp) +{ + if ((dfp->context.status & DEC_Invalid_operation) && + (!decNumberIsSNaN(&dfp->a)) && + (!decNumberIsSNaN(&dfp->b))) { + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FP_VE); + } +} + +static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp) +{ + if (decNumberIsNaN(&dfp->t)) { + dfp->crbf = 1; + } else if (decNumberIsZero(&dfp->t)) { + dfp->crbf = 2; + } else if (decNumberIsNegative(&dfp->t)) { + dfp->crbf = 8; + } else { + dfp->crbf = 4; + } +} + +static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp) +{ + dfp->env->fpscr &= ~(0xF << 12); + dfp->env->fpscr |= (dfp->crbf << 12); +} + +static inline void dfp_makeQNaN(decNumber *dn) +{ + dn->bits &= ~DECSPECIAL; + dn->bits |= DECNAN; +} + +static inline int dfp_get_digit(decNumber *dn, int n) +{ + assert(DECDPUN == 3); + int unit = n / DECDPUN; + int dig = n % DECDPUN; + switch (dig) { + case 0: + return dn->lsu[unit] % 10; + case 1: + return (dn->lsu[unit] / 10) % 10; + case 2: + return dn->lsu[unit] / 100; + default: + assert(0); + } +} + +#define DFP_HELPER_TAB(op, dnop, postprocs, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + dfp_prepare_decimal##size(&dfp, a, b, env); \ + dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + postprocs(&dfp); \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +static void ADD_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_OX(dfp); + dfp_check_for_UX(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXISI_add(dfp); +} + +DFP_HELPER_TAB(dadd, decNumberAdd, ADD_PPs, 64) +DFP_HELPER_TAB(daddq, decNumberAdd, ADD_PPs, 128) + +static void SUB_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_OX(dfp); + dfp_check_for_UX(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXISI_subtract(dfp); +} + +DFP_HELPER_TAB(dsub, decNumberSubtract, SUB_PPs, 64) +DFP_HELPER_TAB(dsubq, decNumberSubtract, SUB_PPs, 128) + +static void MUL_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_OX(dfp); + dfp_check_for_UX(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXIMZ(dfp); +} + +DFP_HELPER_TAB(dmul, decNumberMultiply, MUL_PPs, 64) +DFP_HELPER_TAB(dmulq, decNumberMultiply, MUL_PPs, 128) + +static void DIV_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_OX(dfp); + dfp_check_for_UX(dfp); + dfp_check_for_ZX(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXZDZ(dfp); + dfp_check_for_VXIDI(dfp); +} + +DFP_HELPER_TAB(ddiv, decNumberDivide, DIV_PPs, 64) +DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128) + +#define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \ +uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + dfp_prepare_decimal##size(&dfp, a, b, env); \ + dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + postprocs(&dfp); \ + return dfp.crbf; \ +} + +static void CMPU_PPs(struct PPC_DFP *dfp) +{ + dfp_set_CRBF_from_T(dfp); + dfp_set_FPCC_from_CRBF(dfp); + dfp_check_for_VXSNAN(dfp); +} + +DFP_HELPER_BF_AB(dcmpu, decNumberCompare, CMPU_PPs, 64) +DFP_HELPER_BF_AB(dcmpuq, decNumberCompare, CMPU_PPs, 128) + +static void CMPO_PPs(struct PPC_DFP *dfp) +{ + dfp_set_CRBF_from_T(dfp); + dfp_set_FPCC_from_CRBF(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXVC(dfp); +} + +DFP_HELPER_BF_AB(dcmpo, decNumberCompare, CMPO_PPs, 64) +DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128) + +#define DFP_HELPER_TSTDC(op, size) \ +uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +{ \ + struct PPC_DFP dfp; \ + int match = 0; \ + \ + dfp_prepare_decimal##size(&dfp, a, 0, env); \ + \ + match |= (dcm & 0x20) && decNumberIsZero(&dfp.a); \ + match |= (dcm & 0x10) && decNumberIsSubnormal(&dfp.a, &dfp.context); \ + match |= (dcm & 0x08) && decNumberIsNormal(&dfp.a, &dfp.context); \ + match |= (dcm & 0x04) && decNumberIsInfinite(&dfp.a); \ + match |= (dcm & 0x02) && decNumberIsQNaN(&dfp.a); \ + match |= (dcm & 0x01) && decNumberIsSNaN(&dfp.a); \ + \ + if (decNumberIsNegative(&dfp.a)) { \ + dfp.crbf = match ? 0xA : 0x8; \ + } else { \ + dfp.crbf = match ? 0x2 : 0x0; \ + } \ + \ + dfp_set_FPCC_from_CRBF(&dfp); \ + return dfp.crbf; \ +} + +DFP_HELPER_TSTDC(dtstdc, 64) +DFP_HELPER_TSTDC(dtstdcq, 128) + +#define DFP_HELPER_TSTDG(op, size) \ +uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +{ \ + struct PPC_DFP dfp; \ + int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \ + is_extreme_exp, is_subnormal, is_normal, leftmost_is_nonzero, \ + match; \ + \ + dfp_prepare_decimal##size(&dfp, a, 0, env); \ + \ + if ((size) == 64) { \ + minexp = -398; \ + maxexp = 369; \ + nzero_digits = 16; \ + nzero_idx = 5; \ + } else if ((size) == 128) { \ + minexp = -6176; \ + maxexp = 6111; \ + nzero_digits = 34; \ + nzero_idx = 11; \ + } \ + \ + is_negative = decNumberIsNegative(&dfp.a); \ + is_zero = decNumberIsZero(&dfp.a); \ + is_extreme_exp = (dfp.a.exponent == maxexp) || \ + (dfp.a.exponent == minexp); \ + is_subnormal = decNumberIsSubnormal(&dfp.a, &dfp.context); \ + is_normal = decNumberIsNormal(&dfp.a, &dfp.context); \ + leftmost_is_nonzero = (dfp.a.digits == nzero_digits) && \ + (dfp.a.lsu[nzero_idx] != 0); \ + match = 0; \ + \ + match |= (dcm & 0x20) && is_zero && !is_extreme_exp; \ + match |= (dcm & 0x10) && is_zero && is_extreme_exp; \ + match |= (dcm & 0x08) && \ + (is_subnormal || (is_normal && is_extreme_exp)); \ + match |= (dcm & 0x04) && is_normal && !is_extreme_exp && \ + !leftmost_is_nonzero; \ + match |= (dcm & 0x02) && is_normal && !is_extreme_exp && \ + leftmost_is_nonzero; \ + match |= (dcm & 0x01) && decNumberIsSpecial(&dfp.a); \ + \ + if (is_negative) { \ + dfp.crbf = match ? 0xA : 0x8; \ + } else { \ + dfp.crbf = match ? 0x2 : 0x0; \ + } \ + \ + dfp_set_FPCC_from_CRBF(&dfp); \ + return dfp.crbf; \ +} + +DFP_HELPER_TSTDG(dtstdg, 64) +DFP_HELPER_TSTDG(dtstdgq, 128) + +#define DFP_HELPER_TSTEX(op, size) \ +uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + int expa, expb, a_is_special, b_is_special; \ + \ + dfp_prepare_decimal##size(&dfp, a, b, env); \ + \ + expa = dfp.a.exponent; \ + expb = dfp.b.exponent; \ + a_is_special = decNumberIsSpecial(&dfp.a); \ + b_is_special = decNumberIsSpecial(&dfp.b); \ + \ + if (a_is_special || b_is_special) { \ + int atype = a_is_special ? (decNumberIsNaN(&dfp.a) ? 4 : 2) : 1; \ + int btype = b_is_special ? (decNumberIsNaN(&dfp.b) ? 4 : 2) : 1; \ + dfp.crbf = (atype ^ btype) ? 0x1 : 0x2; \ + } else if (expa < expb) { \ + dfp.crbf = 0x8; \ + } else if (expa > expb) { \ + dfp.crbf = 0x4; \ + } else { \ + dfp.crbf = 0x2; \ + } \ + \ + dfp_set_FPCC_from_CRBF(&dfp); \ + return dfp.crbf; \ +} + +DFP_HELPER_TSTEX(dtstex, 64) +DFP_HELPER_TSTEX(dtstexq, 128) + +#define DFP_HELPER_TSTSF(op, size) \ +uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + unsigned k; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + k = *a & 0x3F; \ + \ + if (unlikely(decNumberIsSpecial(&dfp.b))) { \ + dfp.crbf = 1; \ + } else if (k == 0) { \ + dfp.crbf = 4; \ + } else if (unlikely(decNumberIsZero(&dfp.b))) { \ + /* Zero has no sig digits */ \ + dfp.crbf = 4; \ + } else { \ + unsigned nsd = dfp.b.digits; \ + if (k < nsd) { \ + dfp.crbf = 8; \ + } else if (k > nsd) { \ + dfp.crbf = 4; \ + } else { \ + dfp.crbf = 2; \ + } \ + } \ + \ + dfp_set_FPCC_from_CRBF(&dfp); \ + return dfp.crbf; \ +} + +DFP_HELPER_TSTSF(dtstsf, 64) +DFP_HELPER_TSTSF(dtstsfq, 128) + +static void QUA_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); + dfp_check_for_VXCVI(dfp); +} + +static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp) +{ + dfp_set_round_mode_from_immediate(0, rmc, dfp); + decNumberQuantize(&dfp->t, &dfp->b, &dfp->a, &dfp->context); + if (decNumberIsSNaN(&dfp->a)) { + dfp->t = dfp->a; + dfp_makeQNaN(&dfp->t); + } else if (decNumberIsSNaN(&dfp->b)) { + dfp->t = dfp->b; + dfp_makeQNaN(&dfp->t); + } else if (decNumberIsQNaN(&dfp->a)) { + dfp->t = dfp->a; + } else if (decNumberIsQNaN(&dfp->b)) { + dfp->t = dfp->b; + } +} + +#define DFP_HELPER_QUAI(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ + uint32_t te, uint32_t rmc) \ +{ \ + struct PPC_DFP dfp; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + decNumberFromUInt32(&dfp.a, 1); \ + dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \ + \ + dfp_quantize(rmc, &dfp); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + QUA_PPs(&dfp); \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_QUAI(dquai, 64) +DFP_HELPER_QUAI(dquaiq, 128) + +#define DFP_HELPER_QUA(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ + uint64_t *b, uint32_t rmc) \ +{ \ + struct PPC_DFP dfp; \ + \ + dfp_prepare_decimal##size(&dfp, a, b, env); \ + \ + dfp_quantize(rmc, &dfp); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + QUA_PPs(&dfp); \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_QUA(dqua, 64) +DFP_HELPER_QUA(dquaq, 128) + +static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax, + struct PPC_DFP *dfp) +{ + int msd_orig, msd_rslt; + + if (unlikely((ref_sig == 0) || (dfp->b.digits <= ref_sig))) { + dfp->t = dfp->b; + if (decNumberIsSNaN(&dfp->b)) { + dfp_makeQNaN(&dfp->t); + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FPSCR_VE); + } + return; + } + + /* Reround is equivalent to quantizing b with 1**E(n) where */ + /* n = exp(b) + numDigits(b) - reference_significance. */ + + decNumberFromUInt32(&dfp->a, 1); + dfp->a.exponent = dfp->b.exponent + dfp->b.digits - ref_sig; + + if (unlikely(dfp->a.exponent > xmax)) { + dfp->t.digits = 0; + dfp->t.bits &= ~DECNEG; + dfp_makeQNaN(&dfp->t); + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE); + return; + } + + dfp_quantize(rmc, dfp); + + msd_orig = dfp_get_digit(&dfp->b, dfp->b.digits-1); + msd_rslt = dfp_get_digit(&dfp->t, dfp->t.digits-1); + + /* If the quantization resulted in rounding up to the next magnitude, */ + /* then we need to shift the significand and adjust the exponent. */ + + if (unlikely((msd_orig == 9) && (msd_rslt == 1))) { + + decNumber negone; + + decNumberFromInt32(&negone, -1); + decNumberShift(&dfp->t, &dfp->t, &negone, &dfp->context); + dfp->t.exponent++; + + if (unlikely(dfp->t.exponent > xmax)) { + dfp_makeQNaN(&dfp->t); + dfp->t.digits = 0; + dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FP_VE); + /* Inhibit XX in this case */ + decContextClearStatus(&dfp->context, DEC_Inexact); + } + } +} + +#define DFP_HELPER_RRND(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ + uint64_t *b, uint32_t rmc) \ +{ \ + struct PPC_DFP dfp; \ + int32_t ref_sig = *a & 0x3F; \ + int32_t xmax = ((size) == 64) ? 369 : 6111; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + _dfp_reround(rmc, ref_sig, xmax, &dfp); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + QUA_PPs(&dfp); \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_RRND(drrnd, 64) +DFP_HELPER_RRND(drrndq, 128) + +#define DFP_HELPER_RINT(op, postprocs, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ + uint32_t r, uint32_t rmc) \ +{ \ + struct PPC_DFP dfp; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + dfp_set_round_mode_from_immediate(r, rmc, &dfp); \ + decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + postprocs(&dfp); \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +static void RINTX_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_XX(dfp); + dfp_check_for_VXSNAN(dfp); +} + +DFP_HELPER_RINT(drintx, RINTX_PPs, 64) +DFP_HELPER_RINT(drintxq, RINTX_PPs, 128) + +static void RINTN_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_VXSNAN(dfp); +} + +DFP_HELPER_RINT(drintn, RINTN_PPs, 64) +DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) + +void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) +{ + struct PPC_DFP dfp; + uint32_t b_short = *b; + dfp_prepare_decimal64(&dfp, 0, 0, env); + decimal32ToNumber((decimal32 *)&b_short, &dfp.t); + decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); + dfp_set_FPRF_from_FRT(&dfp); +} + +void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +{ + struct PPC_DFP dfp; + dfp_prepare_decimal128(&dfp, 0, 0, env); + decimal64ToNumber((decimal64 *)b, &dfp.t); + + dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); + dfp_set_FPRF_from_FRT(&dfp); + + decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); + t[0] = dfp.t64[HI_IDX]; + t[1] = dfp.t64[LO_IDX]; +} + +void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) +{ + struct PPC_DFP dfp; + uint32_t t_short = 0; + dfp_prepare_decimal64(&dfp, 0, b, env); + decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context); + decimal32ToNumber((decimal32 *)&t_short, &dfp.t); + + dfp_set_FPRF_from_FRT_short(&dfp); + dfp_check_for_OX(&dfp); + dfp_check_for_UX(&dfp); + dfp_check_for_XX(&dfp); + + *t = t_short; +} + +void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +{ + struct PPC_DFP dfp; + dfp_prepare_decimal128(&dfp, 0, b, env); + decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.b, &dfp.context); + decimal64ToNumber((decimal64 *)&dfp.t64, &dfp.t); + + dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); + dfp_set_FPRF_from_FRT_long(&dfp); + dfp_check_for_OX(&dfp); + dfp_check_for_UX(&dfp); + dfp_check_for_XX(&dfp); + + decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); + t[0] = dfp.t64[0]; + t[1] = 0; +} + +#define DFP_HELPER_CFFIX(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + decNumberFromInt64(&dfp.t, (int64_t)(*b)); \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + CFFIX_PPs(&dfp); \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +static void CFFIX_PPs(struct PPC_DFP *dfp) +{ + dfp_set_FPRF_from_FRT(dfp); + dfp_check_for_XX(dfp); +} + +DFP_HELPER_CFFIX(dcffix, 64) +DFP_HELPER_CFFIX(dcffixq, 128) + +#define DFP_HELPER_CTFIX(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + if (unlikely(decNumberIsSpecial(&dfp.b))) { \ + uint64_t invalid_flags = FP_VX | FP_VXCVI; \ + if (decNumberIsInfinite(&dfp.b)) { \ + dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + } else { /* NaN */ \ + dfp.t64[0] = INT64_MIN; \ + if (decNumberIsSNaN(&dfp.b)) { \ + invalid_flags |= FP_VXSNAN; \ + } \ + } \ + dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \ + } else if (unlikely(decNumberIsZero(&dfp.b))) { \ + dfp.t64[0] = 0; \ + } else { \ + decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \ + dfp.t64[0] = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ + if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \ + dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \ + } else { \ + dfp_check_for_XX(&dfp); \ + } \ + } \ + \ + *t = dfp.t64[0]; \ +} + +DFP_HELPER_CTFIX(dctfix, 64) +DFP_HELPER_CTFIX(dctfixq, 128) + +static inline void dfp_set_bcd_digit_64(uint64_t *t, uint8_t digit, + unsigned n) +{ + *t |= ((uint64_t)(digit & 0xF) << (n << 2)); +} + +static inline void dfp_set_bcd_digit_128(uint64_t *t, uint8_t digit, + unsigned n) +{ + t[(n & 0x10) ? HI_IDX : LO_IDX] |= + ((uint64_t)(digit & 0xF) << ((n & 15) << 2)); +} + +static inline void dfp_set_sign_64(uint64_t *t, uint8_t sgn) +{ + *t <<= 4; + *t |= (sgn & 0xF); +} + +static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn) +{ + t[HI_IDX] <<= 4; + t[HI_IDX] |= (t[LO_IDX] >> 60); + t[LO_IDX] <<= 4; + t[LO_IDX] |= (sgn & 0xF); +} + +#define DFP_HELPER_DEDPD(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ +{ \ + struct PPC_DFP dfp; \ + uint8_t digits[34]; \ + int i, N; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + decNumberGetBCD(&dfp.b, digits); \ + dfp.t64[0] = dfp.t64[1] = 0; \ + N = dfp.b.digits; \ + \ + for (i = 0; (i < N) && (i < (size)/4); i++) { \ + dfp_set_bcd_digit_##size(dfp.t64, digits[N-i-1], i); \ + } \ + \ + if (sp & 2) { \ + uint8_t sgn; \ + \ + if (decNumberIsNegative(&dfp.b)) { \ + sgn = 0xD; \ + } else { \ + sgn = ((sp & 1) ? 0xF : 0xC); \ + } \ + dfp_set_sign_##size(dfp.t64, sgn); \ + } \ + \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_DEDPD(ddedpd, 64) +DFP_HELPER_DEDPD(ddedpdq, 128) + +static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n) +{ + return *t >> ((n << 2) & 63) & 15; +} + +static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) +{ + return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15; +} + +#define DFP_HELPER_ENBCD(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ +{ \ + struct PPC_DFP dfp; \ + uint8_t digits[32]; \ + int n = 0, offset = 0, sgn = 0, nonzero = 0; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + decNumberZero(&dfp.t); \ + \ + if (s) { \ + uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + switch (sgnNibble) { \ + case 0xD: \ + case 0xB: \ + sgn = 1; \ + break; \ + case 0xC: \ + case 0xF: \ + case 0xA: \ + case 0xE: \ + sgn = 0; \ + break; \ + default: \ + dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + return; \ + } \ + } \ + \ + while (offset < (size)/4) { \ + n++; \ + digits[(size)/4-n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + if (digits[(size)/4-n] > 10) { \ + dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ + return; \ + } else { \ + nonzero |= (digits[(size)/4-n] > 0); \ + } \ + } \ + \ + if (nonzero) { \ + decNumberSetBCD(&dfp.t, digits+((size)/4)-n, n); \ + } \ + \ + if (s && sgn) { \ + dfp.t.bits |= DECNEG; \ + } \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + dfp_set_FPRF_from_FRT(&dfp); \ + if ((size) == 64) { \ + t[0] = dfp.t64[0]; \ + } else if ((size) == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_ENBCD(denbcd, 64) +DFP_HELPER_ENBCD(denbcdq, 128) + +#define DFP_HELPER_XEX(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + if (unlikely(decNumberIsSpecial(&dfp.b))) { \ + if (decNumberIsInfinite(&dfp.b)) { \ + *t = -1; \ + } else if (decNumberIsSNaN(&dfp.b)) { \ + *t = -3; \ + } else if (decNumberIsQNaN(&dfp.b)) { \ + *t = -2; \ + } else { \ + assert(0); \ + } \ + } else { \ + if ((size) == 64) { \ + *t = dfp.b.exponent + 398; \ + } else if ((size) == 128) { \ + *t = dfp.b.exponent + 6176; \ + } else { \ + assert(0); \ + } \ + } \ +} + +DFP_HELPER_XEX(dxex, 64) +DFP_HELPER_XEX(dxexq, 128) + +static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw) +{ + *t &= 0x8003ffffffffffffULL; + *t |= (raw << (63-13)); +} + +static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) +{ + t[HI_IDX] &= 0x80003fffffffffffULL; + t[HI_IDX] |= (raw << (63-17)); +} + +#define DFP_HELPER_IEX(op, size) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +{ \ + struct PPC_DFP dfp; \ + uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \ + int bias; \ + int64_t exp = *((int64_t *)a); \ + \ + dfp_prepare_decimal##size(&dfp, 0, b, env); \ + \ + if ((size) == 64) { \ + max_exp = 767; \ + raw_qnan = 0x1F00; \ + raw_snan = 0x1F80; \ + raw_inf = 0x1E00; \ + bias = 398; \ + } else if ((size) == 128) { \ + max_exp = 12287; \ + raw_qnan = 0x1f000; \ + raw_snan = 0x1f800; \ + raw_inf = 0x1e000; \ + bias = 6176; \ + } else { \ + assert(0); \ + } \ + \ + if (unlikely((exp < 0) || (exp > max_exp))) { \ + dfp.t64[0] = dfp.b64[0]; \ + dfp.t64[1] = dfp.b64[1]; \ + if (exp == -1) { \ + dfp_set_raw_exp_##size(dfp.t64, raw_inf); \ + } else if (exp == -3) { \ + dfp_set_raw_exp_##size(dfp.t64, raw_snan); \ + } else { \ + dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \ + } \ + } else { \ + dfp.t = dfp.b; \ + if (unlikely(decNumberIsSpecial(&dfp.t))) { \ + dfp.t.bits &= ~DECSPECIAL; \ + } \ + dfp.t.exponent = exp - bias; \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + } \ + if (size == 64) { \ + t[0] = dfp.t64[0]; \ + } else if (size == 128) { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_IEX(diex, 64) +DFP_HELPER_IEX(diexq, 128) + +static void dfp_clear_lmd_from_g5msb(uint64_t *t) +{ + + /* The most significant 5 bits of the PowerPC DFP format combine bits */ + /* from the left-most decimal digit (LMD) and the biased exponent. */ + /* This routine clears the LMD bits while preserving the exponent */ + /* bits. See "Figure 80: Encoding of bits 0:4 of the G field for */ + /* Finite Numbers" in the Power ISA for additional details. */ + + uint64_t g5msb = (*t >> 58) & 0x1F; + + if ((g5msb >> 3) < 3) { /* LMD in [0-7] ? */ + *t &= ~(7ULL << 58); + } else { + switch (g5msb & 7) { + case 0: + case 1: + g5msb = 0; + break; + case 2: + case 3: + g5msb = 0x8; + break; + case 4: + case 5: + g5msb = 0x10; + break; + case 6: + g5msb = 0x1E; + break; + case 7: + g5msb = 0x1F; + break; + } + + *t &= ~(0x1fULL << 58); + *t |= (g5msb << 58); + } +} + +#define DFP_HELPER_SHIFT(op, size, shift_left) \ +void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ + uint32_t sh) \ +{ \ + struct PPC_DFP dfp; \ + unsigned max_digits = ((size) == 64) ? 16 : 34; \ + \ + dfp_prepare_decimal##size(&dfp, a, 0, env); \ + \ + if (sh <= max_digits) { \ + \ + decNumber shd; \ + unsigned special = dfp.a.bits & DECSPECIAL; \ + \ + if (shift_left) { \ + decNumberFromUInt32(&shd, sh); \ + } else { \ + decNumberFromInt32(&shd, -((int32_t)sh)); \ + } \ + \ + dfp.a.bits &= ~DECSPECIAL; \ + decNumberShift(&dfp.t, &dfp.a, &shd, &dfp.context); \ + \ + dfp.t.bits |= special; \ + if (special && (dfp.t.digits >= max_digits)) { \ + dfp.t.digits = max_digits - 1; \ + } \ + \ + decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ + &dfp.context); \ + } else { \ + if ((size) == 64) { \ + dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \ + dfp_clear_lmd_from_g5msb(dfp.t64); \ + } else { \ + dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \ + 0xFFFFC00000000000ULL; \ + dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \ + dfp.t64[LO_IDX] = 0; \ + } \ + } \ + \ + if ((size) == 64) { \ + t[0] = dfp.t64[0]; \ + } else { \ + t[0] = dfp.t64[HI_IDX]; \ + t[1] = dfp.t64[LO_IDX]; \ + } \ +} + +DFP_HELPER_SHIFT(dscli, 64, 1) +DFP_HELPER_SHIFT(dscliq, 128, 1) +DFP_HELPER_SHIFT(dscri, 64, 0) +DFP_HELPER_SHIFT(dscriq, 128, 0) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 7dfc52d159..be7159013f 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -399,6 +399,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= (target_ulong)MSR_HVB; } goto store_current; + case POWERPC_EXCP_FU: /* Facility unavailable exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ LOG_EXCP("PIT exception\n"); goto store_next; @@ -615,8 +620,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (asrr1 != -1) { env->spr[asrr1] = env->spr[srr1]; } - /* If we disactivated any translation, flush TLBs */ - if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { + + if (env->spr[SPR_LPCR] & LPCR_AIL) { + new_msr |= (1 << MSR_IR) | (1 << MSR_DR); + } else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { + /* If we disactivated any translation, flush TLBs */ tlb_flush(cs, 1); } diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index cd8f015bd7..da93d1215a 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -977,7 +977,6 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg) uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; - float32 f32; farg.ll = arg; @@ -991,8 +990,6 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) } farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_div(float64_one, farg.d, &env->fp_status); - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); } return farg.ll; } diff --git a/target-ppc/gdbstub.c b/target-ppc/gdbstub.c index 1c910902ea..381a3c7e31 100644 --- a/target-ppc/gdbstub.c +++ b/target-ppc/gdbstub.c @@ -21,6 +21,55 @@ #include "qemu-common.h" #include "exec/gdbstub.h" +static int ppc_gdb_register_len(int n) +{ + switch (n) { + case 0 ... 31: + /* gprs */ + return sizeof(target_ulong); + case 32 ... 63: + /* fprs */ + if (gdb_has_xml) { + return 0; + } + return 8; + case 66: + /* cr */ + return 4; + case 64: + /* nip */ + case 65: + /* msr */ + case 67: + /* lr */ + case 68: + /* ctr */ + case 69: + /* xer */ + return sizeof(target_ulong); + case 70: + /* fpscr */ + if (gdb_has_xml) { + return 0; + } + return sizeof(target_ulong); + default: + return 0; + } +} + + +static void ppc_gdb_swap_register(uint8_t *mem_buf, int n, int len) +{ + if (len == 4) { + bswap32s((uint32_t *)mem_buf); + } else if (len == 8) { + bswap64s((uint64_t *)mem_buf); + } else { + g_assert_not_reached(); + } +} + /* Old gdb always expects FP registers. Newer (xml-aware) gdb only * expects whatever the target description contains. Due to a * historical mishap the FP registers appear in between core integer @@ -32,23 +81,26 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + int r = ppc_gdb_register_len(n); + + if (!r) { + return r; + } if (n < 32) { /* gprs */ - return gdb_get_regl(mem_buf, env->gpr[n]); + gdb_get_regl(mem_buf, env->gpr[n]); } else if (n < 64) { /* fprs */ - if (gdb_has_xml) { - return 0; - } stfq_p(mem_buf, env->fpr[n-32]); - return 8; } else { switch (n) { case 64: - return gdb_get_regl(mem_buf, env->nip); + gdb_get_regl(mem_buf, env->nip); + break; case 65: - return gdb_get_regl(mem_buf, env->msr); + gdb_get_regl(mem_buf, env->msr); + break; case 66: { uint32_t cr = 0; @@ -56,50 +108,57 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) for (i = 0; i < 8; i++) { cr |= env->crf[i] << (32 - ((i + 1) * 4)); } - return gdb_get_reg32(mem_buf, cr); + gdb_get_reg32(mem_buf, cr); + break; } case 67: - return gdb_get_regl(mem_buf, env->lr); + gdb_get_regl(mem_buf, env->lr); + break; case 68: - return gdb_get_regl(mem_buf, env->ctr); + gdb_get_regl(mem_buf, env->ctr); + break; case 69: - return gdb_get_regl(mem_buf, env->xer); + gdb_get_regl(mem_buf, env->xer); + break; case 70: - { - if (gdb_has_xml) { - return 0; - } - return gdb_get_reg32(mem_buf, env->fpscr); - } + gdb_get_reg32(mem_buf, env->fpscr); + break; } } - return 0; + if (msr_le) { + /* If cpu is in LE mode, convert memory contents to LE. */ + ppc_gdb_swap_register(mem_buf, n, r); + } + return r; } int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + int r = ppc_gdb_register_len(n); + if (!r) { + return r; + } + if (msr_le) { + /* If cpu is in LE mode, convert memory contents to LE. */ + ppc_gdb_swap_register(mem_buf, n, r); + } if (n < 32) { /* gprs */ env->gpr[n] = ldtul_p(mem_buf); - return sizeof(target_ulong); } else if (n < 64) { /* fprs */ - if (gdb_has_xml) { - return 0; - } env->fpr[n-32] = ldfq_p(mem_buf); - return 8; } else { switch (n) { case 64: env->nip = ldtul_p(mem_buf); - return sizeof(target_ulong); + break; case 65: ppc_store_msr(env, ldtul_p(mem_buf)); - return sizeof(target_ulong); + break; case 66: { uint32_t cr = ldl_p(mem_buf); @@ -107,25 +166,22 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) for (i = 0; i < 8; i++) { env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF; } - return 4; + break; } case 67: env->lr = ldtul_p(mem_buf); - return sizeof(target_ulong); + break; case 68: env->ctr = ldtul_p(mem_buf); - return sizeof(target_ulong); + break; case 69: env->xer = ldtul_p(mem_buf); - return sizeof(target_ulong); + break; case 70: /* fpscr */ - if (gdb_has_xml) { - return 0; - } store_fpscr(env, ldtul_p(mem_buf), 0xffffffff); - return sizeof(target_ulong); + break; } } - return 0; + return r; } diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 08f3916e74..509eae52ff 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -539,7 +539,7 @@ DEF_HELPER_2(booke206_tlbivax, void, env, tl) DEF_HELPER_2(booke206_tlbilx0, void, env, tl) DEF_HELPER_2(booke206_tlbilx1, void, env, tl) DEF_HELPER_2(booke206_tlbilx3, void, env, tl) -DEF_HELPER_2(booke206_tlbflush, void, env, i32) +DEF_HELPER_2(booke206_tlbflush, void, env, tl) DEF_HELPER_3(booke_setpid, void, env, i32, tl) DEF_HELPER_2(6xx_tlbd, void, env, tl) DEF_HELPER_2(6xx_tlbi, void, env, tl) @@ -577,6 +577,8 @@ DEF_HELPER_3(store_dcr, void, env, tl, tl) DEF_HELPER_2(load_dump_spr, void, env, i32) DEF_HELPER_2(store_dump_spr, void, env, i32) +DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32) +DEF_HELPER_4(msr_facility_check, void, env, i32, i32, i32) DEF_HELPER_1(load_tbl, tl, env) DEF_HELPER_1(load_tbu, tl, env) DEF_HELPER_1(load_atbl, tl, env) @@ -611,3 +613,58 @@ DEF_HELPER_3(store_dbatu, void, env, i32, tl) DEF_HELPER_3(store_601_batl, void, env, i32, tl) DEF_HELPER_3(store_601_batu, void, env, i32, tl) #endif + +#define dh_alias_fprp ptr +#define dh_ctype_fprp uint64_t * +#define dh_is_signed_fprp dh_is_signed_ptr + +DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp) +DEF_HELPER_4(daddq, void, env, fprp, fprp, fprp) +DEF_HELPER_4(dsub, void, env, fprp, fprp, fprp) +DEF_HELPER_4(dsubq, void, env, fprp, fprp, fprp) +DEF_HELPER_4(dmul, void, env, fprp, fprp, fprp) +DEF_HELPER_4(dmulq, void, env, fprp, fprp, fprp) +DEF_HELPER_4(ddiv, void, env, fprp, fprp, fprp) +DEF_HELPER_4(ddivq, void, env, fprp, fprp, fprp) +DEF_HELPER_3(dcmpo, i32, env, fprp, fprp) +DEF_HELPER_3(dcmpoq, i32, env, fprp, fprp) +DEF_HELPER_3(dcmpu, i32, env, fprp, fprp) +DEF_HELPER_3(dcmpuq, i32, env, fprp, fprp) +DEF_HELPER_3(dtstdc, i32, env, fprp, i32) +DEF_HELPER_3(dtstdcq, i32, env, fprp, i32) +DEF_HELPER_3(dtstdg, i32, env, fprp, i32) +DEF_HELPER_3(dtstdgq, i32, env, fprp, i32) +DEF_HELPER_3(dtstex, i32, env, fprp, fprp) +DEF_HELPER_3(dtstexq, i32, env, fprp, fprp) +DEF_HELPER_3(dtstsf, i32, env, fprp, fprp) +DEF_HELPER_3(dtstsfq, i32, env, fprp, fprp) +DEF_HELPER_5(dquai, void, env, fprp, fprp, i32, i32) +DEF_HELPER_5(dquaiq, void, env, fprp, fprp, i32, i32) +DEF_HELPER_5(dqua, void, env, fprp, fprp, fprp, i32) +DEF_HELPER_5(dquaq, void, env, fprp, fprp, fprp, i32) +DEF_HELPER_5(drrnd, void, env, fprp, fprp, fprp, i32) +DEF_HELPER_5(drrndq, void, env, fprp, fprp, fprp, i32) +DEF_HELPER_5(drintx, void, env, fprp, fprp, i32, i32) +DEF_HELPER_5(drintxq, void, env, fprp, fprp, i32, i32) +DEF_HELPER_5(drintn, void, env, fprp, fprp, i32, i32) +DEF_HELPER_5(drintnq, void, env, fprp, fprp, i32, i32) +DEF_HELPER_3(dctdp, void, env, fprp, fprp) +DEF_HELPER_3(dctqpq, void, env, fprp, fprp) +DEF_HELPER_3(drsp, void, env, fprp, fprp) +DEF_HELPER_3(drdpq, void, env, fprp, fprp) +DEF_HELPER_3(dcffix, void, env, fprp, fprp) +DEF_HELPER_3(dcffixq, void, env, fprp, fprp) +DEF_HELPER_3(dctfix, void, env, fprp, fprp) +DEF_HELPER_3(dctfixq, void, env, fprp, fprp) +DEF_HELPER_4(ddedpd, void, env, fprp, fprp, i32) +DEF_HELPER_4(ddedpdq, void, env, fprp, fprp, i32) +DEF_HELPER_4(denbcd, void, env, fprp, fprp, i32) +DEF_HELPER_4(denbcdq, void, env, fprp, fprp, i32) +DEF_HELPER_3(dxex, void, env, fprp, fprp) +DEF_HELPER_3(dxexq, void, env, fprp, fprp) +DEF_HELPER_4(diex, void, env, fprp, fprp, fprp) +DEF_HELPER_4(diexq, void, env, fprp, fprp, fprp) +DEF_HELPER_4(dscri, void, env, fprp, fprp, i32) +DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32) +DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) +DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 588f6a9b95..f6e8846707 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" +#include "qemu/aes.h" #include "helper_regs.h" /*****************************************************************************/ @@ -396,9 +397,13 @@ target_ulong helper_602_mfrom(target_ulong arg) #if defined(HOST_WORDS_BIGENDIAN) #define HI_IDX 0 #define LO_IDX 1 +#define AVRB(i) u8[i] +#define AVRW(i) u32[i] #else #define HI_IDX 1 #define LO_IDX 0 +#define AVRB(i) u8[15-(i)] +#define AVRW(i) u32[3-(i)] #endif #if defined(HOST_WORDS_BIGENDIAN) @@ -2338,284 +2343,63 @@ uint32_t helper_bcdsub(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) return helper_bcdadd(r, a, &bcopy, ps); } -static uint8_t SBOX[256] = { -0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, -0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, -0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, -0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, -0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, -0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, -0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, -0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, -0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, -0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, -0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, -0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, -0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, -0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, -0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, -0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, -0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, -0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, -0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, -0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, -0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, -0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, -0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, -0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, -0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, -0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, -0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, -0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, -0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, -0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, -0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, -0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, -}; - -static void SubBytes(ppc_avr_t *r, ppc_avr_t *a) -{ - int i; - VECTOR_FOR_INORDER_I(i, u8) { - r->u8[i] = SBOX[a->u8[i]]; - } -} - -static uint8_t InvSBOX[256] = { -0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, -0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, -0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, -0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, -0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, -0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, -0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, -0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, -0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, -0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, -0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, -0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, -0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, -0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, -0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, -0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, -0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, -0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, -0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, -0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, -0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, -0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, -0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, -0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, -0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, -0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, -0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, -0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, -0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, -0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, -0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, -0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D, -}; - -static void InvSubBytes(ppc_avr_t *r, ppc_avr_t *a) +void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a) { int i; VECTOR_FOR_INORDER_I(i, u8) { - r->u8[i] = InvSBOX[a->u8[i]]; + r->u8[i] = AES_sbox[a->u8[i]]; } } -static uint8_t ROTL8(uint8_t x, int n) -{ - return (x << n) | (x >> (8-n)); -} - -static inline int BIT8(uint8_t x, int n) -{ - return (x & (0x80 >> n)) != 0; -} - -static uint8_t GFx02(uint8_t x) -{ - return ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0); -} - -static uint8_t GFx03(uint8_t x) -{ - return x ^ ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0); -} - -static uint8_t GFx09(uint8_t x) -{ - uint8_t term2 = ROTL8(x, 3); - uint8_t term3 = (BIT8(x, 0) ? 0x68 : 0) | (BIT8(x, 1) ? 0x14 : 0) | - (BIT8(x, 2) ? 0x02 : 0); - uint8_t term4 = (BIT8(x, 1) ? 0x20 : 0) | (BIT8(x, 2) ? 0x18 : 0); - return x ^ term2 ^ term3 ^ term4; -} - -static uint8_t GFx0B(uint8_t x) -{ - uint8_t term2 = ROTL8(x, 1); - uint8_t term3 = (x << 3) | (BIT8(x, 0) ? 0x06 : 0) | - (BIT8(x, 2) ? 0x01 : 0); - uint8_t term4 = (BIT8(x, 0) ? 0x70 : 0) | (BIT8(x, 1) ? 0x06 : 0) | - (BIT8(x, 2) ? 0x08 : 0); - uint8_t term5 = (BIT8(x, 1) ? 0x30 : 0) | (BIT8(x, 2) ? 0x02 : 0); - uint8_t term6 = BIT8(x, 2) ? 0x10 : 0; - return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6; -} - -static uint8_t GFx0D(uint8_t x) -{ - uint8_t term2 = ROTL8(x, 2); - uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) | - (BIT8(x, 2) ? 0x03 : 0); - uint8_t term4 = (BIT8(x, 0) ? 0x58 : 0) | (BIT8(x, 1) ? 0x20 : 0); - uint8_t term5 = (BIT8(x, 1) ? 0x08 : 0) | (BIT8(x, 2) ? 0x10 : 0); - uint8_t term6 = BIT8(x, 2) ? 0x08 : 0; - return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6; -} - -static uint8_t GFx0E(uint8_t x) -{ - uint8_t term1 = ROTL8(x, 1); - uint8_t term2 = (x << 2) | (BIT8(x, 2) ? 0x02 : 0) | - (BIT8(x, 1) ? 0x01 : 0); - uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) | - (BIT8(x, 2) ? 0x01 : 0); - uint8_t term4 = (BIT8(x, 0) ? 0x40 : 0) | (BIT8(x, 1) ? 0x28 : 0) | - (BIT8(x, 2) ? 0x10 : 0); - uint8_t term5 = (BIT8(x, 2) ? 0x08 : 0); - return term1 ^ term2 ^ term3 ^ term4 ^ term5; -} - -#if defined(HOST_WORDS_BIGENDIAN) -#define MCB(x, i, b) ((x)->u8[(i)*4 + (b)]) -#else -#define MCB(x, i, b) ((x)->u8[15 - ((i)*4 + (b))]) -#endif - -static void MixColumns(ppc_avr_t *r, ppc_avr_t *x) +void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; - for (i = 0; i < 4; i++) { - MCB(r, i, 0) = GFx02(MCB(x, i, 0)) ^ GFx03(MCB(x, i, 1)) ^ - MCB(x, i, 2) ^ MCB(x, i, 3); - MCB(r, i, 1) = MCB(x, i, 0) ^ GFx02(MCB(x, i, 1)) ^ - GFx03(MCB(x, i, 2)) ^ MCB(x, i, 3); - MCB(r, i, 2) = MCB(x, i, 0) ^ MCB(x, i, 1) ^ - GFx02(MCB(x, i, 2)) ^ GFx03(MCB(x, i, 3)); - MCB(r, i, 3) = GFx03(MCB(x, i, 0)) ^ MCB(x, i, 1) ^ - MCB(x, i, 2) ^ GFx02(MCB(x, i, 3)); - } -} -static void InvMixColumns(ppc_avr_t *r, ppc_avr_t *x) -{ - int i; - for (i = 0; i < 4; i++) { - MCB(r, i, 0) = GFx0E(MCB(x, i, 0)) ^ GFx0B(MCB(x, i, 1)) ^ - GFx0D(MCB(x, i, 2)) ^ GFx09(MCB(x, i, 3)); - MCB(r, i, 1) = GFx09(MCB(x, i, 0)) ^ GFx0E(MCB(x, i, 1)) ^ - GFx0B(MCB(x, i, 2)) ^ GFx0D(MCB(x, i, 3)); - MCB(r, i, 2) = GFx0D(MCB(x, i, 0)) ^ GFx09(MCB(x, i, 1)) ^ - GFx0E(MCB(x, i, 2)) ^ GFx0B(MCB(x, i, 3)); - MCB(r, i, 3) = GFx0B(MCB(x, i, 0)) ^ GFx0D(MCB(x, i, 1)) ^ - GFx09(MCB(x, i, 2)) ^ GFx0E(MCB(x, i, 3)); + VECTOR_FOR_INORDER_I(i, u32) { + r->AVRW(i) = b->AVRW(i) ^ + (AES_Te0[a->AVRB(AES_shifts[4*i + 0])] ^ + AES_Te1[a->AVRB(AES_shifts[4*i + 1])] ^ + AES_Te2[a->AVRB(AES_shifts[4*i + 2])] ^ + AES_Te3[a->AVRB(AES_shifts[4*i + 3])]); } } -static void ShiftRows(ppc_avr_t *r, ppc_avr_t *x) -{ - MCB(r, 0, 0) = MCB(x, 0, 0); - MCB(r, 1, 0) = MCB(x, 1, 0); - MCB(r, 2, 0) = MCB(x, 2, 0); - MCB(r, 3, 0) = MCB(x, 3, 0); - - MCB(r, 0, 1) = MCB(x, 1, 1); - MCB(r, 1, 1) = MCB(x, 2, 1); - MCB(r, 2, 1) = MCB(x, 3, 1); - MCB(r, 3, 1) = MCB(x, 0, 1); - - MCB(r, 0, 2) = MCB(x, 2, 2); - MCB(r, 1, 2) = MCB(x, 3, 2); - MCB(r, 2, 2) = MCB(x, 0, 2); - MCB(r, 3, 2) = MCB(x, 1, 2); - - MCB(r, 0, 3) = MCB(x, 3, 3); - MCB(r, 1, 3) = MCB(x, 0, 3); - MCB(r, 2, 3) = MCB(x, 1, 3); - MCB(r, 3, 3) = MCB(x, 2, 3); -} - -static void InvShiftRows(ppc_avr_t *r, ppc_avr_t *x) -{ - MCB(r, 0, 0) = MCB(x, 0, 0); - MCB(r, 1, 0) = MCB(x, 1, 0); - MCB(r, 2, 0) = MCB(x, 2, 0); - MCB(r, 3, 0) = MCB(x, 3, 0); - - MCB(r, 0, 1) = MCB(x, 3, 1); - MCB(r, 1, 1) = MCB(x, 0, 1); - MCB(r, 2, 1) = MCB(x, 1, 1); - MCB(r, 3, 1) = MCB(x, 2, 1); - - MCB(r, 0, 2) = MCB(x, 2, 2); - MCB(r, 1, 2) = MCB(x, 3, 2); - MCB(r, 2, 2) = MCB(x, 0, 2); - MCB(r, 3, 2) = MCB(x, 1, 2); - - MCB(r, 0, 3) = MCB(x, 1, 3); - MCB(r, 1, 3) = MCB(x, 2, 3); - MCB(r, 2, 3) = MCB(x, 3, 3); - MCB(r, 3, 3) = MCB(x, 0, 3); -} - -#undef MCB - -void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a) -{ - SubBytes(r, a); -} - -void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - ppc_avr_t vtemp1, vtemp2, vtemp3; - SubBytes(&vtemp1, a); - ShiftRows(&vtemp2, &vtemp1); - MixColumns(&vtemp3, &vtemp2); - r->u64[0] = vtemp3.u64[0] ^ b->u64[0]; - r->u64[1] = vtemp3.u64[1] ^ b->u64[1]; -} - void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - ppc_avr_t vtemp1, vtemp2; - SubBytes(&vtemp1, a); - ShiftRows(&vtemp2, &vtemp1); - r->u64[0] = vtemp2.u64[0] ^ b->u64[0]; - r->u64[1] = vtemp2.u64[1] ^ b->u64[1]; + int i; + + VECTOR_FOR_INORDER_I(i, u8) { + r->AVRB(i) = b->AVRB(i) ^ (AES_Te4[a->AVRB(AES_shifts[i])] & 0xFF); + } } void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { /* This differs from what is written in ISA V2.07. The RTL is */ /* incorrect and will be fixed in V2.07B. */ - ppc_avr_t vtemp1, vtemp2, vtemp3; - InvShiftRows(&vtemp1, a); - InvSubBytes(&vtemp2, &vtemp1); - vtemp3.u64[0] = vtemp2.u64[0] ^ b->u64[0]; - vtemp3.u64[1] = vtemp2.u64[1] ^ b->u64[1]; - InvMixColumns(r, &vtemp3); + int i; + ppc_avr_t tmp; + + VECTOR_FOR_INORDER_I(i, u8) { + tmp.AVRB(i) = b->AVRB(i) ^ AES_isbox[a->AVRB(AES_ishifts[i])]; + } + + VECTOR_FOR_INORDER_I(i, u32) { + r->AVRW(i) = + AES_imc[tmp.AVRB(4*i + 0)][0] ^ + AES_imc[tmp.AVRB(4*i + 1)][1] ^ + AES_imc[tmp.AVRB(4*i + 2)][2] ^ + AES_imc[tmp.AVRB(4*i + 3)][3]; + } } void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { - ppc_avr_t vtemp1, vtemp2; - InvShiftRows(&vtemp1, a); - InvSubBytes(&vtemp2, &vtemp1); - r->u64[0] = vtemp2.u64[0] ^ b->u64[0]; - r->u64[1] = vtemp2.u64[1] ^ b->u64[1]; + int i; + + VECTOR_FOR_INORDER_I(i, u8) { + r->AVRB(i) = b->AVRB(i) ^ (AES_Td4[a->AVRB(AES_ishifts[i])] & 0xFF); + } } #define ROTRu32(v, n) (((v) >> (n)) | ((v) << (32-n))) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 8ff1777dcb..561f8ccf2f 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -35,6 +35,7 @@ #include "hw/sysbus.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/ppc.h" #include "sysemu/watchdog.h" #include "trace.h" @@ -61,12 +62,14 @@ static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; static int cap_spapr_tce; +static int cap_spapr_multitce; static int cap_hior; static int cap_one_reg; static int cap_epr; static int cap_ppc_watchdog; static int cap_papr; static int cap_htab_fd; +static int cap_fixup_hcalls; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -97,6 +100,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); + cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE); cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG); cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR); @@ -104,6 +108,7 @@ int kvm_arch_init(KVMState *s) /* Note: we don't set cap_papr here, because this capability is * only activated after this by kvmppc_set_papr() */ cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); + cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -356,6 +361,10 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) /* Convert to QEMU form */ memset(&env->sps, 0, sizeof(env->sps)); + /* + * XXX This loop should be an entry wide AND of the capabilities that + * the selected CPU has with the capabilities that KVM supports. + */ for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) { struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq]; struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik]; @@ -382,9 +391,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) } } env->slb_nr = smmu_info.slb_size; - if (smmu_info.flags & KVM_PPC_1T_SEGMENTS) { - env->mmu_model |= POWERPC_MMU_1TSEG; - } else { + if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) { env->mmu_model &= ~POWERPC_MMU_1TSEG; } } @@ -858,11 +865,32 @@ int kvm_arch_put_registers(CPUState *cs, int level) } #ifdef TARGET_PPC64 + if (msr_ts) { + for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { + kvm_set_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); + } + for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) { + kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]); + } + kvm_set_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr); + kvm_set_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar); + } + if (cap_papr) { if (kvm_put_vpa(cs) < 0) { DPRINTF("Warning: Unable to set VPA information to KVM\n"); } } + + kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); #endif /* TARGET_PPC64 */ } @@ -1082,11 +1110,32 @@ int kvm_arch_get_registers(CPUState *cs) } #ifdef TARGET_PPC64 + if (msr_ts) { + for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) { + kvm_get_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]); + } + for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) { + kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]); + } + kvm_get_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr); + kvm_get_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar); + } + if (cap_papr) { if (kvm_get_vpa(cs) < 0) { DPRINTF("Warning: Unable to get VPA information from KVM\n"); } } + + kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); #endif } @@ -1476,18 +1525,18 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) } /* - * Fallback to always fail hypercalls: + * Fallback to always fail hypercalls regardless of endianness: * + * tdi 0,r0,72 (becomes b .+8 in wrong endian, nop in good endian) * li r3, -1 - * nop - * nop - * nop + * b .+8 (becomes nop in wrong endian) + * bswap32(li r3, -1) */ - hc[0] = 0x3860ffff; - hc[1] = 0x60000000; - hc[2] = 0x60000000; - hc[3] = 0x60000000; + hc[0] = cpu_to_be32(0x08000048); + hc[1] = cpu_to_be32(0x3860ffff); + hc[2] = cpu_to_be32(0x48000008); + hc[3] = cpu_to_be32(bswap32(0x3860ffff)); return 0; } @@ -1507,6 +1556,11 @@ void kvmppc_set_papr(PowerPCCPU *cpu) cap_papr = 1; } +int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version) +{ + return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &cpu_version); +} + void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) { CPUState *cs = CPU(cpu); @@ -1601,6 +1655,11 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) } #endif +bool kvmppc_spapr_use_multitce(void) +{ + return cap_spapr_multitce; +} + void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) { struct kvm_create_spapr_tce args = { @@ -1641,7 +1700,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) return table; } -int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) +int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t nb_table) { long len; @@ -1649,7 +1708,7 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return -1; } - len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(uint64_t); + len = nb_table * sizeof(uint64_t); if ((munmap(table, len) < 0) || (close(fd) < 0)) { fprintf(stderr, "KVM: Unexpected error removing TCE table: %s", @@ -1761,6 +1820,23 @@ bool kvmppc_has_cap_htab_fd(void) return cap_htab_fd; } +bool kvmppc_has_cap_fixup_hcalls(void) +{ + return cap_fixup_hcalls; +} + +static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) +{ + ObjectClass *oc = OBJECT_CLASS(pcc); + + while (oc && !object_class_is_abstract(oc)) { + oc = object_class_get_parent(oc); + } + assert(oc); + + return POWERPC_CPU_CLASS(oc); +} + static int kvm_ppc_register_host_cpu_type(void) { TypeInfo type_info = { @@ -1770,6 +1846,7 @@ static int kvm_ppc_register_host_cpu_type(void) }; uint32_t host_pvr = mfpvr(); PowerPCCPUClass *pvr_pcc; + DeviceClass *dc; pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); if (pvr_pcc == NULL) { @@ -1780,6 +1857,14 @@ static int kvm_ppc_register_host_cpu_type(void) } type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc)); type_register(&type_info); + + /* Register generic family CPU class for a family */ + pvr_pcc = ppc_cpu_get_family_class(pvr_pcc); + dc = DEVICE_CLASS(pvr_pcc); + type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc)); + type_info.name = g_strdup_printf("%s-"TYPE_POWERPC_CPU, dc->desc); + type_register(&type_info); + return 0; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index ff077ec502..412cc7f3c1 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -23,6 +23,7 @@ int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); +int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); int kvmppc_smt_threads(void); int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits); @@ -31,6 +32,7 @@ int kvmppc_set_tcr(PowerPCCPU *cpu); int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu); #ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); +bool kvmppc_spapr_use_multitce(void); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); @@ -48,6 +50,7 @@ void kvmppc_hash64_free_pteg(uint64_t token); void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index, target_ulong pte0, target_ulong pte1); +bool kvmppc_has_cap_fixup_hcalls(void); #else @@ -95,6 +98,11 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } +static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version) +{ + return 0; +} + static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) { } @@ -130,6 +138,11 @@ static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return 0; } +static inline bool kvmppc_spapr_use_multitce(void) +{ + return false; +} + static inline void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *fd) { @@ -137,7 +150,7 @@ static inline void *kvmppc_create_spapr_tce(uint32_t liobn, } static inline int kvmppc_remove_spapr_tce(void *table, int pfd, - uint32_t window_size) + uint32_t nb_table) { return -1; } @@ -211,6 +224,11 @@ static inline void kvmppc_hash64_write_pte(CPUPPCState *env, abort(); } +static inline bool kvmppc_has_cap_fixup_hcalls(void) +{ + abort(); +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/machine.c b/target-ppc/machine.c index d7807f88e6..c801b822c9 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -160,6 +160,11 @@ static int cpu_post_load(void *opaque, int version_id) CPUPPCState *env = &cpu->env; int i; + /* + * We always ignore the source PVR. The user or management + * software has to take care of running QEMU in a compatible mode. + */ + env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value; env->lr = env->spr[SPR_LR]; env->ctr = env->spr[SPR_CTR]; env->xer = env->spr[SPR_XER]; @@ -244,6 +249,38 @@ static const VMStateDescription vmstate_vsx = { }, }; +#ifdef TARGET_PPC64 +/* Transactional memory state */ +static bool tm_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + return msr_ts; +} + +static const VMStateDescription vmstate_tm = { + .name = "cpu/tm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32), + VMSTATE_AVR_ARRAY(env.tm_vsr, PowerPCCPU, 64), + VMSTATE_UINT64(env.tm_cr, PowerPCCPU), + VMSTATE_UINT64(env.tm_lr, PowerPCCPU), + VMSTATE_UINT64(env.tm_ctr, PowerPCCPU), + VMSTATE_UINT64(env.tm_fpscr, PowerPCCPU), + VMSTATE_UINT64(env.tm_amr, PowerPCCPU), + VMSTATE_UINT64(env.tm_ppr, PowerPCCPU), + VMSTATE_UINT64(env.tm_vrsave, PowerPCCPU), + VMSTATE_UINT32(env.tm_vscr, PowerPCCPU), + VMSTATE_UINT64(env.tm_dscr, PowerPCCPU), + VMSTATE_UINT64(env.tm_tar, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, +}; +#endif + static bool sr_needed(void *opaque) { #ifdef TARGET_PPC64 @@ -459,8 +496,7 @@ const VMStateDescription vmstate_ppc_cpu = { .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { - /* Verify we haven't changed the pvr */ - VMSTATE_UINTTL_EQUAL(env.spr[SPR_PVR], PowerPCCPU), + VMSTATE_UNUSED(sizeof(target_ulong)), /* was _EQUAL(env.spr[SPR_PVR]) */ /* User mode architected state */ VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32), @@ -506,6 +542,9 @@ const VMStateDescription vmstate_ppc_cpu = { .needed = sr_needed, } , { #ifdef TARGET_PPC64 + .vmsd = &vmstate_tm, + .needed = tm_needed, + } , { .vmsd = &vmstate_slb, .needed = slb_needed, } , { diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 02b627e47b..50344b81cf 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -25,6 +25,15 @@ //#define DEBUG_OP +static inline bool needs_byteswap(const CPUPPCState *env) +{ +#if defined(TARGET_WORDS_BIGENDIAN) + return msr_le; +#else + return !msr_le; +#endif +} + /*****************************************************************************/ /* Memory load and stores */ @@ -44,7 +53,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { - if (msr_le) { + if (needs_byteswap(env)) { env->gpr[reg] = bswap32(cpu_ldl_data(env, addr)); } else { env->gpr[reg] = cpu_ldl_data(env, addr); @@ -56,7 +65,7 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg) void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg) { for (; reg < 32; reg++) { - if (msr_le) { + if (needs_byteswap(env)) { cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg])); } else { cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]); @@ -199,6 +208,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, #define LO_IDX 0 #endif +/* We use msr_le to determine index ordering in a vector. However, + byteswapping is not simply controlled by msr_le. We also need to take + into account endianness of the target. This is done for the little-endian + PPC64 user-mode target. */ + #define LVE(name, access, swap, element) \ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ target_ulong addr) \ @@ -207,9 +221,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, int adjust = HI_IDX*(n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (needs_byteswap(env)) { \ r->element[LO_IDX ? index : (adjust - index)] = \ swap(access(env, addr)); \ } else { \ @@ -232,9 +248,11 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32) int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (needs_byteswap(env)) { \ access(env, addr, swap(r->element[LO_IDX ? index : \ (adjust - index)])); \ } else { \ diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index 7331b1b240..a577b3afd1 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -34,6 +34,45 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn) qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn, env->spr[sprn]); } + +#ifdef TARGET_PPC64 +static void raise_fu_exception(CPUPPCState *env, uint32_t bit, + uint32_t sprn, uint32_t cause) +{ + qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit); + + env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS); + cause &= FSCR_IC_MASK; + env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS; + + helper_raise_exception_err(env, POWERPC_EXCP_FU, 0); +} +#endif + +void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit, + uint32_t sprn, uint32_t cause) +{ +#ifdef TARGET_PPC64 + if (env->spr[SPR_FSCR] & (1ULL << bit)) { + /* Facility is enabled, continue */ + return; + } + raise_fu_exception(env, bit, sprn, cause); +#endif +} + +void helper_msr_facility_check(CPUPPCState *env, uint32_t bit, + uint32_t sprn, uint32_t cause) +{ +#ifdef TARGET_PPC64 + if (env->msr & (1ULL << bit)) { + /* Facility is enabled, continue */ + return; + } + raise_fu_exception(env, bit, sprn, cause); +#endif +} + #if !defined(CONFIG_USER_ONLY) void helper_store_sdr1(CPUPPCState *env, target_ulong val) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index f029f41965..4d6b1e20c0 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -903,6 +903,11 @@ static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, target_ulong mask; uint32_t tlb_pid; + if (!msr_cm) { + /* In 32bit mode we can only address 32bit EAs */ + address = (uint32_t)address; + } + /* Check valid flag */ if (!(tlb->mas1 & MAS1_VALID)) { return -1; @@ -2886,7 +2891,7 @@ void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address) tlb_flush(CPU(cpu), 1); } -void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type) +void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) { int flags = 0; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f08901470b..48017219a4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -46,17 +46,13 @@ /* global register indexes */ static TCGv_ptr cpu_env; static char cpu_reg_names[10*3 + 22*4 /* GPR */ -#if !defined(TARGET_PPC64) + 10*4 + 22*5 /* SPE GPRh */ -#endif + 10*4 + 22*5 /* FPR */ + 2*(10*6 + 22*7) /* AVRh, AVRl */ + 10*5 + 22*6 /* VSR */ + 8*5 /* CRF */]; static TCGv cpu_gpr[32]; -#if !defined(TARGET_PPC64) static TCGv cpu_gprh[32]; -#endif static TCGv_i64 cpu_fpr[32]; static TCGv_i64 cpu_avrh[32], cpu_avrl[32]; static TCGv_i64 cpu_vsr[32]; @@ -104,13 +100,11 @@ void ppc_translate_init(void) offsetof(CPUPPCState, gpr[i]), p); p += (i < 10) ? 3 : 4; cpu_reg_names_size -= (i < 10) ? 3 : 4; -#if !defined(TARGET_PPC64) snprintf(p, cpu_reg_names_size, "r%dH", i); - cpu_gprh[i] = tcg_global_mem_new_i32(TCG_AREG0, - offsetof(CPUPPCState, gprh[i]), p); + cpu_gprh[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUPPCState, gprh[i]), p); p += (i < 10) ? 4 : 5; cpu_reg_names_size -= (i < 10) ? 4 : 5; -#endif snprintf(p, cpu_reg_names_size, "fp%d", i); cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0, @@ -196,6 +190,7 @@ typedef struct DisasContext { int access_type; /* Translation flags */ int le_mode; + TCGMemOp default_tcg_memop_mask; #if defined(TARGET_PPC64) int sf_mode; int has_cfar; @@ -210,6 +205,16 @@ typedef struct DisasContext { uint64_t insns_flags2; } DisasContext; +/* Return true iff byteswap is needed in a scalar memop */ +static inline bool need_byteswap(const DisasContext *ctx) +{ +#if defined(TARGET_WORDS_BIGENDIAN) + return ctx->le_mode; +#else + return !ctx->le_mode; +#endif +} + /* True when active word size < size of target_long. */ #ifdef TARGET_PPC64 # define NARROW_MODE(C) (!(C)->sf_mode) @@ -279,6 +284,13 @@ static inline void gen_update_nip(DisasContext *ctx, target_ulong nip) tcg_gen_movi_tl(cpu_nip, nip); } +void gen_update_current_nip(void *opaque) +{ + DisasContext *ctx = opaque; + + tcg_gen_movi_tl(cpu_nip, ctx->nip); +} + static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error) { TCGv_i32 t0, t1; @@ -467,6 +479,12 @@ EXTRACT_HELPER(AA, 1, 1); /* Link */ EXTRACT_HELPER(LK, 0, 1); +/* DFP Z22-form */ +EXTRACT_HELPER(DCM, 10, 6) + +/* DFP Z23-form */ +EXTRACT_HELPER(RMC, 9, 2) + /* Create a mask between <start> and <end> bits */ static inline target_ulong MASK(uint32_t start, uint32_t end) { @@ -503,6 +521,7 @@ EXTRACT_HELPER_SPLIT(xC, 3, 1, 6, 5); EXTRACT_HELPER(DM, 8, 2); EXTRACT_HELPER(UIM, 16, 2); EXTRACT_HELPER(SHW, 8, 2); +EXTRACT_HELPER(SP, 19, 2); /*****************************************************************************/ /* PowerPC instructions table */ @@ -1217,6 +1236,7 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, } tcg_gen_xor_tl(t1, arg2, inv1); /* add without carry */ tcg_gen_add_tl(t0, t0, inv1); + tcg_temp_free(inv1); tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changes w/ carry */ tcg_temp_free(t1); tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */ @@ -2652,29 +2672,20 @@ static inline void gen_qemu_ld8s(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2) { - tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { - tcg_gen_bswap16_tl(arg1, arg1); - } + TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { - tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); - tcg_gen_bswap16_tl(arg1, arg1); - tcg_gen_ext16s_tl(arg1, arg1); - } else { - tcg_gen_qemu_ld16s(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_SW | ctx->default_tcg_memop_mask; + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2) { - tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { - tcg_gen_bswap32_tl(arg1, arg1); - } + TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } static void gen_qemu_ld32u_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) @@ -2687,12 +2698,8 @@ static void gen_qemu_ld32u_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { - tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); - tcg_gen_bswap32_tl(arg1, arg1); - tcg_gen_ext32s_tl(arg1, arg1); - } else - tcg_gen_qemu_ld32s(arg1, arg2, ctx->mem_idx); + TCGMemOp op = MO_SL | ctx->default_tcg_memop_mask; + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) @@ -2705,10 +2712,8 @@ static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { - tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { - tcg_gen_bswap64_i64(arg1, arg1); - } + TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; + tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); } static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) @@ -2718,28 +2723,14 @@ static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ext16u_tl(t0, arg1); - tcg_gen_bswap16_tl(t0, t0); - tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; + tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); } static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, arg1); - tcg_gen_bswap32_tl(t0, t0); - tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; + tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); } static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) @@ -2752,13 +2743,8 @@ static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { - TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_bswap64_i64(t0, arg1); - tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx); - tcg_temp_free_i64(t0); - } else - tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx); + TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; + tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); } #define GEN_LD(name, ldop, opc, type) \ @@ -2902,6 +2888,8 @@ static void gen_lq(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x0F); + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary + 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA); gen_addr_add(ctx, EA, EA, 8); @@ -3020,6 +3008,8 @@ static void gen_std(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); + /* We only need to swap high and low halves. gen_qemu_st64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_st64(ctx, cpu_gpr[rs+1], EA); gen_addr_add(ctx, EA, EA, 8); @@ -3049,23 +3039,20 @@ static void gen_std(DisasContext *ctx) } #endif /*** Integer load and store with byte reverse ***/ + /* lhbrx */ static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { - tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { - tcg_gen_bswap16_tl(arg1, arg1); - } + TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER); /* lwbrx */ static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { - tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { - tcg_gen_bswap32_tl(arg1, arg1); - } + TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); } GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); @@ -3073,10 +3060,8 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); /* ldbrx */ static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { - tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { - tcg_gen_bswap64_tl(arg1, arg1); - } + TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); } GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX); #endif /* TARGET_PPC64 */ @@ -3084,30 +3069,16 @@ GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX); /* sthbrx */ static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ext16u_tl(t0, arg1); - tcg_gen_bswap16_tl(t0, t0); - tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); } GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER); /* stwbrx */ static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, arg1); - tcg_gen_bswap32_tl(t0, t0); - tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); } GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); @@ -3115,14 +3086,8 @@ GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); /* stdbrx */ static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { - TCGv t0 = tcg_temp_new(); - tcg_gen_bswap64_tl(t0, arg1); - tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx); - tcg_temp_free(t0); - } else { - tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx); - } + TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); + tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); } GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX); #endif /* TARGET_PPC64 */ @@ -3542,7 +3507,9 @@ static void gen_lfdp(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); - gen_addr_imm_index(ctx, EA, 0); \ + gen_addr_imm_index(ctx, EA, 0); + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary + 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); @@ -3566,6 +3533,8 @@ static void gen_lfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary + 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); @@ -3714,7 +3683,9 @@ static void gen_stfdp(DisasContext *ctx) } gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); - gen_addr_imm_index(ctx, EA, 0); \ + gen_addr_imm_index(ctx, EA, 0); + /* We only need to swap high and low halves. gen_qemu_st64 does necessary + 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); @@ -3738,6 +3709,8 @@ static void gen_stfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); + /* We only need to swap high and low halves. gen_qemu_st64 does necessary + 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); @@ -3913,6 +3886,9 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_update_nip(ctx, ctx->nip); tcg_gen_exit_tb(0); } + if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { + tcg_temp_free(target); + } } static void gen_bc(DisasContext *ctx) @@ -4360,6 +4336,7 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif gen_helper_store_msr(cpu_env, msr); + tcg_temp_free(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); @@ -4469,6 +4446,17 @@ static void gen_dcbtst(DisasContext *ctx) */ } +/* dcbtls */ +static void gen_dcbtls(DisasContext *ctx) +{ + /* Always fails locking the cache */ + TCGv t0 = tcg_temp_new(); + gen_load_spr(t0, SPR_Exxx_L1CSR0); + tcg_gen_ori_tl(t0, t0, L1CSR0_CUL); + gen_store_spr(SPR_Exxx_L1CSR0, t0); + tcg_temp_free(t0); +} + /* dcbz */ static void gen_dcbz(DisasContext *ctx) { @@ -6494,6 +6482,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx) tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]); gen_helper_booke206_tlbsx(cpu_env, t0); + tcg_temp_free(t0); #endif } @@ -6527,6 +6516,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx) gen_addr_reg_index(ctx, t0); gen_helper_booke206_tlbivax(cpu_env, t0); + tcg_temp_free(t0); #endif } @@ -6691,6 +6681,8 @@ static void glue(gen_, name)(DisasContext *ctx) EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ + /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \ + 64-bit byteswap already. */ \ if (ctx->le_mode) { \ gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ @@ -6715,6 +6707,8 @@ static void gen_st##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ + /* We only need to swap high and low halves. gen_qemu_st64 does necessary \ + 64-bit byteswap already. */ \ if (ctx->le_mode) { \ gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ @@ -8180,6 +8174,225 @@ static void gen_xxsldwi(DisasContext *ctx) tcg_temp_free_i64(xtl); } +/*** Decimal Floating Point ***/ + +static inline TCGv_ptr gen_fprp_ptr(int reg) +{ + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg])); + return r; +} + +#if defined(TARGET_PPC64) +static void gen_set_cr6_from_fpscr(DisasContext *ctx) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], tmp, 28); + tcg_temp_free_i32(tmp); +} +#else +static void gen_set_cr6_from_fpscr(DisasContext *ctx) +{ + tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); +} +#endif + +#define GEN_DFP_T_A_B_Rc(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rd, ra, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rd = gen_fprp_ptr(rD(ctx->opcode)); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_env, rd, ra, rb); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr6_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rd); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ +} + +#define GEN_DFP_BF_A_B(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr ra, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + cpu_env, ra, rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_ptr(rb); \ +} + +#define GEN_DFP_BF_A_DCM(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr ra; \ + TCGv_i32 dcm; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + dcm = tcg_const_i32(DCM(ctx->opcode)); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ + cpu_env, ra, dcm); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_i32(dcm); \ +} + +#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rb; \ + TCGv_i32 u32_1, u32_2; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + u32_1 = tcg_const_i32(u32f1(ctx->opcode)); \ + u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr6_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_i32(u32_1); \ + tcg_temp_free_i32(u32_2); \ +} + +#define GEN_DFP_T_A_B_I32_Rc(name, i32fld) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, ra, rb; \ + TCGv_i32 i32; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + ra = gen_fprp_ptr(rA(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + i32 = tcg_const_i32(i32fld(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, ra, rb, i32); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr6_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(ra); \ + tcg_temp_free_i32(i32); \ + } + +#define GEN_DFP_T_B_Rc(name) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rb; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rb = gen_fprp_ptr(rB(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rb); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr6_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rb); \ + } + +#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv_ptr rt, rs; \ + TCGv_i32 i32; \ + if (unlikely(!ctx->fpu_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_FPU); \ + return; \ + } \ + gen_update_nip(ctx, ctx->nip - 4); \ + rt = gen_fprp_ptr(rD(ctx->opcode)); \ + rs = gen_fprp_ptr(fprfld(ctx->opcode)); \ + i32 = tcg_const_i32(i32fld(ctx->opcode)); \ + gen_helper_##name(cpu_env, rt, rs, i32); \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr6_from_fpscr(ctx); \ + } \ + tcg_temp_free_ptr(rt); \ + tcg_temp_free_ptr(rs); \ + tcg_temp_free_i32(i32); \ +} + +GEN_DFP_T_A_B_Rc(dadd) +GEN_DFP_T_A_B_Rc(daddq) +GEN_DFP_T_A_B_Rc(dsub) +GEN_DFP_T_A_B_Rc(dsubq) +GEN_DFP_T_A_B_Rc(dmul) +GEN_DFP_T_A_B_Rc(dmulq) +GEN_DFP_T_A_B_Rc(ddiv) +GEN_DFP_T_A_B_Rc(ddivq) +GEN_DFP_BF_A_B(dcmpu) +GEN_DFP_BF_A_B(dcmpuq) +GEN_DFP_BF_A_B(dcmpo) +GEN_DFP_BF_A_B(dcmpoq) +GEN_DFP_BF_A_DCM(dtstdc) +GEN_DFP_BF_A_DCM(dtstdcq) +GEN_DFP_BF_A_DCM(dtstdg) +GEN_DFP_BF_A_DCM(dtstdgq) +GEN_DFP_BF_A_B(dtstex) +GEN_DFP_BF_A_B(dtstexq) +GEN_DFP_BF_A_B(dtstsf) +GEN_DFP_BF_A_B(dtstsfq) +GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC) +GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC) +GEN_DFP_T_A_B_I32_Rc(dqua, RMC) +GEN_DFP_T_A_B_I32_Rc(dquaq, RMC) +GEN_DFP_T_A_B_I32_Rc(drrnd, RMC) +GEN_DFP_T_A_B_I32_Rc(drrndq, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC) +GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC) +GEN_DFP_T_B_Rc(dctdp) +GEN_DFP_T_B_Rc(dctqpq) +GEN_DFP_T_B_Rc(drsp) +GEN_DFP_T_B_Rc(drdpq) +GEN_DFP_T_B_Rc(dcffix) +GEN_DFP_T_B_Rc(dcffixq) +GEN_DFP_T_B_Rc(dctfix) +GEN_DFP_T_B_Rc(dctfixq) +GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP) +GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP) +GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP) +GEN_DFP_T_B_Rc(dxex) +GEN_DFP_T_B_Rc(dxexq) +GEN_DFP_T_A_B_Rc(diex) +GEN_DFP_T_A_B_Rc(diexq) +GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM) +GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM) /*** SPE extension ***/ /* Register moves */ @@ -8192,50 +8405,28 @@ static inline void gen_evmra(DisasContext *ctx) return; } -#if defined(TARGET_PPC64) - /* rD := rA */ - tcg_gen_mov_i64(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - - /* spe_acc := rA */ - tcg_gen_st_i64(cpu_gpr[rA(ctx->opcode)], - cpu_env, - offsetof(CPUPPCState, spe_acc)); -#else TCGv_i64 tmp = tcg_temp_new_i64(); /* tmp := rA_lo + rA_hi << 32 */ - tcg_gen_concat_i32_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); + tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); /* spe_acc := tmp */ tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); tcg_temp_free_i64(tmp); /* rD := rA */ - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -#endif + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); } static inline void gen_load_gpr64(TCGv_i64 t, int reg) { -#if defined(TARGET_PPC64) - tcg_gen_mov_i64(t, cpu_gpr[reg]); -#else - tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]); -#endif + tcg_gen_concat_tl_i64(t, cpu_gpr[reg], cpu_gprh[reg]); } static inline void gen_store_gpr64(int reg, TCGv_i64 t) { -#if defined(TARGET_PPC64) - tcg_gen_mov_i64(cpu_gpr[reg], t); -#else - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_trunc_i64_i32(cpu_gpr[reg], t); - tcg_gen_shri_i64(tmp, t, 32); - tcg_gen_trunc_i64_i32(cpu_gprh[reg], tmp); - tcg_temp_free_i64(tmp); -#endif + tcg_gen_extr_i64_tl(cpu_gpr[reg], cpu_gprh[reg], t); } #define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ @@ -8254,18 +8445,6 @@ static inline void gen_speundef(DisasContext *ctx) } /* SPE logic */ -#if defined(TARGET_PPC64) -#define GEN_SPEOP_LOGIC2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ - cpu_gpr[rB(ctx->opcode)]); \ -} -#else #define GEN_SPEOP_LOGIC2(name, tcg_op) \ static inline void gen_##name(DisasContext *ctx) \ { \ @@ -8278,7 +8457,6 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ cpu_gprh[rB(ctx->opcode)]); \ } -#endif GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl); GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl); @@ -8290,80 +8468,52 @@ GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl); GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl); /* SPE logic immediate */ -#if defined(TARGET_PPC64) #define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - TCGv_i32 t0 = tcg_temp_local_new_i32(); \ - TCGv_i32 t1 = tcg_temp_local_new_i32(); \ - TCGv_i64 t2 = tcg_temp_local_new_i64(); \ - tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_opi(t0, t0, rB(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ tcg_opi(t0, t0, rB(ctx->opcode)); \ - tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t1, t2); \ - tcg_temp_free_i64(t2); \ - tcg_opi(t1, t1, rB(ctx->opcode)); \ - tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#else -#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ - rB(ctx->opcode)); \ - tcg_opi(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ - rB(ctx->opcode)); \ } -#endif GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32); GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32); GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32); GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32); /* SPE arithmetic */ -#if defined(TARGET_PPC64) #define GEN_SPEOP_ARITH1(name, tcg_op) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - TCGv_i32 t0 = tcg_temp_local_new_i32(); \ - TCGv_i32 t1 = tcg_temp_local_new_i32(); \ - TCGv_i64 t2 = tcg_temp_local_new_i64(); \ - tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_op(t0, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ tcg_op(t0, t0); \ - tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t1, t2); \ - tcg_temp_free_i64(t2); \ - tcg_op(t1, t1); \ - tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ } -#else -#define GEN_SPEOP_ARITH1(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); \ - tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); \ -} -#endif static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1) { @@ -8390,46 +8540,30 @@ GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw); GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32); GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32); -#if defined(TARGET_PPC64) #define GEN_SPEOP_ARITH2(name, tcg_op) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0, t1; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - TCGv_i32 t0 = tcg_temp_local_new_i32(); \ - TCGv_i32 t1 = tcg_temp_local_new_i32(); \ - TCGv_i32 t2 = tcg_temp_local_new_i32(); \ - TCGv_i64 t3 = tcg_temp_local_new_i64(); \ - tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_i64_i32(t2, cpu_gpr[rB(ctx->opcode)]); \ - tcg_op(t0, t0, t2); \ - tcg_gen_shri_i64(t3, cpu_gpr[rA(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t1, t3); \ - tcg_gen_shri_i64(t3, cpu_gpr[rB(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t2, t3); \ - tcg_temp_free_i64(t3); \ - tcg_op(t1, t1, t2); \ - tcg_temp_free_i32(t2); \ - tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + tcg_op(t0, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]); \ + tcg_op(t0, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ tcg_temp_free_i32(t0); \ tcg_temp_free_i32(t1); \ } -#else -#define GEN_SPEOP_ARITH2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \ - cpu_gpr[rB(ctx->opcode)]); \ - tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], \ - cpu_gprh[rB(ctx->opcode)]); \ -} -#endif static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { @@ -8502,18 +8636,8 @@ static inline void gen_evmergehi(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32); - tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); -#else - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -#endif + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); } GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32); static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) @@ -8523,86 +8647,30 @@ static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf); /* SPE arithmetic immediate */ -#if defined(TARGET_PPC64) #define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - TCGv_i32 t0 = tcg_temp_local_new_i32(); \ - TCGv_i32 t1 = tcg_temp_local_new_i32(); \ - TCGv_i64 t2 = tcg_temp_local_new_i64(); \ - tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ + t0 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ tcg_op(t0, t0, rA(ctx->opcode)); \ - tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t1, t2); \ - tcg_temp_free_i64(t2); \ - tcg_op(t1, t1, rA(ctx->opcode)); \ - tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]); \ + tcg_op(t0, t0, rA(ctx->opcode)); \ + tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ + \ tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#else -#define GEN_SPEOP_ARITH_IMM2(name, tcg_op) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ - rA(ctx->opcode)); \ - tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)], \ - rA(ctx->opcode)); \ } -#endif GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32); GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32); /* SPE comparison */ -#if defined(TARGET_PPC64) -#define GEN_SPEOP_COMP(name, tcg_cond) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - int l1 = gen_new_label(); \ - int l2 = gen_new_label(); \ - int l3 = gen_new_label(); \ - int l4 = gen_new_label(); \ - TCGv_i32 t0 = tcg_temp_local_new_i32(); \ - TCGv_i32 t1 = tcg_temp_local_new_i32(); \ - TCGv_i64 t2 = tcg_temp_local_new_i64(); \ - tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_i64_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - tcg_gen_brcond_i32(tcg_cond, t0, t1, l1); \ - tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0); \ - tcg_gen_br(l2); \ - gen_set_label(l1); \ - tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ - CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ - gen_set_label(l2); \ - tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t0, t2); \ - tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32); \ - tcg_gen_trunc_i64_i32(t1, t2); \ - tcg_temp_free_i64(t2); \ - tcg_gen_brcond_i32(tcg_cond, t0, t1, l3); \ - tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ - ~(CRF_CH | CRF_CH_AND_CL)); \ - tcg_gen_br(l4); \ - gen_set_label(l3); \ - tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ - CRF_CH | CRF_CH_OR_CL); \ - gen_set_label(l4); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#else #define GEN_SPEOP_COMP(name, tcg_cond) \ static inline void gen_##name(DisasContext *ctx) \ { \ @@ -8615,15 +8683,20 @@ static inline void gen_##name(DisasContext *ctx) \ int l3 = gen_new_label(); \ int l4 = gen_new_label(); \ \ - tcg_gen_brcond_i32(tcg_cond, cpu_gpr[rA(ctx->opcode)], \ + tcg_gen_ext32s_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); \ + tcg_gen_ext32s_tl(cpu_gprh[rB(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); \ + \ + tcg_gen_brcond_tl(tcg_cond, cpu_gpr[rA(ctx->opcode)], \ cpu_gpr[rB(ctx->opcode)], l1); \ - tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0); \ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0); \ tcg_gen_br(l2); \ gen_set_label(l1); \ tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], \ CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL); \ gen_set_label(l2); \ - tcg_gen_brcond_i32(tcg_cond, cpu_gprh[rA(ctx->opcode)], \ + tcg_gen_brcond_tl(tcg_cond, cpu_gprh[rA(ctx->opcode)], \ cpu_gprh[rB(ctx->opcode)], l3); \ tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], \ ~(CRF_CH | CRF_CH_AND_CL)); \ @@ -8633,7 +8706,6 @@ static inline void gen_##name(DisasContext *ctx) \ CRF_CH | CRF_CH_OR_CL); \ gen_set_label(l4); \ } -#endif GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU); GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT); GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU); @@ -8653,18 +8725,8 @@ static inline void gen_evmergelo(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); -#else - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); -#endif + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); } static inline void gen_evmergehilo(DisasContext *ctx) { @@ -8672,18 +8734,8 @@ static inline void gen_evmergehilo(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); -#else - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -#endif + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); } static inline void gen_evmergelohi(DisasContext *ctx) { @@ -8691,48 +8743,30 @@ static inline void gen_evmergelohi(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32); - tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); -#else if (rD(ctx->opcode) == rA(ctx->opcode)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], tmp); - tcg_temp_free_i32(tmp); + TCGv tmp = tcg_temp_new(); + tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp); + tcg_temp_free(tmp); } else { - tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); - tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); + tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); } -#endif } static inline void gen_evsplati(DisasContext *ctx) { uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27; -#if defined(TARGET_PPC64) - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm); -#else - tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm); - tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm); -#endif + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); } static inline void gen_evsplatfi(DisasContext *ctx) { uint64_t imm = rA(ctx->opcode) << 27; -#if defined(TARGET_PPC64) - tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm); -#else - tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm); - tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm); -#endif + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm); + tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm); } static inline void gen_evsel(DisasContext *ctx) @@ -8742,46 +8776,21 @@ static inline void gen_evsel(DisasContext *ctx) int l3 = gen_new_label(); int l4 = gen_new_label(); TCGv_i32 t0 = tcg_temp_local_new_i32(); -#if defined(TARGET_PPC64) - TCGv t1 = tcg_temp_local_new(); - TCGv t2 = tcg_temp_local_new(); -#endif tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3); tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); -#if defined(TARGET_PPC64) - tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF00000000ULL); -#else tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]); -#endif tcg_gen_br(l2); gen_set_label(l1); -#if defined(TARGET_PPC64) - tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0xFFFFFFFF00000000ULL); -#else tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); -#endif gen_set_label(l2); tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2); tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3); -#if defined(TARGET_PPC64) - tcg_gen_ext32u_tl(t2, cpu_gpr[rA(ctx->opcode)]); -#else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); -#endif tcg_gen_br(l4); gen_set_label(l3); -#if defined(TARGET_PPC64) - tcg_gen_ext32u_tl(t2, cpu_gpr[rB(ctx->opcode)]); -#else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); -#endif gen_set_label(l4); tcg_temp_free_i32(t0); -#if defined(TARGET_PPC64) - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t1, t2); - tcg_temp_free(t1); - tcg_temp_free(t2); -#endif } static void gen_evsel0(DisasContext *ctx) @@ -8819,13 +8828,10 @@ static inline void gen_evmwumi(DisasContext *ctx) t1 = tcg_temp_new_i64(); /* t0 := rA; t1 := rB */ -#if defined(TARGET_PPC64) - tcg_gen_ext32u_tl(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32u_tl(t1, cpu_gpr[rB(ctx->opcode)]); -#else tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32u_i64(t0, t0); tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); -#endif + tcg_gen_ext32u_i64(t1, t1); tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ @@ -8901,13 +8907,10 @@ static inline void gen_evmwsmi(DisasContext *ctx) t1 = tcg_temp_new_i64(); /* t0 := rA; t1 := rB */ -#if defined(TARGET_PPC64) - tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]); -#else - tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); -#endif + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ext32s_i64(t0, t0); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_ext32s_i64(t1, t1); tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ @@ -9008,53 +9011,22 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], addr); -#else TCGv_i64 t0 = tcg_temp_new_i64(); gen_qemu_ld64(ctx, t0, addr); - tcg_gen_trunc_i64_i32(cpu_gpr[rD(ctx->opcode)], t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(cpu_gprh[rD(ctx->opcode)], t0); + gen_store_gpr64(rD(ctx->opcode), t0); tcg_temp_free_i64(t0); -#endif } static inline void gen_op_evldw(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - gen_qemu_ld32u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32); - gen_addr_add(ctx, addr, addr, 4); - gen_qemu_ld32u(ctx, t0, addr); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -#else gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr); gen_addr_add(ctx, addr, addr, 4); gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr); -#endif } static inline void gen_op_evldh(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); -#if defined(TARGET_PPC64) - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 16); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); gen_addr_add(ctx, addr, addr, 2); @@ -9066,7 +9038,6 @@ static inline void gen_op_evldh(DisasContext *ctx, TCGv addr) gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16u(ctx, t0, addr); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } @@ -9074,15 +9045,9 @@ static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); gen_qemu_ld16u(ctx, t0, addr); -#if defined(TARGET_PPC64) - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48); - tcg_gen_shli_tl(t0, t0, 16); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else tcg_gen_shli_tl(t0, t0, 16); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } @@ -9090,13 +9055,8 @@ static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); gen_qemu_ld16u(ctx, t0, addr); -#if defined(TARGET_PPC64) - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } @@ -9104,100 +9064,48 @@ static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); gen_qemu_ld16s(ctx, t0, addr); -#if defined(TARGET_PPC64) - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32); - tcg_gen_ext32u_tl(t0, t0); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); -#if defined(TARGET_PPC64) - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 16); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); -#endif tcg_temp_free(t0); } static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -#else gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr); gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr); -#endif } static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - gen_qemu_ld16s(ctx, t0, addr); - tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16s(ctx, t0, addr); - tcg_gen_shli_tl(t0, t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); -#else gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr); gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr); -#endif } static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); gen_qemu_ld32u(ctx, t0, addr); -#if defined(TARGET_PPC64) - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); -#if defined(TARGET_PPC64) - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48); - tcg_gen_shli_tl(t0, t0, 32); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - gen_addr_add(ctx, addr, addr, 2); - gen_qemu_ld16u(ctx, t0, addr); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_gen_shli_tl(t0, t0, 16); - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); -#else gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16); tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); @@ -9205,32 +9113,20 @@ static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); -#endif tcg_temp_free(t0); } static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], addr); -#else TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(t0, cpu_gpr[rS(ctx->opcode)], cpu_gprh[rS(ctx->opcode)]); + gen_load_gpr64(t0, rS(ctx->opcode)); gen_qemu_st64(ctx, t0, addr); tcg_temp_free_i64(t0); -#endif } static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32); - gen_qemu_st32(ctx, t0, addr); - tcg_temp_free(t0); -#else gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); -#endif gen_addr_add(ctx, addr, addr, 4); gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr); } @@ -9238,19 +9134,10 @@ static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr) static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); -#if defined(TARGET_PPC64) - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48); -#else tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); -#endif gen_qemu_st16(ctx, t0, addr); gen_addr_add(ctx, addr, addr, 2); -#if defined(TARGET_PPC64) - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32); - gen_qemu_st16(ctx, t0, addr); -#else gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); -#endif gen_addr_add(ctx, addr, addr, 2); tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); gen_qemu_st16(ctx, t0, addr); @@ -9262,11 +9149,7 @@ static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr) static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr) { TCGv t0 = tcg_temp_new(); -#if defined(TARGET_PPC64) - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48); -#else tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16); -#endif gen_qemu_st16(ctx, t0, addr); gen_addr_add(ctx, addr, addr, 2); tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); @@ -9276,28 +9159,14 @@ static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr) static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32); - gen_qemu_st16(ctx, t0, addr); - tcg_temp_free(t0); -#else gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr); -#endif gen_addr_add(ctx, addr, addr, 2); gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); } static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr) { -#if defined(TARGET_PPC64) - TCGv t0 = tcg_temp_new(); - tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32); - gen_qemu_st32(ctx, t0, addr); - tcg_temp_free(t0); -#else gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr); -#endif } static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr) @@ -9417,133 +9286,36 @@ GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_S #endif /*** SPE floating-point extension ***/ -#if defined(TARGET_PPC64) #define GEN_SPEFPUOP_CONV_32_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ - TCGv_i32 t0; \ - TCGv t1; \ - t0 = tcg_temp_new_i32(); \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ gen_helper_##name(t0, cpu_env, t0); \ - t1 = tcg_temp_new(); \ - tcg_gen_extu_i32_tl(t1, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ tcg_temp_free_i32(t0); \ - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], \ - 0xFFFFFFFF00000000ULL); \ - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1); \ - tcg_temp_free(t1); \ -} -#define GEN_SPEFPUOP_CONV_32_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0; \ - TCGv t1; \ - t0 = tcg_temp_new_i32(); \ - gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \ - t1 = tcg_temp_new(); \ - tcg_gen_extu_i32_tl(t1, t0); \ - tcg_temp_free_i32(t0); \ - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], \ - 0xFFFFFFFF00000000ULL); \ - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1); \ - tcg_temp_free(t1); \ -} -#define GEN_SPEFPUOP_CONV_64_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \ - tcg_temp_free_i32(t0); \ -} -#define GEN_SPEFPUOP_CONV_64_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ - cpu_gpr[rB(ctx->opcode)]); \ -} -#define GEN_SPEFPUOP_ARITH2_32_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0, t1; \ - TCGv_i64 t2; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ - tcg_temp_free_i32(t1); \ - t2 = tcg_temp_new(); \ - tcg_gen_extu_i32_tl(t2, t0); \ - tcg_temp_free_i32(t0); \ - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], \ - 0xFFFFFFFF00000000ULL); \ - tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t2); \ - tcg_temp_free(t2); \ -} -#define GEN_SPEFPUOP_ARITH2_64_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ -} -#define GEN_SPEFPUOP_COMP_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 t0, t1; \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i32(); \ - tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ - tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ -} -#define GEN_SPEFPUOP_COMP_64(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - if (unlikely(!ctx->spe_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_SPEU); \ - return; \ - } \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \ - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ -} -#else -#define GEN_SPEFPUOP_CONV_32_32(name) \ -static inline void gen_##name(DisasContext *ctx) \ -{ \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ - cpu_gpr[rB(ctx->opcode)]); \ } #define GEN_SPEFPUOP_CONV_32_64(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \ + gen_helper_##name(t1, cpu_env, t0); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); \ tcg_temp_free_i64(t0); \ + tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_CONV_64_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i64 t0 = tcg_temp_new_i64(); \ - gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ tcg_temp_free_i64(t0); \ + tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_CONV_64_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -9557,12 +9329,20 @@ static inline void gen_##name(DisasContext *ctx) \ #define GEN_SPEFPUOP_ARITH2_32_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0, t1; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \ - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(t0, cpu_env, t0, t1); \ + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ + \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_ARITH2_64_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -9584,12 +9364,20 @@ static inline void gen_##name(DisasContext *ctx) \ #define GEN_SPEFPUOP_COMP_32(name) \ static inline void gen_##name(DisasContext *ctx) \ { \ + TCGv_i32 t0, t1; \ if (unlikely(!ctx->spe_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_SPEU); \ return; \ } \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \ - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ + t0 = tcg_temp_new_i32(); \ + t1 = tcg_temp_new_i32(); \ + \ + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ + \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_COMP_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -9607,7 +9395,6 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_temp_free_i64(t0); \ tcg_temp_free_i64(t1); \ } -#endif /* Single precision floating-point vectors operations */ /* Arithmetic */ @@ -9621,12 +9408,10 @@ static inline void gen_evfsabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL); -#else - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000); - tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); -#endif + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + ~0x80000000); + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + ~0x80000000); } static inline void gen_evfsnabs(DisasContext *ctx) { @@ -9634,12 +9419,10 @@ static inline void gen_evfsnabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); -#else - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); - tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); -#endif + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); } static inline void gen_evfsneg(DisasContext *ctx) { @@ -9647,12 +9430,10 @@ static inline void gen_evfsneg(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); -#else - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); - tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); -#endif + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + 0x80000000); + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); } /* Conversion */ @@ -9771,12 +9552,9 @@ static inline void gen_efdabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL); -#else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); -#endif + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + ~0x80000000); } static inline void gen_efdnabs(DisasContext *ctx) { @@ -9784,12 +9562,9 @@ static inline void gen_efdnabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); -#else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); -#endif + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); } static inline void gen_efdneg(DisasContext *ctx) { @@ -9797,12 +9572,9 @@ static inline void gen_efdneg(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_SPEU); return; } -#if defined(TARGET_PPC64) - tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); -#else tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); -#endif + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], + 0x80000000); } /* Conversion */ @@ -9880,7 +9652,7 @@ GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), -GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB), +GEN_HANDLER(popcntb, 0x1F, 0x1A, 0x03, 0x0000F801, PPC_POPCNTB), GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205), #if defined(TARGET_PPC64) @@ -9982,6 +9754,7 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x00000001, PPC_CACHE), GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x00000001, PPC_CACHE), +GEN_HANDLER_E(dcbtls, 0x1F, 0x06, 0x05, 0x02000001, PPC_BOOKE, PPC2_BOOKE206), GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ), GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC), @@ -10999,6 +10772,166 @@ GEN_XXSEL_ROW(0x1F) GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), +#undef GEN_DFP_T_A_B_Rc +#undef GEN_DFP_BF_A_B +#undef GEN_DFP_BF_A_DCM +#undef GEN_DFP_T_B_U32_U32_Rc +#undef GEN_DFP_T_A_B_I32_Rc +#undef GEN_DFP_T_B_Rc +#undef GEN_DFP_T_FPR_I32_Rc + +#define _GEN_DFP_LONG(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_LONGx2(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_LONGx4(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUAD(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUADx2(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) + +#define _GEN_DFP_QUADx4(name, op1, op2, mask) \ +GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ +GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) + +#define GEN_DFP_T_A_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00210800) + +#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00200800) + +#define GEN_DFP_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x001F0000) + +#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x003F0800) + +#define GEN_DFP_Tp_B_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x003F0000) + +#define GEN_DFP_T_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x001F0800) + +#define GEN_DFP_BF_A_B(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00000001) + +#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00610801) + +#define GEN_DFP_BF_A_Bp(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00600801) + +#define GEN_DFP_BF_A_DCM(name, op1, op2) \ +_GEN_DFP_LONGx2(name, op1, op2, 0x00600001) + +#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \ +_GEN_DFP_QUADx2(name, op1, op2, 0x00610001) + +#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x02010800) + +#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x02000800) + +#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) + +#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x00200800) + +#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \ +_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000) + +#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \ +_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800) + +#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x00070000) + +#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x00270800) + +#define GEN_DFP_S_T_B_Rc(name, op1, op2) \ +_GEN_DFP_LONG(name, op1, op2, 0x000F0000) + +#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \ +_GEN_DFP_QUAD(name, op1, op2, 0x002F0800) + +#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \ +_GEN_DFP_LONGx2(name, op1, op2, 0x00000000) + +#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \ +_GEN_DFP_QUADx2(name, op1, op2, 0x00210000) + +GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00), +GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00), +GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10), +GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10), +GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01), +GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01), +GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11), +GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11), +GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14), +GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14), +GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04), +GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04), +GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06), +GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06), +GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07), +GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07), +GEN_DFP_BF_A_B(dtstex, 0x02, 0x05), +GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05), +GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15), +GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15), +GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02), +GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02), +GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00), +GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00), +GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01), +GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01), +GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03), +GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03), +GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07), +GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07), +GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08), +GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08), +GEN_DFP_T_B_Rc(drsp, 0x02, 0x18), +GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18), +GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19), +GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19), +GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09), +GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09), +GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a), +GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a), +GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a), +GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a), +GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b), +GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b), +GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b), +GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b), +GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02), +GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02), +GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03), +GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03), + #undef GEN_SPE #define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) @@ -11337,6 +11270,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, ctx.insns_flags2 = env->insns_flags2; ctx.access_type = -1; ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; + ctx.default_tcg_memop_mask = ctx.le_mode ? MO_LE : MO_BE; #if defined(TARGET_PPC64) ctx.sf_mode = msr_is_64bit(env, env->msr); ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); @@ -11374,6 +11308,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, max_insns = CF_COUNT_MASK; gen_tb_start(); + tcg_clear_temp_count(); /* Set env in case of segfault during code fetch */ while (ctx.exception == POWERPC_EXCP_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end) { @@ -11401,7 +11336,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, ctx.nip, ctx.mem_idx, (int)msr_ir); if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - if (unlikely(ctx.le_mode)) { + if (unlikely(need_byteswap(&ctx))) { ctx.opcode = bswap32(cpu_ldl_code(env, ctx.nip)); } else { ctx.opcode = cpu_ldl_code(env, ctx.nip); @@ -11473,6 +11408,12 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, */ break; } + if (tcg_check_temp_count()) { + fprintf(stderr, "Opcode %02x %02x %02x (%08x) leaked temporaries\n", + opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), + ctx.opcode); + exit(1); + } } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4d94015942..85581c9537 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -28,6 +28,8 @@ #include "mmu-hash32.h" #include "mmu-hash64.h" #include "qemu/error-report.h" +#include "qapi/visitor.h" +#include "hw/qdev-properties.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -173,6 +175,13 @@ static void spr_read_ureg (void *opaque, int gprn, int sprn) gen_load_spr(cpu_gpr[gprn], sprn + 0x10); } +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +static void spr_write_ureg(void *opaque, int sprn, int gprn) +{ + gen_store_spr(sprn + 0x10, cpu_gpr[gprn]); +} +#endif + /* SPR common to all non-embedded PowerPC */ /* DECR */ #if !defined(CONFIG_USER_ONLY) @@ -951,72 +960,72 @@ static void gen_spr_7xx (CPUPPCState *env) 0x00000000); /* Performance monitors */ /* XXX : not implemented */ - spr_register(env, SPR_MMCR0, "MMCR0", + spr_register(env, SPR_7XX_MMCR0, "MMCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_MMCR1, "MMCR1", + spr_register(env, SPR_7XX_MMCR1, "MMCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC1, "PMC1", + spr_register(env, SPR_7XX_PMC1, "PMC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC2, "PMC2", + spr_register(env, SPR_7XX_PMC2, "PMC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC3, "PMC3", + spr_register(env, SPR_7XX_PMC3, "PMC3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC4, "PMC4", + spr_register(env, SPR_7XX_PMC4, "PMC4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_SIAR, "SIAR", + spr_register(env, SPR_7XX_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UMMCR0, "UMMCR0", + spr_register(env, SPR_7XX_UMMCR0, "UMMCR0", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UMMCR1, "UMMCR1", + spr_register(env, SPR_7XX_UMMCR1, "UMMCR1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC1, "UPMC1", + spr_register(env, SPR_7XX_UPMC1, "UPMC1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC2, "UPMC2", + spr_register(env, SPR_7XX_UPMC2, "UPMC2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC3, "UPMC3", + spr_register(env, SPR_7XX_UPMC3, "UPMC3", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC4, "UPMC4", + spr_register(env, SPR_7XX_UPMC4, "UPMC4", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_USIAR, "USIAR", + spr_register(env, SPR_7XX_USIAR, "USIAR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -1117,22 +1126,22 @@ static void gen_spr_604 (CPUPPCState *env) KVM_REG_PPC_DABR, 0x00000000); /* Performance counters */ /* XXX : not implemented */ - spr_register(env, SPR_MMCR0, "MMCR0", + spr_register(env, SPR_7XX_MMCR0, "MMCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC1, "PMC1", + spr_register(env, SPR_7XX_PMC1, "PMC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC2, "PMC2", + spr_register(env, SPR_7XX_PMC2, "PMC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_SIAR, "SIAR", + spr_register(env, SPR_7XX_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1352,12 +1361,12 @@ static void gen_spr_74xx (CPUPPCState *env) &spr_read_generic, &spr_write_pir, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_MMCR2, "MMCR2", + spr_register(env, SPR_74XX_MMCR2, "MMCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UMMCR2, "UMMCR2", + spr_register(env, SPR_74XX_UMMCR2, "UMMCR2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -1448,16 +1457,23 @@ static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256); + tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR0_DCE | L1CSR0_CPE); + gen_store_spr(sprn, t0); + tcg_temp_free(t0); +} + +static void spr_write_e500_l1csr1(void *opaque, int sprn, int gprn) +{ + TCGv t0 = tcg_temp_new(); + + tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR1_ICE | L1CSR1_CPE); gen_store_spr(sprn, t0); tcg_temp_free(t0); } static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn) { - TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_booke206_tlbflush(cpu_env, t0); - tcg_temp_free_i32(t0); + gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]); } static void spr_write_booke_pid (void *opaque, int sprn, int gprn) @@ -3064,6 +3080,7 @@ static void init_excp_POWER7 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; env->excp_vectors[POWERPC_EXCP_VSXU] = 0x00000F40; + env->excp_vectors[POWERPC_EXCP_FU] = 0x00000F60; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; @@ -3102,6 +3119,18 @@ static int check_pow_hid0_74xx (CPUPPCState *env) return 0; } +static bool ppc_cpu_interrupts_big_endian_always(PowerPCCPU *cpu) +{ + return true; +} + +#ifdef TARGET_PPC64 +static bool ppc_cpu_interrupts_big_endian_lpcr(PowerPCCPU *cpu) +{ + return !(cpu->env.spr[SPR_LPCR] & LPCR_ILE); +} +#endif + /*****************************************************************************/ /* PowerPC implementations definitions */ @@ -3156,7 +3185,15 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x00000000000FD201ULL; + pcc->msr_mask = (1ull << MSR_KEY) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_DE) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3203,7 +3240,18 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x00000000001FD231ULL; + pcc->msr_mask = (1ull << 20) | + (1ull << MSR_KEY) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_DE) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3244,7 +3292,19 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x00000000001FD631ULL; + pcc->msr_mask = (1ull << 20) | + (1ull << MSR_KEY) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3291,7 +3351,18 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x00000000001FD231ULL; + pcc->msr_mask = (1ull << 20) | + (1ull << MSR_KEY) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_DE) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3330,7 +3401,15 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x000000000007D00DULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_PE) | + (1ull << MSR_PX) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3389,7 +3468,15 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_40x_EXCP; - pcc->msr_mask = 0x000000000007D00DULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_ME) | + (1ull << MSR_PE) | + (1ull << MSR_PX) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_4xx_Z; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_401; @@ -3447,7 +3534,15 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP; - pcc->msr_mask = 0x000000000006E630ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_SOFT_4xx; pcc->excp_model = POWERPC_EXCP_40x; pcc->bus_model = PPC_FLAGS_INPUT_405; @@ -3540,7 +3635,18 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -3612,7 +3718,18 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -3684,7 +3801,18 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -3774,7 +3902,18 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_MFTB | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -3870,7 +4009,18 @@ POWERPC_FAMILY(460)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -3969,7 +4119,18 @@ POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC; - pcc->msr_mask = 0x000000000006FF30ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4002,7 +4163,18 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | PPC_MFTB; - pcc->msr_mask = 0x000000000001FF43ULL; + pcc->msr_mask = (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_REAL; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_RCPU; @@ -4034,7 +4206,18 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MEM_EIEIO | PPC_MEM_SYNC | PPC_CACHE_ICBI | PPC_MFTB; - pcc->msr_mask = 0x000000000001F673ULL; + pcc->msr_mask = (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_MPC8xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_RCPU; @@ -4100,7 +4283,21 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000006FFF2ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_AL) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -4191,7 +4388,23 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000007FFF3ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_AL) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_G2; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -4249,8 +4462,8 @@ static void init_proc_e200 (CPUPPCState *env) 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", @@ -4331,7 +4544,20 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_BOOKE; - pcc->msr_mask = 0x000000000606FF30ULL; + pcc->msr_mask = (1ull << MSR_UCLE) | + (1ull << MSR_SPE) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4389,7 +4615,23 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000007FFF3ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_AL) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -4438,6 +4680,8 @@ static void init_proc_e500 (CPUPPCState *env, int version) uint64_t ivpr_mask = 0xFFFF0000ULL; uint32_t l1cfg0 = 0x3800 /* 8 ways */ | 0x0020; /* 32 kb */ + uint32_t l1cfg1 = 0x3800 /* 8 ways */ + | 0x0020; /* 32 kb */ #if !defined(CONFIG_USER_ONLY) int i; #endif @@ -4506,6 +4750,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) env->dcache_line_size = 64; env->icache_line_size = 64; l1cfg0 |= 0x1000000; /* 64 byte cache block size */ + l1cfg1 |= 0x1000000; /* 64 byte cache block size */ break; default: cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); @@ -4553,18 +4798,20 @@ static void init_proc_e500 (CPUPPCState *env, int version) 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, l1cfg0); - /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CFG1, "L1CFG1", + &spr_read_generic, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + l1cfg1); spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_e500_l1csr0, 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_e500_l1csr1, 0x00000000); spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", SPR_NOACCESS, SPR_NOACCESS, @@ -4628,7 +4875,20 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206; - pcc->msr_mask = 0x000000000606FF30ULL; + pcc->msr_mask = (1ull << MSR_UCLE) | + (1ull << MSR_SPE) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4658,7 +4918,20 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206; - pcc->msr_mask = 0x000000000606FF30ULL; + pcc->msr_mask = (1ull << MSR_UCLE) | + (1ull << MSR_SPE) | + (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4690,7 +4963,20 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL; - pcc->msr_mask = 0x000000001402FB36ULL; + pcc->msr_mask = (1ull << MSR_GS) | + (1ull << MSR_UCLE) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PX) | + (1ull << MSR_RI); pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4724,7 +5010,21 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206; - pcc->msr_mask = 0x000000009402FB36ULL; + pcc->msr_mask = (1ull << MSR_CM) | + (1ull << MSR_GS) | + (1ull << MSR_UCLE) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PX) | + (1ull << MSR_RI); pcc->mmu_model = POWERPC_MMU_BOOKE206; pcc->excp_model = POWERPC_EXCP_BOOKE; pcc->bus_model = PPC_FLAGS_INPUT_BookE; @@ -4746,7 +5046,17 @@ POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data) dc->desc = "POWER"; /* pcc->insns_flags = XXX_TODO; */ /* POWER RSC (from RAD6000) */ - pcc->msr_mask = 0x00000000FEF0ULL; + pcc->msr_mask = (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_AL) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR); } #define POWERPC_MSRR_601 (0x0000000000001040ULL) @@ -4801,7 +5111,16 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000000FD70ULL; + pcc->msr_mask = (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_601; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -4837,7 +5156,16 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000000FD70ULL; + pcc->msr_mask = (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR); pcc->mmu_model = POWERPC_MMU_601; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -4889,7 +5217,24 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_602_SPEC; - pcc->msr_mask = 0x0000000000C7FF73ULL; + pcc->msr_mask = (1ull << MSR_VSX) | + (1ull << MSR_SA) | + (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); /* XXX: 602 MMU is quite specific. Should add a special case */ pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_602; @@ -4941,7 +5286,22 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000007FF73ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -4992,7 +5352,22 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000007FF73ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_TGPR) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_603E; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -5037,7 +5412,22 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5054,17 +5444,17 @@ static void init_proc_604E (CPUPPCState *env) gen_spr_ne_601(env); gen_spr_604(env); /* XXX : not implemented */ - spr_register(env, SPR_MMCR1, "MMCR1", + spr_register(env, SPR_7XX_MMCR1, "MMCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC3, "PMC3", + spr_register(env, SPR_7XX_PMC3, "PMC3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC4, "PMC4", + spr_register(env, SPR_7XX_PMC4, "PMC4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -5105,7 +5495,22 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5160,7 +5565,22 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5223,7 +5643,22 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5409,7 +5844,22 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5476,7 +5926,22 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5548,7 +6013,22 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5620,7 +6100,22 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5683,7 +6178,22 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -5754,7 +6264,22 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | PPC_SEGMENT | PPC_EXTERN; - pcc->msr_mask = 0x000000000005FF77ULL; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_6xx; pcc->excp_model = POWERPC_EXCP_7x5; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -5812,7 +6337,23 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5880,7 +6421,23 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -5926,22 +6483,22 @@ static void init_proc_7440 (CPUPPCState *env) 0x00000000); /* PMC */ /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -5974,7 +6531,23 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -6043,22 +6616,22 @@ static void init_proc_7450 (CPUPPCState *env) 0x00000000); /* PMC */ /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -6091,7 +6664,23 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -6129,22 +6718,22 @@ static void init_proc_7445 (CPUPPCState *env) 0x00000000); /* PMC */ /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -6211,7 +6800,23 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -6251,22 +6856,22 @@ static void init_proc_7455 (CPUPPCState *env) 0x00000000); /* PMC */ /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -6333,7 +6938,23 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -6397,22 +7018,22 @@ static void init_proc_7457 (CPUPPCState *env) 0x00000000); /* PMC */ /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -6479,7 +7100,23 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) PPC_MEM_TLBIA | PPC_74xx_TLB | PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_SOFT_74xx; pcc->excp_model = POWERPC_EXCP_74xx; pcc->bus_model = PPC_FLAGS_INPUT_6xx; @@ -6518,22 +7155,22 @@ static void init_proc_e600 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC5, "PMC5", + spr_register(env, SPR_7XX_PMC5, "PMC5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC5, "UPMC5", + spr_register(env, SPR_7XX_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC6, "PMC6", + spr_register(env, SPR_7XX_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UPMC6, "UPMC6", + spr_register(env, SPR_7XX_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); @@ -6601,7 +7238,23 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data) PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; pcc->insns_flags2 = PPC_NONE; - pcc->msr_mask = 0x000000000205FF77ULL; + pcc->msr_mask = (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_ILE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_EP) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_32B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; @@ -6621,246 +7274,628 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data) #define POWERPC970_HID5_INIT 0x00000000 #endif +enum BOOK3S_CPU_TYPE { + BOOK3S_CPU_970, + BOOK3S_CPU_POWER5PLUS, + BOOK3S_CPU_POWER6, + BOOK3S_CPU_POWER7, + BOOK3S_CPU_POWER8 +}; + +static void gen_fscr_facility_check(void *opaque, int facility_sprn, int bit, + int sprn, int cause) +{ + TCGv_i32 t1 = tcg_const_i32(bit); + TCGv_i32 t2 = tcg_const_i32(sprn); + TCGv_i32 t3 = tcg_const_i32(cause); + + gen_update_current_nip(opaque); + gen_helper_fscr_facility_check(cpu_env, t1, t2, t3); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_msr_facility_check(void *opaque, int facility_sprn, int bit, + int sprn, int cause) +{ + TCGv_i32 t1 = tcg_const_i32(bit); + TCGv_i32 t2 = tcg_const_i32(sprn); + TCGv_i32 t3 = tcg_const_i32(cause); + + gen_update_current_nip(opaque); + gen_helper_msr_facility_check(cpu_env, t1, t2, t3); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void spr_read_prev_upper32(void *opaque, int gprn, int sprn) +{ + TCGv spr_up = tcg_temp_new(); + TCGv spr = tcg_temp_new(); + + gen_load_spr(spr, sprn - 1); + tcg_gen_shri_tl(spr_up, spr, 32); + tcg_gen_ext32u_tl(cpu_gpr[gprn], spr_up); + + tcg_temp_free(spr); + tcg_temp_free(spr_up); +} + +static void spr_write_prev_upper32(void *opaque, int sprn, int gprn) +{ + TCGv spr = tcg_temp_new(); + + gen_load_spr(spr, sprn - 1); + tcg_gen_deposit_tl(spr, spr, cpu_gpr[gprn], 32, 32); + gen_store_spr(sprn - 1, spr); + + tcg_temp_free(spr); +} + static int check_pow_970 (CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x00600000) + if (env->spr[SPR_HID0] & (HID0_DEEPNAP | HID0_DOZE | HID0_NAP)) { return 1; + } return 0; } -static void init_proc_970 (CPUPPCState *env) +static void gen_spr_970_hid(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_7xx(env); - /* Time base */ - gen_tbl(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, 0x60000000); - /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, POWERPC970_HID5_INIT); - /* Memory management */ - /* XXX: not correct */ - gen_low_BATs(env); +} + +static void gen_spr_970_hior(CPUPPCState *env) +{ spr_register(env, SPR_HIOR, "SPR_HIOR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_hior, &spr_write_hior, 0x00000000); -#if !defined(CONFIG_USER_ONLY) - env->slb_nr = 32; -#endif - init_excp_970(env); - env->dcache_line_size = 128; - env->icache_line_size = 128; - /* Allocate hardware IRQ controller */ - ppc970_irq_init(env); +} + +static void gen_spr_970_lpar(CPUPPCState *env) +{ + /* Logical partitionning */ + /* PPC970: HID4 is effectively the LPCR */ + spr_register(env, SPR_970_HID4, "HID4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void gen_spr_book3s_common(CPUPPCState *env) +{ + spr_register(env, SPR_CTRL, "SPR_CTRL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UCTRL, "SPR_UCTRL", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); +} + +static void gen_spr_book3s_altivec(CPUPPCState *env) +{ + if (!(env->insns_flags & PPC_ALTIVEC)) { + return; + } + + spr_register_kvm(env, SPR_VRSAVE, "VRSAVE", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_VRSAVE, 0x00000000); + /* Can't find information on what this should be on reset. This * value is the one used by 74xx processors. */ vscr_init(env, 0x00010000); } -POWERPC_FAMILY(970)(ObjectClass *oc, void *data) +static void gen_spr_book3s_dbg(CPUPPCState *env) { - DeviceClass *dc = DEVICE_CLASS(oc); - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + /* + * TODO: different specs define different scopes for these, + * will have to address this: + * 970: super/write and super/read + * powerisa 2.03..2.04: hypv/write and super/read. + * powerisa 2.05 and newer: hypv/write and hypv/read. + */ + spr_register_kvm(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DABR, 0x00000000); + spr_register_kvm(env, SPR_DABRX, "DABRX", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DABRX, 0x00000000); +} - dc->desc = "PowerPC 970"; - pcc->init_proc = init_proc_970; - pcc->check_pow = check_pow_970; - pcc->insns_flags = 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_DCBZ | - PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | - PPC_64B | PPC_ALTIVEC | - PPC_SEGMENT_64B | PPC_SLBI; - pcc->msr_mask = 0x900000000204FF36ULL; - pcc->mmu_model = POWERPC_MMU_64B; -#if defined(CONFIG_SOFTMMU) - pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; -#endif - pcc->excp_model = POWERPC_EXCP_970; - pcc->bus_model = PPC_FLAGS_INPUT_970; - pcc->bfd_mach = bfd_mach_ppc64; - pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | - POWERPC_FLAG_BUS_CLK; - pcc->l1_dcache_size = 0x8000; - pcc->l1_icache_size = 0x10000; +static void gen_spr_970_dbg(CPUPPCState *env) +{ + /* Breakpoints */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } -static int check_pow_970FX (CPUPPCState *env) +static void gen_spr_book3s_pmu_sup(CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x00600000) - return 1; + spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_MMCR0, 0x00000000); + spr_register_kvm(env, SPR_POWER_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_MMCR1, 0x00000000); + spr_register_kvm(env, SPR_POWER_MMCRA, "MMCRA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_MMCRA, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC1, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC1, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC2, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC2, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC3, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC4, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC5, 0x00000000); + spr_register_kvm(env, SPR_POWER_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC6, 0x00000000); + spr_register_kvm(env, SPR_POWER_SIAR, "SIAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_SIAR, 0x00000000); + spr_register_kvm(env, SPR_POWER_SDAR, "SDAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_SDAR, 0x00000000); +} - return 0; +static void gen_spr_book3s_pmu_user(CPUPPCState *env) +{ + spr_register(env, SPR_POWER_UMMCR0, "UMMCR0", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UMMCR1, "UMMCR1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UMMCRA, "UMMCRA", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC1, "UPMC1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC2, "UPMC2", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC3, "UPMC3", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC4, "UPMC4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_USIAR, "USIAR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); + spr_register(env, SPR_POWER_USDAR, "USDAR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); } -static void init_proc_970FX (CPUPPCState *env) +static void gen_spr_970_pmu_sup(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_7xx(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_clear, - 0x60000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + spr_register_kvm(env, SPR_970_PMC7, "PMC7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC7, 0x00000000); + spr_register_kvm(env, SPR_970_PMC8, "PMC8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PMC8, 0x00000000); +} + +static void gen_spr_970_pmu_user(CPUPPCState *env) +{ + spr_register(env, SPR_970_UPMC7, "UPMC7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_970_HID5, "HID5", + spr_register(env, SPR_970_UPMC8, "UPMC8", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); +} + +static void gen_spr_power8_pmu_sup(CPUPPCState *env) +{ + spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_MMCR2, 0x00000000); + spr_register_kvm(env, SPR_POWER_MMCRS, "MMCRS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_MMCRS, 0x00000000); +} + +static void gen_spr_power8_pmu_user(CPUPPCState *env) +{ + spr_register(env, SPR_POWER_UMMCR2, "UMMCR2", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, &spr_write_ureg, + 0x00000000); +} + +static void gen_spr_power5p_ear(CPUPPCState *env) +{ + /* External access control */ + spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - POWERPC970_HID5_INIT); - /* Memory management */ - /* XXX: not correct */ - gen_low_BATs(env); - spr_register(env, SPR_HIOR, "SPR_HIOR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_hior, &spr_write_hior, 0x00000000); - spr_register(env, SPR_CTRL, "SPR_CTRL", +} + +static void gen_spr_power5p_lpar(CPUPPCState *env) +{ + /* Logical partitionning */ + spr_register_kvm(env, SPR_LPCR, "LPCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_LPCR, 0x00000000); +} + +static void gen_spr_book3s_ids(CPUPPCState *env) +{ + /* Processor identification */ + spr_register(env, SPR_PIR, "PIR", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + &spr_read_generic, &spr_write_pir, 0x00000000); - spr_register(env, SPR_UCTRL, "SPR_UCTRL", +} + +static void gen_spr_power8_ids(CPUPPCState *env) +{ + /* Thread identification */ + spr_register(env, SPR_TIR, "TIR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", - &spr_read_generic, &spr_write_generic, - &spr_read_generic, &spr_write_generic, - 0x00000000); +} + +static void gen_spr_book3s_purr(CPUPPCState *env) +{ #if !defined(CONFIG_USER_ONLY) - env->slb_nr = 64; + /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ + spr_register_kvm(env, SPR_PURR, "PURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + KVM_REG_PPC_PURR, 0x00000000); + spr_register_kvm(env, SPR_SPURR, "SPURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + KVM_REG_PPC_SPURR, 0x00000000); #endif - init_excp_970(env); - env->dcache_line_size = 128; - env->icache_line_size = 128; - /* Allocate hardware IRQ controller */ - ppc970_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); } -POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) +static void gen_spr_power6_dbg(CPUPPCState *env) { - DeviceClass *dc = DEVICE_CLASS(oc); - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - - dc->desc = "PowerPC 970FX (aka G5)"; - pcc->init_proc = init_proc_970FX; - pcc->check_pow = check_pow_970FX; - pcc->insns_flags = 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_DCBZ | - PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | - PPC_64B | PPC_ALTIVEC | - PPC_SEGMENT_64B | PPC_SLBI; - pcc->msr_mask = 0x800000000204FF36ULL; - pcc->mmu_model = POWERPC_MMU_64B; -#if defined(CONFIG_SOFTMMU) - pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#if !defined(CONFIG_USER_ONLY) + spr_register(env, SPR_CFAR, "SPR_CFAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_cfar, &spr_write_cfar, + 0x00000000); #endif - pcc->excp_model = POWERPC_EXCP_970; - pcc->bus_model = PPC_FLAGS_INPUT_970; - pcc->bfd_mach = bfd_mach_ppc64; - pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | - POWERPC_FLAG_BUS_CLK; - pcc->l1_dcache_size = 0x8000; - pcc->l1_icache_size = 0x10000; } -static int check_pow_970MP (CPUPPCState *env) +static void gen_spr_power5p_common(CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x01C00000) - return 1; - - return 0; + spr_register_kvm(env, SPR_PPR, "PPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_PPR, 0x00000000); } -static void init_proc_970MP (CPUPPCState *env) +static void gen_spr_power6_common(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_7xx(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", +#if !defined(CONFIG_USER_ONLY) + spr_register_kvm(env, SPR_DSCR, "SPR_DSCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DSCR, 0x00000000); +#endif + /* + * Register PCR to report POWERPC_EXCP_PRIV_REG instead of + * POWERPC_EXCP_INVAL_SPR. + */ + spr_register(env, SPR_PCR, "PCR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_clear, - 0x60000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, + 0x00000000); +} + +static void spr_read_tar(void *opaque, int gprn, int sprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); + spr_read_generic(opaque, gprn, sprn); +} + +static void spr_write_tar(void *opaque, int sprn, int gprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR); + spr_write_generic(opaque, sprn, gprn); +} + +static void gen_spr_power8_tce_address_control(CPUPPCState *env) +{ + spr_register(env, SPR_TAR, "TAR", + &spr_read_tar, &spr_write_tar, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_970_HID5, "HID5", - SPR_NOACCESS, SPR_NOACCESS, +} + +static void spr_read_tm(void *opaque, int gprn, int sprn) +{ + gen_msr_facility_check(opaque, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_read_generic(opaque, gprn, sprn); +} + +static void spr_write_tm(void *opaque, int sprn, int gprn) +{ + gen_msr_facility_check(opaque, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_write_generic(opaque, sprn, gprn); +} + +static void spr_read_tm_upper32(void *opaque, int gprn, int sprn) +{ + gen_msr_facility_check(opaque, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_read_prev_upper32(opaque, gprn, sprn); +} + +static void spr_write_tm_upper32(void *opaque, int sprn, int gprn) +{ + gen_msr_facility_check(opaque, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM); + spr_write_prev_upper32(opaque, sprn, gprn); +} + +static void gen_spr_power8_tm(CPUPPCState *env) +{ + spr_register_kvm(env, SPR_TFHAR, "TFHAR", + &spr_read_tm, &spr_write_tm, + &spr_read_tm, &spr_write_tm, + KVM_REG_PPC_TFHAR, 0x00000000); + spr_register_kvm(env, SPR_TFIAR, "TFIAR", + &spr_read_tm, &spr_write_tm, + &spr_read_tm, &spr_write_tm, + KVM_REG_PPC_TFIAR, 0x00000000); + spr_register_kvm(env, SPR_TEXASR, "TEXASR", + &spr_read_tm, &spr_write_tm, + &spr_read_tm, &spr_write_tm, + KVM_REG_PPC_TEXASR, 0x00000000); + spr_register(env, SPR_TEXASRU, "TEXASRU", + &spr_read_tm_upper32, &spr_write_tm_upper32, + &spr_read_tm_upper32, &spr_write_tm_upper32, + 0x00000000); +} + +static void spr_read_ebb(void *opaque, int gprn, int sprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_read_generic(opaque, gprn, sprn); +} + +static void spr_write_ebb(void *opaque, int sprn, int gprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_write_generic(opaque, sprn, gprn); +} + +static void spr_read_ebb_upper32(void *opaque, int gprn, int sprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_read_prev_upper32(opaque, gprn, sprn); +} + +static void spr_write_ebb_upper32(void *opaque, int sprn, int gprn) +{ + gen_fscr_facility_check(opaque, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB); + spr_write_prev_upper32(opaque, sprn, gprn); +} + +static void gen_spr_power8_ebb(CPUPPCState *env) +{ + spr_register(env, SPR_BESCRS, "BESCRS", + &spr_read_ebb, &spr_write_ebb, &spr_read_generic, &spr_write_generic, - POWERPC970_HID5_INIT); - /* XXX : not implemented */ - /* Memory management */ - /* XXX: not correct */ - gen_low_BATs(env); - spr_register(env, SPR_HIOR, "SPR_HIOR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_hior, &spr_write_hior, 0x00000000); - /* Logical partitionning */ - spr_register_kvm(env, SPR_LPCR, "LPCR", + spr_register(env, SPR_BESCRSU, "BESCRSU", + &spr_read_ebb_upper32, &spr_write_ebb_upper32, + &spr_read_prev_upper32, &spr_write_prev_upper32, + 0x00000000); + spr_register(env, SPR_BESCRR, "BESCRR", + &spr_read_ebb, &spr_write_ebb, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BESCRRU, "BESCRRU", + &spr_read_ebb_upper32, &spr_write_ebb_upper32, + &spr_read_prev_upper32, &spr_write_prev_upper32, + 0x00000000); + spr_register_kvm(env, SPR_EBBHR, "EBBHR", + &spr_read_ebb, &spr_write_ebb, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_EBBHR, 0x00000000); + spr_register_kvm(env, SPR_EBBRR, "EBBRR", + &spr_read_ebb, &spr_write_ebb, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_EBBRR, 0x00000000); + spr_register_kvm(env, SPR_BESCR, "BESCR", + &spr_read_ebb, &spr_write_ebb, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_BESCR, 0x00000000); +} + +static void gen_spr_power8_fscr(CPUPPCState *env) +{ +#if defined(CONFIG_USER_ONLY) + target_ulong initval = 1ULL << FSCR_TAR; +#else + target_ulong initval = 0; +#endif + spr_register_kvm(env, SPR_FSCR, "FSCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_LPCR, 0x00000000); + KVM_REG_PPC_FSCR, initval); +} + +static void init_proc_book3s_64(CPUPPCState *env, int version) +{ + gen_spr_ne_601(env); + gen_tbl(env); + gen_spr_book3s_altivec(env); + gen_spr_book3s_pmu_sup(env); + gen_spr_book3s_pmu_user(env); + gen_spr_book3s_common(env); + + switch (version) { + case BOOK3S_CPU_970: + case BOOK3S_CPU_POWER5PLUS: + gen_spr_970_hid(env); + gen_spr_970_hior(env); + gen_low_BATs(env); + gen_spr_970_pmu_sup(env); + gen_spr_970_pmu_user(env); + break; + case BOOK3S_CPU_POWER7: + case BOOK3S_CPU_POWER8: + gen_spr_book3s_ids(env); + gen_spr_amr(env); + gen_spr_book3s_purr(env); + break; + default: + g_assert_not_reached(); + } + if (version >= BOOK3S_CPU_POWER5PLUS) { + gen_spr_power5p_common(env); + gen_spr_power5p_lpar(env); + gen_spr_power5p_ear(env); + } else { + gen_spr_970_lpar(env); + } + if (version == BOOK3S_CPU_970) { + gen_spr_970_dbg(env); + } + if (version >= BOOK3S_CPU_POWER6) { + gen_spr_power6_common(env); + gen_spr_power6_dbg(env); + } + if (version >= BOOK3S_CPU_POWER8) { + gen_spr_power8_tce_address_control(env); + gen_spr_power8_ids(env); + gen_spr_power8_ebb(env); + gen_spr_power8_fscr(env); + gen_spr_power8_pmu_sup(env); + gen_spr_power8_pmu_user(env); + gen_spr_power8_tm(env); + } + if (version < BOOK3S_CPU_POWER8) { + gen_spr_book3s_dbg(env); + } #if !defined(CONFIG_USER_ONLY) - env->slb_nr = 32; + switch (version) { + case BOOK3S_CPU_970: + case BOOK3S_CPU_POWER5PLUS: + env->slb_nr = 64; + break; + case BOOK3S_CPU_POWER7: + case BOOK3S_CPU_POWER8: + default: + env->slb_nr = 32; + break; + } #endif - init_excp_970(env); + /* Allocate hardware IRQ controller */ + switch (version) { + case BOOK3S_CPU_970: + case BOOK3S_CPU_POWER5PLUS: + init_excp_970(env); + ppc970_irq_init(env); + break; + case BOOK3S_CPU_POWER7: + case BOOK3S_CPU_POWER8: + init_excp_POWER7(env); + ppcPOWER7_irq_init(env); + break; + default: + g_assert_not_reached(); + } + env->dcache_line_size = 128; env->icache_line_size = 128; - /* Allocate hardware IRQ controller */ - ppc970_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); } -POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) +static void init_proc_970(CPUPPCState *env) +{ + init_proc_book3s_64(env, BOOK3S_CPU_970); +} + +POWERPC_FAMILY(970)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - dc->desc = "PowerPC 970 MP"; - pcc->init_proc = init_proc_970MP; - pcc->check_pow = check_pow_970MP; + dc->desc = "PowerPC 970"; + pcc->init_proc = init_proc_970; + pcc->check_pow = check_pow_970; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6870,7 +7905,21 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; - pcc->msr_mask = 0x900000000204FF36ULL; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI); pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -6887,61 +7936,7 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) static void init_proc_power5plus(CPUPPCState *env) { - gen_spr_ne_601(env); - gen_spr_7xx(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_clear, - 0x60000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_970_HID5, "HID5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - POWERPC970_HID5_INIT); - /* Memory management */ - /* XXX: not correct */ - gen_low_BATs(env); - spr_register(env, SPR_HIOR, "SPR_HIOR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_hior, &spr_write_hior, - 0x00000000); - spr_register(env, SPR_CTRL, "SPR_CTRL", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_UCTRL, "SPR_UCTRL", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", - &spr_read_generic, &spr_write_generic, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Logical partitionning */ - spr_register_kvm(env, SPR_LPCR, "LPCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_LPCR, 0x00000000); -#if !defined(CONFIG_USER_ONLY) - env->slb_nr = 64; -#endif - init_excp_970(env); - env->dcache_line_size = 128; - env->icache_line_size = 128; - /* Allocate hardware IRQ controller */ - ppc970_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); + init_proc_book3s_64(env, BOOK3S_CPU_POWER5PLUS); } POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) @@ -6952,7 +7947,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER5"; dc->desc = "POWER5+"; pcc->init_proc = init_proc_power5plus; - pcc->check_pow = check_pow_970FX; + pcc->check_pow = check_pow_970; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6962,7 +7957,21 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | PPC_SEGMENT_64B | PPC_SLBI; - pcc->msr_mask = 0x800000000204FF36ULL; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_VR) | + (1ull << MSR_POW) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI); pcc->mmu_model = POWERPC_MMU_64B; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -6977,83 +7986,79 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) pcc->l1_icache_size = 0x10000; } -static void init_proc_POWER7 (CPUPPCState *env) +static void powerpc_get_compat(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) { - gen_spr_ne_601(env); - gen_spr_7xx(env); - /* Time base */ - gen_tbl(env); - /* Processor identification */ - spr_register(env, SPR_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, - 0x00000000); -#if !defined(CONFIG_USER_ONLY) - /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ - spr_register_kvm(env, SPR_PURR, "PURR", - &spr_read_purr, SPR_NOACCESS, - &spr_read_purr, SPR_NOACCESS, - KVM_REG_PPC_PURR, 0x00000000); - spr_register_kvm(env, SPR_SPURR, "SPURR", - &spr_read_purr, SPR_NOACCESS, - &spr_read_purr, SPR_NOACCESS, - KVM_REG_PPC_SPURR, 0x00000000); - spr_register(env, SPR_CFAR, "SPR_CFAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_cfar, &spr_write_cfar, - 0x00000000); - spr_register_kvm(env, SPR_DSCR, "SPR_DSCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_DSCR, 0x00000000); - spr_register_kvm(env, SPR_MMCRA, "SPR_MMCRA", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_MMCRA, 0x00000000); - spr_register_kvm(env, SPR_PMC5, "SPR_PMC5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_PMC5, 0x00000000); - spr_register_kvm(env, SPR_PMC6, "SPR_PMC6", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_PMC6, 0x00000000); -#endif /* !CONFIG_USER_ONLY */ - gen_spr_amr(env); - /* XXX : not implemented */ - spr_register(env, SPR_CTRL, "SPR_CTRLT", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, - 0x80800000); - spr_register(env, SPR_UCTRL, "SPR_CTRLF", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x80800000); - spr_register(env, SPR_VRSAVE, "SPR_VRSAVE", - &spr_read_generic, &spr_write_generic, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_PPR, "PPR", - &spr_read_generic, &spr_write_generic, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Logical partitionning */ - spr_register_kvm(env, SPR_LPCR, "LPCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_LPCR, 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; + char *value = (char *)""; + Property *prop = opaque; + uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop); - /* 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); + switch (*max_compat) { + case CPU_POWERPC_LOGICAL_2_05: + value = (char *)"power6"; + break; + case CPU_POWERPC_LOGICAL_2_06: + value = (char *)"power7"; + break; + case CPU_POWERPC_LOGICAL_2_07: + value = (char *)"power8"; + break; + case 0: + break; + default: + error_setg(errp, "Internal error: compat is set to %x", + max_compat ? *max_compat : -1); + break; + } + + visit_type_str(v, &value, name, errp); +} + +static void powerpc_set_compat(Object *obj, Visitor *v, + void *opaque, const char *name, Error **errp) +{ + Error *error = NULL; + char *value = NULL; + Property *prop = opaque; + uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop); + + visit_type_str(v, &value, name, &error); + if (error) { + error_propagate(errp, error); + return; + } + + if (strcmp(value, "power6") == 0) { + *max_compat = CPU_POWERPC_LOGICAL_2_05; + } else if (strcmp(value, "power7") == 0) { + *max_compat = CPU_POWERPC_LOGICAL_2_06; + } else if (strcmp(value, "power8") == 0) { + *max_compat = CPU_POWERPC_LOGICAL_2_07; + } else { + error_setg(errp, "Invalid compatibility mode \"%s\"", value); + } + + g_free(value); +} + +static PropertyInfo powerpc_compat_propinfo = { + .name = "str", + .legacy_name = "powerpc-server-compat", + .get = powerpc_get_compat, + .set = powerpc_set_compat, +}; + +#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t) + +static Property powerpc_servercpu_properties[] = { + DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat), + DEFINE_PROP_END_OF_LIST(), +}; + +static void init_proc_POWER7 (CPUPPCState *env) +{ + init_proc_book3s_64(env, BOOK3S_CPU_POWER7); } POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) @@ -7063,8 +8068,10 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; + dc->props = powerpc_servercpu_properties; pcc->pvr = CPU_POWERPC_POWER7_BASE; pcc->pvr_mask = CPU_POWERPC_POWER7_MASK; + pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | @@ -7083,7 +8090,22 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206; - pcc->msr_mask = 0x800000000280FF37ULL; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_VR) | + (1ull << MSR_VSX) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_2_06; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -7097,6 +8119,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) POWERPC_FLAG_VSX; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; + pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; } POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data) @@ -7106,8 +8129,10 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER7+"; dc->desc = "POWER7+"; + dc->props = powerpc_servercpu_properties; pcc->pvr = CPU_POWERPC_POWER7P_BASE; pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK; + pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | @@ -7126,7 +8151,22 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data) PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206; - pcc->msr_mask = 0x800000000280FF37ULL; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_VR) | + (1ull << MSR_VSX) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_2_06; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -7140,18 +8180,12 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data) POWERPC_FLAG_VSX; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; + pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; } static void init_proc_POWER8(CPUPPCState *env) { - /* inherit P7 */ - init_proc_POWER7(env); - - /* P8 supports the TAR */ - spr_register(env, SPR_TAR, "TAR", - &spr_read_generic, &spr_write_generic, - &spr_read_generic, &spr_write_generic, - 0x00000000); + init_proc_book3s_64(env, BOOK3S_CPU_POWER8); } POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) @@ -7161,8 +8195,10 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; + dc->props = powerpc_servercpu_properties; pcc->pvr = CPU_POWERPC_POWER8_BASE; pcc->pvr_mask = CPU_POWERPC_POWER8_MASK; + pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06; pcc->init_proc = init_proc_POWER8; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | @@ -7183,7 +8219,23 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_ISA205 | PPC2_ISA207S; - pcc->msr_mask = 0x800000000280FF37ULL; + pcc->msr_mask = (1ull << MSR_SF) | + (1ull << MSR_TM) | + (1ull << MSR_VR) | + (1ull << MSR_VSX) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_SE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR) | + (1ull << MSR_PMM) | + (1ull << MSR_RI) | + (1ull << MSR_LE); pcc->mmu_model = POWERPC_MMU_2_06; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -7197,6 +8249,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) POWERPC_FLAG_VSX; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; + pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; } #endif /* defined (TARGET_PPC64) */ @@ -8083,6 +9136,63 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp) } } +int ppc_get_compat_smt_threads(PowerPCCPU *cpu) +{ + int ret = smp_threads; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + + switch (cpu->cpu_version) { + case CPU_POWERPC_LOGICAL_2_05: + ret = 2; + break; + case CPU_POWERPC_LOGICAL_2_06: + ret = 4; + break; + case CPU_POWERPC_LOGICAL_2_07: + ret = 8; + break; + default: + if (pcc->pcr_mask & PCR_COMPAT_2_06) { + ret = 4; + } else if (pcc->pcr_mask & PCR_COMPAT_2_05) { + ret = 2; + } + break; + } + + return MIN(ret, smp_threads); +} + +int ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version) +{ + int ret = 0; + CPUPPCState *env = &cpu->env; + + cpu->cpu_version = cpu_version; + + switch (cpu_version) { + case CPU_POWERPC_LOGICAL_2_05: + env->spr[SPR_PCR] = PCR_COMPAT_2_05; + break; + case CPU_POWERPC_LOGICAL_2_06: + env->spr[SPR_PCR] = PCR_COMPAT_2_06; + break; + case CPU_POWERPC_LOGICAL_2_06_PLUS: + env->spr[SPR_PCR] = PCR_COMPAT_2_06; + break; + default: + env->spr[SPR_PCR] = 0; + break; + } + + if (kvm_enabled() && kvmppc_set_compat(cpu, cpu->max_compat) < 0) { + error_report("Unable to set compatibility mode in KVM"); + ret = -1; + } + + return ret; +} + static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) { ObjectClass *oc = (ObjectClass *)a; @@ -8218,12 +9328,6 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) } } - for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { - if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) { - return ppc_cpu_class_by_alias(&ppc_cpu_aliases[i]); - } - } - list = object_class_get_list(TYPE_POWERPC_CPU, false); item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); if (item != NULL) { @@ -8231,7 +9335,17 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) } g_slist_free(list); - return ret; + if (ret) { + return ret; + } + + for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { + if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) { + return ppc_cpu_class_by_alias(&ppc_cpu_aliases[i]); + } + } + + return NULL; } PowerPCCPU *cpu_ppc_init(const char *cpu_model) @@ -8416,8 +9530,15 @@ static void ppc_cpu_reset(CPUState *s) #if defined(CONFIG_USER_ONLY) msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ 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 */ +#endif +#if !defined(TARGET_WORDS_BIGENDIAN) + msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ +#endif #endif #if defined(TARGET_PPC64) @@ -8519,6 +9640,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) pcc->parent_realize = dc->realize; pcc->pvr = CPU_POWERPC_DEFAULT_MASK; pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK; + pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_always; dc->realize = ppc_cpu_realizefn; dc->unrealize = ppc_cpu_unrealizefn; |