RTL & Logic Design · lesson 1

What RTL and Logic Design Is

By Tabish Iqbal · Last updated:

Abstraction levels in Verilog, what RTL actually means (datapath plus control), and the spec-to-silicon design loop every lesson in this path follows.

10 min read · Free, no login

This path assumes the Verilog language itself is already familiar from the Verilog pillar โ€” module syntax, ports, assign, always, the non-blocking operator. What that pillar did not cover is the question this lesson opens with: given a written specification for a circuit, how does a designer actually arrive at RTL that a synthesis tool can turn into working silicon? That question, not any new language syntax, is what the next eleven lessons are about.

Reading time: about 10 minutes.

1.1 Four ways to describe the same circuit

Any digital circuit can be written down in Verilog at more than one level of abstraction, and the same circuit looks different โ€” sometimes very different โ€” depending on which level is chosen. It is worth being precise about the four levels this course will keep naming, because interview questions routinely ask a candidate to place a piece of code on this ladder.

At the gate level, a description instantiates primitive gates directly โ€” and, or, xor, not โ€” one at a time, wired together by hand. This is the lowest level in common use and the one closest to an actual schematic (Verilog also has a switch, or transistor, level that is rarely used for design); nobody writes a real design this way past a textbook example, but it is useful for seeing exactly what a higher-level description eventually becomes.

At the dataflow level, a description uses continuous assignment (assign) with Boolean and arithmetic operators to describe how signals flow through combinational logic, without naming individual gates. The simulator and the synthesis tool both still see something close to a direct equation.

At the behavioral level, a description uses procedural blocks (always, if, case) to describe what a circuit does, in terms that read more like a specification than a circuit โ€” "on every clock edge, if enable is high, increment the counter." The Verilog path's lesson on sequential logic already built counters and shift registers this way, and lesson 7 of this path designs them in detail; this course calls that pattern RTL, and most of what gets written from here on is at this level.

At the structural level, a description instantiates other modules and wires them together โ€” not primitive gates, but whole functional blocks, each one possibly written at any of the three levels above. A chip's top-level module is almost always structural: it says which sub-blocks exist and how their ports connect, and leaves the actual logic to the modules being instantiated.

These four are not mutually exclusive inside one file. It is entirely normal, and in fact typical of real RTL, for a top module to be structural (instantiating a datapath block and a control block), the datapath block to be dataflow or behavioral, and one small corner of it to drop to the gate level for a reason specific to that design. The level is a property of a given piece of code, not of the whole design.

The same one-bit full adder at two levels

Dataflow level, using Boolean equations directly:

module full_adder1 (
    input  wire a,
    input  wire b,
    input  wire cin,
    output wire sum,
    output wire cout
);
    assign sum  = a ^ b ^ cin;
    assign cout = (a & b) | (b & cin) | (a & cin);
endmodule

Simulated against all eight input combinations, every output matches the textbook truth table for a full adder:

OK  a=0 b=0 cin=0 -> sum=0 cout=0
OK  a=0 b=1 cin=1 -> sum=0 cout=1
OK  a=1 b=1 cin=1 -> sum=1 cout=1
ALL TESTS PASSED

A gate-level version of the identical function would instantiate two xor gates and a handful of and/or gates by name instead of writing ^ and &; synthesis turns the dataflow version above into essentially that gate netlist automatically. Yosys's generic synthesis of this module produces seven simple cells (three NAND, two OR, one AND and one MUX) and no storage at all. The exact cell mix is the tool's choice rather than an XOR-for-XOR copy of the equations, which is the point: once the function is written down correctly, mapping it to gates is the tool's job.

Composes other blocks Structural Instantiates other modules and wires their ports together mux2 m (.a(a), .y(y)); Behavioral Describes what the block does, using procedural blocks always @(posedge clk) ... Dataflow Describes signal flow with continuous assignment assign sum = a ^ b ^ cin; Gate level Instantiates primitive gates one at a time xor x1 (sum, a, b); Closest to silicon
All four rows can describe the same one-bit full adder. Real RTL mixes levels inside one file rather than committing to a single row.

1.2 RTL as datapath plus control

"RTL" stands for register-transfer level, and the name is a precise description of what the style actually describes: the transfer of values between registers, one clock edge at a time, plus the combinational logic computing what gets transferred. Almost every digital design, from a single counter to a multi-billion-transistor processor, is organized the same way once it is broken down far enough โ€” as a datapath and a control path.

The datapath is the collection of registers and the combinational logic between them that actually carries and transforms data โ€” adders, multiplexers, comparators, shift registers, memories. The control path is the (usually much smaller) logic that decides, cycle by cycle, which of the datapath's operations happens next โ€” typically a finite state machine, covered in lessons 5 and 6, driving select lines, enables, and write signals into the datapath. Lessons 3 and 4 of this path build the small combinational blocks (muxes, encoders, lookup tables) that datapaths are assembled from; lessons 5 and 6 design and minimize the state machines that form the control path; lesson 7 builds the registers and counters that hold state, and lesson 8 explains why all of this stays synchronous; lessons 9 through 12 build the arithmetic units, and lesson 12 closes by putting a datapath and its controller together and verifying the whole assembly against its specification.

A useful habit, and one worth having ready for an interview, is to be able to look at any block diagram and point at which part is datapath and which part is control, before writing a line of Verilog. Getting that split right early is most of what separates RTL that is easy to extend and debug from RTL that is not.

1.3 The design loop: spec to silicon

Writing RTL by trial and error โ€” typing always blocks until the simulation happens to pass โ€” works for a two-line example and fails badly on anything larger. The loop this course follows, and the loop used in real design teams, has five stages, and skipping or shortcutting any of them is where avoidable bugs usually come from.

  • Specification. State in words, and ideally in a table or waveform, exactly what the block must do: its inputs, its outputs, their timing relationship, and its behavior at every corner case (reset, overflow, simultaneous requests). A specification that is vague about corner cases produces RTL that is vague about corner cases.
  • Equations. Turn the specification into Boolean equations or a state table โ€” the content of lessons 2, 5 and 6 โ€” before writing any Verilog at all. This step is where Boolean algebra, Karnaugh maps, and state diagrams earn their place in a digital design course: they are how a specification becomes something mechanical enough to code up without guessing.
  • RTL. Translate the equations or state table into synthesizable Verilog, choosing dataflow, behavioral, or structural style as appropriate for each piece, following the clocked-block template from the Verilog path's lesson on sequential logic.
  • Simulate. Write a testbench that checks the RTL against the specification, not against whatever the RTL happens to produce. Every module in this path, and every well-run real design, is checked this way before it is trusted. A simulation that passes only proves the RTL matches the testbench; it is the testbench's job to actually encode the specification.
  • Synthesize. Run the RTL through a logic synthesis tool and confirm it produces the expected kind of hardware โ€” no accidental latches, no combinational loops, registers where registers were intended. Synthesis is also where style choices that looked harmless in simulation (a signal driven from two different always blocks, say) turn into a tool error or a warning that has to be understood, not ignored.
Specification Equations RTL Simulate Synthesize simulation finds a bug: back to equations, not a patch in the RTL
Each solid arrow is the normal forward path; the dashed arrow shows the loop's real shape โ€” a problem found late routinely sends work back to an earlier stage.

In practice the loop is not strictly linear: a problem found during simulation routinely sends a designer back to the equations, and occasionally all the way back to the specification once it becomes clear the spec itself was ambiguous. Thus, "design loop" is the more accurate name than "design pipeline" โ€” each stage can hand work back to an earlier one, and a design is finished only once all five stages agree with each other.

1.4 Interview questions

What is the difference between dataflow and behavioral Verilog? Dataflow uses continuous assignment with operators to describe signal flow directly, close to an equation. Behavioral uses procedural blocks (always, if, case) to describe what the circuit does in more algorithmic terms. Both can describe the same hardware; the choice is about which is clearer to write and read for a given piece of logic, not about which one is more "real."

What does RTL stand for, and what does the name actually describe? Register-transfer level. It describes a design as registers plus the combinational logic that computes the values transferred between them on each clock edge โ€” in other words, a datapath driven by a control path.

Can one Verilog module mix abstraction levels? Yes. A single module can contain an assign statement (dataflow), an always block (behavioral) and an instance of another module (structural) side by side, and real RTL does this constantly; the level is a property of each piece of code, not of the module.

Why does the design loop include a separate "equations" stage instead of writing Verilog straight from the specification? Because turning a specification into Boolean equations or a state table forces every corner case to be made explicit before any code exists. Skipping straight to Verilog tends to hide ambiguity in the specification inside whatever the first draft of the RTL happens to do, which is a much harder place to find and fix it.

1.5 Further reading

  • Harris, David Money, and Sarah L. Harris. Digital Design and Computer Architecture. Morgan Kaufmann.
  • Mano, M. Morris, and Michael D. Ciletti. Digital Design. Pearson.
  • Cavanagh, Joseph. Verilog HDL Design Examples. CRC Press.
  • Ciletti, Michael D. Advanced Digital Design with the Verilog HDL. Pearson.
  • Dally, William J., and R. Curtis Harting. Digital Design: A Systems Approach. Cambridge University Press.
  • Cummings, Clifford E. Papers from the SNUG (Synopsys Users Group) conference series.
  • HDLBits โ€” online Verilog practice problems.

Key takeaways

  • Verilog supports four abstraction levels โ€” gate, dataflow, behavioral, structural โ€” and one file commonly mixes several of them; the level is a property of a piece of code, not of a whole design.
  • RTL means register-transfer level: registers plus the combinational logic computing what moves between them each clock edge. Almost every design splits into a datapath (data storage and transformation) and a control path (sequencing logic).
  • The design loop has five stages โ€” specification, equations, RTL, simulate, synthesize โ€” and any stage can send work back to an earlier one; it is a loop, not a one-way pipeline.
  • A specification vague about corner cases produces RTL vague about corner cases; the equations stage exists specifically to force that ambiguity into the open before code is written.
  • This path builds, in order: small combinational blocks (lessons 3-4), state machines for control (lessons 5-6), registers, counters and the case for synchronous design (lessons 7-8), and arithmetic datapaths ending in a full datapath-plus-controller project (lessons 9-12).