Introduction
The ESP32 and the ESP32-S3 have a coprocessor with sixteen 32-bit single-precision registers f0 to f15, a control
register FCR and a status register FSR (the user registers 232 and 233), and
the boolean registers for compare results. There is no hardware divide or square root: they are sequences of the step instructions
below (div0.s, nexp01.s, divn.s and the sqrt0.s family), as the compiler emits them.
The ESP32-S2 and ESP8266 have no FPU. A word of the FPU encodings on a chip without it is unavailable.
The coprocessor must be enabled in CPENABLE before use. The register operands are named by the fields r, s
and t; ar and as are address registers, fr, fs, ft are floating-point registers,
br a boolean register.
Loads and stores
| Instruction | Encoding | What it does |
|---|---|---|
lsi ft, as, offset | i i 0 s t 3 | Load a float; the offset is i times 4. |
lsip ft, as, offset | i i 8 s t 3 | Load, then as += the offset. |
ssi ft, as, offset | i i 4 s t 3 | Store a float. |
ssip ft, as, offset | i i c s t 3 | Store, then as += the offset. |
lsx fr, as, at | 0 8 r s t 0 | Load a float from as + at. |
lsxp fr, as, at | 1 8 r s t 0 | Load from as + at, then as += at. |
ssx fr, as, at | 4 8 r s t 0 | Store to as + at. |
ssxp fr, as, at | 5 8 r s t 0 | Store to as + at, then as += at. |
rfr ar, fs | f a r s 4 0 | Move the bits of fs to ar. |
wfr fr, as | f a r s 5 0 | Move the bits of as to fr. |
Arithmetic and moves
| Instruction | Encoding | What it does |
|---|---|---|
add.s fr, fs, ft | 0 a r s t 0 | fr = fs + ft. |
sub.s fr, fs, ft | 1 a r s t 0 | fr = fs - ft. |
mul.s fr, fs, ft | 2 a r s t 0 | fr = fs * ft. |
madd.s fr, fs, ft | 4 a r s t 0 | fr += fs * ft (fused). |
msub.s fr, fs, ft | 5 a r s t 0 | fr -= fs * ft (fused). |
maddn.s fr, fs, ft | 6 a r s t 0 | The multiply-add step of the division and square-root sequences. |
divn.s fr, fs, ft | 7 a r s t 0 | The last step of the division sequence. |
mov.s fr, fs | f a r s 0 0 | Copy. |
abs.s fr, fs | f a r s 1 0 | Absolute value. |
neg.s fr, fs | f a r s 6 0 | Negate. |
const.s fr, n | f a r s 3 0 | Load a small constant selected by s. |
Division and square root
Division is div0.s, a few madd.s/maddn.s steps, nexp01.s and divn.s; reciprocal, square root and reciprocal
square root follow the same pattern with their own first step. The compiler emits the whole fixed sequence.
| Instruction | Encoding | What it does |
|---|---|---|
div0.s fr, fs | f a r s 7 0 | First step of a division. |
recip0.s fr, fs | f a r s 8 0 | First step of a reciprocal. |
sqrt0.s fr, fs | f a r s 9 0 | First step of a square root. |
rsqrt0.s fr, fs | f a r s a 0 | First step of a reciprocal square root. |
nexp01.s fr, fs | f a r s b 0 | Normalise the exponent for the iteration. |
mksadj.s fr, fs | f a r s c 0 | Make the square-root adjustment. |
mkdadj.s fr, fs | f a r s d 0 | Make the division adjustment. |
addexp.s fr, fs | f a r s e 0 | Add the exponent of fs to fr. |
addexpm.s fr, fs | f a r s f 0 | Add the exponent of fs to fr and set the mantissa sign. |
Conversions
The last operand is a scale: integer results are multiplied by 2t, integer sources divided by it.
| Instruction | Encoding | What it does |
|---|---|---|
round.s ar, fs, t | 8 a r s t 0 | To integer, round to nearest. |
trunc.s ar, fs, t | 9 a r s t 0 | To integer, toward zero. |
floor.s ar, fs, t | a a r s t 0 | To integer, toward minus infinity. |
ceil.s ar, fs, t | b a r s t 0 | To integer, toward plus infinity. |
float.s fr, as, t | c a r s t 0 | From a signed integer. |
ufloat.s fr, as, t | d a r s t 0 | From an unsigned integer. |
utrunc.s ar, fs, t | e a r s t 0 | To an unsigned integer, toward zero. |
Compares and conditional moves
| Instruction | Encoding | What it does |
|---|---|---|
un.s br, fs, ft | 1 b r s t 0 | br = unordered (either is NaN). |
oeq.s br, fs, ft | 2 b r s t 0 | br = equal, ordered. |
ueq.s br, fs, ft | 3 b r s t 0 | br = equal or unordered. |
olt.s br, fs, ft | 4 b r s t 0 | br = less than, ordered. |
ult.s br, fs, ft | 5 b r s t 0 | br = less than or unordered. |
ole.s br, fs, ft | 6 b r s t 0 | br = less or equal, ordered. |
ule.s br, fs, ft | 7 b r s t 0 | br = less or equal, or unordered. |
moveqz.s fr, fs, at | 8 b r s t 0 | fr = fs if at is zero. |
movnez.s fr, fs, at | 9 b r s t 0 | fr = fs if at is not zero. |
movltz.s fr, fs, at | a b r s t 0 | fr = fs if at is negative. |
movgez.s fr, fs, at | b b r s t 0 | fr = fs if at is not negative. |
movf.s fr, fs, bt | c b r s t 0 | fr = fs if boolean bt is false. |
movt.s fr, fs, bt | d b r s t 0 | fr = fs if boolean bt is true. |
Not described
Known, not yet covered
- Reference: the FCR and FSR bit fields (rounding mode, exception flags) and the exact constants
const.sloads. - Reference: the exact step semantics of the division and square-root sequences (what each of
div0.s,nexp01.s,divn.sand the others computes).
Unknown
- Reference: encodings and operands are confirmed against objdump; the descriptions are from the manual as remembered.
Links
Reference
- Tensilica – the Xtensa architecture