| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Adds a WITH_RV32E parameter (default 0, fully backwards-compatible)
that configures SERV to use 16 GPRs (x0-x15) instead of 32,
halving the register file RAM depth for ASIC area savings.
Address space with RV32E+CSR uses 5-bit addresses (0-19):
GPRs 0-15, then mscratch=16, mtvec=17, mepc=18, mtval=19
Changes:
- serv_rf_ram: add gpr_regs param, depth formula uses it
- serv_rf_ram_if: add gpr_regs param, raw = $clog2(gpr_regs+csr_regs)
- serv_rf_if: add WITH_RV32E param, update port widths and
use generate blocks for CSR address encoding
- serv_rf_top: add WITH_RV32E param, update RF_L2D, wire widths,
propagate gpr_regs/WITH_RV32E to sub-modules
- serv_top: add WITH_RV32E param, update port widths,
propagate to serv_rf_if
- serv.core: expose WITH_RV32E as a top-level parameter
The x0 zeroing logic in serv_rf_ram automatically adjusts since
it derives the register index field from $clog2(depth).
- Remove [0:0] width constraint from WITH_RV32E parameter so it can be used in arithmetic port dimension expressions like WITH_CSR - Use (|WITH_RV32E) reduction OR for boolean/ternary contexts to avoid WIDTHTRUNC warnings when testing a 32-bit parameter as a condition - Remove nested generate keyword inside generate block in serv_rf_if.v - Add WITH_RV32E to lint target parameters in serv.core - Update verilator_waiver.vlt: fix line numbers (shifted +1 by new param), update UNUSED→UNUSEDSIGNAL for Verilator 5.x rule names, add waivers for unused i_rs1_raddr[4]/i_rs2_raddr[4] bits in RV32E mode All four lint checks now pass (RV32I W=1, RV32I W=4, RV32E W=1, RV32E W=4)
- servant.v: add with_rv32e parameter; adjust rf_l2d and gpr_regs for 16-register file; propagate to servile and serv_rf_ram - servile.v: add with_rv32e parameter; adjust regs formula for 16-GPR count; propagate gpr_regs to serv_rf_ram_if and WITH_RV32E to serv_top - bench/servant_sim.v: add with_rv32e parameter; pass to servant - servant.core: expose with_rv32e as a FuseSoC vlogparam; add to verilator_tb target parameter list - sw/hello_uart_rv32e.hex: add RV32E firmware (word-per-line format for $readmemh, compiled from hello_uart.S with rv32e march)
- Makefile: add specific rules for RV32E targets using -march=rv32e
(-mabi=ilp32e) so the toolchain enforces x0-x15 register constraint:
* hello_uart_rv32e.elf: builds from hello_uart.S with rv32e march
* trap_test_rv32e.elf: builds from trap_test_rv32e.S with rv32e_zicsr
- trap_test_rv32e.S: new firmware that exercises the RV32E CSR address
paths (mtvec at RF[17], mepc at RF[18]) through a complete trap cycle:
la t0, trap_handler / csrw mtvec, t0 -- set trap vector
ecall -- trigger trap
[trap_handler]: csrr/addi/csrw mepc -- advance past ecall
mret -- return; PC = ecall+4
sw zero, 0(HALT_ADDR) -- exit simulation
Simulation reaches 'Test complete' well within 500000 cycles, proving
mtvec and mepc RF addresses are correct for the RV32E register layout.
Adds a self-contained RISCOF configuration that runs the riscv-arch-test
RV32E suite against SERV with WITH_RV32E=1 and compares signatures with
the SAIL reference model.
New files:
- config_rv32e.ini: top-level RISCOF config; DUT=serv_rv32e,
reference=sail_cSim (same reference model as RV32I run)
- plugin-serv/serv_isa_rv32e.yaml: ISA spec for RV32E_Zicsr;
misa reset-val=0x40000010 (MXL=01, E-bit=1)
- plugin-serv/riscof_serv_rv32e.py: DUT plugin derived from
riscof_serv.py with three key changes:
* Builds servant with --with_rv32e=1 into servant_test_rv32e/
(separate work root to avoid clobbering the RV32I build)
* Uses -mabi=ilp32e and constructs isa as rv32e[_zicsr]
* Includes env_rv32e/ instead of env/
- plugin-serv/env_rv32e/link.ld: identical to env/link.ld (same
SERV memory layout, no address changes needed for RV32E)
- plugin-serv/env_rv32e/model_test.h: RV32E-safe version of the
compliance test macros. The RV32I version uses a6 (x16) as a
scratch register in RVMODEL_HALT to hold the constant 10 for
hex-nibble comparison. In RV32E mode x16 maps silently to x0
(always 0), so 'blt a5, a6' would never branch and every nibble
would be mis-encoded. Fixed by replacing:
li a6, 10 / blt a5, a6, target
with:
slti t1, a5, 10 / bnez t1, target
using t1 (x6), which is within the x0-x15 RV32E register file.
Run with:
riscof run --config=$SERV/verif/config_rv32e.ini --suite=riscv-arch-test/riscv-test-suite/rv32e_m/E --env=riscv-arch-test/riscv-test-suite/env
Five issues resolved while running the compliance suite against SAIL: - serv_isa_rv32e.yaml: fix ISA canonical ordering (RV32E_Zicsr → RV32EZicsr); the underscore must only appear between consecutive Z-extensions, not before the first one - riscof_serv_rv32e.py: increase memsize 8 MiB → 16 MiB to accommodate jal-01 (the JAL test binary is ~14.7 MiB due to ±1 MiB jump offsets) - riscof_serv_rv32e.py: fix DUT signature filename from DUT-serv.signature to DUT-serv_rv32e.signature to match the plugin class name that RISCOF uses when looking up the result - riscof_sail_cSim.py: use ilp32e ABI when the ISA contains the E extension; -mabi=ilp32 is incompatible with -march=rv32e - plugin-sail_cSim/env/model_test.h: replace t5 (x30) with t0 (x5) in RVMODEL_HALT; x30 is outside the RV32E register file and is rejected by the assembler under -march=rv32e With all five fixes applied, all 37 rv32e_m/E tests pass against the SAIL reference model.
Add a short section describing the WITH_RV32E parameter, how to simulate and lint with RV32E enabled, and a pointer to the RISCOF compliance setup in verif/.
Enable the C extension alongside RV32E for ~25% code size reduction:
- serv_isa_rv32e.yaml: ISA -> RV32ECZicsr, misa reset-val 0x40000014
- riscof_serv_rv32e.py: detect C in ISA spec, build servant with --compressed=1
- sw/Makefile: add hello_uart_rv32ec.elf target (-march=rv32ec -mabi=ilp32e)
- sw/hello_uart_rv32ec.{elf,hex}: pre-built RV32EC firmware
- README: document --compressed=1 usage with RV32E
No RTL changes needed: COMPRESSED and WITH_RV32E parameters already compose
independently; serv_compdec.v delegates RV32E register checks to the main decoder.
Fix 10 issues identified during code review:
1. rtl/serv_compdec.v: remove false claim that x16-x31 traps on RV32E;
document as known limitation (aliasing to x0-x15, no trap raised)
2. verif/plugin-serv/env_rv32e/model_test.h: replace x31 (outside RV32E
range) with x15 in LOCAL_IO_WRITE_STR
3. sw/hello_uart_rv32ec.elf: remove binary from git; add .gitignore
covering *.elf, build/, riscof_work/ and other generated outputs
4. verif/plugin-serv/riscof_serv_rv32e.py: move servant build from
initialise() to build() so --compressed=1 is only passed when C
appears in the ISA spec yaml
5. rtl/{serv_rf_if,serv_rf_top,serv_top}.v, servant/servant.v,
servile/servile.v, bench/servant_sim.v: declare WITH_RV32E/with_rv32e
as [0:0] for consistent 1-bit typing (prevents silent misbehaviour
if a non-0/1 value is passed)
6. rtl/serv_rf_top.v: add comment explaining why RF_L2D repeats the
(|WITH_RV32E)?16:32 ternary instead of using the GPR_REGS localparam
7. .github/workflows/lint.yml: add lint runs with --WITH_RV32E=1 and
--WITH_RV32E=1 --WITH_CSR=0 for both W=1 and W=4
8. .github/workflows/ci.yml: add RV32EC compliance test step using
config_rv32e.ini against the C test suite
9. sw/Makefile: add trap_test_rv32ec.elf target (same source as
trap_test_rv32e.S, compiled with -march=rv32ec_zicsr); add hex
10. README.md: clarify that FPGA targets see no area reduction from
RV32E (RF fits in one BRAM block); ASIC/DFF targets save ~36% cells
Add hardware detection of illegal register access (x16-x31) in RV32E mode, triggering an illegal instruction trap (mcause=2) with the faulting instruction written to mtval. The detection covers all instruction formats including compressed instructions via the expanded 32-bit form. Key changes: - serv_compdec: expose o_illegal for truly illegal compressed encodings (gated to exclude normal 32-bit instructions passing through) - serv_csr: set mcause=2 on illegal instruction, with interrupt priority preserved (o_new_irq takes precedence) - serv_rf_if: route illegal flag and faulting instruction to mtval - serv_state: include i_illegal in trap condition - serv_top: RV32E register decoder, illegal instruction pipeline registers, and mtval shift register for serializing the faulting instruction
- bench/servant_tb.v: add missing with_rv32e and compressed parameters, wire them through to servant_sim (fixes FuseSoC sim target for RV32E) - servant.core: add compressed parameter to sim target; add with_rv32e to all FPGA board targets for consistent RV32E support - sw/trap_test_rv32e.S: add .balign 4 before trap_handler to ensure mtvec is 4-byte aligned (compressed builds placed the handler at 0x1A, causing SERV to jump to 0x18 instead) - sw/trap_test_rv32ec.hex: rebuilt with alignment fix - README.md: document illegal instruction trapping behavior and Icarus sim commands for RV32E/RV32EC
…arnings Replace 5-bit instr_rs1/rs2/rd wire declarations (where only bit[4] was used) with direct single-bit indexing into i_wb_rdt. Fixes three Verilator -Wall warnings on the RV32E register-range check logic.
serv_rf_if: In RV32E mode the RF only addresses x0-x15, so bit[4] of i_rs1_raddr/i_rs2_raddr is intentionally unused here — illegal register detection (x16-x31 trap) happens upstream in serv_top. Add a local _unused_rv32e_rs_msb wire; the _unused_ prefix suppresses UNUSEDSIGNAL and UNUSED across all Verilator versions (4.x and 5.x). ci.yml: rv32i_m/C tests require the I base ISA and selected no tests against RV32ECZicsr. Switch to rv32e_m/C (the correct E+C suite) and add rv32e_m/E to cover the base integer tests.
| Back | FazBrowse Home | New Git URL |
Add RV32E and RV32EC support
Implements the RV32E ISA variant (16-register subset, x0–x15 only) and the RV32EC extension (RV32E + compressed 16-bit instructions).
New RV32E and RV32EC RISCOF steps added to CI. Local Icarus simulations of trap_test_rv32e and trap_test_rv32ec confirm correct trap entry, mcause/mtval values, and mret resume.
Passes the existing RV32I/IM/IC/Zifencei/Privilege RISCOF suites unchanged
Addressing issue #64