Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Quick Start: Your First Green Build
  • Part 1: How Chips Get Made6
    • Idea to Silicon
    • What RTL Is
    • ASIC, FPGA, SoC and IP
    • Front-End and Back-End: Who Does What
    • PPA Primer
    • What Happens After RTL
  • Part 2: Your Workstation5
  • Part 3: Specify and Architect3
  • Part 4: The Design Loop6
  • Part 5: The Verification Ladder6
  • Part 6: Automation and Reproducibility5
  • Part 7: Hand-Off to the Back-End3
  • Part 8: When Things Go Wrong3
  • Part 9: Project and Next Steps3
  • Reference4
Loading lesson

‹Part 1: How Chips Get Made
  1. Topics
  2. Start Here: RTL and Verification
  3. Part 1: How Chips Get Made
  4. What RTL Is

Part 1 · How Chips Get Made · Foundation (F)

What RTL Is

RTL describes registers and the logic that computes their next values: what the enabled register does on each of eight clock edges, and why it is not a program.

On this page

    Note

    Level: Foundation (F) · Answers: What does a few lines of RTL actually describe?

    Before this: Idea to Silicon

    The file at the end of this lesson is short: a 4-bit register with an enable input and a reset input, plus the test code that drives it. Nothing in it looks like hardware. There are no gates, no wires, no transistors, only assignments and conditions.

    What does a few lines of RTL actually describe?

    Registers hold values; logic computes the next ones

    RTL means register-transfer level. It describes hardware as registers and the logic that computes the next value of each register. A register is storage that updates once per clock edge: a small group of memory cells that all capture their inputs together. A clock edge is the moment the clock signal rises from 0 to 1. In this lesson every register captures on the rising edge, and nothing changes between edges.

    The logic between registers comes in two kinds. Combinational logic computes its outputs from its current inputs and has no memory: change an input and the output follows after the gate delays. Sequential logic has memory: its output depends on the current inputs and on values stored earlier. Every register is sequential logic, and so is anything built from registers.

    Here is the part that surprises software engineers. Everything described in RTL happens at the same time. When the edge arrives, every register in the design captures at once. The lines of code are not steps in a program: separate blocks and separate register assignments update together, so their order in the file does not change the hardware. (Inside one if / else if chain the order still matters, because the first true condition wins.) There is no top to bottom, only edge to edge.

    The enabled register shows the whole idea in three lines. At each rising edge, reset wins first: while the reset input sits low, the register takes 0. Otherwise the enable input decides: high loads the input d, low keeps the current value. Reset here is synchronous, which means it takes effect only at the edge, never in between.

    One loop every RTL block follows

    The figure below draws the pattern behind every RTL block. Read it clockwise starting from the output: the current q feeds back to a multiplexer, the enable input steers that multiplexer between d and the current q, and each rising clock edge loads the chosen value into the register. The dashed cloud between the two registers is where the combinational logic lives.

    The clocked-register model. Trace the loop from the output q back to the multiplexer, then watch the enable input choose between d and the current q before each rising clock edge.

    Eight edges, one working register

    The figure below is the simulation of the register driven through eight rising edges. The test code changes the inputs on each falling edge, so every input is stable when the rising edge samples it. Read the q row from left to right and check each step against the three-line rule above.

    How to read it, slot by slot:

    • Edge 0: the reset input is low at the edge, so q becomes 0. Reset wins over everything.

    • Edge 1: reset is high, enable is high, d is 5, so q becomes 5.

    • Edge 2: enable is still high and d is 9, so q becomes 9.

    • Edge 3: enable is low and d is 3, so the register ignores d and q holds at 9.

    • Edge 4: enable is still low, so q holds at 9 a second time.

    • Edge 5: enable is high again and d is 3, so q becomes 3.

    • Edge 6: enable is low while d is 7, so q holds at 3.

    • Edge 7: enable stays low, so q holds at 3 to the end of the run.

    The whole design in one file

    The listing uses a few forms that may be new: [3:0] for a four-bit bus, 4'd0 for the number zero written with its width, posedge for a rising clock edge, and <= for a register update. The Syntax Primer names each one and runs them in a short program; read it first if any of these look unfamiliar.

    The listing below is the complete experiment: the register design plus the test code that drives its eight edges and checks each answer. The waveform above comes from this file.

    enabled_reg.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    `timescale 1ns/1ps
    // What RTL is: a 4-bit register with enable and synchronous active-low reset.
    // On every rising edge of clk: reset (rst_n == 0) forces q to 0; otherwise,
    // when en is high q takes the value of d, and when en is low q holds.
    // Reset is synchronous: it only takes effect at a rising edge.
    module enabled_reg (
        input  logic       clk,
        input  logic       rst_n,
        input  logic       en,
        input  logic [3:0] d,
        output logic [3:0] q
    );
        always_ff @(posedge clk) begin
            if (!rst_n)
                q <= 4'd0;
            else if (en)
                q <= d;
        end
    endmodule
    
    // Self-checking testbench. Inputs change on the falling edge; the register
    // samples on the rising edge; q is checked 1 ns after each rising edge.
    // Eight rising edges: reset, load 5, load 9, hold, hold, load 3, hold, hold.
    // Not synthesizable.
    module tb;
        logic clk = 0;
        logic rst_n = 0;    // edge 0 stimulus: hold reset (matches the first check)
        logic en = 0;
        logic [3:0] d = 4'd0;
        logic [3:0] q;
    
        enabled_reg dut (.clk, .rst_n, .en, .d, .q);
    
        always #5 clk = ~clk;
    
        initial begin $dumpfile("wave.vcd"); $dumpvars(0, tb); end
    
        int errors = 0;
    
        // Check q 1 ns after the rising edge. Mismatches are reported but do not
        // stop the run, so one failure cannot hide the rest of the sequence.
        task automatic check(input logic [3:0] want, input int idx);
            if (q !== want) begin
                errors++;
                $display("ERROR edge %0d: expected q=%0d got %0d", idx, want, q);
            end
        endtask
    
        initial begin
            @(posedge clk); #1; check(4'd0, 0);   // edge 0: reset -> q = 0
    
            @(negedge clk); rst_n = 1; en = 1; d = 4'd5;
            @(posedge clk); #1; check(4'd5, 1);   // edge 1: en=1, d=5 -> q = 5
    
            @(negedge clk); rst_n = 1; en = 1; d = 4'd9;
            @(posedge clk); #1; check(4'd9, 2);   // edge 2: en=1, d=9 -> q = 9
    
            @(negedge clk); rst_n = 1; en = 0; d = 4'd3;
            @(posedge clk); #1; check(4'd9, 3);   // edge 3: en=0 -> holds 9
    
            @(negedge clk); rst_n = 1; en = 0; d = 4'd3;
            @(posedge clk); #1; check(4'd9, 4);   // edge 4: en=0 -> holds 9
    
            @(negedge clk); rst_n = 1; en = 1; d = 4'd3;
            @(posedge clk); #1; check(4'd3, 5);   // edge 5: en=1, d=3 -> q = 3
    
            @(negedge clk); rst_n = 1; en = 0; d = 4'd7;
            @(posedge clk); #1; check(4'd3, 6);   // edge 6: en=0 -> holds 3
    
            @(negedge clk); rst_n = 1; en = 0; d = 4'd7;
            @(posedge clk); #1; check(4'd3, 7);   // edge 7: en=0 -> holds 3
    
            if (errors == 0) $display("PASS: enabled register");
            else $fatal(1, "FAIL: %0d mismatches", errors);
            $finish;
        end
    endmodule

    This listing is the register design next to the test code that drives it, so you can match each of the eight edges to the line that caused it. Running it looks like this:

    Diagram
    # captured terminal output
    $ iverilog -g2012 -Wall -s tb -o build/reg.vvp enabled_reg.sv
    $ vvp build/reg.vvp | grep -v finish
    VCD info: dumpfile wave.vcd opened for output.
    PASS: enabled register

    The first command compiles the file and prints nothing when it succeeds. The second runs the simulation: the first line says the testbench opened its waveform file, and the last line is the testbench's own verdict that all eight edges matched. This output came from Icarus Verilog 13.0 on macOS.

    What is q after edge 3?

    Predict first Look at edge 3, where the enable input is low and d is 3. Cover the slot list above and say what q is after that edge, and why.

    9. The enable input is low, so the multiplexer feeds the current q back into the register and d is ignored. A changing d with a low enable is the normal case for holding a value, not a conflict.

    Three mistakes beginners make

    • Reading RTL from top to bottom. The reset branch sits above the enable branch in the file, and it is tempting to imagine reset being checked first in time. In hardware both are evaluated together at the edge. Read each register block as one sentence: at every edge, this register takes the first value whose condition holds.

    • Expecting q to follow d between edges. When d changes from 9 to 3 with enable low, nothing happens to q until an edge arrives, and then q still holds. The register samples d only at the edge and only when enable is high. If your mental picture shows q tracking d, replace it with the figure above.

    • Leaving out reset. Without the reset branch the register starts at an unknown value and the first edges check garbage. Real designs give every register a defined starting value, exactly as this one does with its synchronous active-low reset.

    Rule: RTL says what every register becomes at the next clock edge; everything else is the logic in between.

    Check yourself Enable stays high and d changes halfway between two edges. When does q change?

    At the next rising edge, and it takes the value d holds at that edge, not the value d held earlier. Between edges q keeps its old value no matter how often d moves, because the register samples only at the edge.

    Check yourself Why does the test code change the inputs on the falling edge instead of the rising edge?

    So every input is stable when the register samples it on the rising edge. Changing an input at the same instant the register captures it would make the result a race between the two, and the check 1 ns later would compare against luck instead of logic.

    Check yourself What would q do if the reset input stayed low for all eight edges?

    Stay at 0 for every edge. Reset sits above enable in priority, so a low reset forces q to 0 at each edge even with enable high and d nonzero. That priority is why the reset branch is safe to check first when you read the code.

    Interview

    Asked: "What is the difference between combinational and sequential logic?"

    Weak answer: Combinational logic is simple gates and sequential logic is logic with a clock.

    Strong answer: Combinational logic has no memory: its outputs follow its current inputs, like the multiplexer steering in this lesson. Sequential logic has memory: its outputs depend on stored state, like the register that holds q between edges and updates it only at the clock edge. The two always pair up: combinational logic computes each next value, and registers decide when it is captured.

    Follow-ups: (1) Where is the combinational logic in the enabled register? (2) What would break if reset acted between edges instead of at them?

    Simulation is where this register comes alive, and the course that owns simulation detail is the RTL course:

    Related topics

    • RTL course: Simulation and Testbenches

    • Lesson 1.1, Idea to Silicon

    Keep going

    Next: Lesson 1.3, ASIC, FPGA, SoC and IP. You know what RTL describes. The next lesson sorts out the four names people mix up: ASIC, FPGA, SoC and IP.

    Key takeaways

    • RTL describes registers and the logic that computes their next values; every register captures at the clock edge.

    • Combinational logic has no memory and sequential logic does; the register is sequential and the steering around it is combinational.

    • Code order means nothing in hardware: all registers update together, so read each block as one edge-to-edge rule.

    Previous

    5 / 47

    Next: ASIC, FPGA, SoC and IP

    Up next

    Up nextASIC, FPGA, SoC and IP

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Front-End and Back-End: Who Does What
    • PPA Primer
    • What Happens After RTL
    clkrst_nend05937q0593
    Eight rising edges of the enabled register. Follow the q row from left to right: 0 after reset, 5, 9, two holds at 9, 3, then two holds at 3.