Create your own
Lesson illustration

FPGA Design Workflow: From Synthesis to Device Programming

Hello, and welcome to the first lesson. This opening module establishes the practical open-source workflow you will use throughout the course on the iCEBreaker: starting with RTL, turning it into a physical configuration for an iCE40 FPGA, then programming and observing real hardware.

For this lesson, the goal is not to memorize commands yet. Instead, build a reliable mental model of what each stage proves, what it produces, and what it cannot guarantee. That distinction makes later build logs and failures much easier to diagnose.

By the end, you should be able to explain the roles of synthesis, place-and-route, static timing analysis, bitstream generation, and device programming in one coherent workflow.


The central idea: RTL is a specification, not FPGA configuration

A SystemVerilog or Verilog module describes intended digital behavior: registers update on clock edges, combinational logic calculates values, and ports interact with the outside world. It does not say which physical lookup table implements an expression, where that lookup table sits in the FPGA, or which programmable wires connect it to its neighbours.

An FPGA has a fixed physical fabric consisting of:

  • configurable logic cells, including LUTs and flip-flops;
  • dedicated hardware such as block RAM or carry chains;
  • I/O cells connected to package pins;
  • a large grid of programmable routing resources.

The toolchain must translate your abstract RTL into settings for all of those physical resources.

This is the useful high-level sequence:

  1. Synthesis converts RTL into a technology-mapped logical design.
  2. Place-and-route assigns that design to actual FPGA resources and programmable wires.
  3. Static timing analysis checks whether the routed design can meet its clocking requirements.
  4. Bitstream generation encodes the final physical configuration into a device-specific file.
  5. Device programming transfers that configuration to the FPGA or its configuration flash.

Each step consumes a more concrete representation of the design than the one before it.

Introduction to FPGA Part 2 - Getting Started with Yosys, IceStorm, and Apio | Digi-Key Electronics

Watch “Introduction to FPGA Part 2 - Getting Started with Yosys, IceStorm, and Apio” from DigiKey for a compact first view of the open-source iCE40 toolchain. Its board differs from the iCEBreaker, but the roles of Yosys, nextpnr, icepack, and iceprog are directly relevant.

Watch the tool overview to identify the four core tools. Then watch build and upload, which shows how synthesis, place-and-route, packing, and programming appear in an actual build. Finally, watch configuration storage for the distinction between configuring FPGA fabric and storing a configuration for boot.


1. Synthesis: RTL becomes FPGA-oriented logic

Synthesis takes your HDL source and determines a network of hardware primitives that realizes its behavior. In this course’s open-source flow, Yosys performs synthesis.

For example, consider this conceptual RTL:

always_ff @(posedge clk) begin
    if (enable)
        count <= count + 1'b1;
end

Synthesis recognizes the essential hardware structure:

  • a bank of flip-flops holding count;
  • an adder that computes the next count;
  • selection logic that either retains the old value or loads the incremented value;
  • a clock connection to the flip-flops.

It also performs optimizations. If part of the expression is constant, unused, or logically redundant, Yosys may remove or simplify it. Synthesis is therefore not a line-by-line “compilation” of HDL. It preserves the intended hardware behavior while choosing an efficient logical implementation.

For an iCE40 target, synthesis maps the design toward resources the device actually offers: LUTs, flip-flops, RAM blocks, I/O cells, and particular forms of arithmetic support. Its output is typically a technology-mapped netlist, often represented as JSON for the nextpnr flow.

What a successful synthesis run tells you

It tells you that, at least from the tool’s perspective:

  • the RTL parsed and elaborated;
  • the requested top-level module was found;
  • the logic could be mapped to available types of FPGA resources;
  • obvious issues, such as an undriven signal or unsupported construct, may have been reported.

It does not tell you:

  • whether ports are assigned to the right physical pins;
  • whether the logic fits into the selected chip;
  • whether the routed design meets a clock frequency;
  • whether the programmed board behaves as intended.

A synthesis warning deserves attention even when the build continues. A warning that an output is driven by a constant, for example, might be expected for an intentionally unused LED; it might also reveal that control logic was optimized away.

Project IceStorm — Project Icestorm documentation

Read the Project IceStorm documentation to connect the conceptual pipeline to the actual open-source iCE40 utilities used later in this module.

In “What is Project IceStorm?”, read the opening definition for the scope of the project. Then go to “How do I use the Fully Open Source iCE40 Flow?” and inspect the example command sequence: identify which command performs synthesis, implementation, bitstream conversion, and programming; do not worry about executing it yet. Finally, in “What are the IceStorm Tools?” read the “IcePack/IceUnpack,” “IceTime,” and “IceProg” subsections. Focus especially on the distinction between ASCII configuration data and the binary bitstream.


2. Place-and-route: logic becomes a physical circuit

After synthesis, your design is a collection of logical cells and nets. It is not yet a realizable layout on a particular FPGA part.

Place-and-route, often abbreviated PnR, is the stage that turns the logical design into a physical one. In the iCE40 flow, this is handled by nextpnr-ice40.

The backend diagram below provides a useful conceptual view. The left side contains reusable workflow functions such as placement, routing, and timing analysis. The right side contains architecture-specific knowledge: the iCE40 device database tells the tools which resources exist, how they connect, and what delays they have.

A conceptual open-source FPGA backend: a synthesized Yosys netlist is packed, placed, routed, timing-analysed, and converted to a bitstream using an architecture-specific device database. The iCE40 flow used in this course follows this same division between general implementation tasks and device-specific knowledge.

Packing

Before placement, the tool may perform packing: grouping synthesized logical elements into the physical structures offered by the device.

An FPGA logic tile is not simply an unlimited collection of independent gates. It has specific internal structures and rules. For example, a physical logic cell may combine a LUT with a flip-flop in certain permitted ways. Packing makes the netlist conform to these architecture-level rules.

A useful principle is:

Synthesis decides what logical resources are needed. Packing and placement decide how those resources can legally inhabit this FPGA.

Placement

Placement assigns every logical cell to a legal physical location.

A LUT is assigned to a particular logic cell. A RAM inference is assigned to a particular block-RAM site. A top-level output is associated with an I/O cell that is connected to the requested package pin.

Placement affects performance. Two cells that communicate frequently should usually be physically close, especially if their connection is timing-critical. But the placer must also obey many constraints: no two cells can occupy the same location, specialized blocks have limited locations, and I/O must match the board’s wiring.

Routing

Routing selects the actual programmable connections between placed resources.

The iCE40 fabric contains fixed wire segments and programmable interconnect points (PIPs). Configuring a PIP selectively connects wire segments. Routing must find legal paths for every net without creating conflicts with other nets.

A physical net is not just a logical statement such as “connect counter[0] to this adder input.” It becomes a particular sequence of metal segments and programmable switches inside the FPGA. That path has real delay, capacitance, and fan-out implications.

This is why two builds of logically identical RTL can have different timing results after a small unrelated change: a change can alter placement and routing choices across the design.

nextpnr Open source FPGA place & route

Read the nextpnr slides for a more physical explanation of what placement, routing, and post-route timing analysis do. The analytical placement mathematics is useful context, but the main aim is to understand the engineering purpose of each stage.

In the “nextpnr - Terminology” material, read the terminology. A BEL is a location where a cell can be placed; a wire is fixed metal; a PIP is a configurable connection. Then read the “nextpnr - Placement” and “nextpnr - Router” material. In the placement discussion, use the placement outline to see why a good location must still be made legal. Finally, read the “nextpnr - Timing engine” slides through the timing terminology, focusing on how timing quality guides implementation.


3. Static timing analysis: can the physical design run reliably?

A synchronous circuit only works if each register receives stable input data before its next active clock edge.

For a register-to-register path, the main timing budget includes:

  • clock-to-output delay from the launching flip-flop;
  • combinational logic delay through LUTs, carry logic, and other cells;
  • routing delay through the FPGA fabric;
  • setup time required by the receiving flip-flop.

A simplified setup-time condition is:

Real timing analysis also considers clock uncertainty, skew, and device-specific timing models. The central idea remains the same: data launched at one clock edge must arrive sufficiently early for capture at the next edge.

Suppose a path has:

  • logic plus routing delay of

For a clock period, corresponding to , the setup slack is:

Positive slack means the path meets that requirement, with margin. Negative slack means it misses the deadline. A timing failure may appear to work on a particular board at room temperature, but it is not a reliable design: device variation, voltage, temperature, or a later routing change can make it fail.

Why it is called static

Static timing analysis (STA) examines timing paths using timing models. Unlike simulation, it does not require you to provide input test vectors or run the design over time. It asks a structural question:

Given the implemented hardware and declared timing requirements, what is the slowest possible timing path?

This makes STA complementary to simulation:

MethodPrimary question answeredDepends on chosen stimulus?
SimulationDoes the RTL behave correctly in the scenarios tested?Yes
Static timing analysisCan registered paths meet declared timing requirements?No
Hardware testDoes this programmed board exhibit the expected observable behavior?Yes, and only for what you observe

None replaces the others.

For the iCE40 open-source ecosystem, timing analysis may be integrated into the implementation flow and reported by nextpnr, or performed with an associated tool such as icetime. The exact tool boundary matters less than the discipline: define the clocks and interfaces correctly, then read the timing report rather than assuming a successful bitstream is fast enough.

FPGA concepts: Timing

Watch “FPGA concepts: Timing” from Some Assembly Required for a clear physical explanation of setup/hold requirements and why synthesis success alone is not a timing result. The video uses Vivado rather than the open-source tools, but the timing principles transfer directly.

Watch setup and hold for the sampling requirements of flip-flops. Then watch timing and implementation. Focus on the distinction between logical logic inferred during synthesis, physical delays introduced by implementation, and the need for a declared clock requirement before timing can be checked.


4. Bitstream generation: encode the physical configuration

Once the design is placed, routed, and accepted for the intended timing requirements, the final physical configuration must be encoded for the target device.

This is the job of bitstream generation.

For the Project IceStorm flow, nextpnr commonly produces an ASCII configuration representation, often with an .asc extension. icepack converts that representation into a binary configuration image, commonly with a .bin extension.

The bitstream contains device-specific configuration bits that determine, among other things:

  • LUT truth tables;
  • whether and how flip-flops are used;
  • the state of routing PIPs;
  • I/O configuration;
  • configuration of supported dedicated resources.

A bitstream is therefore not a generic executable file. It is a configuration image for a particular FPGA architecture and usually a particular device family and package. A bitstream built for an iCE40 device cannot be programmed into an unrelated FPGA family.

This is also why the device database is so important. The place-and-route and bitstream-generation stages must know the exact resources and configuration encoding of the target FPGA.


5. Device programming: make the board use the bitstream

Device programming transfers the bitstream to hardware.

For iCE40 development boards, there are commonly two closely related possibilities:

  • configure the FPGA’s volatile configuration memory for the current powered session;
  • write the bitstream to external SPI flash so the FPGA loads it automatically at power-up.

The iCEBreaker includes an iCE40 FPGA and board-level configuration hardware. In the practical build lesson, you will use iceprog to program the appropriate target and verify the result on the board. The exact programming option affects persistence: a configuration loaded only into volatile FPGA memory disappears when power is removed, whereas a configuration stored in flash can be reloaded on boot.

A successful programming message means the host-to-board transfer completed. It is important evidence, but it is not full functional verification. A programmed board might still be wrong because of:

  • an incorrect pin assignment;
  • active-low LED or button wiring misunderstood in RTL;
  • an incorrect clock frequency assumption;
  • a timing failure;
  • a logic bug that simulation did not expose.

That is why practical FPGA work uses a chain of evidence: simulation, reports, programming confirmation, and observable board behavior.


Reading build results as a diagnostic boundary

When a build fails, locate the first stage that fails. This simple habit prevents wasted debugging.

StageTypical questionCommon failure category
SynthesisCan the RTL be elaborated and mapped logically?syntax error, missing module, unsupported construct, invalid parameters
Place-and-routeCan this specific FPGA legally host and connect the design?incorrect device, resource overflow, invalid pin constraint, unroutable design
Static timing analysisCan the implemented design meet its timing requirements?missing clock definition, unconstrained paths, negative slack
Bitstream generationCan the routed configuration be encoded for this device?incompatible target or malformed implementation output
ProgrammingCan the host transfer the image to the board?cable, permissions, board selection, power, programmer connection
Board testDoes the actual system behave as intended?wiring polarity, functional RTL error, timing issue, external electrical issue

One practical rule is worth carrying into every future lesson:

A build is not complete merely because it produced a .bin file. It is complete when the design has passed the relevant checks for logic, constraints, timing, programming, and observed behavior.


Key takeaways

  • Synthesis transforms RTL into an FPGA-oriented logical netlist; in this course, Yosys performs that role.
  • Place-and-route maps that netlist onto real FPGA resources and routing; nextpnr performs this architecture-specific implementation work.
  • Static timing analysis uses physical delays and timing requirements to determine whether register-to-register paths meet deadlines. It is not simulation.
  • Bitstream generation converts the implemented device configuration into a binary image; icepack is the key iCE40 utility here.
  • Device programming transfers that image to the FPGA or its configuration flash; iceprog provides this connection to the physical board.
  • A failure’s location in the workflow is a powerful first clue about its cause.

Next, you will move from this mental model to a concrete minimal iCEBreaker project: invoke Yosys, nextpnr-ice40, icepack, and iceprog, then observe a known design on real hardware.

Can't find a good explanation? Sign up and we'll make it for you

Sign up