P32 adds the RV32M multiply/divide extension. The core still has the same
external-memory platform, UART loader, MMIO timer, and machine interrupt path,
but OP instructions with funct7=0000001 are now real instructions instead
of illegal traps.
Status: hardened with timing cleanup left. The compiled RV32IM runtime passes, ACT4/Sail
rv32i/Ipasses withPASS=39 FAIL=0 NOT RUN=0, and ACT4/Sailrv32i/Mpasses withPASS=8 FAIL=0 NOT RUN=0. LibreLane runRUN_2026-05-01_12-10-27produced final GDS and passed DRC, LVS, and antenna checks. Slow-corner setup timing, max slew, and max cap still need cleanup.
The Result
Run it:
make -C projects/32_rv32im_runtime_probe/test
Result: PASS
| check | result |
|---|---|
Build linked rv32im_zicsr runtime ELF | PASS |
| UART-load compiled image | PASS |
Execute C *, /, and % through RV32M | PASS |
Execute mulh, mulhsu, and mulhu | PASS |
| Check divide-by-zero and overflow edge cases | PASS |
MMIO UART writes M, T, E | PASS |
| MMIO timer interrupt visible to C | PASS |
| External interrupt visible to C | PASS |
Halt with x5 = 1 | PASS |
ACT4/Sail rv32i/I: PASS=39 FAIL=0 NOT RUN=0
ACT4/Sail rv32i/M: PASS=8 FAIL=0 NOT RUN=0
Harden status: PASS with timing cleanup left
| harden check | result |
|---|---|
| Run directory | projects/32_rv32im_runtime_probe/librelane/runs/RUN_2026-05-01_12-10-27 |
| Final GDS | projects/32_rv32im_runtime_probe/librelane/runs/RUN_2026-05-01_12-10-27/final/gds/top.gds |
| Metrics | projects/32_rv32im_runtime_probe/librelane/runs/RUN_2026-05-01_12-10-27/final/metrics.json |
| Magic DRC | PASS (0 errors) |
| KLayout DRC | PASS (0 errors) |
| LVS | PASS (0 errors) |
| Antenna | PASS (0 violations) |
| Hold timing | PASS (0 violations) |
| Setup timing | FAIL at slow corners; worst setup slack -7.798 ns |
| Max slew / max cap | FAIL; 8158 max-slew and 127 max-cap violations |
What Changed
The core now implements:
| instruction | behavior |
|---|---|
MUL | low 32 bits of signed/unsigned product |
MULH | high 32 bits of signed x signed product |
MULHSU | high 32 bits of signed x unsigned product |
MULHU | high 32 bits of unsigned x unsigned product |
DIV, DIVU | signed and unsigned quotient |
REM, REMU | signed and unsigned remainder |
RISC-V edge cases are included: divide by zero, signed overflow on
0x80000000 / -1, and the corresponding remainder behavior.
misa now reports IM: 0x40001100.
Runtime Shape
The runtime still uses the P31 reset/trap shape, but main.c now includes an
RV32M probe. Ordinary C operators force mul, div, divu, rem, and remu
to appear in the compiler output. Inline assembly covers mulh, mulhsu, and
mulhu, because C has no direct 32-bit high-product operator.
The generated runtime binary is 888 bytes in the current build.
Scope
This is no longer simulation-only: the backend completed and emitted final GDS. The worst part is no longer a single-cycle divider. Multiply and high-half multiply use combinational product logic; divide and remainder use a 32-cycle restoring divider. That gets P32 through physical signoff checks, but the remaining timing reports say the arithmetic datapath is too slow in the slow corners at this clock target.
Still unsupported: atomics, compressed instructions, supervisor mode, vectored
mtvec, delegation CSRs, satp, an MMU, and official full compliance
packaging.