Software engineers treat CI as a given. Push a branch, watch the pipeline, merge when green. The practice is so normalized that teams barely think about it. Hardware verification teams are arriving at the same destination, but the path looks different enough that transplanting software CI patterns directly onto RTL workflows produces frustration more often than results.
We've spent time watching how IC design teams at mid-size ASIC houses try to bolt Jenkins or GitHub Actions onto their verification flows. Some succeed. Many start, stall, and quietly revert to the manual run-before-tape-out ritual. The difference between the teams that stick with hardware CI and the ones that abandon it usually comes down to three decisions: what you gate on, how long you're willing to wait, and where you put static analysis in the pipeline.
Why Hardware CI Is Different
Software CI typically does four things: compile, run unit tests, run integration tests, report. Total runtime for a modern web service might be 10–20 minutes. The feedback loop is tight enough to be useful without being disruptive.
Hardware verification has no clean equivalent. Simulation runtimes for a mid-complexity RTL block can run 4–12 hours. Full-chip regression suites in a 28nm ASIC design routinely require 48–72 hours of compute. You cannot gate every commit on a full simulation run without completely breaking developer velocity. The wall-clock cost is too high, and the compute cost — whether that's on-prem EDA licenses or cloud burst capacity — makes it economically unworkable as a per-push trigger.
This is not a reason to skip hardware CI. It's a constraint that forces you to be precise about what belongs in which pipeline stage.
The Gate Hierarchy: Fast, Medium, Slow
The teams we've seen succeed with hardware CI decompose verification checks into three tiers by runtime. Each tier gets its own trigger cadence.
Fast gates (under 5 minutes): Lint, static analysis, RTL synthesis checks, and any CDC structural analysis that doesn't require full elaboration. These run on every push to any branch under active development. The goal here is to catch the cheapest-to-find violations before they accumulate. An uninitialized register or an inferred latch doesn't need simulation time to surface — a lint pass catches it in seconds. If a static analysis check finds a clear clock-domain crossing without a synchronizer, that's also fast enough to gate on pre-review.
Medium gates (30 minutes to 2 hours): Block-level simulation smoke tests, structural formal checks on specific modules, and targeted coverage closure for recently-modified code paths. These run on pull request creation and update. Not every commit — just the ones that signal "I want this reviewed." The medium tier is where you start applying team-specific violation weighting. A bus protocol block has different risk areas than a clock-generation module. The checks should reflect that.
Slow gates (hours to overnight): Full regression simulation, sign-off formal, timing closure at target frequency. These run on merge to main or on a scheduled basis — nightly or twice a week. They are not gates that block PR approval. They are gates that block tape-out readiness. Treating them as PR-level gates is the mistake that makes teams abandon hardware CI entirely, because every PR suddenly requires 48 hours to merge.
What to Actually Put in a Pre-Merge Gate
The pre-merge gate needs to be opinionated. Running everything "just to be safe" defeats the purpose. The practical question is: what checks, if they fail, would you genuinely want to block a merge for?
Based on where violation classes tend to be introduced and when they're cheapest to fix, the pre-merge gate for RTL development should consistently include: structural lint with an established rule profile, CDC topology checks for any modified clock-crossing paths, synthesis elaboration to catch undeclared port widths and parameter mismatches, and a quick sanity simulation if you have a testbench that covers the modified block in under 20 minutes.
What it should not include: exhaustive simulation coverage, full formal property checking across the entire design, or any check whose primary value is sign-off confirmation rather than development feedback. Those belong in the slow gate, scheduled separately, not blocking engineer flow.
The boundary here matters. We're not saying slow gates are unimportant — they're where tape-out decisions get made. We're saying that conflating "important check" with "pre-merge blocking check" creates the latency that kills CI adoption in hardware teams.
CI Infrastructure for Hardware: Practical Constraints
Running RTL verification in CI requires compute that most standard CI runners don't provide. GitHub Actions' default runners and Jenkins agents won't have commercial EDA licenses installed. This creates an infrastructure gap that teams have to address before CI can work at all.
The two patterns we see working: on-premise CI agents with EDA licenses mounted via NFS or license server floating pools, and cloud burst using vendor-provided AMIs with license tokens. Both work. The on-premise path is more common for teams with existing EDA infrastructure; the cloud burst path trades per-run cost for flexibility and faster scaling during regression crunch periods.
For the fast tier — lint and static analysis — you have more flexibility. Tools that run purely on RTL source without a simulation kernel can be containerized and run on standard runners with reasonable resource profiles. This is part of why static analysis makes sense as the first CI gate: it doesn't require the same license and compute overhead as simulation.
A practical starting point for a team adopting hardware CI for the first time: configure one fast-gate pipeline with lint and static analysis running on every push. Get that stable and trusted before building out the medium and slow tiers. The common failure mode is trying to automate everything at once, hitting infrastructure problems, and abandoning the effort entirely when the fast tier alone would have provided meaningful value.
Integrating Fpgawright Into the CI Flow
The way we built Fpgawright's CLI specifically targets this fast-gate use case. The analysis runs in under 3 minutes on a standard block-level RTL set. It produces structured JSON output that can feed directly into CI step results, violation counts per category, and an exit code that reflects whether the run should block or warn.
One thing that took us a few iterations to get right: violation severity in CI should be configurable at the project level, not globally. A team hardening a PCIe subsystem has different tolerances than a team doing early exploratory work on a new interconnect block. Exiting with failure on every lint warning during exploratory work discourages CI adoption. Exiting with failure on a new CDC violation in a hardened block is exactly right. The configuration should encode that distinction rather than forcing a binary "strict or lenient" choice.
Our integration with GitHub Actions uses a YAML action that wraps the CLI, reads a project-level `.fpgawright.yml` config for severity thresholds, and posts inline PR annotations for any new violations in the diff. That last part matters for review ergonomics: violation reports that show up as annotations on the changed lines get looked at. Violation reports that require navigating to a separate artifact URL get ignored.
Metrics That Tell You If Hardware CI Is Working
Once CI is running, you need to know whether it's actually catching things that matter or just running and reporting green. The signal that CI is working is not "no failures." It's "violation classes that used to surface at full simulation now surface at commit time."
Track the distribution of where violations are first detected: in the fast gate, the medium gate, the slow gate, or (worst case) in a human review or tape-out debrief. A healthy CI pipeline shifts the detection distribution left over time. You want to see more violations caught in the fast gate quarter over quarter, fewer caught late.
If the fast gate is catching the same violation classes repeatedly in the same files, that's a different signal: the underlying code has structural issues that lint is surfacing rather than engineers fixing. That's a conversation to have about code patterns, not about the CI configuration. CI's job is to make that conversation unavoidable, not to substitute for it.
The measurement we find most useful internally: time-to-detection for each violation class, tracked from the commit that introduced the violation to the step in the pipeline where it was first reported. For teams that didn't have CI, that number is often "days to weeks." For teams with well-tuned hardware CI, it should be under an hour for any structural violation that a static analysis pass covers.
Hardware CI isn't magic, and the first few months of setup require real investment in infrastructure and pipeline configuration. But once the fast gate is stable, the feedback loop it creates changes how RTL engineers think about what "done" means for a change. That shift in habits is worth more than any single caught violation.