diff options
-rw-r--r-- | sys/arch/arm/arm/cpu.c | 5 | ||||
-rw-r--r-- | sys/arch/arm/arm/exception.S | 11 | ||||
-rw-r--r-- | sys/arch/arm/arm/fault.c | 9 | ||||
-rw-r--r-- | sys/arch/arm/arm/irq_dispatch.S | 7 | ||||
-rw-r--r-- | sys/arch/arm/arm/syscall.c | 6 | ||||
-rw-r--r-- | sys/arch/arm/arm/undefined.c | 14 | ||||
-rw-r--r-- | sys/arch/arm/arm/vfp.c | 197 | ||||
-rw-r--r-- | sys/arch/arm/arm/vm_machdep.c | 5 | ||||
-rw-r--r-- | sys/arch/arm/conf/files.arm | 3 | ||||
-rw-r--r-- | sys/arch/arm/include/cpu.h | 3 | ||||
-rw-r--r-- | sys/arch/arm/include/fp.h | 15 | ||||
-rw-r--r-- | sys/arch/arm/include/pcb.h | 9 | ||||
-rw-r--r-- | sys/arch/arm/include/vfp.h | 136 |
13 files changed, 391 insertions, 29 deletions
diff --git a/sys/arch/arm/arm/cpu.c b/sys/arch/arm/arm/cpu.c index 5b6a9ce1f8a..6a23a685288 100644 --- a/sys/arch/arm/arm/cpu.c +++ b/sys/arch/arm/arm/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.44 2018/01/15 14:11:16 kettenis Exp $ */ +/* $OpenBSD: cpu.c,v 1.45 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $ */ @@ -62,6 +62,7 @@ #include <arm/cpuconf.h> #include <arm/undefined.h> +#include <arm/vfp.h> #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_clock.h> @@ -116,6 +117,8 @@ cpu_attach(struct device *parent, struct device *dev, void *aux) identify_arm_cpu(dev, ci); + vfp_init(); + if (OF_getproplen(faa->fa_node, "clocks") > 0) { cpu_node = faa->fa_node; cpu_cpuspeed = cpu_clockspeed; diff --git a/sys/arch/arm/arm/exception.S b/sys/arch/arm/arm/exception.S index f1bceac6864..3cf4e2c266c 100644 --- a/sys/arch/arm/arm/exception.S +++ b/sys/arch/arm/arm/exception.S @@ -1,4 +1,4 @@ -/* $OpenBSD: exception.S,v 1.6 2016/09/21 11:33:05 kettenis Exp $ */ +/* $OpenBSD: exception.S,v 1.7 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $ */ /* @@ -54,6 +54,14 @@ .text .align 2 +#define RESTOREVFP \ + ldr r0, [sp] /* Get the SPSR from stack */ ;\ + and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\ + cmp r0, #(PSR_USR32_MODE) ;\ + bne 1f ;\ + bl _C_LABEL(vfp_enable) ;\ +1: + AST_LOCALS /* @@ -194,6 +202,7 @@ Laddress_exception_msg: exception_exit: DO_AST + RESTOREVFP PULLFRAMEFROMSVCANDEXIT /* diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c index 96c0e1b54a5..8ece22e083b 100644 --- a/sys/arch/arm/arm/fault.c +++ b/sys/arch/arm/arm/fault.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fault.c,v 1.31 2018/01/15 14:11:16 kettenis Exp $ */ +/* $OpenBSD: fault.c,v 1.32 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */ /* @@ -99,6 +99,7 @@ #include <arm/db_machdep.h> #include <arch/arm/arm/disassem.h> #include <arm/machdep.h> +#include <arm/vfp.h> #ifdef DEBUG int last_fault_code; /* For the benefit of pmap_fault_fixup() */ @@ -188,6 +189,9 @@ data_abort_handler(trapframe_t *tf) /* Update vmmeter statistics */ uvmexp.traps++; + /* Before enabling interrupts, save FPU state */ + vfp_save(); + /* Re-enable interrupts if they were enabled previously */ if (__predict_true((tf->tf_spsr & PSR_I) == 0)) enable_interrupts(PSR_I); @@ -581,6 +585,9 @@ prefetch_abort_handler(trapframe_t *tf) if (__predict_false(!TRAP_USERMODE(tf))) dab_fatal(tf, fsr, far, NULL, NULL); + /* Before enabling interrupts, save FPU state */ + vfp_save(); + /* * Enable IRQ's (disabled by the abort) This always comes * from user mode so we know interrupts were not disabled. diff --git a/sys/arch/arm/arm/irq_dispatch.S b/sys/arch/arm/arm/irq_dispatch.S index 63ce56424db..015c7bb6cb4 100644 --- a/sys/arch/arm/arm/irq_dispatch.S +++ b/sys/arch/arm/arm/irq_dispatch.S @@ -1,4 +1,4 @@ -/* $OpenBSD: irq_dispatch.S,v 1.13 2017/01/06 00:06:02 jsg Exp $ */ +/* $OpenBSD: irq_dispatch.S,v 1.14 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: irq_dispatch.S,v 1.5 2003/10/30 08:57:24 scw Exp $ */ /* @@ -90,6 +90,9 @@ .Lcpu_info_primary: .word _C_LABEL(cpu_info_primary) +#define STOREVFP \ + bl _C_LABEL(vfp_save) + AST_LOCALS ASENTRY_NP(irq_entry) @@ -97,6 +100,8 @@ ASENTRY_NP(irq_entry) PUSHFRAMEINSVC /* Push an interrupt frame */ + STOREVFP /* save fpu state before irq handler */ + /* * Increment the interrupt nesting depth and call the interrupt * dispatch routine. We've pushed a frame, so we can safely use diff --git a/sys/arch/arm/arm/syscall.c b/sys/arch/arm/arm/syscall.c index 7ffa07e22bb..adc0c07c78a 100644 --- a/sys/arch/arm/arm/syscall.c +++ b/sys/arch/arm/arm/syscall.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.c,v 1.18 2016/01/31 00:14:50 jsg Exp $ */ +/* $OpenBSD: syscall.c,v 1.19 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: syscall.c,v 1.24 2003/11/14 19:03:17 scw Exp $ */ /*- @@ -89,6 +89,7 @@ #include <machine/frame.h> #include <machine/pcb.h> #include <arm/swi.h> +#include <arm/vfp.h> #define MAXARGS 8 @@ -103,6 +104,9 @@ swi_handler(trapframe_t *frame) uvmexp.syscalls++; + /* Before enabling interrupts, save FPU state */ + vfp_save(); + /* Re-enable interrupts if they were enabled previously */ if (__predict_true((frame->tf_spsr & PSR_I) == 0)) enable_interrupts(PSR_I); diff --git a/sys/arch/arm/arm/undefined.c b/sys/arch/arm/arm/undefined.c index afe94ef85b7..2120de0ca2a 100644 --- a/sys/arch/arm/arm/undefined.c +++ b/sys/arch/arm/arm/undefined.c @@ -1,4 +1,4 @@ -/* $OpenBSD: undefined.c,v 1.10 2017/04/30 16:45:45 mpi Exp $ */ +/* $OpenBSD: undefined.c,v 1.11 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */ /* @@ -62,6 +62,7 @@ #include <machine/cpu.h> #include <machine/frame.h> #include <arm/undefined.h> +#include <arm/vfp.h> #include <machine/trap.h> @@ -150,6 +151,9 @@ undefinedinstruction(trapframe_t *frame) #endif union sigval sv; + /* Before enabling interrupts, save FPU state */ + vfp_save(); + /* Enable interrupts if they were enabled before the exception. */ if (!(frame->tf_spsr & PSR_I)) enable_interrupts(PSR_I); @@ -194,10 +198,14 @@ undefinedinstruction(trapframe_t *frame) * instruction trap. */ + coprocessor = 0; if ((fault_instruction & (1 << 27)) != 0) coprocessor = (fault_instruction >> 8) & 0x0f; - else - coprocessor = 0; + else { /* check for special instructions */ + if (((fault_instruction & 0xfe000000) == 0xf2000000) || + ((fault_instruction & 0xff100000) == 0xf4000000)) + coprocessor = 10; /* vfp / simd */ + } if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) { /* diff --git a/sys/arch/arm/arm/vfp.c b/sys/arch/arm/arm/vfp.c new file mode 100644 index 00000000000..ec5b4a28504 --- /dev/null +++ b/sys/arch/arm/arm/vfp.c @@ -0,0 +1,197 @@ +/* $OpenBSD: vfp.c,v 1.1 2018/01/26 16:22:19 kettenis Exp $ */ + +/* + * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <arm/include/cpufunc.h> +#include <arm/include/vfp.h> +#include <arm/include/undefined.h> + +static inline void +set_vfp_fpexc(uint32_t val) +{ + __asm __volatile("vmsr fpexc, %0" :: "r" (val)); +} + +static inline uint32_t +get_vfp_fpexc(void) +{ + uint32_t val; + __asm __volatile("vmrs %0, fpexc" : "=r" (val)); + return val; +} + +int vfp_fault(unsigned int, unsigned int, trapframe_t *, int); +void vfp_load(struct proc *p); +void vfp_store(struct fpreg *vfpsave); + +void +vfp_init(void) +{ + uint32_t val; + + install_coproc_handler(10, vfp_fault); + install_coproc_handler(11, vfp_fault); + + __asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val)); + val |= COPROC10 | COPROC11; + __asm volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val)); + __asm volatile("isb"); +} + +void +vfp_store(struct fpreg *vfpsave) +{ + uint32_t scratch; + + if (get_vfp_fpexc() & VFPEXC_EN) { + __asm __volatile( + "vstmia %1!, {d0-d15}\n" /* d0-d15 */ + "vstmia %1!, {d16-d31}\n" /* d16-d31 */ + "vmrs %0, fpscr\n" + "str %0, [%1]\n" /* save vfpscr */ + : "=&r" (scratch) : "r" (vfpsave)); + } + + /* disable FPU */ + set_vfp_fpexc(0); +} + +void +vfp_save(void) +{ + struct cpu_info *ci = curcpu(); + struct pcb *pcb = curpcb; + struct proc *p = curproc; + uint32_t cr_8; + + if (ci->ci_fpuproc == 0) + return; + + cr_8 = get_vfp_fpexc(); + + if ((cr_8 & VFPEXC_EN) == 0) + return; /* not enabled, nothing to do */ + + if (cr_8 & VFPEXC_EX) + panic("vfp exceptional data fault, time to write more code"); + + if (pcb->pcb_fpcpu == NULL || ci->ci_fpuproc == NULL || + !(pcb->pcb_fpcpu == ci && ci->ci_fpuproc == p)) { + /* disable fpu before panic, otherwise recurse */ + set_vfp_fpexc(0); + + panic("FPU unit enabled when curproc and curcpu dont agree %p %p %p %p", pcb->pcb_fpcpu, ci, ci->ci_fpuproc, p); + } + + vfp_store(&p->p_addr->u_pcb.pcb_fpstate); + + /* + * NOTE: fpu state is saved but remains 'valid', as long as + * curpcb()->pcb_fpucpu == ci && ci->ci_fpuproc == curproc() + * is true FPU state is valid and can just be enabled without reload. + */ +} + +void +vfp_enable(void) +{ + struct cpu_info *ci = curcpu(); + + if (curproc->p_addr->u_pcb.pcb_fpcpu == ci && + ci->ci_fpuproc == curproc) { + disable_interrupts(PSR_I|PSR_F); + + /* FPU state is still valid, just enable and go */ + set_vfp_fpexc(VFPEXC_EN); + } +} + +void +vfp_load(struct proc *p) +{ + struct cpu_info *ci = curcpu(); + struct pcb *pcb = &p->p_addr->u_pcb; + uint32_t scratch = 0; + int psw; + + /* do not allow a partially synced state here */ + psw = disable_interrupts(PSR_I|PSR_F); + + /* + * p->p_pcb->pcb_fpucpu _may_ not be NULL here, but the FPU state + * was synced on kernel entry, so we can steal the FPU state + * instead of signalling and waiting for it to save + */ + + /* enable to be able to load ctx */ + set_vfp_fpexc(VFPEXC_EN); + + __asm __volatile( + "vldmia %1!, {d0-d15}\n" /* d0-d15 */ + "vldmia %1!, {d16-d31}\n" /* d16-d31 */ + "ldr %0, [%1]\n" /* set old vfpscr */ + "vmsr fpscr, %0\n" + : "=&r" (scratch) : "r" (&pcb->pcb_fpstate)); + + ci->ci_fpuproc = p; + pcb->pcb_fpcpu = ci; + + /* disable until return to userland */ + set_vfp_fpexc(0); + + restore_interrupts(psw); +} + +int +vfp_fault(unsigned int pc, unsigned int insn, trapframe_t *tf, int fault_code) +{ + struct proc *p = curproc; + struct pcb *pcb = &p->p_addr->u_pcb; + + if (get_vfp_fpexc() & VFPEXC_EN) { + /* + * We probably ran into an unsupported instruction, + * like NEON on a non-NEON system. Let the process know. + */ + return 1; + } + + /* we should be able to ignore old state of pcb_fpcpu ci_fpuproc */ + if ((pcb->pcb_flags & PCB_FPU) == 0) { + pcb->pcb_flags |= PCB_FPU; + memset(&pcb->pcb_fpstate, 0, sizeof(pcb->pcb_fpstate)); + } + vfp_load(p); + + return 0; +} + +void +vfp_discard(void) +{ + struct cpu_info *ci = curcpu(); + + if (curpcb->pcb_fpcpu == ci && ci->ci_fpuproc == curproc) { + ci->ci_fpuproc = NULL; + curpcb->pcb_fpcpu = NULL; + } +} diff --git a/sys/arch/arm/arm/vm_machdep.c b/sys/arch/arm/arm/vm_machdep.c index d755b8cd59f..87e0032cfaa 100644 --- a/sys/arch/arm/arm/vm_machdep.c +++ b/sys/arch/arm/arm/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.21 2017/08/17 20:50:51 tom Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.22 2018/01/26 16:22:19 kettenis Exp $ */ /* $NetBSD: vm_machdep.c,v 1.31 2004/01/04 11:33:29 jdolecek Exp $ */ /* @@ -62,6 +62,8 @@ #include <machine/reg.h> #include <machine/vmparam.h> +#include <arm/vfp.h> + extern pv_addr_t systempage; int process_read_regs (struct proc *p, struct reg *regs); @@ -132,6 +134,7 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb, void cpu_exit(struct proc *p) { + vfp_discard(); pmap_deactivate(p); sched_exit(p); } diff --git a/sys/arch/arm/conf/files.arm b/sys/arch/arm/conf/files.arm index 9dae5a17689..b694cfe3127 100644 --- a/sys/arch/arm/conf/files.arm +++ b/sys/arch/arm/conf/files.arm @@ -1,4 +1,4 @@ -# $OpenBSD: files.arm,v 1.46 2017/04/30 13:04:49 mpi Exp $ +# $OpenBSD: files.arm,v 1.47 2018/01/26 16:22:20 kettenis Exp $ # $NetBSD: files.arm,v 1.76 2003/11/05 12:53:15 scw Exp $ # generic networking files @@ -73,6 +73,7 @@ file arch/arm/armv7/armv7_a4x_space.c cpu_armv7 file arch/arm/armv7/armv7_a4x_io.S cpu_armv7 file arch/arm/armv7/armv7_mutex.c cpu_armv7 file arch/arm/armv7/bus_space_asm_armv7.S cpu_armv7 +file arch/arm/arm/vfp.c cpu_armv7 pseudo-device openprom file arch/arm/arm/openprom.c openprom needs-flag diff --git a/sys/arch/arm/include/cpu.h b/sys/arch/arm/include/cpu.h index 2d783aaf374..9fd273e6dcf 100644 --- a/sys/arch/arm/include/cpu.h +++ b/sys/arch/arm/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.49 2018/01/15 14:11:16 kettenis Exp $ */ +/* $OpenBSD: cpu.h,v 1.50 2018/01/26 16:22:20 kettenis Exp $ */ /* $NetBSD: cpu.h,v 1.34 2003/06/23 11:01:08 martin Exp $ */ /* @@ -185,6 +185,7 @@ struct cpu_info { struct schedstate_percpu ci_schedstate; /* scheduler state */ struct proc *ci_curproc; + struct proc *ci_fpuproc; u_int32_t ci_cpuid; u_int32_t ci_randseed; diff --git a/sys/arch/arm/include/fp.h b/sys/arch/arm/include/fp.h index 5d9096e0fa5..d503ea1167f 100644 --- a/sys/arch/arm/include/fp.h +++ b/sys/arch/arm/include/fp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */ +/* $OpenBSD: fp.h,v 1.2 2018/01/26 16:22:20 kettenis Exp $ */ /* $NetBSD: fp.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */ /* @@ -60,19 +60,6 @@ typedef struct fp_extended_precision { typedef struct fp_extended_precision fp_reg_t; /* - * Information about the FPE-SP state that is stored in the pcb - * - * This needs to move and be hidden from userland. - */ - -struct fpe_sp_state { - unsigned int fp_flags; - unsigned int fp_sr; - unsigned int fp_cr; - fp_reg_t fp_registers[16]; -}; - -/* * Type for a saved FP context, if we want to translate the context to a * user-readable form */ diff --git a/sys/arch/arm/include/pcb.h b/sys/arch/arm/include/pcb.h index 1f63d2bf044..fc43b1c9a21 100644 --- a/sys/arch/arm/include/pcb.h +++ b/sys/arch/arm/include/pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcb.h,v 1.7 2016/09/24 21:02:31 patrick Exp $ */ +/* $OpenBSD: pcb.h,v 1.8 2018/01/26 16:22:20 kettenis Exp $ */ /* $NetBSD: pcb.h,v 1.10 2003/10/13 21:46:39 scw Exp $ */ /* @@ -38,9 +38,9 @@ #define _ARM_PCB_H_ #include <machine/frame.h> -#include <machine/fp.h> #include <arm/pte.h> +#include <arm/reg.h> struct trapframe; @@ -77,13 +77,14 @@ struct pcb_arm32 { */ struct pcb { u_int pcb_flags; -#define PCB_OWNFPU 0x00000001 +#define PCB_FPU 0x00000001 /* Process had FPU initialized */ struct trapframe *pcb_tf; caddr_t pcb_onfault; /* On fault handler */ union { struct pcb_arm32 un_32; } pcb_un; - struct fpe_sp_state pcb_fpstate; /* Floating Point state */ + struct fpreg pcb_fpstate; /* Floating Point state */ + struct cpu_info *pcb_fpcpu; void *pcb_tcb; }; diff --git a/sys/arch/arm/include/vfp.h b/sys/arch/arm/include/vfp.h new file mode 100644 index 00000000000..511be722ec0 --- /dev/null +++ b/sys/arch/arm/include/vfp.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2012 Mark Tinguely + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. + * $FreeBSD$ + */ + + +#ifndef _MACHINE__VFP_H_ +#define _MACHINE__VFP_H_ + +#ifdef _KERNEL +/* Only kernel defines exist here */ + +/* fpsid, fpscr, fpexc are defined in the newer gas */ +#define VFPSID cr0 +#define VFPSCR cr1 +#define VMVFR1 cr6 +#define VMVFR0 cr7 +#define VFPEXC cr8 +#define VFPINST cr9 /* vfp 1 and 2 except instruction */ +#define VFPINST2 cr10 /* vfp 2? */ + +/* VFPSID */ +#define VFPSID_IMPLEMENTOR_OFF 24 +#define VFPSID_IMPLEMENTOR_MASK (0xff000000) +#define VFPSID_HARDSOFT_IMP (0x00800000) +#define VFPSID_SINGLE_PREC 20 /* version 1 and 2 */ +#define VFPSID_SUBVERSION_OFF 16 +#define VFPSID_SUBVERSION2_MASK (0x000f0000) /* version 1 and 2 */ +#define VFPSID_SUBVERSION3_MASK (0x007f0000) /* version 3 */ +#define VFP_ARCH3 (0x00030000) +#define VFPSID_PARTNUMBER_OFF 8 +#define VFPSID_PARTNUMBER_MASK (0x0000ff00) +#define VFPSID_VARIANT_OFF 4 +#define VFPSID_VARIANT_MASK (0x000000f0) +#define VFPSID_REVISION_MASK 0x0f + +/* VFPSCR */ +#define VFPSCR_CC_N (0x80000000) /* comparison less than */ +#define VFPSCR_CC_Z (0x40000000) /* comparison equal */ +#define VFPSCR_CC_C (0x20000000) /* comparison = > unordered */ +#define VFPSCR_CC_V (0x10000000) /* comparison unordered */ +#define VFPSCR_QC (0x08000000) /* saturation cululative */ +#define VFPSCR_DN (0x02000000) /* default NaN enable */ +#define VFPSCR_FZ (0x01000000) /* flush to zero enabled */ + +#define VFPSCR_RMODE_OFF 22 /* rounding mode offset */ +#define VFPSCR_RMODE_MASK (0x00c00000) /* rounding mode mask */ +#define VFPSCR_RMODE_RN (0x00000000) /* round nearest */ +#define VFPSCR_RMODE_RPI (0x00400000) /* round to plus infinity */ +#define VFPSCR_RMODE_RNI (0x00800000) /* round to neg infinity */ +#define VFPSCR_RMODE_RM (0x00c00000) /* round to zero */ + +#define VFPSCR_STRIDE_OFF 20 /* vector stride -1 */ +#define VFPSCR_STRIDE_MASK (0x00300000) +#define VFPSCR_LEN_OFF 16 /* vector length -1 */ +#define VFPSCR_LEN_MASK (0x00070000) +#define VFPSCR_IDE (0x00008000) /* input subnormal exc enable */ +#define VFPSCR_IXE (0x00001000) /* inexact exception enable */ +#define VFPSCR_UFE (0x00000800) /* underflow exception enable */ +#define VFPSCR_OFE (0x00000400) /* overflow exception enable */ +#define VFPSCR_DNZ (0x00000200) /* div by zero exception en */ +#define VFPSCR_IOE (0x00000100) /* invalid op exec enable */ +#define VFPSCR_IDC (0x00000080) /* input subnormal cumul */ +#define VFPSCR_IXC (0x00000010) /* Inexact cumulative flag */ +#define VFPSCR_UFC (0x00000008) /* underflow cumulative flag */ +#define VFPSCR_OFC (0x00000004) /* overflow cumulative flag */ +#define VFPSCR_DZC (0x00000002) /* division by zero flag */ +#define VFPSCR_IOC (0x00000001) /* invalid operation cumul */ + +/* VFPEXC */ +#define VFPEXC_EX (0x80000000) /* exception v1 v2 */ +#define VFPEXC_EN (0x40000000) /* vfp enable */ + +/* version 3 registers */ +/* VMVFR0 */ +#define VMVFR0_RM_OFF 28 +#define VMVFR0_RM_MASK (0xf0000000) /* VFP rounding modes */ + +#define VMVFR0_SV_OFF 24 +#define VMVFR0_SV_MASK (0x0f000000) /* VFP short vector supp */ +#define VMVFR0_SR_OFF 20 +#define VMVFR0_SR (0x00f00000) /* VFP hw sqrt supp */ +#define VMVFR0_D_OFF 16 +#define VMVFR0_D_MASK (0x000f0000) /* VFP divide supp */ +#define VMVFR0_TE_OFF 12 +#define VMVFR0_TE_MASK (0x0000f000) /* VFP trap exception supp */ +#define VMVFR0_DP_OFF 8 +#define VMVFR0_DP_MASK (0x00000f00) /* VFP double prec support */ +#define VMVFR0_SP_OFF 4 +#define VMVFR0_SP_MASK (0x000000f0) /* VFP single prec support */ +#define VMVFR0_RB_MASK (0x0000000f) /* VFP 64 bit media support */ + +/* VMVFR1 */ +#define VMVFR1_SP_OFF 16 +#define VMVFR1_SP_MASK (0x000f0000) /* Neon single prec support */ +#define VMVFR1_I_OFF 12 +#define VMVFR1_I_MASK (0x0000f000) /* Neon integer support */ +#define VMVFR1_LS_OFF 8 +#define VMVFR1_LS_MASK (0x00000f00) /* Neon ld/st instr support */ +#define VMVFR1_DN_OFF 4 +#define VMVFR1_DN_MASK (0x000000f0) /* Neon prop NaN support */ +#define VMVFR1_FZ_MASK (0x0000000f) /* Neon denormal arith supp */ + +#define COPROC10 (0x3 << 20) +#define COPROC11 (0x3 << 22) + +void vfp_init(void); +void vfp_discard(void); +void vfp_save(void); +void vfp_enable(void); + +#endif /* _KERNEL */ +#endif /* _MACHINE__VFP_H_ */ |