Inside the fabric, the lookup table and the flip-flop

FPGA design · Building blocks · Jul 2026

An ordinary processor is fixed silicon that reads instructions and does one thing after another. A field programmable gate array (FPGA) is the other idea. It is a sheet of silicon whose function is not decided at the factory but written afterward, and rewritten whenever you like, so that the chip becomes the exact circuit you described. You do not tell it what to do step by step. You tell it what to be, and every part of your design runs at once, in parallel, because it is all real hardware laid out side by side. This first page is about what that sheet of silicon is actually made of, because almost every practical decision later in the series comes back to two primitives and the wires between them.

The lookup table is a tiny reprogrammable truth table

Any combinational function, meaning any output that depends only on the current inputs, can be written as a truth table. List every combination of the inputs on the left and the desired output on the right. A lookup table (LUT) is hardware that stores exactly that right-hand column and nothing else. Give it a $k$-bit input and it uses those bits as an address into a small memory holding $2^k$ bits, returning the one bit you wrote at that address. Because you can write any pattern into that memory, one $k$-input LUT can implement any of the $2^{2^k}$ possible functions of $k$ inputs. That is the whole trick. Programming the FPGA to do logic is really just filling these little memories with the right bits.

Modern devices from both major vendors settle on the six-input LUT, a 64-bit memory that also splits into two five-input functions when a design needs many small gates. To make this concrete, take the sum bit of a full adder, which depends on three inputs. Its truth table has eight rows, so it fits in a six-input LUT with room to spare.

abcinsum = a ⊕ b ⊕ cin
0000
0011
0101
0110
1001
1010
1100
1111

In SystemVerilog you never write the eight rows by hand. You write the function and let synthesis fill the LUT. This whole module collapses to a single lookup table.

full_adder.svmodule full_adder (
    input  logic a,
    input  logic b,
    input  logic cin,
    output logic sum,
    output logic cout
);
    // sum depends on three inputs, so it is one lookup table
    assign sum  = a ^ b ^ cin;
    // the carry out is a second three-input function, a second lookup table,
    // though in practice the tools steer this onto the dedicated carry chain
    assign cout = (a & b) | (cin & (a ^ b));
endmodule

A larger function of more than six inputs does not fit in one LUT, so synthesis splits it across several and wires their outputs into the inputs of another. A wide multiplexer or a big comparator becomes a small tree of LUTs. The depth of that tree is the number of LUTs a signal passes through, and since each one takes time, that depth is the first thing that decides how fast the circuit can run.

The flip-flop is the only thing that remembers

A LUT has no memory of its own. Change the inputs and the output follows after a short delay, and nothing is retained. To build anything that counts, waits, or holds a result you need state, and state on an FPGA lives in the D flip-flop. A flip-flop watches one signal, the clock, and on each rising edge it copies its data input to its output and then holds that value steady until the next edge. Between edges the world can change and the flip-flop does not care. This is the heartbeat that makes an entire chip full of parallel logic behave predictably.

dff.svmodule dff (
    input  logic clk,
    input  logic d,
    output logic q
);
    // capture d on the rising edge of the clock, hold it until the next one
    always_ff @(posedge clk)
        q <= d;
endmodule

Every LUT in the fabric is paired with one or more flip-flops right next to it, so the natural unit of an FPGA design is a chunk of combinational logic that computes something followed by a flip-flop that captures the result on a clock edge. The next page builds the combinational half, and the page after that builds the clocked half. Almost every synchronous design is those two shapes repeated.

The slice packages LUTs, flip-flops, and a carry chain

The LUTs and flip-flops are not scattered loose. The vendors group a handful of them into a block called a slice or a logic cell, and group slices into a configurable logic block. What matters at this level is the extra hardware the vendors add inside that block, because it is there for the operations too important to leave to general LUTs. The most important addition is the carry chain. Adding two numbers means each bit produces a carry that the next bit needs, and if every carry had to travel through a LUT the adder would be slow and its speed would fall as the numbers got wider. So the fabric includes a dedicated fast path for carries that runs vertically up a column of slices. When you write a + b, synthesis puts the per-bit sum in the LUTs and the carry on this chain, which is why a wide adder on an FPGA is far faster than its LUT count alone would suggest.

Block RAM and DSP slices, the hardened helpers

Two operations are so common that building them out of LUTs and flip-flops would waste most of the chip, so the vendors harden them into dedicated columns. The first is memory. Storing a few kilobytes in flip-flops would consume thousands of them, so the fabric includes block RAM (BRAM), dedicated memory tiles of roughly 18 or 36 kilobits each. A block RAM has two independent ports, so one part of your design can write while another reads, which is exactly what a buffer between two stages needs. On-chip memory gets its own page later.

The second hardened block is arithmetic. Multiplication is expensive in LUTs, and signal processing and machine learning do enormous numbers of multiplies, so the fabric includes columns of digital signal processing (DSP) slices. Each one is a small fixed circuit that multiplies two moderately wide numbers and adds the result into a running total, a multiply-accumulate, in a single clock. A modern DSP slice handles something like a 27 by 18 bit multiply feeding a 48 bit accumulator. The capstone of this series streams matrices through a grid of these slices, which is the same structure that sits underneath machine-learning inference on real accelerators.

Routing is the wiring, and it is often the hard part

None of these blocks would be useful if you could not connect them, and the connections are themselves programmable. Between the logic runs a dense mesh of wires with programmable switches at the crossings, so configuring an FPGA means both filling the LUTs and closing the right switches to route signals from one block to the next. This routing fabric is a large fraction of the silicon, and on a full design it is frequently the part that limits speed. Two blocks that must talk but end up placed far apart pay for every switch and every millimeter of wire in between. A great deal of the craft of FPGA design is keeping things that talk to each other close together, a theme that returns when the series reaches timing closure.

From SystemVerilog to a configured chip

The tools turn your description into a configured device through a fixed sequence, and knowing the names makes the tool reports readable. It helps to picture the same small design moving through each stage.

  • Synthesis reads your register transfer level (RTL) code, the SystemVerilog, and works out which LUTs, flip-flops, block RAMs, and DSP slices are needed to realize it. The output is a netlist, a graph of fabric primitives and the connections between them.
  • Mapping packs that netlist into the concrete resources of the target device, deciding which functions share a slice and which multiply lands on which kind of block.
  • Placement chooses a physical location on the die for every primitive, trying to put connected blocks near each other so the wires stay short.
  • Routing commits to the actual switches and wires that carry each signal between the placed blocks.
  • Timing analysis adds up the real delays along every path and checks that each signal arrives before its flip-flop captures it. This is the pass that tells you whether the design runs at the clock speed you asked for, and it gets its own page.
  • Bitstream generation writes out the file that programs the chip, the LUT contents and every switch setting, which is loaded into the FPGA to make it become the circuit.

That is the whole machine. Two primitives, a few hardened helpers, a sea of programmable wire, and a flow that maps a description onto all of it. Everything else in this series is about using these pieces well, and it starts on the next page with combinational logic, the circuits that compute a result from their inputs with no clock in sight.

Next, combinational logic in SystemVerilog.