%%{init: {"theme":"base","flowchart":{"curve":"basis","htmlLabels":true},"themeVariables":{"fontFamily":"system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif","fontSize":"17px","lineColor":"#607089","primaryTextColor":"#172033"}}}%%
flowchart TB
INTENT["<div style='width:540px'><b>1 · PRESERVE DESIGN INTENT</b><br/><br/><b>Source & language</b> · firrtl · chirrtl · moore · llhd<br/><b>Generation & scheduling</b> · calyx · handshake · pipeline · kanagawa · loopschedule · ssp</div>"]
CORE["<div style='width:540px'><b>2 · SHARE HARDWARE ABSTRACTIONS</b><br/><br/><b>Structure</b> · hw <b>Logic</b> · comb · hwarith <b>State</b> · seq · fsm<br/><b>Dynamic control</b> · dc <b>System composition</b> · esi · msft · om · interop</div>"]
TARGET["<div style='width:540px'><b>3 · IMPLEMENT, EXECUTE, OR EMIT</b><br/><br/><b>Optimize</b> · datapath · synth <b>Emit</b> · sv · emit · systemc<br/><b>Compile simulation</b> · arc</div>"]
CROSS["<div style='width:540px'><b>CROSS-CUTTING AT EVERY LEVEL</b><br/><br/><b>Verify & test</b> · verif · ltl · sim · rtg<br/><b>Preserve source meaning</b> · dbg</div>"]
INTENT --> CORE
CORE --> TARGET
INTENT -.-> CROSS
CORE -.-> CROSS
TARGET -.-> CROSS
classDef intent fill:#e8f0ff,stroke:#4d6fdc,stroke-width:2px,color:#172033;
classDef core fill:#e2f7ed,stroke:#168d66,stroke-width:3px,color:#172033;
classDef target fill:#ffe8e5,stroke:#ce6259,stroke-width:2px,color:#172033;
classDef cross fill:#f0e8ff,stroke:#7655c5,stroke-width:2px,color:#172033;
class INTENT intent;
class CORE core;
class TARGET target;
class CROSS cross;
118 The CIRCT Dialect Ecosystem
CIRCT is not one hardware dialect. It is a collection of cooperating dialects that let a compiler preserve the right hardware abstraction at each point in a design flow. Some dialects retain the meaning of a source language, some make scheduling decisions explicit, some provide a shared vocabulary for RTL, and others carry verification, simulation, debug, or emission intent alongside the design.
That is the key to navigating CIRCT: choose a dialect for the information it preserves, not simply because it is “higher” or “lower” than another dialect. A single module can legitimately contain hw structure, comb expressions, seq registers, verif assertions, and sv emission-specific constructs at the same time.
Intent-rich dialects describe what the designer meant. Core dialects describe the reusable hardware structure and behavior. Backend dialects describe how the result will be implemented, executed, or emitted. Cross-cutting dialects keep verification and source meaning attached throughout that journey.
118.1 The Abstraction Map
The solid arrows below show common directions of lowering. They are not the only legal paths, and not every flow visits every box. Dashed arrows show concerns that can accompany a design across several abstraction levels.
The center of the map is the most reusable part of CIRCT. hw provides modules, ports, instances, hierarchy, and hardware types; comb provides pure bit-vector logic; and seq provides clocks, registers, memories, and other stateful elements. Many otherwise unrelated frontends lower into some combination of these dialects because optimizations and backends can share that common form.
The map is deliberately not a strict hierarchy. esi, for example, is a higher-level communication abstraction, but it can coexist with hw modules. verif and dbg do not sit at one fixed height at all: they carry intent alongside other IR. sv may appear next to core operations whenever a design needs a SystemVerilog construct that the generic hardware dialects should not model.
118.2 Dialect Families
118.2.1 Source And Language Semantics
These dialects retain the rules and concepts of an input language or event-driven hardware model. Use them while those source-level distinctions still matter.
firrtlrepresents Chisel/FIRRTL designs, including connects, aggregates, annotations, width inference, memories, and other FIRRTL semantics.chirrtlis FIRRTL’s temporary behavioral-memory layer. It preserves memory use until concrete FIRRTL port kinds can be inferred.moorerepresents elaborated SystemVerilog semantics. It is useful after parsing but before source-language behavior has been reduced to generic hardware.llhdrepresents signals, time, events, processes, and drives. It is especially useful for event-driven HDL semantics and simulation lowering.
These are not interchangeable source dialects. Choose the one that matches the frontend and the semantics that must survive parsing.
118.2.2 Hardware Generation And Scheduling
These dialects preserve decisions that disappear once a design becomes plain RTL: resource allocation, concurrency, dataflow, pipeline stages, and the schedule of operations.
calyxseparates allocated hardware resources from a control program that schedules their use. It fits control-oriented HLS and accelerator generation.handshakerepresents dynamically scheduled dataflow in which values move through explicit handshaking operations.pipelinerepresents unscheduled or scheduled pipelines before stage boundaries become ordinary registers.kanagawarepresents class- and method-oriented hardware with static scheduling concepts before lowering to core hardware.loopscheduleattaches pipeline schedules and stage structure to affine loops.sspserializes static scheduling problems and solutions. It is primarily a scheduling interchange and testing dialect, not a circuit representation.
Stay at this level while a compiler still needs to move operations between cycles, share resources, alter concurrency, or solve a schedule. After lowering to registers and muxes, recovering that intent is difficult.
118.2.4 System Composition And Design Metadata
This family operates around and across compute blocks. It handles how blocks communicate, how tools describe them, and how external systems refer to them.
esiprovides typed channels, bundles, services, buffering, host connectivity, and system manifests for hardware communication.msftcarries support constructs and physical-design intent used by Microsoft-oriented flows, including placement and Tcl collateral.omis a typed object model for design metadata such as clocks, power domains, interfaces, paths, and software-facing descriptions.interopmodels procedural interaction across module and simulator boundaries, especially SystemC or Verilated integration.
Use these dialects when the problem is larger than the logic inside one block: connecting accelerators, preserving physical constraints, describing the system to software, or crossing a simulation boundary.
118.2.5 Implementation, Simulation, And Output
These dialects move from logical hardware intent toward a chosen implementation, executable model, or emitted artifact.
datapathexposes compressor trees and partial products so arithmetic circuits can be optimized before final carry propagation.synthrepresents synthesis-oriented Boolean networks and rewriting choices, including AIG-like logic.svrepresents SystemVerilog-specific surface constructs such as procedural blocks, interfaces, macros, assertions, and verbatim text.emitcontrols files, file lists, fragments, references, and other output packaging rather than hardware behavior.systemcrepresents modules, signals, processes, and C++ constructs for structured SystemC emission.arcturns hardware state transfer into an executable, compiler-friendly simulation model used by Arcilator.
sv is usually a late representation, but it is not synonymous with “the backend.” Core operations can be exported directly alongside SV operations, and emit may independently control how the resulting files are organized.
118.2.6 Verification, Testing, And Debug
These dialects describe how to check or understand hardware rather than only how to implement it.
verifrepresents assertions, assumptions, coverage, symbolic values, formal problems, simulation tests, and contracts.ltlrepresents temporal sequences and properties over clocked behavior.simrepresents simulator services such as printing, DPI, plusargs, files, queues, formatting, and simulation control.rtgdescribes randomized test templates, target resources, sequences, and instruction-oriented test generation. It does not represent synthesizable hardware.dbgmaps optimized IR values back to source variables, scopes, aggregates, arrays, and types for human-facing debug views.
Verification and debug are cross-cutting. Add them at the level where their meaning is clearest, then use the appropriate lowering or preservation passes as the implementation changes underneath them.
118.3 What Can You Build With CIRCT?
CIRCT supports several distinct kinds of work:
- Compile hardware generators and HDLs. Preserve Chisel/FIRRTL or SystemVerilog meaning, normalize it, and produce shared hardware IR or HDL.
- Build hardware from programs. Convert control flow, loops, or dataflow into scheduled pipelines, handshaking networks, accelerators, and RTL.
- Transform and analyze RTL. Work directly with hierarchy, logic, clocks, state, memories, names, and parameters without first reducing everything to gates or text.
- Integrate accelerator systems. Connect blocks with typed channels and services, preserve placement intent, and generate host-visible metadata and collateral.
- Verify and test designs. Carry assertions and temporal properties, build formal or simulation problems, and generate randomized tests.
- Generate artifacts or executable models. Emit SystemVerilog or SystemC, organize output files, or compile a design into an efficient simulator.
No single CIRCT pipeline does all of these. The dialect set is a toolbox from which a frontend or compiler flow selects the abstractions it needs.
118.4 Common Journeys Through The Stack
The following paths are representative. Exact pass sequences and intermediate dialects vary with the frontend, chosen options, and CIRCT version.
118.4.1 Chisel Or FIRRTL To SystemVerilog
Chisel / .fir
-> firrtl + chirrtl
-> hw + comb + seq + verif/ltl/sim as needed
-> sv
-> ExportVerilog
-> .sv files
FIRRTL is where source semantics, annotations, aggregates, and inference are resolved. The HW/Comb/Seq layer exposes reusable RTL structure. SV carries the remaining output-language constructs.
118.4.2 SystemVerilog To Core IR Or Simulation
SystemVerilog source
-> frontend elaboration
-> moore
-> hw + comb + seq and/or llhd
-> sv output or arc executable model
Moore preserves the source language after parsing and elaboration. Core dialects are better for generic hardware transformation; LLHD and Arc serve event-driven or executable simulation paths.
118.4.3 High-Level Synthesis
control flow, affine loops, or dataflow
-> calyx / handshake / loopschedule / pipeline
-> fsm / dc / hw + comb + seq
-> sv
-> hardware
Different HLS paths make different choices. Calyx emphasizes resources and an explicit control schedule. Handshake emphasizes dynamic dataflow. Pipeline and LoopSchedule preserve static stage decisions. They should not be treated as four spellings of the same abstraction.
118.4.4 System Integration
typed accelerator blocks and services
-> esi + hw + om/msft metadata
-> concrete channels, modules, interfaces, and placement collateral
-> SystemVerilog + manifests + support files
The hardware output is only one product in this flow. Software APIs, manifests, placement constraints, and other collateral may be equally important.
118.4.5 Verification And Debug
design at any useful abstraction level
+ verif / ltl / sim
+ dbg source mappings
-> SystemVerilog assertions or simulation
-> formal/SMT checking
-> source-correlated traces and debug information
Verification is a parallel concern, not merely the final box in a lowering pipeline.
118.5 Which Dialect Should I Reach For?
| If you need to… | Start with… | Why |
|---|---|---|
| Define modules, ports, instances, and hierarchy | hw |
It is CIRCT’s shared structural hardware vocabulary. |
| Express pure bit-vector logic | comb |
It preserves combinational operations without source-language syntax. |
| Model registers, clocks, memories, or FIFOs | seq |
It keeps stateful hardware explicit. |
| Retain Chisel/FIRRTL semantics | firrtl and chirrtl |
They preserve FIRRTL inference, connects, annotations, and memory intent. |
| Retain elaborated SystemVerilog semantics | moore |
It models the source language before generic hardware lowering. |
| Describe time, events, signals, and processes | llhd |
It is designed for event-driven hardware behavior. |
| Allocate resources and explicitly schedule their use | calyx |
It separates structural resources from control. |
| Build dynamically scheduled dataflow hardware | handshake or dc |
They make token flow and latency-insensitive control explicit. |
| Assign computations to pipeline stages | pipeline or loopschedule |
They preserve scheduling before registers are materialized. |
| Connect blocks with typed channels and services | esi |
It abstracts communication protocols and system services. |
| Represent states and guarded transitions | fsm |
It retains the state-machine model before RTL encoding. |
| Write assertions, assumptions, or coverage | verif and ltl |
They preserve verification and temporal intent. |
| Optimize arithmetic or Boolean implementation | datapath or synth |
They expose implementation-oriented structures. |
| Control SystemVerilog-specific output | sv |
It models constructs that should survive to emitted SV. |
| Control generated files and fragments | emit |
It describes output organization, not circuit behavior. |
| Produce an executable hardware model | arc |
It represents state transfer for compiled simulation. |
| Preserve source-level debug views | dbg |
It connects source variables and types to lowered values. |
118.6 A Rule For Choosing The Right Level
Start with the highest-level dialect that directly represents the decisions you still want to change. Lower only when that information is no longer needed.
If you still want to reschedule an operation, keep a scheduling dialect. If you only need to optimize an adder, use comb, datapath, or synth. If the remaining concern is exact SystemVerilog spelling, use sv. Moving downward usually makes implementation details more explicit, but it also discards choices that are expensive or impossible to reconstruct later.
The chapters that follow use this map as their shared context. Read hw, comb, and seq first for the reusable core; then choose the source, scheduling, integration, verification, or backend family that matches the flow you are trying to build.
118.7 A Potential Workflow Using CIRCT
Suppose you have a small FPGA board and a trained PyTorch model. You want to turn that model into a custom accelerator: not software running on a soft CPU, but actual multipliers, adders, registers, memories, and control logic placed in the FPGA fabric.
This is possible, but it is important to be precise about what exists today. Torch-MLIR can bring a PyTorch program into MLIR and lower it to tensor-oriented dialects. CIRCT can lower suitable loop and control-flow programs through HLS dialects to SystemVerilog. The middle step—turning tensor operations into a particular scheduled, quantized, memory-aware hardware architecture—is not currently a turnkey torch-mlir-to-CIRCT pipeline. That step is the FPGA accelerator compiler you would be building.
The realistic first target is a frozen inference model: model.eval(), fixed weights, static input shapes, a batch size of one, and no arbitrary Python behavior. Training requires gradients, mutable optimizer state, much more memory, and a substantially larger compiler and runtime problem.
118.7.1 The End-To-End Shape
%%{init: {"theme":"base","flowchart":{"curve":"basis","htmlLabels":true,"nodeSpacing":18,"rankSpacing":28},"themeVariables":{"fontFamily":"system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif","fontSize":"15px","lineColor":"#607089","primaryTextColor":"#172033"}}}%%
flowchart TB
subgraph TOP[" "]
direction LR
MODEL["<b>1 · PyTorch</b><br/>frozen, static,<br/>quantized model"]
TORCH["<b>2 · Torch-MLIR</b><br/>Linalg / TOSA /<br/>StableHLO"]
MAP["<b>3 · FPGA mapping</b><br/>precision, tiling,<br/>memory, parallelism"]
LOOPS["<b>4 · Loop IR</b><br/>scf/cf + arith<br/>+ memref"]
MODEL --> TORCH --> MAP --> LOOPS
end
subgraph BOTTOM[" "]
direction RL
HLS["<b>5 · CIRCT HLS</b><br/>Calyx or<br/>Handshake/DC"]
RTL["<b>6 · CIRCT RTL</b><br/>hw + comb + seq<br/>+ fsm + esi → sv"]
FPGA["<b>7 · FPGA tools</b><br/>synthesize, place,<br/>route, bitstream"]
HLS --> RTL --> FPGA
end
LOOPS --> HLS
classDef model fill:#e8f0ff,stroke:#4d6fdc,stroke-width:2px,color:#172033;
classDef bridge fill:#fff2d8,stroke:#d88a10,stroke-width:3px,color:#172033;
classDef circt fill:#e2f7ed,stroke:#168d66,stroke-width:2px,color:#172033;
classDef output fill:#ffe8e5,stroke:#ce6259,stroke-width:2px,color:#172033;
class MODEL,TORCH model;
class MAP bridge;
class LOOPS,HLS,RTL circt;
class FPGA output;
style TOP fill:transparent,stroke:transparent
style BOTTOM fill:transparent,stroke:transparent
The arrows are abstraction changes, not file-format conversions. Each one commits to decisions that become harder to reverse later. In particular, the FPGA architecture mapping decides whether a mathematical operation becomes one large parallel circuit, a small circuit reused over many cycles, or something between those extremes.
118.7.2 A Concrete First Model
A good first experiment is deliberately small:
import torch
from torch import nn
class TinyMLP(nn.Module):
def __init__(self):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(16, 8),
nn.ReLU(),
nn.Linear(8, 4),
)
def forward(self, x):
return self.layers(x)Compile this for a fixed input such as tensor<1x16xi8>, not an arbitrary ranked tensor. Quantize weights and activations to eight-bit integers, use a wider accumulator such as 24 or 32 bits, and requantize between layers. The exact accumulator width must be derived from the operand ranges and the number of summed products; simply keeping every intermediate at eight bits would overflow.
This model is small enough to simulate exhaustively with many inputs, yet it contains the central problems of neural-network hardware: matrix multiplication, bias addition, activation, precision conversion, weights, and resource scheduling.
118.7.3 Stage 1: Capture And Normalize PyTorch
The model first needs to become a closed graph. A PyTorch export or FX-based frontend captures tensor operations and constants. Torch-MLIR then represents the program in the torch dialect and normalizes it to its backend contract.
Torch-MLIR currently documents three principal output families:
- Linalg-on-Tensors, plus
tensorandarith; - TOSA, a compact tensor operator set that is useful for inference and quantized operations;
- StableHLO, a portable high-level tensor computation representation.
For this experiment, Linalg-on-Tensors is the shortest route toward loops. The two linear layers become matrix multiplication and elementwise operations; ReLU becomes a maximum or select operation. Schematically, the important part looks like this:
tensor<1x16xi8> input
-> linalg.matmul with tensor<16x8xi8> weights
-> add tensor<8xi32> bias
-> elementwise max(value, 0)
-> requantize
-> linalg.matmul with tensor<8x4xi8> weights
-> add tensor<4xi32> bias
-> tensor<1x4xi8> result
At this level, the compiler knows the computation but does not yet know how many FPGA multipliers to create or where any tensor is stored.
118.7.4 Stage 2: Quantize And Make Shapes Static
Hardware needs finite widths and finite storage. Before HLS, the pipeline must:
- Resolve every tensor dimension needed by the accelerator.
- Freeze weights as constants or external memory images.
- Choose signed integer or fixed-point types for inputs, weights, accumulators, and outputs.
- Insert explicit rescaling, rounding, saturation, and clamping operations.
- Verify the quantized MLIR result against the quantized PyTorch model.
Quantization is not merely an optimization. It changes numerical behavior. Every lowering stage should therefore be checked against the same reference inputs with a declared tolerance or, where possible, bit-exact expected outputs.
For a first design, store the weights on chip. A tiny model can use constants, distributed ROM, or block RAM. A large model introduces an external-memory controller and a bandwidth problem that can dominate the arithmetic.
118.7.5 Stage 3: Choose The Accelerator Architecture
Consider the first 16 × 8 linear layer. It needs 128 multiply operations per inference. The tensor IR does not say how those multiplications occupy space and time. Some possible implementations are:
| Architecture | Multiplier hardware | Approximate schedule | Tradeoff |
|---|---|---|---|
| Fully parallel | 128 multipliers | All products begin together | Highest throughput and largest area |
| Eight MAC lanes | 8 multipliers | Reuse each lane across input elements | A useful small-FPGA compromise |
| One MAC lane | 1 multiplier | Serialize nearly all products | Smallest area and longest latency |
The exact cycle counts also depend on multiplier latency, accumulation structure, memory ports, and pipelining. The table expresses architecture, not a timing guarantee.
A compiler pass or FPGA-specific MLIR dialect must record decisions such as:
- tile the matrix operation into groups that fit the chosen number of lanes;
- unroll only the loops that should become parallel hardware;
- pipeline the multiply-accumulate loop;
- map arrays to registers, ROMs, or block RAMs with realistic port counts;
- decide whether layers stream directly into one another or materialize an activation buffer;
- expose a start/done interface or a ready/valid streaming interface;
- attach latency and resource information required by scheduling.
This is the creative center of the compiler. Lowering tensor syntax without making these choices may produce loops, but it does not produce a useful FPGA architecture.
118.7.6 Stage 4: Lower Tensors To A Hardware-Ready Program
After fusion, tiling, and architecture selection, upstream MLIR transformations can bufferize tensors and lower structured computation into explicit loops, loads, stores, arithmetic, and control flow. The desired boundary for CIRCT HLS looks roughly like:
func.func @accelerator(...)
scf.for / affine.for statically bounded iteration
arith.muli / arith.addi fixed-width arithmetic
memref.load / store explicit activation and weight storage
scf.if / cf.cond_br explicit control
func.return accelerator result
This boundary is where the two repositories can meet. Torch-MLIR produces the tensor computation; upstream MLIR removes the remaining tensor abstraction; CIRCT receives a program made from operations its HLS conversions understand.
The bridge still needs legalization. Not every upstream operation is accepted by every CIRCT HLS path. Unsupported math functions may need lookup tables or custom hardware operators, dynamic allocations must disappear, and memory layouts must match the capabilities of the selected lowering.
118.7.7 Stage 5: Select A CIRCT HLS Route
There are two especially useful routes for this example.
118.7.7.1 Static Scheduling Through Calyx
func + scf + arith + memref
-> calyx components, cells, groups, and control
-> fsm control
-> hw + comb + seq
-> sv
-> SystemVerilog
Use calyx when the accelerator should explicitly allocate resources and schedule their reuse. A MAC unit can be a cell; groups describe the assignments for one action; Calyx control determines which actions run in sequence, in parallel, or in a loop. This is a natural fit for the eight-lane or one-lane implementations above.
CIRCT’s hlstool contains a Calyx flow that lowers SCF to Calyx, compiles Calyx control through fsm, lowers to hw, and then converts the result toward sv.
118.7.7.2 Dynamic Scheduling Through Handshake
func + scf/cf + arith + memref
-> handshake dataflow
-> optional dc control network
-> hw + comb + seq
-> sv
-> SystemVerilog
Use handshake when operations should communicate through latency-insensitive channels. Forks, joins, merges, buffers, and memory interfaces make the availability of data and control explicit. This route is attractive for streaming accelerators and computations whose blocks may have variable or decoupled latency.
The official CIRCT HLS documentation describes hlstool and points to integration tests that convert CF-level programs to Verilog. The CIRCT repository includes a matrix multiplication Handshake test that starts with func, cf, arith, and memref, invokes hlstool --dynamic-hw --verilog, and verifies the emitted design with cocotb. That does not make PyTorch-to-FPGA automatic, but it demonstrates that the lower half of this proposed pipeline is real and executable.
CIRCT describes these HLS flows as actively developed research flows rather than production-ready tools. Expect unsupported operations, changing pass pipelines, and cases where a new legalization or lowering must be implemented. That makes this workflow suitable for learning and compiler development, but not yet a drop-in replacement for a vendor HLS product.
118.7.8 Stage 6: Build The RTL And Its Interface
After HLS, the dialect responsibilities become concrete:
hwdefines the accelerator module, ports, instances, and hierarchy.combrepresents adders, multipliers, comparisons, muxes, extracts, and other combinational logic.seqrepresents pipeline registers, state, clocks, and memories.fsmcan preserve controller states before they become RTL.esican describe typed streaming channels and system services before they become concrete ports and buffers.svcarries SystemVerilog-specific constructs needed for readable emission.
The neural-network datapath is not a complete FPGA design by itself. A usable top level also needs:
- clock and reset handling;
- input and output handshaking;
- a way to load inputs and read predictions;
- memory initialization or a weight-loading interface;
- optional AXI, Avalon, FIFO, UART, or board-specific wrappers;
- constraints describing clock frequency and physical pins.
For the first experiment, a ready/valid input stream and output stream are much simpler than a full external-memory subsystem. Inputs can be sent from a test bench or a small host controller, and all weights can remain on chip.
118.7.9 Stage 7: Verify At Every Boundary
Do not wait for a bitstream to discover a numerical or control bug. Keep a reference result and compare after every major lowering:
| Checkpoint | What to compare |
|---|---|
| PyTorch versus quantized PyTorch | Accuracy loss introduced by quantization |
| Quantized PyTorch versus tensor MLIR | Imported operations, shapes, constants, and rounding |
| Tensor MLIR versus loop-level MLIR | Bufferization, tiling, indexing, and fixed-width arithmetic |
| Loop-level MLIR versus Calyx/Handshake simulation | Scheduling, memory accesses, and channel behavior |
| CIRCT RTL versus previous stage | Cycle-level protocol and bit-exact outputs |
| Post-synthesis netlist versus RTL | Reset behavior, initialization, and synthesis assumptions |
| FPGA versus test vectors | Board interface, timing, and real data movement |
Useful tools include MLIR interpreters or reference backends at the tensor level, handshake-runner for suitable Handshake IR, cocotb or Verilator for RTL simulation, and verif or ltl for properties such as “an accepted input eventually produces exactly one output.”
118.7.10 Stage 8: Produce The Bitstream
Exported SystemVerilog is synthesizable source code, not yet an FPGA image. A board toolchain must still perform:
SystemVerilog
-> RTL synthesis
-> mapping to LUTs, flip-flops, DSPs, and block RAMs
-> placement and routing
-> static timing analysis
-> bitstream generation
-> program the FPGA
AMD/Xilinx designs commonly use Vivado, Intel/Altera designs use Quartus, and some FPGA families are supported by open-source flows built around Yosys and nextpnr. This stage determines whether the design actually fits and meets its clock constraint. If it does not, the useful feedback travels upward: reduce parallelism, change bit widths, add pipeline stages, or revise memory banking.
118.7.11 Evidence That The Larger Idea Works
The exact torch-mlir-to-CIRCT bridge proposed here is a compiler project, but PyTorch-to-FPGA compilation is not hypothetical.
- hls4ml converts supported PyTorch and other ML models into configurable HLS projects for FPGA toolchains.
- FINN’s end-to-end flow starts from a trained PyTorch/Brevitas quantized network and can produce a running dataflow accelerator, including bitstreams and drivers for supported AMD/Xilinx boards.
- Torch-MLIR already supplies the PyTorch-to-tensor-MLIR frontend, while CIRCT’s HLS integration tests supply examples of loop/control-flow-to-Verilog lowering. The work needed here is to connect those capabilities with a hardware-aware mapping layer.
These systems also demonstrate an important lesson: successful FPGA compilers do not lower an arbitrary model blindly. They constrain supported operators, make shapes and precision explicit, expose architecture knobs, and repeatedly measure accuracy, resource use, latency, throughput, and timing.
118.7.12 A Practical First Milestone
A credible first success is not “compile every PyTorch model.” It is:
- Support the
TinyMLPabove with a batch size of one. - Use eight-bit inputs and weights with a proven accumulator width.
- Keep weights and activations on chip.
- Implement one resource schedule, such as eight reusable MAC lanes.
- Lower through Calyx or Handshake to SystemVerilog.
- Prove bit-exact agreement in simulation for hundreds of test vectors.
- Synthesize for one named FPGA and report LUT, register, DSP, and block-RAM use together with maximum clock frequency.
- Run the same vectors on the programmed board.
Once that path works, expand one dimension at a time: add convolution, stream layers together, introduce external memory, support more quantization schemes, or explore different scheduling strategies. That incremental path turns the potential workflow into a real compiler without hiding where the difficult hardware decisions occur.