Verilator as a first-class simulator: integration branch#3
Open
nanavati wants to merge 61 commits into
Open
Conversation
simCOpt moves block-local defs into their using function; the order came from the Id sort, which is hierarchy-dependent. Sort by base name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The port list came from an AId-keyed map, whose Ord is run-dependent. Sort by base name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tsort breaks ties by the run-dependent AId Ord. Rank def nodes by id-name around the tsort so the statement order is stable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The member defs were ordered by an AId-keyed map, whose Ord is run-dependent. Sort by base name. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When linking a Bluesim simulation (bsc -sim -e <top>), bsc generates the per-module and whole-design-model C++ source, then compiles and links it into a shared object. The new -sim-codegen-only flag stops after generation: it writes the .cxx/.h files to the simulation directory without compiling or linking them. This lets an external build system own the C++ compile and link as separate steps, so that identical per-module C++ can be compiled once and shared across simulation executables instead of being recompiled inside every link. The flag also disables the stale-object reuse analysis so the generated file set is deterministic and complete on every run, and is rejected when linking with a non-Bluesim backend. The top-module runtime-suitability checks (always_enabled interfaces, top-level arguments and parameters) are skipped under the flag, since the generated model is never executed and any module may serve as the codegen root. Note: the new Flags field changes the .ba serialization, so .ba files are not interchangeable across this change. Includes a testsuite test under bsc.bluesim/codegen_only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The old name implied a simulation top; the flag emits one module's Bluesim C++ with no top-level. Pure rename: flag, Flags field, S0096 error, golden -help/-print-flags-raw output, and the codegen_only test dir. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Check that block-codegen of a module matches a normal -sim build, and that a submodule's C++ is identical across hierarchies. Also cover the always_enabled case (rejected as a top with G0062, accepted as a block-codegen root). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A reusable block is never run as a top, so generate the root as it would appear as a submodule: mkScheduleStmts emits no statements for the root's own interface-method nodes (their enable/argument ports then go unreferenced and are optimized away), and simBlocksToC skips the "model_" wrapper. The result is byte-identical to the C++ the module gets as a submodule, so the object can be built once and shared across simulations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend the shared test_c_veri worker: for every multi-module test, regenerate each bsc submodule on its own with -block-codegen and confirm the .cxx/.h are byte-identical to the in-design version. parallel.exp also adds an explicit check for mkGCD. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Skip modules that cannot stand alone as a root (imported BDPI functions), and skip the check under -show-timestamps/-show-version, which embed build metadata that legitimately differs between bsc invocations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a fixture family that steps each "access count" 0 -> 1 -> 2 -> n: rules reading a shared value, method arguments, method count, method kind, submodule instances, wide method ports named out of sorted order, a kitchen-sink module, and subinterface forwarding. Each is a submodule of the testbench, so the shared check confirms every module's per-module C++ is byte-identical. This exposed the member-def ordering case the rest of the corpus missed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record in DEVELOP.md why -block-codegen output is byte-identical to a module's submodule form (the property that makes object reuse sound), with one-line pointers at the load-bearing sites. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the last case where -block-codegen output differed from submodule form. moveDefsOntoStack keeps a def as a member iff two functions read it. A top interface method's CAN_FIRE is read by both its RDY function and the module's own schedule (arbitration), so it stays a member; as a submodule that arbitration moves to the parent, leaving one reader, so it moves to a local. Drop those own-schedule reads (interface-method CAN_FIREs only) so block-codegen matches. Gated on -block-codegen; normal output unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Code generation is now its own mode alongside -g (elaborate) and -e (link): "bsc -sim -c M" generates M's Bluesim C++ from M.ba, named for the cc -c contract (compile, don't link). The blockCodegen field remains as an internal driver bit, so every codegen site is untouched and the output is byte-identical to -block-codegen's. Conflicts (-e, a source file, -systemc, non-.ba files, no backend) are rejected at decode with errors S0096-S0099. Tests and goldens migrate to the new spelling; the .ba tag is bumped for the new Flags field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
-c M now writes only M's generated files (the cc -c contract: one module in, that module's outputs out); submodules get theirs from their own -c invocations, and link remains the closure that generates whatever is missing. The SimSystem is still loaded in full; only which files are written changes, never their bytes, so byte-identity with the submodule form is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A module linked as the top is generated in "top form" -- the form the link's own schedule and model_ expect -- unlike the block form that -c produces and that submodules reuse. Record the form in the .h options descriptor so reuse never mixes them: a block-form artifact is not taken as a link's top (previously a C++ compile error at the schedule file), and a top-form artifact is regenerated rather than reused as a submodule (previously reused; generate shareable objects with -c). A top from an earlier link of the same design still matches and is still reused. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Define "block form" and "top form" up front in the DEVELOP.md byte-identity section, and reword the SimCOpt comment that relied on the opaque phrase "own-schedule reads". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The -u up-to-date check accepted any .ba newer than its source, even one that cannot be used: elaborated for a different backend (e.g. left by "-verilog -elab -g"; a following -sim compile would skip codegen and then fail the link with a backend mismatch), written by another BSC version (previously a link-time error), or unreadable. Such a .ba now forces re-elaboration instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
-verilog now sets genABin, as -sim always has, so every backend keeps the elaborated .ba alongside its generated code; -no-elab (after the backend flag) suppresses it. This gives Verilog flows the elaboration artifact needed for .ba -> .v generation and link-time checks. Golden outputs gain the "Elaborated ... module file created" lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The hidden -elab-verilog flag stored the generated VProgram in the .ba (abmi_vprogram) "for accessing in bluetcl", but nothing ever read it back -- bluetcl included. Delete the flag, the field, and its serialization, and bump the .ba format tag for the layout change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"bsc -verilog -c M" generates M.v from M.ba, reviving the vGenMods hook
that vLink left commented out ("XXX Until we allow re-generation of
Verilog files"). genModuleVerilog now returns the written file names
(its VProgram result lost its only consumer with abmi_vprogram).
Root-only, like the Bluesim mode: each named module's .v is generated
from its own .ba, found among the command-line .ba files or on the
search path. The output is byte-identical to the .v written by -g for
the same elaboration under the same generation flags.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verilog linking already loaded the design's .ba hierarchy and discarded
it ("XXX Until we allow re-generation of Verilog files"). Now the link
regenerates any module .v that is missing or older than its .ba, reuses
the rest (reported like Bluesim's object reuse), and passes the module
.v files to the simulator explicitly. A .v given on the command line is
the user's to provide and is never regenerated; file arguments can be
glob patterns (bsc forwards them to the simulator's shell unexpanded),
so module names are matched against the patterns -- "*.v" keeps its
longstanding meaning of "the user provides every module". When no .ba
hierarchy can be found, the link warns (S0099) and uses the .v files as
found, as before. This makes a link self-sufficient regardless of which
subset of the design was pre-generated with -c: -c is point codegen,
link is the closure.
Rather than adding a third variant of generated-file staleness checking,
the timestamp conventions move to a shared StaleUtils (missing product
is never fresh, equal times are fresh), used by the -u check, Bluesim
object reuse, and the new VFileUtils; the checks now agree by
construction, and each keeps only its own validity details (options
descriptor for Bluesim objects, .ba usability for -u).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Describe the three compilation stages and the -c flag (generating code from a module's elaborated .ba file); note that .ba files are written by default for both back ends (-no-elab suppresses them); and describe how linking reuses up-to-date generated files and regenerates the rest, for both Bluesim and Verilog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The link's .ba check is all-or-nothing per design: if any module's .ba is missing -- a submodule's while the top's is present, or the top's while a submodule's is present -- the link warns (S0099) and uses the .v files as found, never regenerating part of a design it cannot fully see. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Polymorphic BDPI imports previously failed with S0015 ("Polymorphic types
are not yet supported with DPI"). SystemVerilog DPI-C imports need concrete
widths, so a polymorphic import is now monomorphized: for each concrete width
at which it is used, BSC emits one fixed-width DPI import (name-mangled by the
polymorphic-operand widths) that links, via a "c_identifier =" alias, to a
generated C wrapper which forwards to the single user C function.
A fixed-width packed operand ("bit [W-1:0]") is passed on the C side as the
word-canonical svBitVecVal* for every width, which matches the polymorphic C
function's word-pointer ABI, so each wrapper just casts and forwards. This
avoids DPI open arrays entirely (whose Verilator C runtime is unreliable --
svGetArrayPtr can return NULL for reg-backed values) and depends only on core
DPI features, so it works on old Verilator too (verified on 5.032 and 5.049).
Details:
- ForeignFunctions: DPIInst, width mangling, getDPIInstantiations (scans the
package for concrete uses), and a per-width mkDPIDeclarations.
- Verilog/GenABin: VDPI carries the c_identifier alias and the underlying C
function name.
- AVerilogUtil: vco carries the ff-map and def widths; call names are mangled
by concrete width at all three emission sites (vExpr, vForeignCall,
vDefMpd).
- AVerilog: feed instantiations to mkDPIDeclarations.
- DPIWrappers: generate the wrappers from the monomorphized VDPIs (one file
per C function, so the link step finds them by the existing name).
- bsc/bsc_build_vsim_verilator: generate wrappers once widths are known and
hand the wrapper C sources to Verilator to compile.
Monomorphic and non-foreign codegen is unchanged. The whole
bsc.codegen/foreign suite passes under -use-dpi with Verilator.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verilator merges all files into one $unit, so file-scope import "DPI-C"
declarations collide ("Duplicate declaration of function") when a testbench
and DUT both use the same foreign function. Emit the imports as module-body
items (new VMDPI) instead, so each module is self-contained. Fixes multi-module
designs for both monomorphic and polymorphic imports; inert for the non-DPI flow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…iming lock Designs that instantiate a generated clock or reset (mkAbsoluteClock, clock dividers, gated clocks, ...) rely on delay-based library Verilog (ClockGen.v etc.) that only simulates under Verilator's --timing, and their tops drive their own clocks, needing a timing-aware harness. Verilator support for both is incomplete, so such designs are locked by default (BSC_VERILATOR_ENABLE_TIMING is the back door to try them). Whether a design needs timing is analyzed at link time from the design's .ba hierarchy: any module instantiating a submodule with an output clock or reset (instGensClockOrReset, evaluated over every module's state instances) marks the design, and the verdict is passed to the build script as BSC_VSIM_NEEDS_TIMING=0|1. sim_main.cpp gains a BSC_VERILATOR_TIMING harness variant for generated-clock designs (advancing simulated time to each scheduled event, with the async reset negedge SyncResetA needs), used when the back door enables --timing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Under Verilator, expect-fail the designs Verilator cannot build: clock/reset generators and no-main tops need a delay-based (--timing) harness, which the build script refuses by default (BSC_VERILATOR_ENABLE_TIMING is the back door; see bsc_build_vsim_verilator). The refusal is detected after the link by its distinctive message and recorded as a per-design XFAIL (verilator_link_lock_reason), and the run/compare steps are skipped; the no-main path (link_verilog_no_main_pass) XFAILs directly. Adds the verilator_no_timing / verilator_link_locked helpers (verilog.tcl) and guards the two hand-driven example flows (Amba_dmac, MacTestBench). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BSC can emit a foreign function literally named srandom(), which collides
with the SystemVerilog built-in srandom() method: Verilator internal-errors
("Classless rand-thing should have failed in V3LinkDot"), while iverilog
treats it as an ordinary user function. There is no back door, so under
Verilator XFAIL the link (and skip run/compare) for any design whose linked
Verilog calls srandom() -- e.g. bsc.codegen/foreign/battery's TestActionValues.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…link Foreign functions compile to DPI-C (-use-dpi) instead of VPI; this is orthogonal to the simulator, except that Verilator requires it (no VPI) and iverilog cannot use it (no DPI). Introduce a first-class use_dpi flag derived from the simulator (verilator=1, iverilog=0; other simulators via the USE_DPI env var) and apply -use-dpi only at the Verilog compile/link points (bsc_compile_verilog and friends, bsc_link_verilog) via a dpi_flag helper -- never globally through BSC_OPTIONS -- so it cannot leak into flag/error-dump output and is never given to iverilog or the C backend. Also make the VPI-wrapper tests DPI-aware: the VPI wrapper mechanism (compile-time vpi_wrapper_* files, a link-time startup array, the "VPI wrapper files created" message) does not exist under DPI, so bsc.options and bsc.driver/depend skip those checks when useDPI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two comparisons hard-coded VPI-only output that legitimately differs under -use-dpi: - bsc.options/verilog-e: the -vsim /bin/echo probe captures the exact link command bsc hands the vsim script. Under -use-dpi bsc appends -dpi to that command, so filter the token out before comparing against the simulator-agnostic golden (no-op under iverilog). - bsc.names/signal_names (check_ats FFunc): the compile log line "VPI wrapper files created: ..." is absent under -use-dpi (the DPI wrapper is built at link, not compile), so drop that line from the filtered comparison when useDPI. Both now pass under verilator and iverilog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Under -use-dpi the BDPI import becomes a DPI-C function called directly (my_time(...)), not a VPI $imported_ system-task wrapper. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sim_verilog_status: when only a nonzero (error) status is expected, accept any nonzero exit. Simulators differ on the code -- verilator's $fatal aborts with 134 where iverilog exits 1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bsc_build_vsim_verilator: make the generated build's -j configurable via BSC_VERILATOR_BUILD_JOBS (default unbounded for fast standalone builds). parallel.mk sets it to 1 so concurrent test dirs don't each fan out and oversubscribe the machine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…bered A newline-less $write puts verilator's "$finish" banner on the same line as the value, and clean_verilator_output strips it along with the value. $display adds a trailing newline so all simulators agree; this test checks type reflection, so the newline is immaterial to what it exercises. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the internal flag systemVerilogTasks -> systemVerilogOutput. -system-verilog-output is now the canonical spelling and -system-verilog-tasks is kept as a deprecated, backward-compatible spelling of it (both are Toggles setting the same field, so -no-system-verilog-tasks still works). Under the flag, a String module parameter is emitted as a SystemVerilog 'parameter string' rather than an untyped bit-vector parameter, so SV consumers (VCS, verilator) treat it as a string. parameter string is IEEE 1800-2005+ (rejected by classic Verilog), hence opt-in. Verilog task emission ($error/$fatal via the former -system-verilog-tasks) is unchanged. Update the -print-flags-raw golden for the field rename. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… order) The separately-synthesized InputClocksSameDomain puts its rg1/rg2 displays in independent always blocks, so their order within a timestamp is not guaranteed across simulators (verilator orders them differently than iverilog/Bluesim). The output leads with a fixed-width timestamp, so sort_output canonicalizes the same-cycle order while preserving time order, letting all three simulators share the goldens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RegFile and prod_con differ from the iverilog/Bluesim goldens only by the order of $displays within a timestamp (the design and testbench run in separately-synthesized modules, so same-cycle cross-module order is not guaranteed across simulators). Both goldens lead with a fixed-width timestamp, so enable sort_output to canonicalize the same-cycle order while preserving time order -- all three simulators then share the goldens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mark the Verilog output comparisons that differ under verilator for legitimate,
LRM-permitted reasons that cannot be reconciled by sorting. All of these XFAIL
under verilator and pass normally under iverilog/Bluesim (0 XPASS on both).
Deferred $finish drops a final same-timestamp $display (verilator's VL_FINISH
sets a flag and stops the run before emitting the coincident display, whereas
iverilog/Bluesim complete the timestamp). Both behaviors are legal, but we
prefer the Bluesim-equivalent full output; the designs have no display-free
cycle for $finish to fire on, so they cannot be reshaped into pure reorders:
- relax_method_urgency/BypassFIFO (final "Data enqued")
- bugs/b898 Bug898_2 (final "Counter incremented at 55")
- driver/no_filenames (final timestamp's two submodule lines)
- misc/fwrite FOpen/FOpen_MCD/FWrites (one extra $fwrite line; also MCD
$fopen channel numbering -- verilator allocates top-down from 1<<30 vs the
iverilog/IEEE bottom-up from 2)
2-state (verilator) vs 4-state (iverilog) X/Z:
- interra/OVL assertNeverUnknown2/assertNeverUnknownAsync2 (the
"contains X or Z" violation cannot fire under 2-state)
- misc/divmod DivideByZero/DivideByZeroWide (yields 0, not x)
- verilog/parameters ModulePort_WithStaticValue_TopLevel (the undriven
top-level port reads 0, not z)
- verilog/tasks LogicBetweenTasks3 v-bug and interfacecalls
sysInterfaceTaskCalls (the captured GitHub B-Lang-org#559/B-Lang-org#215 "bug output" is
iverilog-specific: X under iverilog, all-1s or a different wrong order
under verilator)
Other per-simulator manifestations:
- verilog/tasks LogicBetweenTasks2 (B-Lang-org#559 zero-delay-between-tasks: verilator
schedules the inlined logic differently and computes a different s1 value)
- verilog/tasks sysErrorTest ($error/$fatal render differently and the $fatal
message is dropped under verilator)
- lib/SquareRoot ($random stimulus differs; verilator does not implement the
IEEE 1364 reference algorithm -- DUT self-checks still pass)
- typechecker/display DisplayRealLiteral (bare-real $display uses LRM default
%g, which strips trailing zeros -- verilator and VCS agree on 0.5; iverilog
keeps 0.500000 and is the outlier, so the golden holds the standard form and
iverilog is the veribug here)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A design that manages its own VCD via $dumpfile/$dumpvars/$dumpon/$dumpoff
aborts under verilator ("Turning on wave traces requires
Verilated::traceEverOn(true) call before time 0"), because verilator requires
tracing to be armed before time 0. Add a +bsctrace run-time plusarg to the
verilator harness (sim_main.cpp) that arms Verilated::traceEverOn(true) without
opening the harness dump.vcd (that remains +bscvcd's job); it parallels the
build-time --trace.
Wire the two tests whose designs drive their own VCD to pass +bsctrace:
- bsc.verilog/vcd DumpOnOff (verilog-only) via an explicit sim_verilog call.
- bsc.bluesim/vcd VCDTest1/VCDTest2 (test_c_veri) via sim_options, using
test_c_veri_bsv_modules_options.
+bsctrace is scoped to just these dumping tests rather than armed globally:
Verilated::traceEverOn makes verilator compute traced signals on every eval,
so arming it on every verilator sim would be a needless per-cycle cost.
iverilog supports $dump* natively and ignores the unknown plusarg, and Bluesim
likewise ignores it, so it is safe to pass unconditionally at these call sites.
These tests now execute under verilator (were aborting) and still pass under
iverilog and Bluesim.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vector_interfaces and relax-schedule each generate a compile-time,
backend-independent dump (-dwrapper_typecheck / -dvschedinfo) and then check it,
but generated it with compile_object_pass -- which is guarded by
"if {$ctest == 1}" -- while the consuming find_n_strings / compare_file check is
ungated. Under a -no-ctest run (e.g. a verilog-only run) the setup is skipped,
so the check runs against a file that was never created and fails spuriously.
(The failure was previously masked by stale dump files left over from earlier
-ctest runs.)
Generate the dump with an ungated compile_pass ... -verilog instead. Both dumps
are backend-independent -- the .sched is byte-identical under -verilog, and the
wrapper-typecheck dump has the same match count -- so the goldens are unchanged
and both tests now run and pass under -ctest and -no-ctest alike.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ng order) Under verilator, Test2/3/4's Verilog output differs from the golden purely by the order of two coincident FIFO error_checks warnings: the fifo and zfifo instances are separate always blocks, and verilator emits their same-time $displays in the opposite order from iverilog. Confirmed (by temporarily timestamping the warnings) that both simulators fire every warning at the identical simulation time; only the intra-timestamp order of the two coincident warnings differs, which is unspecified per the Verilog LRM. The root cause is that the FIFO primitive warnings carry no $time (B-Lang-org/bsc issue B-Lang-org#989); until they do, the same-time order cannot be canonicalized, so XFAIL the affected Verilog outputs under verilator. Test1 (size 1) does not exhibit the reorder and still matches, so it is left as-is. The Bluesim .c.out XFAILs (cbug) are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a link-time -dump-formats flag selecting which waveform formats a
simulation is built to support: a comma-separated subset of {vcd,fst,fsdb},
"none" for no dumping, defaulting to "vcd" (so existing behavior is unchanged).
At run time +bscvcd/+bscfst/+bscfsdb select which compiled-in format to dump.
The value is threaded to the per-simulator build script via the
BSC_VSIM_TRACE_FORMATS environment variable, and each backend translates it to
its own mechanism or errors if it can't provide the format.
Rework src/Verilog/main.v (used by iverilog/VCS/etc.) so that VCD, FST, and FSDB
are additive rather than fsdb-xor-vcd: VCD is always compiled in, FSDB stays
behind `ifdef BSC_FSDB (the Verdi PLI), and FST fires $dumpvars into a .fst file
(the on-disk format is chosen by the simulator at run time, e.g. iverilog's
vvp -fst). A request for a format that was not compiled in now prints a clear
error instead of silently doing nothing.
This wires up iverilog FST end to end (bsc -dump-formats fst, run with +bscfst
and vvp -fst, producing a valid dump.fst). bsc_build_vsim_verilator validates
the requested formats and errors on fst/fsdb (verilator FST is a follow-up;
--trace vs --trace-fst is a build-time, mutually-exclusive choice there).
Flags/FlagsDecode gain the field, default, decoder (with EBadArgFlag validation)
and -print-flags-raw entry; GenABin gains the matching positional slot; the
bsc.options goldens are updated for the new flag in -help/-print-flags output.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Teach bsc_build_vsim_vcs to honor -dump-formats: VCD is native ($dumpvars, no extra flags), and fsdb is enabled by passing -kdb -debug_access+all (modern VCS bundles the Verdi FSDB writer, so no external Verdi PLI / VERDI_HOME is needed) plus +define+BSC_FSDB, which makes the main.v harness call $fsdbDumpvars. VCS does not produce FST, so fst (and any unknown format) is rejected with a clear error. NOTE: verified only by construction -- shell logic and the standard -kdb flags were checked, but this was not exercised against a real VCS installation (none available here); the -debug_access level may need adjustment on a given VCS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire FST support for verilator. bsc_build_vsim_verilator maps -dump-formats to verilator's trace flag: vcd -> --trace, fst -> --trace-fst, none -> no tracing (a faster build). --trace and --trace-fst are mutually exclusive, so a request for both vcd and fst is rejected; fsdb (not a verilator format) already errors. sim_main.cpp selects the writer class from verilator's VM_TRACE_FST macro (VerilatedFstC vs VerilatedVcdC) and dumps to dump.fst/dump.vcd accordingly. The runtime dump trigger matches the built format (+bscfst for an FST build, +bscvcd for a VCD build); passing the other format's plusarg, or any +bsc<fmt> to a -dump-formats none build, now prints a clear error instead of silently producing nothing. tfp is now a VM_TRACE-guarded global and step() no longer takes it, so the none build compiles with no trace class at all. Verified: -dump-formats fst produces a valid dump.fst (fst2vcd round-trips); default vcd still produces dump.vcd; wrong-plusarg and none builds error; and the normal verilator VCD/tracing tests (verilog/vcd, bluesim/vcd, mcd/Hierarchy) are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With -dump-formats none, the Bluesim codegen now stubs out the per-signal VCD dumping machinery: dump_VCD_defs and dump_VCD collapse to empty methods (they must still exist -- they are pure-virtual on Module), and the per-member/port vcd_write_def / vcd_write_x / change-detection / full-value emission and the per-submodule recursion are not generated. The VCD helper prototypes are likewise omitted from the class declaration. Default (vcd) output is unchanged. Measured on a 1000-register module: generated C++ shrinks ~20% (426KB -> 343KB; the VCD recursion was ~22% of the module file). Note this is a code-size reduction, not a compile-time one -- the g++ time is dominated by optimizing the schedule/model file, which this does not change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The generated model_<top>.cxx (the schedule) is dispatch code: compiling it at the default -O3 is disproportionately slow -- its g++ time grows much faster than the file size and dwarfs the rest of the link -- while buying no measurable simulation speed, since the hot compute lives in the per-module files. Allow its compiler flags to be overridden with the TOP_CXXFLAGS environment variable, falling back to CXXFLAGS (and then the built-in -O3) when unset, so default behavior is unchanged. The per-module files continue to use CXXFLAGS. Measured on a 1000-register design: model_*.cxx compiles 21s at -O3 vs 2s at -O1 with identical simulation output, and 2M-cycle run times equal within noise; end-to-end bsc link time drops 35s -> 17s with TOP_CXXFLAGS=-O1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A -dump-formats none build was only honest under verilator; elsewhere a runtime dump request silently misbehaved: the main.v simulators (iverilog, VCS, ...) still dumped VCD on +bscvcd (the $dumpvars trigger was compiled in unconditionally), and a Bluesim none build given -V silently wrote a headers-only VCD with no signals. Now "none" uniformly means: the harness dump trigger is not compiled in, and a runtime dump request errors loudly. - main.v: the +bscvcd/+bscfst dump branch is compiled out under a new BSC_NO_DUMP define, replaced by a clear $display error. - bsc_build_vsim_iverilog: new -dump-formats handling (vcd/fst are free at build time, fsdb rejected); defines BSC_NO_DUMP for "none". - bsc_build_vsim_vcs: defines BSC_NO_DUMP when no format is requested (VCD is native to vcs, so this is the only honest way to honor "none"). - Bluesim: the generated model's dump_VCD_defs reports "built with -dump-formats none" on stderr when dumping is requested (it runs once, at VCD-header time), instead of silently producing an empty VCD. Verified: iverilog none + +bscvcd errors with no dump.vcd; Bluesim none + -V errors; default vcd behavior unchanged on both (real dumps, tests green: verilog/vcd 4/0, bluesim/vcd 26/0, b925 26/0). VCS is by construction (not installed here): same main.v define mechanism as iverilog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tinel) Three fixes that together make MPEG4 pass under Bluesim, iverilog and verilator: 1. The Verilog output differed under verilator only by the order of two coincident $displays from separately-synthesized modules (a single swap in 30k lines; the outputs are sorted-equal). Enable sort_output on the Verilog comparison so all simulators share the golden. 2. The $check_vcd=0 argument (intended to disable the VCD check "because the files are too large") was landing in the sort_output slot, so the giant VCD-dump run had silently been executing all along. Plumb it to the right position on both the Bluesim and Verilog calls. 3. bitstream.txt ended with a malformed 'ffffffff' sentinel in an 8-bit stream: Bluesim's "Malformed value" load error was baked into the .c golden, and iverilog 12+ newly warns "Excess hex digits" at load, breaking the .v comparison. Fix the data (-> 'ff', the value Verilog simulators truncated to anyway; the address is never read), drop the error from the .c golden, and accept Bluesim's now-accurate gap warning (the file has always been one entry short of the declared range). Also update the testbench comments that documented the old loader error. Verified: verilator CTEST=1 8/0 (Bluesim + sorted Verilog), iverilog 4/0, no VCD-dump runs, 0 XPASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Iverilog 12+ warns about excess hex digits when $readmemh data is wider than the target register, which breaks output comparisons against goldens produced by older iverilog. Filter the warning in clean_iverilog_output, alongside the existing $readmem warning filters. This is B-Lang-org/bsc PR B-Lang-org#937 applied locally; it complements the MPEG4 root-cause fix (the one known offender in this tree) by shielding any other test data with wide readmem entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rilator)
BSV's parser rejects Verilog-2001 keywords as identifiers, but words that are
reserved only in SystemVerilog pass through and are emitted verbatim -- so a
design with a register named "process" (bsc.bsv_examples/h264) produces
Verilog that no SystemVerilog-mode consumer can parse (verilator with DPI
fails with "syntax error ... expecting '{").
Three-part fix:
1. The Verilog printer emits identifiers that collide with SV-reserved words
as escaped identifiers (\global ), which are legal in both Verilog-2001
and SystemVerilog, so the output parses under either language level. The
set is the IEEE 1800-2017 reserved words minus Verilog-2001, plus the std
package class names. (Of these, BSV's parser currently admits process,
semaphore, mailbox, global, soft, strong and weak; the parser's own
keyword table stops at SV 3.1.)
2. Escaping cannot help with the std built-in class names (process,
semaphore, mailbox): verilator resolves even the escaped identifier to
the std class. Since generated code never uses the std package, pass
--no-std to verilator.
3. Verilog generation warns once per colliding identifier (G0129, with the
identifier's source position), since users may prefer to rename. The
warning is suppressible and can be promoted to an error with
-promote-warnings G0129 for a strict "reserved word" policy; reserving
the words outright in the parser was rejected as a breaking change
(h264 itself would stop compiling).
Adds bsc.verilog/svkeywords testing all seven admitted identifiers: compile
(expecting 7 G0129 warnings), link and run identically under Bluesim,
iverilog and verilator.
Verified: h264 now compiles, links and runs under verilator (previously the
last verilator-specific failure besides log2_loop); signal_names, vcd, b925
and Hierarchy regressions unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Noinline functions and Classic foreign functions both appear as ANoInlineFun instantiations, and the .ba hierarchy walk followed both like submodules, demanding a .ba. A noinline function is elaborated by bsc and has one (so its Verilog can be checked and regenerated at link), but a Classic foreign function is bound to hand-written Verilog -- e.g. the library's Fork, shipped as $BLUESPECDIR/Verilog/Fork.v with no elaboration -- so a .ba never exists and the walk failed on any design using one. Follow a function module's .ba when it can be found, and otherwise record it as a foreign leaf (like a BVI import), whose Verilog is the user's or the library's to provide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verilog linking warns (S0099) and falls back to "the .v files as found" when the design's .ba hierarchy cannot be loaded. For verilator that is not safe: the link analyzes the hierarchy to configure the build (whether the design needs a delay-based --timing harness), and a wrong guess is a broken simulation. So when the resolved simulator is verilator, report the real reason the hierarchy could not be loaded (e.g. a missing submodule .ba, S0040) as an error instead. Two cases keep the warn-and-link-as-found behavior even under verilator: other simulators (they consume no link-time analysis), and a top module with no .ba at all -- that is the hand-written-Verilog-top flow (e.g. a Verilog testbench around generated modules), for which a .ba never exists; the main.v harness drives such designs, so the timing analysis default is correct. The error is reserved for the genuinely unsafe case: a loadable design with a missing piece, which can neither be checked nor regenerated. The simulator is resolved once, before the hierarchy check, and passed to vSimLink. The vlink_regen scenarios cover all three behaviors: submodule .ba missing under a loadable top errors under verilator (and warns elsewhere); a missing top .ba warns and links as found everywhere. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BRAM0Test exercises zero-width-address BRAMs (one location) but loaded them all from the shared 8-entry bram2.txt. $readmem data beyond the memory range is only a warning under iverilog but a runtime fatal under verilator, so the test aborted there. Load the one-location BRAMs from a one-entry bram1.txt instead (the 8-bit-address BRAMs keep bram2.txt; underfilling is tolerated everywhere). The loaded values are overwritten before ever being read, so the expected output is unchanged. Verified: 10/0 under both verilator (previously aborted) and iverilog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bsc bound every inout port of a generated module to its internal net with a port expression in the module header -- ".iioo(x$INOUT)", or ".arg(arg)" for a module argument -- a header form some tools (notably Verilator, which rejects it outright) cannot parse. When the port is the only one on its net the expression serves no purpose: rename the net to the port name throughout the module (renameInoutPorts, a pass over the final VModule) and emit a plain port. This makes the common wrapper/pass-through patterns (e.g. a BVI module wrapped and re-exported) buildable by such tools, and gives the net the documented, attribute-controlled port name in waveforms instead of an internal name. Truly shorted boundary inouts -- two or more ports on one net, e.g. a module argument re-exported as an interface inout, or two boundary inouts joined by mkConnection -- have no plain rendering and keep the port-expression form; the alternatives are no more portable (Verilator rejects port aliases, SystemVerilog alias and the V1995 tran primitive alike, and iverilog rejects alias too). The basicinout.pl -verilog-filter fixture (a user-space rewrite of exactly the rendering this commit fixes) now passes already-plain ports through instead of dying, which also makes it idempotent -- the "basicinout Bug" double-application XFAIL becomes a pass. Golden .v files with one-port-per-net inouts are regenerated (the old filter renamed the header and instance connections but not the wire declaration; the compiler rename covers all of them). bsc.verilog/inout and bsc.verilog/filter pass under iverilog (171/0/0/0 and 10/0/0/0). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bsc renders a shorted boundary inout -- two or more ports on one net,
e.g. a module argument re-exported as an interface inout, or two
boundary inouts joined by mkConnection -- as Verilog port aliases
(".X1(net), .X2(net)" in the module header; one-port-per-net inouts
are plain ports since the previous commit). Verilator rejects that
header syntax outright, and supports none of the alternative
renderings either: SystemVerilog alias and the V1995 tran primitive
are also unsupported (Verilator 5.032), and iverilog rejects alias
too, so the port-alias form bsc emits is already the most portable.
Designs compiled with -no-inline-inout-connect additionally pull in
the library InoutConnect.v, whose header is itself a port alias.
Detect the situation from the design's .ba hierarchy at link time
(modUsesInoutPortExpressions, mirroring the needs-timing analysis) and
tell the build script via BSC_VSIM_INOUT_PORTS, which refuses with a
clear error instead of a Verilator syntax error. Each module's
InoutConnect inlining is judged by the flags that produced its .v
(this link's flags for a .v it regenerated, the .ba-stored flags
otherwise); shorted boundary ports are a topological property no
conforming rendering avoids, so every module in the hierarchy is
judged; zero-width inouts are ignored (they never reach the port
list); and inout expressions that defeat the net resolution
conservatively lock.
The testsuite records the refusal as a per-design XFAIL through the
same post-link lock detection as the --timing lock
(verilator_link_lock_reason "verilator-inout-ports"). With this,
bsc.verilog/inout and bsc.verilog/filter run clean under verilator (90
PASS / 29 XFAIL / 0 FAIL / 0 XPASS and 10/0/0/0): designs whose inout
wiring Verilator can build -- internal tristate buses, wrapped BVI
modules (TbBoth's three-driver bus now simulates correctly) -- pass,
and the genuinely unbuildable shorts are tracked XFAILs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verilator 4.x falsely flags shared counters updated from generated always blocks (e.g. the OVL error_count in std_ovl_task.h) as circular logic, and UNOPTFLAT is fatal by default, so every OVL checker fails to build. Verilator 5.x does not warn on these at all, so the waiver is inert there. (UNOPTFLAT is a performance lint, not a correctness one.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a Verilator testsuite job to the release build/test matrix on every platform: iverilog is replaced as the Verilog simulator (TEST_BSC_VERILOG_SIM=verilator) and the run is Verilog-only (CTEST=0 SYSTEMCTEST=0), since the Bluesim and SystemC backends are already covered by the main testsuite job. Verilator is installed from the distribution (apt/brew), so the matrix brackets the supported range: ubuntu-22.04 ships Verilator 4.038 at the old end, Homebrew tracks the current release at the new end. The job is informational for now (continue-on-error): the testsuite is not yet expected to be clean under Verilator until the remaining enablement changes land, and Verilator 4.038 additionally predates several upstream Verilator fixes. The job gives visibility without blocking merges, and can be promoted to a required check once it is green on the supported floor (Verilator >= 5). The job runs only in the release matrix (verilator_testsuite: true); the GHC-version matrices skip it, since Verilator results do not vary by GHC version. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration branch for the complete "Verilator as a first-class simulator" stack: the full set of compiler, testsuite, and CI changes under which the BSC testsuite runs clean under Verilator (verilog-only
checkparallel/fullparallelwith zero unexpected failures on Verilator 5.032; the only FAILs arebsc.long_tests/log2_loop, which fails identically under iverilog).This PR is the assembled whole, for review of the end state and for running the branch as a unit. The pieces land upstream individually — this branch is the integration of:
Upstream PRs already open (B-Lang-org/bsc)
$displayso verilator output isn't clobbered$ctestTOP_CXXFLAGSoverrides C++ flags for the model/schedule file-system-verilog-output; emit SystemVerilog string parametersimport "BDPI"functions over the DPI path (-use-dpi)-dump-formats: select waveform dump formats at link time (vcd/fst/fsdb/none)Fork PR this stack builds on
.bahierarchy at Verilog link time), which the link-time analyses below require.Not yet carved into upstream PRs (present here)
use_dpifrom the simulator; DPI-aware format checks (verilog-e, signal_names, b1758); XFAIL srandom under verilator; filter verilator runtime warnings; quiet the verilator build; accept any nonzero sim exit as error; bound verilator C++ build parallelism; the veribug batch (genuine simulator-difference XFAILs);+bsctraceplusarg for design-controlled VCD dumping; UNOPTFLAT waiver in the shipped lint config..ba-hierarchy cluster (opens after Regenerate missing or stale Verilog when linking #2 and Verilog: render one-port-per-net inout ports plainly B-Lang-org/bsc#1001 merge): require the.bahierarchy when linking Verilog for verilator; treat.ba-less function modules as foreign leaves; link-time needs-timing analysis +--timinglock; XFAIL verilator designs that cannot be simulated; refuse designs whose generated Verilog shorts inout ports.Validation on this branch
$readmem, escaped-identifier lexing, BLKANDNBLK,$fclose({...}),VL_SHIFTL_WWQ, ...). The CI wiring keeps 22.04 as a non-blocking compatibility canary.🤖 Generated with Claude Code