From schematics to code
Every circuit so far has been drawn: gates, wires, flip-flops. That works for an adder. The 6502 has about 3,500 transistors, and its designers drew its layout by hand, on large sheets, a few times bigger than life. A modern processor has tens of billions. Nobody draws those.
They’re written instead, in a hardware description language (HDL): text that says what the circuit is, which a computer turns into gates. The two in widest use are Verilog (from 1984, a standard since 1995) and VHDL (made for the US Department of Defense, a standard since 1987). These pages use Verilog. Everything on this page runs here: each figure sends its Verilog to Yosys, an open-source tool used for real chips, which turns it into gates and flip-flops, and the page simulates those.
1 · A module
Section titled “1 · A module”A circuit in Verilog is a module: a name, a list of its inputs and outputs (its ports), and what’s inside. Here’s the full adder from Adding:
The full adder as Verilog. Click the inputs, and the outputs follow; the waveforms below add a column each time an
input changes. assign says an output is always equal to an expression: ^ is exclusive OR, & AND, | OR
(and ~ NOT). Try breaking it (change a ^ to |) and click Build: Yosys takes a few seconds the first time,
while the page downloads it.
An assign isn’t an instruction that runs once. It’s a wire: s is joined to the output of those gates, all the
time, and whenever an input changes, s does too.
2 · Buses and arithmetic
Section titled “2 · Buses and arithmetic”Wires come in bundles. input [7:0] a is an 8-bit bus, bits 7 down to 0, and operators work on whole buses: +
adds two of them. That one character stands for eight full adders and the carries between them, and Yosys picks the
circuit.
An 8-bit adder in one line. Type numbers into a and b (0 to 255). The curly brackets join wires into one bus:
{cout, s} is 9 bits, the carry on top, so the 9-bit sum lands in both. Change a + b + cin to a - b and build:
the same adder, with the subtractor’s inverted inputs, made for you.
3 · Describing behaviour: always and case
Section titled “3 · Describing behaviour: always and case”Writing every output as an expression gets hard for something like the 7-segment decoder, where each segment is its own sum of products. Verilog can describe what the circuit does instead. An always @* block recalculates its outputs whenever any input changes, and inside it, ordinary-looking code (if, case) says what they should be.
The decoder as a case statement: the truth table, written out row by row. Set d, and the digit shows it. The
default row covers 10 to 15. Yosys works out the gates; nobody here drew a Karnaugh map.
It looks like a program, but it describes a circuit with no memory: for every possible d, an answer for s. Leave
out the default row and that’s no longer true, since for 10 to 15 the block wouldn’t say. The circuit would then
have to remember the last s, and Yosys would build a latch to do it, usually by mistake. The
synthesis page shows it happening.
4 · Clocked logic
Section titled “4 · Clocked logic”Flip-flops come from a different kind of block: always @(posedge clk) runs once at each rising edge of the
clock, and whatever it gives a value to becomes a flip-flop. Inside it, <= sets what each flip-flop will hold
after the edge.
The counter from Clocked circuits, 0 to 9, on the
display. Click Clock ▲ for one clock cycle; set reset to 1 and clock to go back to 0. The counter uses the
decoder as a part: seg7 decoder(...) is one seg7, wired up inside the counter, the way a schematic places a part.
initial gives the flip-flops their value at power-on, which FPGAs can do (a chip designed from scratch would use
the reset instead).
Modules inside modules is how large designs stay readable: a CPU is a module made of an ALU, registers and a control unit, each a module of its own.
5 · It’s hardware, not a program
Section titled “5 · It’s hardware, not a program”Verilog’s code looks like software, which makes it easy to forget that none of it runs in order. Every assign
and every always block is a piece of circuit, and they all work at once. Swap two assign lines and nothing
changes: they’re two wires, not two steps.
Inside a clocked block, the difference between <= and = shows this best:
Non-blocking (<=): a and b swap at every clock edge, 1 and 2, then 2 and 1. Both right-hand sides are read
before the edge, as with real flip-flops: two flip-flops, each wired to the other’s output. Switch to Blocking
(=) and clock: a takes b, then b takes the new a, so both end up 2, the way two lines of a program would run.
The rule most designers follow: <= in clocked blocks, = in always @* blocks. Then the code means what the
circuit does.
6 · A state machine
Section titled “6 · A state machine”The door lock was a state machine: a register holding the state, and logic working out the next state from the state and the key pressed. In Verilog, that’s a register and a clocked block:
Press keys on the keypad: each press is one clock cycle with press = 1 and the key’s number on key. 2, 7, 1 opens
it. The states have names (localparam makes constants), and the order of the if lines is the transition
table: a 2 starts again from any state, as in the fixed table on that page. Try changing the code to 2-7-1-1 by
adding a state (state will need a third bit).
7 · Simulation, and testing
Section titled “7 · Simulation, and testing”Simulation is how hardware is checked before it’s built: run it, and look at the waveforms. On this page you’re the one clicking. For real projects, the test is written in Verilog too, as a testbench: a module with no ports that holds the design and drives its inputs, using parts of Verilog that only make sense in simulation, such as delays:
module counter_test; reg clk = 0, reset = 0; wire [3:0] count; wire [6:0] seg; counter c(.clk(clk), .reset(reset), .seg(seg), .count(count));
always #5 clk = ~clk; // a clock: flip every 5 time units
initial begin #95; // let 9 rising edges go by if (count !== 9) $display("wrong: %d", count); $finish; endendmoduleSimulators such as Icarus Verilog and Verilator run testbenches like this one. A test only checks the inputs it tries, though; formal verification checks all of them.
Summary
Section titled “Summary”- Big circuits are written, in a hardware description language such as Verilog, and a tool turns the text into gates.
- A module has ports; assign makes a wire equal to an expression; buses like
[7:0]carry numbers, and+builds an adder. - always @* describes logic with no memory, with if and case; it must give every output a value every time, or it makes a latch.
- always @(posedge clk) makes flip-flops; use
<=in it, so every flip-flop changes at once, as real ones do. - None of it runs in order: every line is a piece of circuit, all working at once.
- Testbenches check designs in simulation, but only for the inputs they try.
Further reading
Section titled “Further reading”- Donald Thomas and Philip Moorby, The Verilog Hardware Description Language, 5th edition, 2002 (Moorby wrote the first version of Verilog).
- David Harris and Sarah Harris, Digital Design and Computer Architecture, chapter 4: hardware description languages, with every example in both Verilog and VHDL.
- The Yosys documentation (yosyshq.readthedocs.io), and the HDLBits exercises (hdlbits.01xz.net), which check your Verilog in the browser.