* VFP versions:
- VFPv1
  - for ARMv5 somethingsomething?
    - "VFP10 revision 0 silicion", ARM10200 (AN98)
    - has FPSID 0x410000A0 (SW=0,fmt=0,SNG=0,arch=0,part=0,variant=&A,rev=0)
      - contains bug in vector length when trap triggered!
  - ARMv5 ARM p574+
  - 32x32bit registers
  - FPSID, FPSCR, FPEXC
    - rest is implementation defined (FPINST, etc.)
  - VFPv1xD - single precision only (plus signed/unsigned int)
  - VFPv1D - single + double (plus signed/unsigned int)
  - p597, FLDMX/FSTMX:
    - "N double-precision registers are stored in at most 2N+1 words"
    - must use "matching" LDM/STM - i.e. reload exactly same regs
    - p598 - details of format word that may be used
    - p602 - FPSID indicates storage format used
    - FLDMX/FSTMX deprecation in ARMv6+ means we should just use F[LDM|STM][S|D] for VFPv2+ without caring about the data type in the register (see ARMv6 ARM, p880)
- VFPv2
  - for ARMv5TE, 5TEJ, v6, v6K, v6T2 (and other obsoleted ARMv5 variants?)
    - "VFP10 revision 1 (ARM10200E), VFP9-S" (AN98)
    - VFP10 rev 1 has FPSID 0x410101A0 (SW=0,fmt=0,SNG=0,arch=1,part=1,variant=&A,rev=0)
    - VFP9-S & VFP11 don't need support code iff using FtZ, default NaN, round-to-nearest, and exceptions disabled?
    - VFP9-S FPSID = 0x410101A0
    - VFP11 also uses VFPv2
      - has MVFR0, MVFR1 in r1p0!
        - but looks like some of the fields are different to the VFPv3 version
      - FPSID = 0x410120Bx
      - MVFR0 = 0x11111111
      - MVFR1 = 0x00000000
  - 16x64bit registers (i.e. 32x32bit)
  - VFPv1 to VFPv2 changes (ARMv6 ARM p853):
    - FMDRR, FMRRD, FMSRR, FMRRS
    - default NaN
    - input denormal trap/detection
    - "changes to ftz"
- VFPv3
  - for ARMv7-A/R
  - VFPv3-D32
    - 32x64bit registers (64x32)
    - must be this variant if ASIMD implemented as well
    - upper half of register file not accessible as 32bit!
  - VFPv3-D16
    - 16x64bit registers (32x32)
  - is D32 if VFP present and CPACR b30 == 0
* ASIMD versions:
- ARMv7-A/R
- ASIMD present iff VFP present and CPACR b31 == 0?
  - what if VFP not present?
- 32x64bit registers
  - implies that MVFR0 3..0 must be 2 for ASIMD to be present?
- ASIMD integer only:		MVFR1 = xx001xxx
- ASIMD int+single:		MVFR1 = xx011xxx
- ASIMD int+single+half:	MVFR1 = xx111xxx
* Since CPACR is only present on ARMv6+, ARMv6+ are the only architectures we can support VFP auto-detection on
* ASIMD + VFP combinations: (ARMv7 p52)
  ASIMD		VFP
  none		none
  integer	none
  int+single	single (with double load/store support)
  int+single	single+double
  none		single (with double load/store support)
  none		single+double
* Reported VFP variants:
- VFPv1xD
- VFPv1D
- VFPv2 (plus xD, as implied above?)
- VFPv3[U]-D16 (plus xD, as indicated by MVFR0)
- VFPv3[U]-D32 (plus xD, as indicated by MVFR0?)
- so the following attributes exist:
  - VFP version (1,2,3)
  - trapped exception support (U)
  - register file size (16 or 32 x64)
  - double support
  - halfword support (not VFPv1 according to ARMv5 ARM?)
  - short vector support (since it's gone in Cortex-A9)
  - default NaN (VFPv1 always propagates according to FPSCR in ARMv5 ARM?)
  - flush-to-zero
  - single precision support
  - rounding modes
  - SQRT
  - DIV
- need to indicate both the hardware availability & software availability
- easiest to just return the MVFR values?
  - returning simulated values for VFPv1/v2
  - or software-enhanced values if software support is acceptable
  - however VFP11 uses its own special MVFR format that doesn't match VFPv3
* context initialisation
- ARMv5 ARM p608 

FPSID: (ARMv5)

31..24		23	22..21	20	19..16	15..8	7..4	3..0
implementor	SW	format	SNG	arch	part	variant	revision

implementor:	0x41 = ARM
SW:		0 = contains hardware
		1 = pure software implementation
format:		00 = FSTMX/FLDMX standard format 1 (raw data)
		01 = FSTMX/FLDMX standard format 2 (format word)
		10 = reserved
		11 = non-standard format
SNG:		0 = supports both single & double precision (VFPv1D)
		1 = only single precision (VFPv1xD)
arch:		0 = VFPv1
part:		implementation defined primary part number
variant:	implementation defined variant
revision:	implementation defined revision

CPACR: (ARMv7 ARM p1378) - only present in ARMv6+

bit 31 = ASEDIS = ASIMD disable:

  VFP	ASIMD	value
  yes	no	RAO/WI
  no	no	UNK/SBZP
  yes	yes	implementation defined whether supported or not
  		0 = doesn't cause ASIMD-only instructions to trap
  		1 = causes ASIMD-only instructions to trap
  no	yes	unspecified


bit 30 = D32DIS = D16-D31 VFP disable

  VFP	value
  no	UNK/SBZP
  D16	RAO/WI
  D32	implementation defined whether supported or not
  	0 = doesn't cause VFPv3 D16-D31 accesses to trap
  	1 = causes VFPv3 D16-D31 accesses to trap

- bits 31 & 30 are shown as UNP/SBZP in ARMv6 ARM

FPSID: (ARMv7 p1552)

31..24		23	22..16		15..8	7..4	3..0
implementor	SW	subarchitecture	part	variant	revision

implementor:	0x41 = ARM
		other values same as MIDR
SW:		0 = contains hardware
		1 = pure software implementation
subarch:	0000000 = VFPv1 with implementation defined subarch
		0000001 = VFPv2 with common VFP subarch v1
		0000010 = VFPv3+ with common VFP subarch v2. Has MVFR0/MVFR1
		0000011 = VFPv3+ with null subarch. Has MVFR0/MVFR1
		0000100 = VFPv3+ with common VFP subarch v3. Has MVFR0/MVFR1
		1xxxxxx = non-ARM subarchitecture
		other:
		0100000 = VFPv1D with standard format 2
		0010000 = VFPv1xD
		0110000 = VFPv1xD with standard format 2
part:		implementation defined primary part number
variant:	implementation defined variant
revision:	implementation defined revision

MVFR0:
- only contains details of stuff that's supported by hardware, not stuff which support code may implement instead

31..28	VFP rounding modes
	0 = only round-to-nearest (except VCVT which always uses round-to-zero)
	1 = all modes supported
27..24	VFP short vectors (aka FPSCR.LEN != 0)
	0 = not supported
	1 = supported
23..20	VFP SQRT
	0 = not supported
	1 = supported (iff single/doubles are supported, as appropriate)
19..16	VFP divide
	0 = not supported
	1 = supported (iff single/doubles are supported, as appropriate)
15..12	VFP exception trapping
	0 = not supported (VFPv3)
	1 = supported (VFPv3U, VFPv2, VFPv1?)
11..8	VFP double precision
	0 = not supported
	1 = supported, VFPv2
	2 = supported, VFPv3 (double-precision constant load, double<->fixed conversion)
	- FSQRTD only supported if SQRT field is 1
	- FDIVD only supported if DIV field is 1
	- double<->single conversion only supported if single precision field nonzero
7..4	VFP single precision
	0 = not supported
	1 = supported, VFPv2
	2 = supported, VFPv3 (single-precision constant load, single<->fixed conversion)
	- FSQRTS only supported if SQRT field is 1
	- FDIVS only supported if DIV field is 1
	- double<->single conversion only supported if double precision field is nonzero
3..0	A_SIMD registers
	0 = not supported
	1 = 16x64bit regs
	2 = 32x64bit regs
	- if nonzero, all VFP LDC/STC/MCR/MRC supported
	- if nonzero, VFP MCRR/MRRC supported (iff CPUID reg says MCRR/MRRC exist)

MVFR1:
- only contains details of stuff that's supported by hardware, not stuff which support code may implement instead

31..28	reserved
	RAZ
27..24	VFP HPFH
	0 = VFP half-precision not supported
	1 = VFP half-precision supported
23..20	A_SIMD HPFP
	0 = not supported
	1 = supported (only permitted if A_SIMD SPFP == 1)
19..16	A_SIMD SPFP
	0 = not supported
	1 = supported (only permitted if A_SIMD int == 1)
15..12	A_SIMD int
	0 = not supported
	1 = supported
11..8	A_SIMD load/store
	0 = not supported
	1 = supported
7..4	D_NaN
	0 = hardware only supports default NaN
	1 = hardware supports NaN propagation
3..0	FtZ
	0 = hardware only supports flush-to-zero
	1 = hardware supportes full denormalized number arithmetic

--------------------------------------------------------------------------------

VFP feature/version determination:

1. Check CP10/CP11 presence
   - if <ARMv5, not present
   - if ARMv5, try reading FPSID and see if it aborts
   - if ARMv6+, test with CPACR
2. Determine VFP version
   - if bit 23 set, is software-only implementation, so abort and do whatever the hell we want
   - if ARMv5/ARMv6 then version = FPSID[19..16]
   - if ARMv7 then version = FPSID[22..16]
3. Determine trapped exception support
   - if VFPv3+ use MVFR0[15..12]
   - else trapped exceptions are always supported?
4. Determine register file size
   - if VFPv3+ use MVFR0[3..0]
   - else 16x64bit
5. Determine double support
   - if VFPv3+ use MVFR0[11..8]
   - else use FPSID[20]
6. Determine halfword support
   - if VFPv3+ use MVFR1[27..24]
   - else not supported?
7. Determine short vector support
   - if VFPv3+ use MVFR0[27..24]
   - else supported
8. Determine default NaN/NaN propagation
   - if VFPv3+ use MVFR1[7..4]
   - if VFPv1 only NaN propagation
   - if VFPv2 both modes supported
9. Determine flush-to-zero support
   - if VFPv3+ use MVFR1[3..0]
   - else both modes supproted
10. Determine single precision support
   - if VFPv3+ use MVFR0[7..4]
   - else supported
11. Determine rounding mode support
   - if VFPv3+ use MVFR0[31..28]
   - else all supported
12. Determine SQRT hardware
   - if VFPv3+ use MVFR0[23..20]
   - else supported
13. Determine DIV hardware
   - if VFPv3+ use MVFR0[19..16]
   - else supported

NEON feature/version determination:

1. Check ARM architecture
   - only supported in ARMv7+
2. Check CP10/CP11 presence
   - using CPACR
3. Check MVFR1
   - guaranteed to exist if CP10/11 are present, since must be VFPv3+ on ARMv7 (or just NEON)
4. if MVFR1 = xx001xxx, is integer-only NEON
5. if MVFR1 = xx011xxx, is integer + single NEON
6. if MVFR1 = xx111xxx, is integer + single + half NEON

VFP-D32/NEON disable ability:

1. Check ARM architecture
   - D32/NEON can only be disabled in ARMv7+
2. Write CPACR[31..30] = 11 and read back to see if the bits stick
   - if they stick, we can disable D32/NEON access?
   - not that we really care - just need to make sure we only modify the bits if on ARMv7
