Expand/Shrink

ARM fpu

The CDP (Coprocessor Data Processing) instructions include all floating point operations, this page also covers all supported MCR/MRC register transfers.

There are probably over a thousand different floating point instructions (at least that’s what fasmarm’s ARMDOC\InstructionFormatsVFP.asm implies), so this page deliberately omits many/most single-presision and vectorial operations. Note the disassembler is quite ad-hoc and more than likely to mis-report many of the ~950 other instructions as things they are not, aka I’m not about to undertake perhaps two years worth(!) of back-breaking debugging for no good reason.
There are 16 double precision registers, d0..d15, and 32 single precision registers, s0..s31, which overlap the double precision registers in pairs, so for instance writing to s8 or s9 clobbers d4. Only the single precision operations that are necessary for data conversion are documented. There is certainly some attraction to using s0..s31 as a first level register spill cache in the planned linear scan register allocation implementation.

Opcode 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
O8 LIT8
COND OOO P U D W S RN RD RS V X M Z RM
fmdrr[cond] Dm,Rd,Rn cond 1 1 0 0 0 1 0 0 Rn Rd 1 0 1 1 0 0 0 1 Dm
fmrrd[cond] Rd,Rn,Dm cond 1 1 0 0 0 1 0 1 Rn Rd 1 0 1 1 0 0 0 1 Dm
fpop[cond] {Dd-Dd+imm8/2-1} cond 1 1 0 0 1 0 1 1 1 1 0 1 Dd 1 0 1 1 #r 0
fpush[cond] {Dd-Dd+imm8/2-1} cond 1 1 0 1 0 0 1 0 1 1 0 1 Dd 1 0 1 1 #r 0
fstd[cond] Dd,[Rn+(2u-1)*imm8*4] cond 1 1 0 1 U 0 0 0 Rn Dd 1 0 1 1 imm8
fldd[cond] Dd,[Rn+(2u-1)*imm8*4] cond 1 1 0 1 U 0 0 1 Rn Dd 1 0 1 1 imm8
fmsr[cond] Rd,Sn*2+n cond 1 1 1 0 0 0 0 0 Sn Rd 1 0 1 0 N 0 0 1 0 0 0 0
fmrs[cond] Rd,Sn*2+n cond 1 1 1 0 0 0 0 1 Sn Rd 1 0 1 0 N 0 0 1 0 0 0 0
faddd[cond] Dd,Dn,Dm cond 1 1 1 0 0 0 1 1 Dn Dd 1 0 1 1 0 0 0 0 Dm
fsubd[cond] Dd,Dn,Dm cond 1 1 1 0 0 0 1 1 Dn Dd 1 0 1 1 0 1 0 0 Dm
fmuld[cond] Dd,Dn,Dm cond 1 1 1 0 0 0 1 0 Dn Dd 1 0 1 1 0 0 0 0 Dm
fdivd[cond] Dd,Dn,Dm cond 1 1 1 0 1 0 0 0 Dn Dd 1 0 1 1 0 0 0 0 Dm
fmxr[cond] FPSCR,Rn cond 1 1 1 0 1 1 1 0 0 0 0 1 Rd 1 0 1 0 0 SBZ 1 SBZ
fmrx[cond] Rn,FPSCR cond 1 1 1 0 1 1 1 1 0 0 0 1 Rd 1 0 1 0 0 SBZ 1 SBZ
fmstat[cond] cond 1 1 1 0 1 1 1 1 0 0 0 1 1 1 1 1 1 0 1 0 0 0 0 1 0 0 0 0
fcpyd[cond] Dd,Dm cond 1 1 1 0 1 0 1 1 0 0 0 0 Dd 1 0 1 1 0 1 0 0 Dm
fabsd[cond] Dd,Dm cond 1 1 1 0 1 0 1 1 0 0 0 0 Dd 1 0 1 1 1 1 0 0 Dm
fnegd[cond] Dd,Dm cond 1 1 1 0 1 0 1 1 0 0 0 1 Dd 1 0 1 1 0 1 0 0 Dm
fsqrtd[cond] Dd,Dm cond 1 1 1 0 1 0 1 1 0 0 0 1 Dd 1 0 1 1 1 1 0 0 Dm
fcmpzd[cond] Dd cond 1 1 1 0 1 0 1 1 0 1 0 1 Dd 1 0 1 1 0 1 0 0 0 0 0 0
fcmpd[cond] Dd,Dm cond 1 1 1 0 1 0 1 1 0 1 0 0 Dd 1 0 1 1 0 1 0 0 Dm
fto{s}i{z}d[cond] Sd*2+d,Dm cond 1 1 1 0 1 D 1 1 1 1 0 S Sd 1 0 1 1 Z 1 0 0 Dm
f{s}itod[cond] Dd,Sm*2+m cond 1 1 1 0 1 0 1 1 1 0 0 0 Dd 1 0 1 1 S 1 M 0 Sm


Note that many of these are quite likely to have been implemented without any (assembler-side) condition logic.
fldd with U of 0 is Dn := (double)[Rn-imm8*4], wth U of 1 is Dn := (double)[Rn+imm8*4], and obviously likewise fstd.
The disassembler also supports flds, fcpys, but the assembler doesn’t, so those entries are commented out for my sanity.
Many single-precision instructions such as fsitos are commented-out and syntax-coloured red (in .s/.arm files), not so much because they are illegal or unsupported (ymmv), but because they (probably) bear little relevance to hll Phix, and should therefore (probably) be changed to their double-precision counterparts.

examples

Instruction Description Aliases
fpush {d0-d3} save #r consecutive registers fstmfdd, fstmdbd, vpush
fpop {d0-d3} restore #r consecutive registers fldmfdd, fldmiad, vpop
fstd d0,[r0] (double)[r0] := d0 vstr.64, vstr.f64
fldd d0,[r0] d0 := (double)[r0] vldr.64, vldr.f64
fmsr s0,r0 s0 := r0 (int/exact bit copy) vmov
fmrs r0,s0 r0 := s0 (int/exact bit copy) vmov
fmdrr d0,r1,r2 d0 := r1,r2 (int/exact bit copy) vmov
fmrrd r0,r1,d0 r0,r1 := d0 (int/exact bit copy) vmov
faddd d0,d1,d2 d0 := d1+d2 vadd.f64
faddd d0,d1 d0 := d0+d1 aka d0 += d1 (shorthand)
fsubd d0,d1,d2 d0 := d1-d2 vsub.f64
fmuld d0,d1,d2 d0 := d1*d2 vmul.f64
fdivd d0,d1,d2 d0 := d1/d2 vdiv.f64
fmrx r0,FPSCR fpu flags := r0 (or FPSID maybe?)
fmxr FPSCR,r0 r0 := fpu flags (or FPSID maybe?)
fmstat alu flags := fpu flags vmrs APSR_nzcv, FPSCR
fcpyd d0,d1 d0 := d1 vmov
fnegd d0 d0 := -d0 vneg.f64
fsqrtd d0,d1 d0 := sqrt(d1) vsqrt.f64
fcmpzd d0 fpu flags := (d0==0 0) vcmp.f64 d0,#0
ftosid s4,d0 s4 := (int)d0 (fpscr rounding mode) vcvtr.s32.f64
ftouizd s4,d0 s4 := (uint)d0 (round towards zero) vcvt.u32.f64
fsitod d0,s4 d0 := (float)s4 vcvt.f64.s32

By (double) I mean that memory address should contain an eight byte IEEE 754 64-bit float, as per poke(mem8,atom_to_float64(v)).
By (int) I really do mean a non IEEE 754 normal integer sitting in the bits of the floating point register, as per poke4(mem4,i).
Not all shorthands may be implemented correctly, and some may be ambiguous: if in any doubt simply use the full longhand form.
Aliases: just because someone else thinks vldr.f64 is a sensible way to say fldd, I don’t, and won’t support that, plus right now
I’m really feeling the need to banish each and every possible distraction, one of which is floating point ops not beginning 'f',
or perhaps more accurately, being forced to used v for vector when you’re trying to perform a simple single scalar operation.
Besides, trying to syntax-colour or F1-lookup mnemonics with dots in them promises to cause a ridiculous amount of grief!
Hence that Aliases column is just for reference here, trying to actually use anything in it will be bluntly rejected as an error.
Finally of course there is quite some bias towards meeting my needs and fitting my odd little ways of thinking, rather anyone else’s.