FPSCR modes: one word, several meanings
The floating-point instructions all live in line F (1111 ...). Two bits of the FPSCR register, which the instruction stream does not carry, change what some of them are:
| PR | SZ | FMOV | FADD, FSUB, FMUL, FDIV, FCMP, FABS, FNEG, FSQRT, FLOAT, FTRC |
|---|---|---|---|
| 0 | 0 | Moves one 32-bit register: fmov fr1,fr2, fmov.s @r4,fr0 | Single precision, on fr registers. |
| 0 | 1 | Moves a 64-bit pair: fmov dr2,dr4, fmov xd0,dr2, fmov.d @r4,dr0. An odd register field names the other bank (xd). | Single precision, on fr registers. |
| 1 | 0 or 1 | As for the SZ bit. | Double precision, on dr pairs. The register field must be even: fadd dr2,dr4 is 1111 nnn0 mmm0 0000. An odd field is reserved. |
The same bit patterns therefore decode differently: 0xF20C is fmov fr0,fr2 with SZ = 0, and fmov dr0,dr2 with SZ = 1; 0xF200 is
fadd fr0,fr2 with PR = 0 and fadd dr0,dr2 with PR = 1. A few instructions exist in only one precision:
fmac, fldi0, fldi1, fipr, ftrv, fsca
and fsrra need PR = 0; fcnvsd and fcnvds need PR = 1. Used in the wrong mode the manual says the result is
undefined and the explorer gives the status unpredictable.
What the explorer tracks. Nothing: it cannot see the value in FPSCR. SZ and PR are options (the options bar of the viewer: "FPSCR.SZ" and "FPSCR.PR") with the default 0, and the choice applies to the whole region.
The instructions that change the bits say so in their notes: fschg (toggles SZ), frchg (toggles FR),
fpchg (toggles PR, SH-4A), and lds Rm,fpscr and lds.l @Rm+,fpscr (load all bits).
Dreamcast code uses fschg in pairs around 64-bit block copies, and lds of a constant from a literal pool at the start of a function to set PR and SZ.
The FR bit swaps which bank is called fr and which xf; it does not change any encoding, so the disassembly does not depend on it.
Arithmetic and comparison
Shown for PR = 0 (single precision, registers FRm, FRn); with PR = 1 the same encodings use DRm, DRn (bits 7 and 11 must be 0). All of these read FPSCR.
| Instruction | Encoding | Chip | What it does |
|---|---|---|---|
fadd FRm,FRn | 1111 nnnn mmmm 0000 | SH-4 | FRn = FRn + FRm. |
fsub FRm,FRn | 1111 nnnn mmmm 0001 | SH-4 | FRn = FRn - FRm. |
fmul FRm,FRn | 1111 nnnn mmmm 0010 | SH-4 | FRn = FRn * FRm. |
fdiv FRm,FRn | 1111 nnnn mmmm 0011 | SH-4 | FRn = FRn / FRm. |
fcmp/eq FRm,FRn | 1111 nnnn mmmm 0100 | SH-4 | T = 1 when FRn = FRm. |
fcmp/gt FRm,FRn | 1111 nnnn mmmm 0101 | SH-4 | T = 1 when FRn > FRm. |
fmac FR0,FRm,FRn | 1111 nnnn mmmm 1110 | SH-4 | Multiply and add: FRn = FRn + FR0 * FRm. PR = 0 only. |
fabs FRn | 1111 nnnn 0101 1101 | SH-4 | FRn = |FRn|. |
fneg FRn | 1111 nnnn 0100 1101 | SH-4 | FRn = -FRn. |
fsqrt FRn | 1111 nnnn 0110 1101 | SH-4 | FRn = the square root of FRn. |
fsrra FRn | 1111 nnnn 0111 1101 | SH-4A | FRn = an approximation of 1 / sqrt(FRn) (SH-4A only). PR = 0 only. |
Moves, constants, conversion
| Instruction | Encoding | Chip | What it does |
|---|---|---|---|
fmov FRm,FRnfmov.s @Rm,FRnfmov.s @Rm+,FRnfmov.s @(R0,Rm),FRnfmov.s FRm,@Rnfmov.s FRm,@-Rnfmov.s FRm,@(R0,Rn) |
1111 nnnn mmmm 11001111 nnnn mmmm 10001111 nnnn mmmm 10011111 nnnn mmmm 01101111 nnnn mmmm 10101111 nnnn mmmm 10111111 nnnn mmmm 0111 |
SH-4 | Copy or load or store one single-precision register. With SZ = 1 each moves a 64-bit pair (fmov.d, dr for an even field, xd of the other bank for an odd field), and the post-increment and pre-decrement steps are 8. |
fldi0 FRn | 1111 nnnn 1000 1101 | SH-4 | FRn = 0.0. PR = 0 only. |
fldi1 FRn | 1111 nnnn 1001 1101 | SH-4 | FRn = 1.0. PR = 0 only. |
flds FRm,FPUL | 1111 mmmm 0001 1101 | SH-4 | FPUL = FRm (the raw 32 bits). |
fsts FPUL,FRn | 1111 nnnn 0000 1101 | SH-4 | FRn = FPUL (the raw 32 bits). |
float FPUL,FRn | 1111 nnnn 0010 1101 | SH-4 | Convert the integer in FPUL to floating point in FRn (PR = 1: DRn). |
ftrc FRm,FPUL | 1111 mmmm 0011 1101 | SH-4 | Convert FRm to an integer in FPUL, truncating toward zero (PR = 1: DRm). |
fcnvsd FPUL,DRn | 1111 nnn0 1010 1101 | SH-4 | Convert the single-precision value in FPUL to double precision in DRn. PR = 1 only. |
fcnvds DRm,FPUL | 1111 mmm0 1011 1101 | SH-4 | Convert the double-precision value in DRm to single precision in FPUL. PR = 1 only. |
Vector and matrix instructions
These work on four single-precision values at once: fv0, fv4, fv8, fv12 are the four-element vectors of the front bank, and xmtrx is the 4 x 4 matrix in the back bank (xf0 to xf15).
A 3D transform is one ftrv per vertex; a dot product is one fipr. They need PR = 0.
| Instruction | Encoding | Chip | What it does |
|---|---|---|---|
fipr FVm,FVn | 1111 nnmm 1110 1101 | SH-4 | Inner product: the last element of FVn (fr3, fr7, fr11 or fr15) = the sum of FVn[i] * FVm[i]. |
ftrv XMTRX,FVn | 1111 nn01 1111 1101 | SH-4 | FVn = the matrix in the back bank times the vector FVn. |
fsca FPUL,DRn | 1111 nnn0 1111 1101 | SH-4A | The sine and cosine of the angle in FPUL (a 16.16 fixed-point count of turns, 65536 = one turn) into the pair DRn (sine in the even, cosine in the odd register). SH-4A only. |
Mode instructions
| Instruction | Encoding | Chip | What it does |
|---|---|---|---|
fschg | 1111 0011 1111 1101 | SH-4 | Toggle FPSCR.SZ: the 32/64-bit choice of FMOV. |
frchg | 1111 1011 1111 1101 | SH-4 | Toggle FPSCR.FR: swap the front and back register banks. |
fpchg | 1111 0111 1111 1101 | SH-4A | Toggle FPSCR.PR (SH-4A only; on an SH-4 PR is set with lds). |
Not described
Known, not yet covered
- Reference and viewer: the single-precision subsets of the SH-2E and SH-3E, and the SH-2A double-precision unit with its own encodings.
- Viewer: tracking of FPSCR through a function (the viewer takes SZ and PR as options).
- Reference: the exception behaviour (cause and enable bits, denormal handling, the FPU error) and the exact results of
fsca,fsrraandfipr, which are not IEEE-exact.
Unknown
- Reference: whether every odd-field encoding with PR = 1 is "reserved" or "undefined" differs between manuals; the explorer says reserved.
- Reference: the encodings were written from memory of the SH-4 manual. The whole line was compared with a second hand-written table (the same author) for all four modes, and the integer part and a part of the FPU (single-precision, SZ = 0) with the debugger's SH-4 disassembler; the double-precision and SZ = 1 forms, FIPR, FTRV, FSCA and FSRRA have no independent check.