Home · ASPLOS 2025 · Accelerators & Hardware Design

Parendi: Thousand-Way Parallel RTL Simulation

Mahyar Emami, Thomas Bourgeat and James R. Larus

Conference
ASPLOS 2025
Published
2025
Pages
783-797
Citations
5

Chip designers test their designs by simulating them cycle by cycle in software, and as chips grow the single-threaded simulators cannot keep up, while multi-core versions stall at a few dozen threads because synchronizing threads on an ordinary server costs thousands of cycles — Parendi compiles a chip design into a bulk-synchronous program for the Graphcore IPU, a 1,472-core chip with a hardware barrier and a fast on-chip network, partitions the design's smallest units of work across up to 5,888 cores with a duplication-aware merging algorithm, and simulates large designs up to 4 times faster than the best x64 servers at about half the cost.

The argument in one glance

  1. Problem

    Chips grow faster than the single thread that simulates them

    Before a chip is manufactured, its register-transfer-level (RTL) description is run in a software simulator, one clock cycle at a time, to find bugs. Hardware developers spend up to a quarter of their time running such simulations. Since about 2006 single-thread performance has barely improved while transistor counts have kept climbing, so simulating a new chip at the old rate now needs hundreds to thousands of cores working together.

  2. What people did

    Parallel simulation on multi-core servers

    Verilator, the fastest open-source RTL simulator, can split a design across threads. RepCut and others use the bulk synchronous parallel model: every thread computes its part of one clock cycle, all threads meet at a barrier, values are exchanged, and the next cycle begins.

  3. Why it fell short

    Barriers and cache traffic cap x64 at a few dozen threads

    Two global barriers are needed per simulated cycle. On an x64 server a barrier is built from atomic memory operations and costs thousands of cycles at 56 threads, so each thread needs hundreds of thousands of instructions of work per cycle just to hide it. Communication between threads goes through the last-level cache, and crossing a chiplet or socket boundary makes it worse. In the paper's measurements Verilator's speedup stops at 8 threads on an AMD server and 28 on an Intel one, and small designs get no speedup at all.

  4. This paper's idea

    Compile the design for a 1,472-core chip built for bulk-synchronous programs

    The Graphcore IPU has 1,472 cores, each with 624 KiB of private memory, a hardware barrier that costs a few hundred cycles, and an 11 TiB per second on-chip exchange. Parendi is a Verilog compiler, forked from Verilator, that breaks a design into fibers, the minimal computation that produces one register's next value, and merges fibers into one process per core using a cost model that accounts for duplicated logic, communication and memory. A hypergraph partitioner first splits the design across up to four IPUs to minimize off-chip traffic. On designs of 200 thousand to 20 million gates, Parendi on 5,888 cores runs up to 4 times faster than Verilator on the best x64 server, compiles 12 times faster, uses 18 times less compiler memory, and costs about half as much in the cloud.

Why this problem is worth solving

A team designing a 100-core system on chip cannot tape it out without simulating it. The RTL description is compiled into a program that evaluates every register and every gate for one clock cycle, then the next, for millions or billions of cycles. Verilator, the fastest open-source tool, simulates the largest design in this paper, a 15 by 15 mesh of RISC-V cores with about 20 million gates, at 430 simulated cycles per second on one thread of a modern Intel server. Booting an operating system takes billions of cycles. At that rate, one billion cycles is 27 days.

Multithreading helps, but only so far. The paper’s Figure 1 plots single-thread performance against transistor count and shows the gap widening every year; the dashed line, which estimates the cores needed to simulate a current chip at the 2006 rate, already reaches into the thousands. Yet on the servers the authors tested, Verilator’s best speedup on that 20-million-gate design is 21.6 times on 28 threads, giving 9.2 kHz, and adding threads beyond a socket or chiplet boundary makes it slower, not faster. The question the paper asks is whether RTL simulation can use thousands of cores, and what kind of machine that requires.

What people did before, and where it broke

  • Verilator on x64. Compiles RTL to C++ and, since version 4, runs it on multiple threads with fine-grained point-to-point synchronization between tasks. Where it broke. Synchronization on x64 is expensive. In the paper’s microbenchmark, a barrier across 56 threads costs a few thousand cycles, and a thread needs hundreds of thousands of instructions of work per simulated cycle to hide it. Small designs see no speedup; large ones stop scaling at chiplet (8 threads on AMD) or socket (28 threads on Intel) boundaries.
  • RepCut on x64. A bulk synchronous simulator that partitions the design with a hypergraph and replicates logic to cut communication, reaching superlinear speedups up to 32 cores. Where it broke. Same ceiling: no gains past 32 threads on a 48-core machine.
  • GPU simulators. RTLFlow runs many copies of one design in lockstep, and GCS accelerates gate-level simulation. Where it broke. RTL is irregular, so single-instruction multiple-data execution wastes most of the GPU, and an H100 has only about 50 MiB of on-chip memory, far too little to hold a large design’s state next to the cores.
  • Custom hardware: Manticore, Nexus, ASH. Purpose-built cores for bulk-synchronous RTL simulation, prototyped on FPGAs or in simulation. Where it broke. FPGAs have too little SRAM to hold large designs, and ASH exists only as a simulated architecture.
  • The gap. Nobody had run RTL simulation on thousands of real cores. Doing so needs a machine where synchronization is cheap and on-chip memory is large, and a compiler that decides which of tens of thousands of tiny tasks go on which core.

Where Parendi sits

From Verilog to a program running on 5,888 cores

  1. Verilog design

    The RTL description, plus a Verilog test driver.

  2. Verilator front end

    Parses and optimizes the design into a data dependence graph. Parendi is forked from Verilator v5.006.

  3. Fiber extraction new

    Walk the graph backwards from each register to find the minimal logic that computes its next value.

  4. Partition and merge new

    Split fibers across IPUs with a hypergraph partitioner, then merge fibers into one process per tile using a submodular cost model.

  5. Generate BSP C++ new

    Emit a Poplar program with per-tile code, exchange schedules and IPU-specific optimizations.

  6. Run on IPUs

    Each simulated cycle: compute, barrier, exchange, barrier.

The three new boxes are the compiler work. The IPU is unmodified commercial hardware, and the design is unmodified Verilog.

The idea

The execution model: bulk synchronous parallel. A digital circuit at RTL is a set of registers and the combinational logic between them. In cycle-accurate simulation, each register has a current value read at the start of a cycle and a next value written at the end.

Bulk synchronous parallel A parallel execution model that alternates a computation phase, in which processes read shared values and write only private ones, with a communication phase, separated by global barriers.
(BSP) simulation maps this directly: every process computes the next values of its registers from current values, all processes hit a barrier, next values are shipped to whoever reads them, a second barrier, and the cycle is done. The whole simulation reduces to two global barriers per clock cycle, which is why the cost of a barrier matters so much. The simulation rate is one over the sum of three per-cycle costs: synchronization, communication and computation.

Why the IPU and not x64. The paper measures each cost on both machines. Synchronization: with independent random-number generators as the workload, adding cores costs the IPU almost nothing once each core has a few thousand instructions of work, because its barrier is in hardware and takes a few hundred cycles. On x64, even 47,104 tiny tasks per thread lose 25 percent to synchronization, and 736 per thread lose more than 75 percent. Communication: within one IPU, latency depends only on how many bytes each core sends, not on how many cores are talking, since the experiment uses 13 percent of the 7.7 TiB per second exchange. Between IPUs, latency grows with total volume, because the 107 GiB per second link runs at 82 percent utilization, so off-chip traffic must be minimized. Computation: an IPU core is slow, 84 times slower than an x64 core on one small design, so it must win through parallelism.

Fibers and the straggler. A

fiber The smallest set of operations that computes the next value of one register; the atomic unit of work Parendi schedules.
is found by crawling the dependence graph backwards from each register. Fibers are not equal: in a small RISC-V core one fiber may take 14,000 IPU cycles while most take a few hundred. Because BSP finishes a cycle only when every process finishes, the slowest process bounds the whole simulation, and once a design has fewer fibers than cores the longest fiber, the
straggler The single slowest fiber in a design, whose execution time is a floor on the per-cycle computation time no matter how many cores are used.
, is the floor. On x64 this never bites, since even small designs have hundreds of fibers and servers have tens of cores. On an IPU with 1,472 cores, small designs hit the straggler floor quickly.

Merging is submodular, which makes partitioning hard. Two fibers often share intermediate logic. Put them on the same core and the shared part runs once, so the merged cost is less than the sum, and any communication between them disappears. The cost of a process is therefore a

submodular function A set function with diminishing returns: adding an element to a larger set increases the cost by no more than adding it to a smaller one.
of its fibers, and the scheduling problem becomes submodular load balancing, which is harder than ordinary makespan scheduling and admits only weak approximation guarantees. Parendi solves it with a four-stage heuristic. First, fibers that touch the same very large RTL array (128 KiB or more) are merged to keep any single process from needing more data than a tile holds. Second, for multiple IPUs, the KaHyPar hypergraph partitioner splits fibers into k balanced sets minimizing the cut, where hyperedges are registers weighted by their word count. Third, within each IPU, the smallest process is repeatedly merged with a communicating neighbour as long as the merged time does not exceed the current worst process and memory fits, using dense bitsets to compute the duplication between fibers quickly. Fourth, only if the tile count is still too high, merging continues while allowing the worst-case time to rise.

IPU-specific compilation. Three optimizations matter. Differential exchange: a process that reads a register file or cache bank would need a full copy each cycle, so static analysis counts how many entries can change per cycle and only those updates are sent. Aggressive block splitting: Verilator’s splitting pass is pushed to split every clocked block for maximum parallelism, accepting code growth. Aggressive inlining: the generated program has no function calls at all, which would bloat an x64 instruction cache but is fine on an IPU, where each tile has 200 KiB of code memory with no cache and the chip totals about 300 MiB of instruction space.

Tracing one simulated cycle on two tiles

How the paper's Figure 3 circuit runs under BSP

Three registers, three fibers f1, f2, f3. Node a3 is shared by f1 and f2. Partition: process p1 = f1 on tile 1, process p2 = f2 and f3 on tile 2. read_i and write_i are the current and next values of register i.

Step 1 of 6

Extract fibers

Crawling backwards from write1 collects a1, a2, a3, b1, c1: that is fiber f1. From write2: a3, a4, b2, and so on for f2. From write3: a5, b3, b4 for f3. Node a3 appears in both f1 and f2, so if they land on different tiles it is computed twice.

f1 = {a1,a2,a3,b1,c1} -> write1 | f2 = {a3,a4,b2} -> write2 | f3 = {a5,b3,b4} -> write3

Why it works

  • A hardware barrier makes fine-grained parallelism affordable. The IPU hides synchronization behind a few thousand instructions per tile; x64 needs hundreds of thousands. Because RTL naturally splits into tens of thousands of tiny fibers, the IPU can use all of them while x64 must lump them into a few dozen coarse threads.
  • Private on-chip memory removes the cache problem. Each item in an RTL simulation is touched once per simulated cycle, which may be millions of machine cycles later, so caches perform badly. The IPU’s 900 MiB of on-chip SRAM, split into 624 KiB per tile, holds the design’s state and code next to the cores with no cache at all.
  • Cheap on-chip communication means more tiles never hurt within an IPU. Since intra-IPU latency depends on bytes per tile rather than tile count, performance on one IPU rises monotonically with tiles. x64 loses that monotonicity at chiplet and socket boundaries.
  • Duplication-aware merging keeps the straggler from dominating. Merging fibers that share logic runs the shared part once and eliminates their communication, and the heuristic never merges past the current worst process, so t_comp stays at its floor while t_comm falls.
  • Off-chip traffic is cut before it exists. Because cross-IPU latency grows with total volume, partitioning fibers across IPUs with a min-cut hypergraph partitioner before merging (rather than after) gives the most freedom to find small cuts. Going from 1 to 4 IPUs still yields a 60 percent gain on one large design.
  • Bigger designs scale better. Fiber imbalance limits strong scaling of small designs but helps weak scaling: doubling a system on chip doubles the fibers, but only a few are stragglers, so the spare tiles absorb the new work and the rate stays flat over a long range where Verilator’s rate keeps falling.

What it costs

  • A slow core needs a lot of parallelism. One IPU tile is 37 to 84 times slower than an x64 core on the small designs. Parendi does not match Verilator’s single thread on a small RISC-V core or a small pipelined Rocket core even using every tile, and it loses on the two-core mesh designs (0.62 and 0.67 of Verilator’s speed). The wins begin at a few hundred thousand gates.
  • BSP forbids overlap and dynamic balancing. The IPU’s exchange is statically scheduled and must start at a barrier, so computation cannot overlap communication and load cannot be rebalanced at run time.
  • Memory limits are hard. A design whose code and state exceed about 4 times 900 MiB will not compile, and a single Verilog array larger than roughly 400 KiB must be split by hand. The paper only explored up to 4 IPUs; 16 or 64 are future work.
  • Language coverage is partial. One top-level clock plus gated or divided clocks; Verilog test drivers only, since a C++ testbench interacting every cycle would be impractically slow on the IPU; no combinational loops; DPI support is experimental. A compiler bug prevented evaluating the BOOM out-of-order core.
  • Off-chip scaling is modest. Four IPUs over one gives 60 percent on the large designs, not 4 times, and for some designs fewer IPUs are faster.
  • Compile time is minutes, not seconds. Up to 40 minutes and 55 GiB for the largest design, though that is 12 times faster and 18 times leaner than Verilator’s 8 hours and 1,043 GiB for the same design.

The evaluation

The benchmarks are an option-pricing Monte Carlo engine (mc), the VTA machine-learning accelerator, and two families of Chipyard systems on chip: srN, an N by N mesh network on chip with N squared minus 3 small Rocket RISC-V cores, for N from 2 to 15, and lrN with large Rocket cores including floating point and virtual memory, for N from 2 to 10. Sizes range from about 200 thousand gates (sr2) to about 20 million (sr15, lr10), excluding SRAMs. Parendi runs on a Graphcore M2000 with four MK2 IPUs at 1.35 GHz (5,888 tiles, 2020 hardware); Verilator v5.006 at -O3 runs on a dual-socket AMD EPYC 9554 (64 cores per socket, chiplets of 8) and a dual-socket Intel Xeon 6348 (28 cores per socket), with 2 to 32 threads. All benchmarks use Verilog drivers without DPI calls on both sides.

Best simulation rate, Parendi versus multithreaded Verilator

PropertyVerilator, Intel Xeon 6348Verilator, AMD EPYC 9554Parendi, 4 IPUs
sr15, 15x15 mesh, 222 cores, about 20 M gates
lr10, 10x10 mesh of large cores9.27 kHz6.27 kHz
mc, Monte Carlo pricing88.96 kHz on 8 threads143.88 kHz
sr2, the smallest mesh, about 200 K gates176.5 kHz
Geometric mean over 25 designs1.01.0
Compile time and memory, largest design8 h, 1,043 GiB—
From Tables 2 and 3 of the paper. Verilator threads were swept 2 to 32; Parendi was run on 1, 2, 3 and 4 IPUs and the best is reported. The M2000 is 2020 hardware; a BOW-2000 clocks 37 percent higher with the same tile count.Underlined values explain themselves when clicked.

Three further results complete the picture. Cost. On cloud prices at the time (IPU-POD4 at 2.13 dollars per hour; a 16-core Azure Dv4 at 0.77), a one-billion-cycle run of sr15 takes 9 hours and 19.20 dollars on the IPU versus 57 hours and 43.78 dollars on x64, and the IPU stays cheaper unless Verilator achieved 3.2 times superlinear scaling. For nightly regressions of many one-million-cycle tests, the IPU is cheaper under both scheduling strategies tried. Measured power is 185 W for the four IPUs; the authors estimate the x64 runs at 80 to 118 W, so at 3.4 to 4.9 times the speed the IPU uses about half the energy. Versus research simulators. Against RepCut on an older Rocket SoC, Verilator wins small designs, RepCut medium ones, and Parendi the largest; RepCut’s code for the 32-core SoC crashes the compiler. Against Manticore’s published numbers, Manticore’s huge register file wins a small bitcoin design, and Parendi’s 1,472 tiles win vta and mc. Partitioning choices. On a single IPU, Parendi’s bottom-up merge and RepCut’s hypergraph approach each win some designs. Across four IPUs, partitioning fibers before merging beats partitioning processes after, and ignoring the multi-IPU structure is far worse.

Check yourself

Check your understanding

  1. 1. Why does bulk synchronous parallel simulation need exactly two global barriers per simulated clock cycle?

  2. 2. What makes the partitioning problem submodular rather than ordinary makespan scheduling?

  3. 3. Predict what happens if Parendi is given a small design with 111 fibers on a 1,472-tile IPU and told to use all tiles.

  4. 4. Why did the authors partition fibers across IPUs before merging them into processes, rather than after?

  5. 5. Which property of the IPU matters most for hiding synchronization cost, according to the microbenchmark?

Sources

The paper is “Parendi: Thousand-Way Parallel RTL Simulation” by Mahyar Emami, Thomas Bourgeat and James R. Larus, EPFL, published at ASPLOS 2025, Volume 2, DOI 10.1145/3676641.3716010, under a Creative Commons Attribution licence. This explainer was written from the full text of the arXiv preprint (2403.04714, version 2, March 2025). Numbers are taken from Tables 1 to 3 and Figures 4 to 17. Parendi is open source at github.com/epfl-vlsc/parendi.

Related papers on Accelerators & Hardware Design

See all 118 →