Conversation
haugoug
left a comment
There was a problem hiding this comment.
Hi Marco,
thanks a lot for your contribution !
It seems you used co-simulation to do fine-grain comparison with RTL, can you give more details ?
|
Hi Germain! The idea is to have a full model of the cv32e40p in GVSOC, so inside the testbench, at each instruction retire of bot the RTL and the GVSOC implementation, PC, GPRs and CSRs are compared. I opened the PR since the model, GVSOC side, is stable enough. It does follow this openHW docmentaion (https://docs.openhwgroup.org/projects/cv32e40p-user-manual/en/cv32e40p_v1.8.3/intro.html). |
|
Nice thanks ! |
|
There are lots of modifications in the generic part of the ISS. Unfortunately, this ISS is still used for some old targets for which I don't have access to the tests anymore. |
c8f567e to
c03a77f
Compare
Branch refreshed — ready for review @haugougThe branch has been refactored and force-pushed. Head is now Commit history (linear, cleaned)Each commit is atomic, has a focused subject, and a short generic body without internal jargon. Cross-target safetyThe 4 cross-template call sites that touch shared headers ( Upstream Related PRs
Suggested merge order: this PR first, then Happy to address any feedback. |
|
Hi @haugoug I have reviewd and modified most of the files, at least I have cleaned up commetns, added a few ifguard and restructured the code a bit. There are a few part of the shared code which have been modified, but every single of them is commented and explained on how the modification of the sahred code does not affects the functionality of GVSOC. I cannot be really sure obviusly, I have build other targets with make all in GVSOC to check if nothing else was having problems, and it looked like it. But let me know if i can do other checks that you know to validate that this PR does not break anything! |
|
Unfortunately I don't have access anymore to part of the tests, so I just prefer to have zero modification in the generic. There are still modifications, can you guard them as well ? |
c03a77f to
2221697
Compare
|
memory_config.hpp was an unused leftover, it's gone. All the CV32E40P changes |
|
Hello @haugoug, do you think we can merge this? @marpac3, will you open/merge a PR also for this dpi-fidelity. Actually we moved to cv32e40p core model also on magia_V3 and I might need this merged before to open a PR for magia. Thanks. |
Add a CV32E40P core model implemented as subclasses of the generic ISS (Csr, Core, Irq, Exception): M-mode-only privilege handling, the CV32E40P CSR map (mtvec/mstatus/mcause write masks, hwloop and trigger CSRs), RTL-accurate IRQ timing, and the CoreV v2 ISA generator description. All files compile only when CONFIG_GVSOC_ISS_CV32E40P is set.
Restructure the CoreV (Xpulp) ISA header for the CV32E40P v2 encodings: hwloop immediate targets use word offsets, and p.* label aliases map to the canonical handlers per the isa_gen naming scheme. This header has no in-tree consumer on master; its only user is the CV32E40P core model.
Hook the CV32E40P subclasses into the shared ISS sources. Every change in the shared files sits inside CONFIG_GVSOC_ISS_CV32E40P (declaration of the subclass hook points, CV32E40P CSR registration, IRQ timing check); with the config unset the sources are identical to master, so other targets are unaffected.
…tion Add a virtual compute_trap_entry(base, cause, is_interrupt) so the ISS computes the trap-vector entry itself when an interrupt is taken. The base implementation returns the mtvec base (direct mode), preserving upstream behaviour for non-CV32E40P targets; Cv32e40pIrq overrides it to return the vectored entry base + cause*4 when mtvec.MODE selects vectored. This lets an external step-and-compare driver own interrupt entry via informed injection (the DUT is the oracle for which interrupt fires; the ISS takes exactly that cause and computes the matching vectored entry) instead of copying the DUT trap CSRs. The call site in Irq::check() is guarded by CONFIG_GVSOC_ISS_CV32E40P (else branch keeps the upstream mtvec.value), so the shared ISS preprocesses byte-identical without the define.
The RTL decoder (cv32e40p_decoder.sv) raises illegal-instruction on any write op to UHARTID/PRIVLV/ZFINX, and rejects even reads of ZFINX (0xCD2) when FPU=1 && ZFINX=0. The ISS declared all three in every PULP config with silently-ignored writes, so a 'csrr 0xCD2' that traps on the RTL executed on the ISS (matmul_32b_float probes exactly that at runtime). Declare ZFINX only when the RTL accepts it (FPU=0 or ZFINX=1) so the unsupported-CSR path raises illegal-instruction like the RTL, and mark all three write_illegal (csrrs/csrrc with rs1=x0 count as reads on both sides, so read-only ops stay legal).
The FS-dirty promotion block in isa_lib/macros.h redefined FREG_SET/ FREG32_SET to REG_SET under the assumption that CV32E40P always builds with ISS_SINGLE_REGFILE. That is only true for ZFINX builds: with FPU=1 ZFINX=0 the FP bank is separate, and the redefinition sent every FP arithmetic result to the integer regfile while FREG_GET kept reading the FP bank. On matmul_32b_float (pulp_fpu) an fmadd.s overwrote the x15 data pointer and the next flw faulted outside the memory map; fmv.w.x results never reached the FP bank at all. Keep REG_SET on single-regfile builds and use set_freg otherwise. With this and the 0xCD2 fix, matmul_32b_float runs correctly through all FP arithmetic.
The RTL decoder rejects the reserved rounding modes (static rm 101/110, and dynamic rounding when frm holds 101/110/111); the ISS silently fell through the setFFRoundingMode switch and executed the instruction with the previous host rounding mode, diverging from the RTL at the first reserved-rm encoding of illegal_fp_instr_test. Raise ISS_EXCEPT_ILLEGAL from setFFRoundingMode for those encodings and kill the side effects of the trapped instruction, as the RTL does: the fflags update returns early when an exception is pending, and the CV32E40P FREG_SET/FREG32_SET writeback macros evaluate the value first (the raise happens inside it - testing has_exception before would always see the pre-raise state) and then skip both the register write and the FS=Dirty promotion. All the changes stay inside the CONFIG_GVSOC_ISS_CV32E40P block; RMM (rm=4) keeps the pre-existing unimplemented-mode exit, pending a decision on implementing it. illegal_fp_instr_test (pulp_fpu) now passes end to end, every trap matching the RTL one for one. Non-regression: matmul_32b_float (pulp_fpu), pulp_hardware_loop (pulp) and hello-world (default) all pass; the zfinx build (single-regfile branch of the same macros) is unchanged.
REG_SET now applies the same has_exception guard as the FP write-back macros. A reserved FP rounding mode raises illegal-instruction inside the value expression, and fcvt-class results land in an integer rd, so guarding only the FP macros left that path writing a trapped result. The value is evaluated before the guard so the raise is observed.
Make corev.hpp compile on both ISS generations, following the CONFIG_GVSOC_ISS_V2 dual-implementation pattern already used by pulp_v2.hpp: - Include the isa_lib macros directly (like rv32i.hpp does): iss_v2 emits ISA-subset includes in subset order, so this header can no longer rely on rv32i.hpp having pulled them in first. - Guard the v1-only hardware-loop machinery (stub handler, exec/csr shadow state) and add iss_v2 setters that program the Hwloop module directly. Same RTL-grounded semantics as the v1 path: lpstart/lpend bits [1:0] hardwired to 0, and the module end set to LPEND - 4 because the v2 check() compares the just-executed pc (the core loops back from the last body instruction). Known bring-up limitation: the v2 Hwloop module also backs the CSR read path, so a raw lpend csrr reads back LPEND - 4 until a CV32E40P hwloop personality keeps the architectural value. - cv.elw falls back to a plain load on iss_v2 (no event-load LSU on this core), mirroring the pulp_v2.hpp fallback. - The CoreV2 ISA subset now declares its handler header via includes=, like PulpV2 does; v1 builds keep getting it from the core class.hpp (double include is guarded). Validated on the cv32e40p-v2-spike target (hello + hand-encoded cv.lw post-increment and lp.setupi probes, all passing); the v1 targets are unchanged (two identical runs).
…tatus policy Two generic knobs for core personalities whose RTL implements a closed, M-mode-only CSR map: - Csr::raise_on_unsupported_csr: when set, a CSR address missing from the declared-register map raises illegal-instruction instead of falling back to the legacy switch, so the declared map is the whole CSR space. The exception is raised at most once per instruction: the csrrw handlers dispatch the read and the write back-to-back and Exception::raise is not idempotent (a second call would capture mpie after irq_enable was already cleared). - CONFIG_GVSOC_ISS_CORE_MSTATUS_WRITE_MASK: the recipe takes over the whole mstatus policy; the generic vector/user-state clears and the forced-dirty FS/SD reset bits do not apply. Plus CsrAbtractReg::set_write_mask and Csr::undeclare_csr accessors used by such personalities. Default behaviour is unchanged for every existing core.
…ent irq_riscv header On iss_v2 the corev handlers are only pulled in by the CoreV2 subset, so the CV32E40P word-offset encoding of lp.starti/lp.endi applies there unconditionally (the v1 gate keys on CONFIG_GVSOC_ISS_CV32E40P, which v2 builds do not define). irq_riscv.hpp uses InsnEntry but did not include insn.hpp; the generated ISA header can emit it first, before any header that provides the type.
Restore the disabled exception stubs in the unsupported-CSR fallthroughs and the original comment wording in the Core constructor: the strict-CSR and mstatus-mask additions must not drop or reword any upstream line.
…efine The RTL forces mstatus.FS to Dirty on any FP register-file write (FP loads included) when the FPU registers are in the ISA. A core recipe opts in with CONFIG_GVSOC_ISS_FP_STATE_DIRTY, which adds an iss->csr.fp_state_dirty() call to the iss_v2 FREG_SET/FREG32_SET macros and to the flw handlers (the LSU writes the register there, the macros never see it). Without the define every branch compiles exactly as before.
Inactive rows never decode nor execute (the decoder checks is_active first), but their emitted handler symbols forced the generated table to reference handlers from headers of disabled subsets. With NULL on inactive rows an rv32imc core without the FPU module now builds on iss_v2 (the compressed FP rows no longer pull in rvf.hpp).
…v2 core Extend the three CONFIG_GVSOC_ISS_CV32E40P gates in the FP rounding helpers to a standalone CONFIG_GVSOC_ISS_CV32E40P_FP_TRAPS define so the iss_v2 recipe can enable reserved rounding-mode traps without the v1 core define, arming the regfile write-back suppression on the raise (the v2 macros have no write-back guard). On hwloop end writes, keep the architectural LPEND in the csr personality: the loop module stores end - 4 and re-deriving the CSR readback as get_end() + 4 would return 4 on a never-programmed loop.
The CoreV2 table accepted encodings the RTL decoder rejects, so on an illegal-instruction probe the reference model executed the word and trapped one instruction late (mepc off by 4). Exhaustive sweep of the four custom opcode spaces against the cv32e40p_decoder.sv rules found three gap classes, all fixed here: - custom-3 SIMD: bit 25 must be zero for the non-.sci variants, cv.abs and cv.cplxconj require rs2=0, extract/insert and the .sci shifts and shuffles bound their immediates (138 rows tightened); - cv.bitrev: bits 29:27 must be zero; - cv.elw decodes only when the core is built for a cluster - the subset takes an elw parameter now, defaulting to the RTL COREV_CLUSTER=0. The inverse direction was also swept: no RTL-legal encoding was left without a decoder row.
The RTL raises fflags_we on apu_valid, so compare, convert, classify and fmv.x ops dirty FS even when no flag ends up set. FP register write-backs already got this from the FREG*_SET macros; route the GPR-writing handlers through the same fp_state_dirty hook, guarded by the existing CONFIG_GVSOC_ISS_FP_STATE_DIRTY opt-in.
A zero-latency first beat retires synchronously inside data_req_aligned and frees its request entry; arming the second-beat state on the entry peeked afterwards contaminated the free list, so a later aligned access fired a phantom second beat and its instruction was never terminated (commit starvation). Arm the state before issuing the first beat, disarm it when the queue stalls the request, and retire the held instruction inline when the second beat completes synchronously.
PrefetchSingleLine::flush() only set buffer_start_addr=-1 and relied on the unsigned fast-path index going out of window. The index wraps to addr+1 for every address, so a fetch in the first bytes of the address space (addr <= 0x0b with a 16-byte line) is still in-window and the flushed line was read without a refill: stale bytes were decoded (bogus next-PC on a redirect into that window). Track validity with an explicit buffer_valid flag, force the refill path while it is clear, and honor a pending front-end flush in the fast dispatch handler too (only the slow handler did).
The CV32E40P manual (instruction_set_extensions.rst, cv.clipr/cv.clipur) defines the register-form clip bound as rs2' = rs2 & 0x7FFFFFFF; the handlers used rs2 as-is, so a negative rs2 produced an inverted range (low > high) and lib_CLIP returned the low bound where the RTL, per spec, clips against the masked value (verified 28/28 on a characterization program incl. INT_MIN edge cases). Masking also removes the implementation-defined signed narrowing of the previous code.
External co-simulation controllers live in a separate shared object and can only call ISS methods that inline: the model library does not export its symbols, so a .cpp-defined method links but fails at its first call. Hwloop state is restored through set_start/set_end/set_count; their definitions move to the header - a pure relocation, no semantic change.
The norm-round MAC helpers (lib_MAC_*_NR_R) computed the accumulate sum in exact precision and added the rounding constant after the fact. The RI5CY-family mult datapath wraps a + b*c + round to 32 bits before the arithmetic (signed) or logical (unsigned) shift, so whenever the exact sum crosses the 32-bit boundary the two disagree on the sign of the result. Move the rounding constant inside the 32-bit wrap and shift the wrapped value. The unsigned pair also gains an explicit uint32_t multiply: uint16_t operands promote to int and 65535*65535 overflows it. CV32E40P exercises the SL/SH path (its Z* variants go through local reimplementations); the ZL/ZH helpers get the same fix for consistency.
The cv.lb/lh/lw post-increment handlers performed the load first and wrote the incremented base last, so with rd == rs1 the increment overwrote the loaded data. The CV32E40P ISA extension spec gives the loaded data priority in that case. Capture the base (and, for the register-register forms, the offset - rs2 may alias rd too) up front, write the incremented base, then perform the load so the loaded data lands last. Covers the 20 RI/RR handlers in both the fast and the event-accounting paths.
…g semantics) Shared RVC decoder header (v1 and v2 exec models): - Reserved code-points now raise an illegal-instruction exception instead of executing as their all-zero-field neighbours: c.addi4spn with nzuimm=0, c.addi16sp/c.lui with imm=0, c.lwsp with rd=0 and c.jr with rs1=0. Guards test the raw opcode with the same masks the CV32E40P compressed decoder uses; both fast and checked handler variants are covered. - c_ebreak_exec now mirrors the 32-bit ebreak_exec semantics: in debug mode it re-enters the debug ROM at the halt address (the previous dcsr-bit test was dead code and the ISS walked past the instruction); with dcsr.ebreakm set in M-mode it enters debug; otherwise it raises BREAKPOINT. The semihosting probe stays on the uncompressed form only, where it is specified. The reserved code-point checks are opt-in via CONFIG_GVSOC_ISS_RVC_STRICT (defined by cv32e40p_v2.py): spec-correct, but 0x0000 turning from a silent nop into a trap would change the traces of every other core - they keep the historical permissive decoding by default. The c.ebreak debug-mode alignment with the 32-bit twin stays ungated (inert for cores that never enter debug mode).
New CONFIG_GVSOC_ISS_CV32E40P_V2 branch in the shared decoders: when csr.ebreak_m_mode_enters_debug() (dcsr.ebreakm=1 in M-mode) the instruction arms a debug request (cause=1) instead of raising the breakpoint exception. The v2 personality's Cv32e40pIrq::check() performs the actual entry at the next dispatch boundary, so the ebreak never retires and mcause/mepc stay untouched, matching the hardware, which redirects straight to the debug-ROM entry. The v1 flag (CONFIG_GVSOC_ISS_CV32E40P) stays off in v2 builds: its branch calls dbgunit.set_halt_mode, which does not exist in the v2 personality.
A store into an already-decoded page (self-modifying code executed without fence.i) left the stale decoded instructions in place: cores that fetch straight from memory, like CV32E40P, see the new code on the next fetch, so the model must follow. The LSU store path now queues a deferred front-end flush when the target hits a decoded page (InsnCache::covers); the flush itself runs at the next dispatch boundary (icache_flush), because flushing inline would free the page holding the store instruction itself. The check runs after address translation (insn-cache pages are keyed on physical addresses - the virtual address would be the wrong key on an MMU-enabled core), the second page lookup only fires when the access actually crosses a page boundary (one hash per store on the hot path) and size==0 cannot underflow. The latent SC/AMO gap is documented at the hook: no iss_v2 core wires LsuV2::atomic today. Seen on cv32e40p debug_hwloop_test: the debugger overwrites an ebreak inside a hardware-loop body and jumps back into it.
The dispatch loop ran hwloop.check() unconditionally after insn_exec, so a trapping loop-end instruction (e.g. an ebreak sitting at lpend) still decremented the loop counter. On the RTL the exception kills the instruction before the loop update - lpcount must not move. Both dispatch paths now skip the check when the handler raised.
Address the core enters on an exception taken while in debug mode (and, on CV32E40P, on mret in debug mode). Defaults to debug_handler when not given, so existing platforms are unchanged.
The dispatch called check() only when skip_irq_check was clear, so a personality could never evaluate synchronous debug conditions (execute- address triggers, mcontrol timing=before) on a suppressed boundary - an external lockstep controller holding the line high had to peek at the model's trigger CSRs to open the gate itself, a layering violation. The call is now unconditional and each check() implementation consumes the flag at its head; semantics are unchanged for every existing caller (reset, gdb resume, external stepping).
Rounding mode 4 (round to nearest, ties to max magnitude) used to abort the simulation because fenv has no such mode. flexfloat_sanitize already resolves rounding in software from the round and sticky bits, so RMM only needs a flag: with FE_TONEAREST set and flexfloat_rmm active, a tie rounds away from zero instead of to even. The flag is scoped to the per-instruction set/restore pair in setFFRoundingMode. Overflow now honours the direction of the rounding mode as IEEE 754 requires: toward-zero (always), downward (positive results) and upward (negative results) clamp to the largest finite value instead of returning infinity.
The RMM path of the flexfloat float-to-int conversions negated the input to round on its magnitude, then dropped the sign: - lib_flexfloat_cvt_wu_ff_round returned |x| for a negative x instead of 0. Unsigned conversion of a negative value saturates to 0; the negation hid the sign from double_to_uint, which already saturates correctly, so the magnitude leaked through (0xffffffff / |x| instead of 0). - lib_flexfloat_cvt_w_ff_round saturated a negative overflow to INT32_MIN+1 (0x80000001) instead of INT32_MIN (0x80000000): |INT32_MIN| = 2^31 is not representable as a positive int32, so the magnitude saturated to INT32_MAX and negating it was off by one. Fix: do not hide the sign from double_to_uint/double_to_int, which saturate with the correct signed/unsigned bounds; restore the saved rounding mode (was passing new_round instead of old, unlike the unsigned sibling). quick_val: data_fwd, mlt_cyc (F) and test, sanity (Zfinx) flip FAIL->PASS; 76 PASS / 10 FAIL (was 72 / 14), no regressions.
Four fixes in the shared FP backend (every core using flexfloat via isa_lib is affected; all are spec-driven and format-generic): - ff_fma/ff_fnma: round-to-odd binary64 intermediate (truncate toward zero, force the mantissa LSB on inexact). An odd intermediate keeps faithful round/sticky bits for any narrower destination, removing the fused-op double rounding structurally. Exact zeros are recomputed in the instruction rounding mode (on the negated fusion in ff_fnma) so the -0 sign under RDN survives; INVALID is re-raised, INEXACT is re-derived downstream. - flexfloat_sanitize: the one-ulp rounding increment is applied after an integer truncation of the discarded bits, so the grid-step addition is exact. The former a->value += ulp rounded in the backend format and could overshoot the target grid by one ulp when the discarded bits extended to the bottom of the backend mantissa. - underflow now follows IEEE 754 tininess after rounding with unbounded exponent range (matching FPnew's uf_after_round formula, including the subnormal-to-smallest-normal carry-out escape), gated on inexact. - sticky bit: a shift beyond the backend width means every significant bit of a nonzero value lies below the sticky window; return 1 instead of 0 (fixes lost NX/UF and directed rounding to the smallest subnormal for deeply tiny results, e.g. min_normal/2 squared in RUP). Validated bit- and flag-exact against the CV32E40P FPnew implementation (F and Zfinx configurations) on directed boundary vectors. The tininess detection point (the one genuinely implementation-defined choice IEEE 754 leaves open) is opt-in: the after-rounding-unbounded escape probe (FPnew parity) is gated by FLEXFLOAT_TININESS_AFTER_ROUNDING (enabled by cv32e40p_v2.py); the default keeps flexfloat's historical before-rounding detection for the other cores. The unconditional-UF fix (underflow = tiny AND inexact) applies to everyone: exact subnormals must not raise UF.
Five exception-flag defects in the shared FP backend, all spec-driven and
format-generic:
- flexfloat_sanitize: a backend value that is already infinite no longer
raises OF|NX. IEEE 754 7.4 defines overflow as the result rounded with an
unbounded exponent range exceeding the destination range; an infinity
propagated from an operand is exact, and a division by zero raises its own
flag. A genuine destination overflow leaves the backend finite and is
still handled by the (exp >= inf_exp) branch.
- lib_flexfloat_min: raise NV on a signaling NaN input. IEEE 754-2019
minimumNumber/maximumNumber, which is the semantics RISC-V gives
fmin/fmax, signals invalid on sNaN; the fmax twin already did this.
- ff_fma/ff_fnma: inf*0 raises NV even when the addend is a quiet NaN.
IEEE 754 7.2 leaves that sub-case implementation-defined and the host FMA
propagates the NaN silently, but RISC-V mandates the flag (unpriv F).
- double_to_{int,uint,long,ulong}: NX is raised only on a valid conversion.
An invalid float-to-integer, NaN or out of range, raises NV alone; the old
test fired on NaN as well, since NaN != NaN holds.
- lib_flexfloat_cvt_ff_{w,wu,l,lu}_round: collect NX on an inexact
integer-to-float. flexfloat_sanitize already raised FE_INEXACT in the host
fenv, it was simply never read back into fflags.
The integer-to-float change also restores inexact reporting on the vector
vfcvt/vfncvt lanes, which go through the same conversion helpers.
Checked against riscv-arch-test 3.9.1 with the Sail C emulator 0.13.1 as
reference model through RISCOF: the F suite goes from 313/342 to 342/342 and
the whole run from 402/434 to 431/434. The three residual failures are the
mtvec reset MODE difference in the reference configuration (cebreak, ebreak,
ecall) - unrelated to floating point and out of scope here.
flexfloat and isa_lib are shared with the other cores built on this backend
(ara, cva6, snitch, spatz), so the flag behaviour changes for all of them.
Anything downstream whose golden output was calibrated on the previous flags
may move; the new behaviour is the one IEEE 754 and the RISC-V F extension
prescribe.
…lags Three residual flag defects in the shared flexfloat backend, follow-up to the fflags conformance pass: - lib_flexfloat_cvt_w_ff_round, RMM: the +0.5 nudge fed the nudged value to the generic converter, so the flags were computed against the WRONG operand - a spurious NX on every exact-integer input (x+0.5 truncates) and a lost NX on every half-tie (x+0.5 lands on an integer). RMM is now trunc(|x|+0.5) with the sign re-applied, NX decided against the original operand, NV alone on saturation (IEEE 754 7.2, RISC-V F 11.7), and a NaN input keeps the generic path. - lib_flexfloat_cvt_wu_ff_round, RMM: same flag discipline; in addition a negative operand that rounds half-away below zero is out of range for the unsigned destination and must raise NV alone with result 0 - the old path handed it unrounded to the RTZ converter, so RMM(-0.5) came back 0 with a mere NX. - lib_flexfloat_cvt_ff_ff_round: a narrowing format conversion rounds and can overflow/underflow; flexfloat_sanitize raises the host fenv flags inside ff_cast but they were never collected here, unlike every sibling conversion in this file. Clear + collect around the cast. Validated with riscv-arch-test 3.9.1 via RISCOF against Sail: 431/434 overall, F suite 342/342.
…inity In flexfloat_sanitize, the rounding step for a round-away decision at the top of the largest binade builds its increment with flexfloat_pack at exponent inf_exp, which packs the increment itself as infinity: adding it turns the value into Inf during rounding, and the overflow tail then reads the exponent as an operand-propagated infinity and raises no flags. Guard the head of the rounding path so a finite value that crosses into the infinite exponent through rounding still goes through the overflow tail: the result keeps the directed clamp and now raises OF|NX as required by IEEE 754. The window is a single exponent value per format, which is why targeted conformance suites miss it.
2221697 to
056b4bd
Compare
|
Force-pushed: the branch is reworked and extended since the last push. The |
|
I don't know how to review this huge PR to be honest. When so many files need to be modified, maybe it is time to create a new component. Could you just create a CV32 component in gvsoc_pulp repo and put all the code here ? It seems you used AI for this PR, it's something AI can do very easily. |
CV32E40P reference-model line for the GVSOC core repo:
CONFIG_GVSOC_ISS_*defines (preprocessor-dead unless a CV32E40P platform enables them);
models/cpu/iss/include/cores/cv32e40p/);on;
(flexfloat: fix fcvt.w/wu saturation and RMM rounding #160, flexfloat: FP corner cases for single-rounding parity #161, iss: RVC decoder spec compliance (reserved code-points, c.ebreak debug semantics) #162, flexfloat: fflags conformance for IEEE 754 / RISC-V F #163): they sit at the base of this branch.
History is grouped by theme (flexfloat, RVC decoding, shared-ISS guards,
v2 exec/prefetch/LSU, debug, CV32E40P core model); each commit message
states what changed, why, and how it maps to the CV32E40P RTL or the
RISC-V spec.
Validation on this exact tree: lockstep RVVI co-simulation against the
CV32E40P RTL, 4 configurations, corev-dv random plus directed tests;
riscv-arch-test 3.9.1 via RISCOF with Sail 0.13.1 (431/434 overall, F suite
342/342); build smoke on
pulp-openandsnitchwith bit-identical traces.Once the standalone flexfloat/RVC PRs merge, this branch rebases onto master
and shrinks to the CV32E40P-specific commits.