R7FA2L1A92DFN: No Floating Point Unit, and the Library That Replaces It
A 32-bit core at 48 MHz with no floating-point unit is a deliberate engineering choice. It costs silicon area and power that a product at this price point cannot spend, and it is entirely adequate for the arithmetic these products actually do.
The consequence for firmware is that any decimal arithmetic is performed by a software library, and a software floating-point library is a large, distinctive, oddly-shaped block of integer code that looks nothing like the rest of the image. That makes it both a landmark and a diagnostic.
What the core does and does not have
The core is an Armv8-M baseline design: thirty-two-bit registers, the Thumb instruction set, a hardware multiplier, and no floating-point registers at all. Single-precision and double-precision values are just bit patterns in ordinary registers, and every operation on them is a function call.
That has three effects worth knowing before opening a disassembly:
- there are no floating-point instructions in a valid image for this part, because the core cannot decode them;
- every decimal addition in the source becomes a call in the binary, which changes the shape of the call graph;
- the library is shared, so it appears once, near the end of the image, rather than at each use site.
The third point is the useful one. A single copy of the library serves the whole program, which means one location explains every decimal operation in the product.
The constants that give the library away
A software implementation of binary floating point manipulates the format directly: sign bit, exponent field, mantissa field. It therefore contains the format’s masks as literal constants, and those constants are unmistakable.
| constant | width | what it masks |
|---|---|---|
| 0x7F800000 | 32-bit | the exponent field of a single-precision value |
| 0x007FFFFF | 32-bit | the mantissa of a single-precision value |
| 0x00800000 | 32-bit | the implicit leading bit |
| 0x80000000 | 32-bit | the sign bit |
| 0x7FF0000000000000 | 64-bit | the exponent field of a double |
| 0x000FFFFFFFFFFFFF | 64-bit | the mantissa of a double |
On a core with no floating-point unit these have to be built with a pair of immediate loads, so each one appears as two consecutive instructions followed immediately by a logical operation. A search for the 32-bit pair alone locates the single-precision routines with near certainty.
Around those constants the code has a characteristic texture: shifts and rotates in both directions, conditional paths for zero and for denormal inputs, and a normalisation loop that shifts left until the leading bit appears. Normalisation is the giveaway, because ordinary integer code almost never does it.
Why the library matters to a reader
Two reasons, both practical.
The first is navigation. The library is usually the largest single block in the image and it is entirely uninteresting to the customer. Identifying it lets it be set aside, which reduces the code that has to be read by a third or more on a firmware that does any real arithmetic.
The second is interpretation. Where the library is called, something is being computed in engineering units. That is where the scaling, filtering and control laws live, and those are usually what a customer wants reconstructed. A call into the library is a signpost saying «the interesting arithmetic starts here».
| call site pattern | what it suggests |
|---|---|
| convert integer to single precision, multiply by a constant | scaling a measurement |
| a chain of multiply and add on converted values | a polynomial or a filter |
| conversions on both sides of a comparison | a threshold expressed in engineering units |
| conversion only at the output | internal computation is fixed point |
The last row is the common case in well-written embedded code, and it tells you the designer knew what the core could do.
The inverse test
Here is a use of the library that is not about reading but about verifying.
Because this core cannot execute floating-point instructions, an image containing them did not come from this part. That is a decisive test rather than a hint: a single floating-point instruction in the stream proves the image belongs to a different device, one with an FPU.
| observation | conclusion |
|---|---|
| library constants present, no FPU instructions | consistent with this part |
| FPU instructions present anywhere | not from a baseline core |
| no library and no FPU instructions | all arithmetic is integer; consistent with this part |
The second row is worth applying to any image whose provenance is uncertain, particularly where a product family has both variants and the customer does not know which board they sent.
Fixed point, and how it differs
The alternative to the library is fixed point: values held as scaled integers, with a shift after each multiply. It produces code that is faster, smaller and much harder to read, because the scaling is implicit in the constants rather than stated by the type.
The signature is a multiply immediately followed by a shift right, repeated throughout the arithmetic, with no conversion calls anywhere. Where that pattern appears alongside calibration constants, the reader is looking at a design that was optimised by somebody who knew the cost of a library call.
Reading a numeric firmware
- Locate the library by searching for the mantissa mask pair.
- Map its entry points: the add, subtract, multiply, divide and comparison routines are usually adjacent.
- Find the callers. Each is a computation in engineering units.
- Read outward from the callers to the constants they use, which are the physical scaling factors.
- Where no library exists, look for multiply-followed-by-shift instead, and treat the shift as the scale.
Step four is where the value is. The arithmetic itself is generic; the constants are the product.
What the deliverable contains
The return set is the code flash image, the data flash separately, the configuration words, the identification words as read, a disassembly with the library identified and its entry points labelled, and a note on which arithmetic style the firmware uses.
That note matters for a rebuild. A customer who commissions a replacement in floating point on the same part will get a slower, larger product than the one they had, and the note is the evidence for that warning.
The calibration constants that feed this arithmetic are covered in R7FA2L1A93CFL software recovery. The crypto block that also lives outside the core in R7FA2L1A92DFP heximal recovery, and the clock that sets how expensive each library call is in R7FA2L1A93CNE binary recovery.
FAQ
Can this part run floating-point code? Yes, through a software library. The core executes integer instructions that implement the format.
How large is the library? Large enough to be the biggest single block in most images on a part this small, which is why identifying it saves so much reading.
Does the presence of the library affect a recovery? No. It makes the image bigger and the disassembly noisier, and it is removed from consideration once located.
Conclusion
A core without an FPU forces decimal arithmetic into a library, and the library announces itself with masks that cannot appear in ordinary integer code. Finding it does two jobs at once: it removes a third of the image from the reading list, and it marks the places where the product computes something real. Its absence is equally informative, because an image with floating-point instructions did not come from this part.