Index: stable/12/sys/conf/files.powerpc =================================================================== --- stable/12/sys/conf/files.powerpc (revision 342781) +++ stable/12/sys/conf/files.powerpc (revision 342782) @@ -1,277 +1,277 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # # font.h optional sc \ compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" # # There is only an asm version on ppc64. cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs powerpc | dtrace powerpc | zfs powerpcspe | dtrace powerpcspe compile-with "${ZFS_C}" cddl/contrib/opensolaris/common/atomic/powerpc64/opensolaris_atomic.S optional zfs powerpc64 | dtrace powerpc64 compile-with "${ZFS_S}" cddl/dev/dtrace/powerpc/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" cddl/dev/dtrace/powerpc/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" cddl/dev/fbt/powerpc/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" crypto/blowfish/bf_enc.c optional crypto | ipsec | ipsec_support crypto/des/des_enc.c optional crypto | ipsec | ipsec_support | netsmb dev/bm/if_bm.c optional bm powermac dev/adb/adb_bus.c optional adb dev/adb/adb_kbd.c optional adb dev/adb/adb_mouse.c optional adb dev/adb/adb_hb_if.m optional adb dev/adb/adb_if.m optional adb dev/adb/adb_buttons.c optional adb dev/agp/agp_apple.c optional agp powermac dev/fb/fb.c optional sc dev/hwpmc/hwpmc_e500.c optional hwpmc dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc dev/hwpmc/hwpmc_powerpc.c optional hwpmc dev/hwpmc/hwpmc_ppc970.c optional hwpmc dev/iicbus/ad7417.c optional ad7417 powermac dev/iicbus/adm1030.c optional powermac windtunnel | adm1030 powermac dev/iicbus/adt746x.c optional adt746x powermac dev/iicbus/ds1631.c optional ds1631 powermac dev/iicbus/ds1775.c optional ds1775 powermac dev/iicbus/max6690.c optional max6690 powermac dev/iicbus/ofw_iicbus.c optional iicbus aim dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_opal.c optional powernv ipmi dev/nand/nfc_fsl.c optional nand mpc85xx dev/nand/nfc_rb.c optional nand mpc85xx # Most ofw stuff below is brought in by conf/files for options FDT, but # we always want it, even on non-FDT platforms. dev/fdt/simplebus.c standard dev/ofw/openfirm.c standard dev/ofw/openfirmio.c standard dev/ofw/ofw_bus_if.m standard dev/ofw/ofw_cpu.c standard dev/ofw/ofw_if.m standard dev/ofw/ofw_bus_subr.c standard dev/ofw/ofw_console.c optional aim dev/ofw/ofw_disk.c optional ofwd aim dev/ofw/ofwbus.c standard dev/ofw/ofwpci.c optional pci dev/ofw/ofw_standard.c optional aim powerpc dev/ofw/ofw_subr.c standard dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx dev/random/darn.c optional powerpc64 random dev/scc/scc_bfe_macio.c optional scc powermac dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci dev/sec/sec.c optional sec mpc85xx dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac dev/sound/macio/davbus.c optional snd_davbus powermac dev/sound/macio/i2s.c optional snd_ai2s powermac dev/sound/macio/onyx.c optional snd_ai2s iicbus powermac dev/sound/macio/snapper.c optional snd_ai2s iicbus powermac dev/sound/macio/tumbler.c optional snd_ai2s iicbus powermac dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc dev/tsec/if_tsec.c optional tsec dev/tsec/if_tsec_fdt.c optional tsec dev/uart/uart_cpu_powerpc.c optional uart dev/usb/controller/ehci_fsl.c optional ehci mpc85xx dev/vt/hw/ofwfb/ofwfb.c optional vt aim kern/kern_clocksource.c standard kern/subr_dummy_vdso_tc.c standard kern/syscalls.c optional ktr kern/subr_sfbuf.c standard libkern/ashldi3.c optional powerpc | powerpcspe libkern/ashrdi3.c optional powerpc | powerpcspe libkern/bcmp.c standard libkern/bcopy.c standard libkern/cmpdi2.c optional powerpc | powerpcspe libkern/divdi3.c optional powerpc | powerpcspe libkern/ffs.c standard libkern/ffsl.c standard libkern/ffsll.c standard libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/lshrdi3.c optional powerpc | powerpcspe libkern/memcmp.c standard libkern/memset.c standard libkern/moddi3.c optional powerpc | powerpcspe libkern/qdivrem.c optional powerpc | powerpcspe libkern/ucmpdi2.c optional powerpc | powerpcspe libkern/udivdi3.c optional powerpc | powerpcspe libkern/umoddi3.c optional powerpc | powerpcspe powerpc/aim/isa3_hashtb.c optional aim powerpc64 powerpc/aim/locore.S optional aim no-obj powerpc/aim/aim_machdep.c optional aim powerpc/aim/mmu_oea.c optional aim powerpc powerpc/aim/mmu_oea64.c optional aim powerpc/aim/moea64_if.m optional aim powerpc/aim/moea64_native.c optional aim powerpc/aim/mp_cpudep.c optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/booke/locore.S optional booke no-obj powerpc/booke/booke_machdep.c optional booke powerpc/booke/machdep_e500.c optional booke_e500 powerpc/booke/mp_cpudep.c optional booke smp powerpc/booke/platform_bare.c optional booke powerpc/booke/pmap.c optional booke powerpc/booke/spe.c optional powerpcspe powerpc/cpufreq/dfs.c optional cpufreq powerpc/cpufreq/mpc85xx_jog.c optional cpufreq mpc85xx powerpc/cpufreq/pcr.c optional cpufreq aim powerpc/cpufreq/pmcr.c optional cpufreq aim powerpc64 powerpc/cpufreq/pmufreq.c optional cpufreq aim pmu -powerpc/fpu/fpu_add.c optional fpu_emu -powerpc/fpu/fpu_compare.c optional fpu_emu -powerpc/fpu/fpu_div.c optional fpu_emu +powerpc/fpu/fpu_add.c optional fpu_emu | powerpcspe +powerpc/fpu/fpu_compare.c optional fpu_emu | powerpcspe +powerpc/fpu/fpu_div.c optional fpu_emu | powerpcspe powerpc/fpu/fpu_emu.c optional fpu_emu -powerpc/fpu/fpu_explode.c optional fpu_emu -powerpc/fpu/fpu_implode.c optional fpu_emu -powerpc/fpu/fpu_mul.c optional fpu_emu +powerpc/fpu/fpu_explode.c optional fpu_emu | powerpcspe +powerpc/fpu/fpu_implode.c optional fpu_emu | powerpcspe +powerpc/fpu/fpu_mul.c optional fpu_emu | powerpcspe powerpc/fpu/fpu_sqrt.c optional fpu_emu -powerpc/fpu/fpu_subr.c optional fpu_emu +powerpc/fpu/fpu_subr.c optional fpu_emu | powerpcspe powerpc/mambo/mambocall.S optional mambo powerpc/mambo/mambo.c optional mambo powerpc/mambo/mambo_console.c optional mambo powerpc/mambo/mambo_disk.c optional mambo powerpc/mikrotik/platform_rb.c optional mikrotik powerpc/mikrotik/rb_led.c optional mikrotik powerpc/mpc85xx/atpic.c optional mpc85xx isa powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 powerpc/mpc85xx/ds1553_core.c optional ds1553 powerpc/mpc85xx/fsl_diu.c optional mpc85xx diu powerpc/mpc85xx/fsl_espi.c optional mpc85xx spibus powerpc/mpc85xx/fsl_sata.c optional mpc85xx ata powerpc/mpc85xx/i2c.c optional iicbus powerpc/mpc85xx/isa.c optional mpc85xx isa powerpc/mpc85xx/lbc.c optional mpc85xx powerpc/mpc85xx/mpc85xx.c optional mpc85xx powerpc/mpc85xx/mpc85xx_cache.c optional mpc85xx powerpc/mpc85xx/mpc85xx_gpio.c optional mpc85xx gpio powerpc/mpc85xx/platform_mpc85xx.c optional mpc85xx powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx powerpc/mpc85xx/pci_mpc85xx_pcib.c optional pci mpc85xx powerpc/mpc85xx/qoriq_gpio.c optional mpc85xx gpio powerpc/ofw/ofw_machdep.c standard powerpc/ofw/ofw_pcibus.c optional pci powerpc/ofw/ofw_pcib_pci.c optional pci powerpc/ofw/ofw_real.c optional aim powerpc/ofw/ofw_syscons.c optional sc aim powerpc/ofw/ofwcall32.S optional aim powerpc powerpc/ofw/ofwcall64.S optional aim powerpc64 powerpc/ofw/openpic_ofw.c standard powerpc/ofw/rtas.c optional aim powerpc/ofw/ofw_initrd.c optional md_root_mem powerpc64 powerpc/powermac/ata_kauai.c optional powermac ata | powermac atamacio powerpc/powermac/ata_macio.c optional powermac ata | powermac atamacio powerpc/powermac/ata_dbdma.c optional powermac ata | powermac atamacio powerpc/powermac/atibl.c optional powermac atibl powerpc/powermac/cuda.c optional powermac cuda powerpc/powermac/cpcht.c optional powermac pci powerpc/powermac/dbdma.c optional powermac pci powerpc/powermac/fcu.c optional powermac fcu powerpc/powermac/grackle.c optional powermac pci powerpc/powermac/hrowpic.c optional powermac pci powerpc/powermac/kiic.c optional powermac kiic powerpc/powermac/macgpio.c optional powermac pci powerpc/powermac/macio.c optional powermac pci powerpc/powermac/nvbl.c optional powermac nvbl powerpc/powermac/platform_powermac.c optional powermac powerpc/powermac/powermac_thermal.c optional powermac powerpc/powermac/pswitch.c optional powermac pswitch powerpc/powermac/pmu.c optional powermac pmu powerpc/powermac/smu.c optional powermac smu powerpc/powermac/smusat.c optional powermac smu powerpc/powermac/uninorth.c optional powermac powerpc/powermac/uninorthpci.c optional powermac pci powerpc/powermac/vcoregpio.c optional powermac powerpc/powernv/opal.c optional powernv powerpc/powernv/opal_console.c optional powernv powerpc/powernv/opal_dev.c optional powernv powerpc/powernv/opal_i2c.c optional iicbus fdt powernv powerpc/powernv/opal_i2cm.c optional iicbus fdt powernv powerpc/powernv/opal_pci.c optional powernv pci powerpc/powernv/opal_sensor.c optional powernv powerpc/powernv/opalcall.S optional powernv powerpc/powernv/platform_powernv.c optional powernv powerpc/powernv/powernv_centaur.c optional powernv powerpc/powernv/powernv_xscom.c optional powernv powerpc/powerpc/altivec.c optional powerpc | powerpc64 powerpc/powerpc/autoconf.c standard powerpc/powerpc/bus_machdep.c standard powerpc/powerpc/busdma_machdep.c standard powerpc/powerpc/clock.c standard powerpc/powerpc/copyinout.c standard powerpc/powerpc/copystr.c standard powerpc/powerpc/cpu.c standard powerpc/powerpc/cpu_subr64.S optional powerpc64 powerpc/powerpc/db_disasm.c optional ddb powerpc/powerpc/db_hwwatch.c optional ddb powerpc/powerpc/db_interface.c optional ddb powerpc/powerpc/db_trace.c optional ddb powerpc/powerpc/dump_machdep.c standard powerpc/powerpc/elf32_machdep.c optional powerpc | powerpcspe | compat_freebsd32 powerpc/powerpc/elf64_machdep.c optional powerpc64 powerpc/powerpc/exec_machdep.c standard powerpc/powerpc/fpu.c standard powerpc/powerpc/gdb_machdep.c optional gdb powerpc/powerpc/in_cksum.c optional inet | inet6 powerpc/powerpc/interrupt.c standard powerpc/powerpc/intr_machdep.c standard powerpc/powerpc/iommu_if.m standard powerpc/powerpc/machdep.c standard powerpc/powerpc/mem.c optional mem powerpc/powerpc/mmu_if.m standard powerpc/powerpc/mp_machdep.c optional smp powerpc/powerpc/nexus.c standard powerpc/powerpc/openpic.c standard powerpc/powerpc/pic_if.m standard powerpc/powerpc/pmap_dispatch.c standard powerpc/powerpc/platform.c standard powerpc/powerpc/platform_if.m standard powerpc/powerpc/ptrace_machdep.c standard powerpc/powerpc/sc_machdep.c optional sc powerpc/powerpc/setjmp.S standard powerpc/powerpc/sigcode32.S optional powerpc | powerpcspe | compat_freebsd32 powerpc/powerpc/sigcode64.S optional powerpc64 powerpc/powerpc/swtch32.S optional powerpc | powerpcspe powerpc/powerpc/swtch64.S optional powerpc64 powerpc/powerpc/stack_machdep.c optional ddb | stack powerpc/powerpc/syncicache.c standard powerpc/powerpc/sys_machdep.c standard powerpc/powerpc/trap.c standard powerpc/powerpc/uio_machdep.c standard powerpc/powerpc/uma_machdep.c standard powerpc/powerpc/vm_machdep.c standard powerpc/ps3/ehci_ps3.c optional ps3 ehci powerpc/ps3/ohci_ps3.c optional ps3 ohci powerpc/ps3/if_glc.c optional ps3 glc powerpc/ps3/mmu_ps3.c optional ps3 powerpc/ps3/platform_ps3.c optional ps3 powerpc/ps3/ps3bus.c optional ps3 powerpc/ps3/ps3cdrom.c optional ps3 scbus powerpc/ps3/ps3disk.c optional ps3 powerpc/ps3/ps3pic.c optional ps3 powerpc/ps3/ps3_syscons.c optional ps3 vt powerpc/ps3/ps3-hvcall.S optional ps3 powerpc/pseries/phyp-hvcall.S optional pseries powerpc64 powerpc/pseries/mmu_phyp.c optional pseries powerpc64 powerpc/pseries/phyp_console.c optional pseries powerpc64 uart powerpc/pseries/phyp_llan.c optional llan powerpc/pseries/phyp_vscsi.c optional pseries powerpc64 scbus powerpc/pseries/platform_chrp.c optional pseries powerpc/pseries/plpar_iommu.c optional pseries powerpc64 powerpc/pseries/plpar_pcibus.c optional pseries powerpc64 pci powerpc/pseries/rtas_dev.c optional pseries powerpc/pseries/rtas_pci.c optional pseries pci powerpc/pseries/vdevice.c optional pseries powerpc64 powerpc/pseries/xics.c optional pseries powerpc64 powerpc/psim/iobus.c optional psim powerpc/psim/ata_iobus.c optional ata psim powerpc/psim/openpic_iobus.c optional psim powerpc/psim/uart_iobus.c optional uart psim Index: stable/12/sys/powerpc/booke/spe.c =================================================================== --- stable/12/sys/powerpc/booke/spe.c (revision 342781) +++ stable/12/sys/powerpc/booke/spe.c (revision 342782) @@ -1,634 +1,682 @@ /*- * Copyright (C) 1996 Wolfgang Solfrank. * Copyright (C) 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include void spe_handle_fpdata(struct trapframe *); void spe_handle_fpround(struct trapframe *); static int spe_emu_instr(uint32_t, struct fpemu *, struct fpn **, uint32_t *); static void save_vec_int(struct thread *td) { int msr; struct pcb *pcb; pcb = td->td_pcb; /* * Temporarily re-enable the vector unit during the save */ msr = mfmsr(); mtmsr(msr | PSL_VEC); - isync(); /* * Save the vector registers and SPEFSCR to the PCB */ #define EVSTDW(n) __asm ("evstdw %1,0(%0)" \ :: "b"(pcb->pcb_vec.vr[n]), "n"(n)); EVSTDW(0); EVSTDW(1); EVSTDW(2); EVSTDW(3); EVSTDW(4); EVSTDW(5); EVSTDW(6); EVSTDW(7); EVSTDW(8); EVSTDW(9); EVSTDW(10); EVSTDW(11); EVSTDW(12); EVSTDW(13); EVSTDW(14); EVSTDW(15); EVSTDW(16); EVSTDW(17); EVSTDW(18); EVSTDW(19); EVSTDW(20); EVSTDW(21); EVSTDW(22); EVSTDW(23); EVSTDW(24); EVSTDW(25); EVSTDW(26); EVSTDW(27); EVSTDW(28); EVSTDW(29); EVSTDW(30); EVSTDW(31); #undef EVSTDW __asm ( "evxor 0,0,0\n" "evaddumiaaw 0,0\n" "evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.spare[0])); pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR); /* * Disable vector unit again */ isync(); mtmsr(msr); } void enable_vec(struct thread *td) { int msr; struct pcb *pcb; struct trapframe *tf; pcb = td->td_pcb; tf = trapframe(td); /* * Save the thread's SPE CPU number, and set the CPU's current * vector thread */ td->td_pcb->pcb_veccpu = PCPU_GET(cpuid); PCPU_SET(vecthread, td); /* * Enable the vector unit for when the thread returns from the * exception. If this is the first time the unit has been used by * the thread, initialise the vector registers and VSCR to 0, and * set the flag to indicate that the vector unit is in use. */ tf->srr1 |= PSL_VEC; if (!(pcb->pcb_flags & PCB_VEC)) { memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec); pcb->pcb_flags |= PCB_VEC; pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR); } /* * Temporarily enable the vector unit so the registers * can be restored. */ msr = mfmsr(); mtmsr(msr | PSL_VEC); /* Restore SPEFSCR and ACC. Use %r0 as the scratch for ACC. */ mtspr(SPR_SPEFSCR, pcb->pcb_vec.vscr); __asm __volatile("evldd 0, 0(%0); evmra 0,0\n" :: "b"(&pcb->pcb_vec.spare[0])); /* * The lower half of each register will be restored on trap return. Use * %r0 as a scratch register, and restore it last. */ #define EVLDW(n) __asm __volatile("evldw 0, 0(%0); evmergehilo "#n",0,"#n \ :: "b"(&pcb->pcb_vec.vr[n])); EVLDW(1); EVLDW(2); EVLDW(3); EVLDW(4); EVLDW(5); EVLDW(6); EVLDW(7); EVLDW(8); EVLDW(9); EVLDW(10); EVLDW(11); EVLDW(12); EVLDW(13); EVLDW(14); EVLDW(15); EVLDW(16); EVLDW(17); EVLDW(18); EVLDW(19); EVLDW(20); EVLDW(21); EVLDW(22); EVLDW(23); EVLDW(24); EVLDW(25); EVLDW(26); EVLDW(27); EVLDW(28); EVLDW(29); EVLDW(30); EVLDW(31); EVLDW(0); #undef EVLDW isync(); mtmsr(msr); } void save_vec(struct thread *td) { struct pcb *pcb; pcb = td->td_pcb; save_vec_int(td); /* * Clear the current vec thread and pcb's CPU id * XXX should this be left clear to allow lazy save/restore ? */ pcb->pcb_veccpu = INT_MAX; PCPU_SET(vecthread, NULL); } /* * Save SPE state without dropping ownership. This will only save state if * the current vector-thread is `td'. */ void save_vec_nodrop(struct thread *td) { struct thread *vtd; vtd = PCPU_GET(vecthread); if (td != vtd) { return; } save_vec_int(td); } #define SPE_INST_MASK 0x31f #define EADD 0x200 #define ESUB 0x201 #define EABS 0x204 #define ENABS 0x205 #define ENEG 0x206 #define EMUL 0x208 #define EDIV 0x209 #define ECMPGT 0x20c #define ECMPLT 0x20d #define ECMPEQ 0x20e #define ECFUI 0x210 #define ECFSI 0x211 #define ECTUI 0x214 #define ECTSI 0x215 #define ECTUF 0x216 #define ECTSF 0x217 #define ECTUIZ 0x218 #define ECTSIZ 0x21a #define SPE 0x4 #define SPFP 0x6 #define DPFP 0x7 #define SPE_OPC 4 #define OPC_SHIFT 26 #define EVFSADD 0x280 #define EVFSSUB 0x281 #define EVFSABS 0x284 #define EVFSNABS 0x285 #define EVFSNEG 0x286 #define EVFSMUL 0x288 #define EVFSDIV 0x289 #define EVFSCMPGT 0x28c #define EVFSCMPLT 0x28d #define EVFSCMPEQ 0x28e #define EVFSCFUI 0x290 #define EVFSCFSI 0x291 #define EVFSCTUI 0x294 #define EVFSCTSI 0x295 #define EVFSCTUF 0x296 #define EVFSCTSF 0x297 #define EVFSCTUIZ 0x298 #define EVFSCTSIZ 0x29a #define EFSADD 0x2c0 #define EFSSUB 0x2c1 #define EFSABS 0x2c4 #define EFSNABS 0x2c5 #define EFSNEG 0x2c6 #define EFSMUL 0x2c8 #define EFSDIV 0x2c9 #define EFSCMPGT 0x2cc #define EFSCMPLT 0x2cd #define EFSCMPEQ 0x2ce #define EFSCFD 0x2cf #define EFSCFUI 0x2d0 #define EFSCFSI 0x2d1 #define EFSCTUI 0x2d4 #define EFSCTSI 0x2d5 #define EFSCTUF 0x2d6 #define EFSCTSF 0x2d7 #define EFSCTUIZ 0x2d8 #define EFSCTSIZ 0x2da #define EFDADD 0x2e0 #define EFDSUB 0x2e1 #define EFDABS 0x2e4 #define EFDNABS 0x2e5 #define EFDNEG 0x2e6 #define EFDMUL 0x2e8 #define EFDDIV 0x2e9 #define EFDCMPGT 0x2ec #define EFDCMPLT 0x2ed #define EFDCMPEQ 0x2ee #define EFDCFS 0x2ef #define EFDCFUI 0x2f0 #define EFDCFSI 0x2f1 #define EFDCTUI 0x2f4 #define EFDCTSI 0x2f5 #define EFDCTUF 0x2f6 #define EFDCTSF 0x2f7 #define EFDCTUIZ 0x2f8 #define EFDCTSIZ 0x2fa enum { NONE, SINGLE, DOUBLE, VECTOR, }; static uint32_t fpscr_to_spefscr(uint32_t fpscr) { uint32_t spefscr; spefscr = 0; if (fpscr & FPSCR_VX) spefscr |= SPEFSCR_FINV; if (fpscr & FPSCR_OX) spefscr |= SPEFSCR_FOVF; if (fpscr & FPSCR_UX) spefscr |= SPEFSCR_FUNF; if (fpscr & FPSCR_ZX) spefscr |= SPEFSCR_FDBZ; if (fpscr & FPSCR_XX) spefscr |= SPEFSCR_FX; return (spefscr); } /* Sign is 0 for unsigned, 1 for signed. */ static int spe_to_int(struct fpemu *fpemu, struct fpn *fpn, uint32_t *val, int sign) { uint32_t res[2]; res[0] = fpu_ftox(fpemu, fpn, res); if (res[0] != UINT_MAX && res[0] != 0) fpemu->fe_cx |= FPSCR_OX; else if (sign == 0 && res[0] != 0) fpemu->fe_cx |= FPSCR_UX; else *val = res[1]; return (0); } /* Masked instruction */ /* * For compare instructions, returns 1 if success, 0 if not. For all others, * returns -1, or -2 if no result needs recorded. */ static int spe_emu_instr(uint32_t instr, struct fpemu *fpemu, struct fpn **result, uint32_t *iresult) { switch (instr & SPE_INST_MASK) { case EABS: case ENABS: case ENEG: /* Taken care of elsewhere. */ break; case ECTUIZ: fpemu->fe_cx &= ~FPSCR_RN; fpemu->fe_cx |= FP_RZ; case ECTUI: spe_to_int(fpemu, &fpemu->fe_f2, iresult, 0); return (-1); case ECTSIZ: fpemu->fe_cx &= ~FPSCR_RN; fpemu->fe_cx |= FP_RZ; case ECTSI: spe_to_int(fpemu, &fpemu->fe_f2, iresult, 1); return (-1); case EADD: *result = fpu_add(fpemu); break; case ESUB: *result = fpu_sub(fpemu); break; case EMUL: *result = fpu_mul(fpemu); break; case EDIV: *result = fpu_div(fpemu); break; case ECMPGT: fpu_compare(fpemu, 0); if (fpemu->fe_cx & FPSCR_FG) return (1); return (0); case ECMPLT: fpu_compare(fpemu, 0); if (fpemu->fe_cx & FPSCR_FL) return (1); return (0); case ECMPEQ: fpu_compare(fpemu, 0); if (fpemu->fe_cx & FPSCR_FE) return (1); return (0); default: printf("Unknown instruction %x\n", instr); } return (-1); } static int spe_explode(struct fpemu *fe, struct fpn *fp, uint32_t type, uint32_t hi, uint32_t lo) { uint32_t s; fp->fp_sign = hi >> 31; fp->fp_sticky = 0; switch (type) { case SINGLE: s = fpu_stof(fp, hi); break; case DOUBLE: s = fpu_dtof(fp, hi, lo); break; } if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) { /* * Input is a signalling NaN. All operations that return * an input NaN operand put it through a ``NaN conversion'', * which basically just means ``turn on the quiet bit''. * We do this here so that all NaNs internally look quiet * (we can tell signalling ones by their class). */ fp->fp_mant[0] |= FP_QUIETBIT; fe->fe_cx = FPSCR_VXSNAN; /* assert invalid operand */ s = FPC_SNAN; } fp->fp_class = s; return (0); } +/* + * Save the high word of a 64-bit GPR for manipulation in the exception handler. + */ +static uint32_t +spe_save_reg_high(int reg) +{ + uint32_t vec[2]; +#define EVSTDW(n) case n: __asm ("evstdw %1,0(%0)" \ + :: "b"(vec), "n"(n)); break; + switch (reg) { + EVSTDW(0); EVSTDW(1); EVSTDW(2); EVSTDW(3); + EVSTDW(4); EVSTDW(5); EVSTDW(6); EVSTDW(7); + EVSTDW(8); EVSTDW(9); EVSTDW(10); EVSTDW(11); + EVSTDW(12); EVSTDW(13); EVSTDW(14); EVSTDW(15); + EVSTDW(16); EVSTDW(17); EVSTDW(18); EVSTDW(19); + EVSTDW(20); EVSTDW(21); EVSTDW(22); EVSTDW(23); + EVSTDW(24); EVSTDW(25); EVSTDW(26); EVSTDW(27); + EVSTDW(28); EVSTDW(29); EVSTDW(30); EVSTDW(31); + } +#undef EVSTDW + + return (vec[0]); +} + +/* + * Load the given value into the high word of the requested register. + */ +static void +spe_load_reg_high(int reg, uint32_t val) +{ +#define EVLDW(n) case n: __asm __volatile("evmergelo "#n",%0,0," \ + :: "r"(val)); break; + switch (reg) { + EVLDW(1); EVLDW(2); EVLDW(3); EVLDW(4); + EVLDW(5); EVLDW(6); EVLDW(7); EVLDW(8); + EVLDW(9); EVLDW(10); EVLDW(11); EVLDW(12); + EVLDW(13); EVLDW(14); EVLDW(15); EVLDW(16); + EVLDW(17); EVLDW(18); EVLDW(19); EVLDW(20); + EVLDW(21); EVLDW(22); EVLDW(23); EVLDW(24); + EVLDW(25); EVLDW(26); EVLDW(27); EVLDW(28); + EVLDW(29); EVLDW(30); EVLDW(31); EVLDW(0); + } +#undef EVLDW + +} + void spe_handle_fpdata(struct trapframe *frame) { struct fpemu fpemu; struct fpn *result; uint32_t instr, instr_sec_op; uint32_t cr_shift, ra, rb, rd, src; - uint32_t high, low, res; /* For vector operations. */ + uint32_t high, low, res, tmp; /* For vector operations. */ uint32_t spefscr = 0; uint32_t ftod_res[2]; int width; /* Single, Double, Vector, Integer */ int err; + uint32_t msr; err = fueword32((void *)frame->srr0, &instr); if (err != 0) return; /* Fault. */; if ((instr >> OPC_SHIFT) != SPE_OPC) return; + msr = mfmsr(); /* * 'cr' field is the upper 3 bits of rd. Magically, since a) rd is 5 * bits, b) each 'cr' field is 4 bits, and c) Only the 'GT' bit is * modified for most compare operations, the full value of rd can be * used as a shift value. */ rd = (instr >> 21) & 0x1f; ra = (instr >> 16) & 0x1f; rb = (instr >> 11) & 0x1f; src = (instr >> 5) & 0x7; cr_shift = 28 - (rd & 0x1f); instr_sec_op = (instr & 0x7ff); memset(&fpemu, 0, sizeof(fpemu)); width = NONE; switch (src) { case SPE: - save_vec_nodrop(curthread); + mtmsr(msr | PSL_VEC); switch (instr_sec_op) { case EVFSABS: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] & ~(1U << 31); + high = spe_save_reg_high(ra) & ~(1U << 31); frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31); + spe_load_reg_high(rd, high); break; case EVFSNABS: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] | (1U << 31); + high = spe_save_reg_high(ra) | (1U << 31); frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31); + spe_load_reg_high(rd, high); break; case EVFSNEG: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] ^ (1U << 31); + high = spe_save_reg_high(ra) ^ (1U << 31); frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31); + spe_load_reg_high(rd, high); break; default: /* High word */ spe_explode(&fpemu, &fpemu.fe_f1, SINGLE, - curthread->td_pcb->pcb_vec.vr[ra][0], 0); + spe_save_reg_high(ra), 0); spe_explode(&fpemu, &fpemu.fe_f2, SINGLE, - curthread->td_pcb->pcb_vec.vr[rb][0], 0); + spe_save_reg_high(rb), 0); high = spe_emu_instr(instr_sec_op, &fpemu, &result, - &curthread->td_pcb->pcb_vec.vr[rd][0]); + &tmp); + if (high < 0) + spe_load_reg_high(rd, tmp); + spefscr = fpscr_to_spefscr(fpemu.fe_cx) << 16; /* Clear the fpemu to start over on the lower bits. */ memset(&fpemu, 0, sizeof(fpemu)); /* Now low word */ spe_explode(&fpemu, &fpemu.fe_f1, SINGLE, frame->fixreg[ra], 0); spe_explode(&fpemu, &fpemu.fe_f2, SINGLE, frame->fixreg[rb], 0); spefscr |= fpscr_to_spefscr(fpemu.fe_cx); low = spe_emu_instr(instr_sec_op, &fpemu, &result, &frame->fixreg[rd]); if (instr_sec_op == EVFSCMPEQ || instr_sec_op == EVFSCMPGT || instr_sec_op == EVFSCMPLT) { res = (high << 3) | (low << 2) | ((high | low) << 1) | (high & low); width = NONE; } else width = VECTOR; break; } - enable_vec(curthread); goto end; case SPFP: switch (instr_sec_op) { case EFSABS: frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31); break; case EFSNABS: frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31); break; case EFSNEG: frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31); break; case EFSCFD: spe_explode(&fpemu, &fpemu.fe_f3, DOUBLE, - curthread->td_pcb->pcb_vec.vr[rb][0], - frame->fixreg[rb]); + spe_save_reg_high(rb), frame->fixreg[rb]); result = &fpemu.fe_f3; width = SINGLE; break; default: spe_explode(&fpemu, &fpemu.fe_f1, SINGLE, frame->fixreg[ra], 0); spe_explode(&fpemu, &fpemu.fe_f2, SINGLE, frame->fixreg[rb], 0); width = SINGLE; } break; case DPFP: - save_vec_nodrop(curthread); + mtmsr(msr | PSL_VEC); switch (instr_sec_op) { case EFDABS: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] & ~(1U << 31); + high = spe_save_reg_high(ra) & ~(1U << 31); + frame->fixreg[rd] = frame->fixreg[ra]; + spe_load_reg_high(rd, high); break; case EFDNABS: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] | (1U << 31); + high = spe_save_reg_high(ra) | (1U << 31); + frame->fixreg[rd] = frame->fixreg[ra]; + spe_load_reg_high(rd, high); break; case EFDNEG: - curthread->td_pcb->pcb_vec.vr[rd][0] = - curthread->td_pcb->pcb_vec.vr[ra][0] ^ (1U << 31); + high = spe_save_reg_high(ra) ^ (1U << 31); + frame->fixreg[rd] = frame->fixreg[ra]; + spe_load_reg_high(rd, high); break; case EFDCFS: spe_explode(&fpemu, &fpemu.fe_f3, SINGLE, frame->fixreg[rb], 0); result = &fpemu.fe_f3; width = DOUBLE; break; default: spe_explode(&fpemu, &fpemu.fe_f1, DOUBLE, - curthread->td_pcb->pcb_vec.vr[ra][0], - frame->fixreg[ra]); + spe_save_reg_high(ra), frame->fixreg[ra]); spe_explode(&fpemu, &fpemu.fe_f2, DOUBLE, - curthread->td_pcb->pcb_vec.vr[rb][0], - frame->fixreg[rb]); + spe_save_reg_high(rb), frame->fixreg[rb]); width = DOUBLE; } break; } switch (instr_sec_op) { case EFDCFS: case EFSCFD: /* Already handled. */ break; default: res = spe_emu_instr(instr_sec_op, &fpemu, &result, &frame->fixreg[rd]); if (res != -1) res <<= 2; break; } switch (instr_sec_op & SPE_INST_MASK) { case ECMPEQ: case ECMPGT: case ECMPLT: frame->cr &= ~(0xf << cr_shift); frame->cr |= (res << cr_shift); break; case ECTUI: case ECTUIZ: case ECTSI: case ECTSIZ: break; default: switch (width) { case NONE: case VECTOR: break; case SINGLE: frame->fixreg[rd] = fpu_ftos(&fpemu, result); break; case DOUBLE: - curthread->td_pcb->pcb_vec.vr[rd][0] = - fpu_ftod(&fpemu, result, ftod_res); + spe_load_reg_high(rd, fpu_ftod(&fpemu, result, ftod_res)); frame->fixreg[rd] = ftod_res[1]; - enable_vec(curthread); break; default: panic("Unknown storage width %d", width); break; } } end: spefscr |= (mfspr(SPR_SPEFSCR) & ~SPEFSCR_FINVS); mtspr(SPR_SPEFSCR, spefscr); frame->srr0 += 4; + mtmsr(msr); return; } void spe_handle_fpround(struct trapframe *frame) { /* * Punt fpround exceptions for now. This leaves the truncated result in * the register. We'll deal with overflow/underflow later. */ return; } Index: stable/12 =================================================================== --- stable/12 (revision 342781) +++ stable/12 (revision 342782) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r341751-341752,342025,342107