3.5.6 · D4HDL & Digital Design Flow

Exercises — RTL (register transfer level) design

3,181 words14 min readBack to topic

Before we start, one picture fixes every timing number on this page. Two registers, logic between them, one clock — the "compute-then-catch" pipeline.

Figure — RTL (register transfer level) design

Read it left to right: register R1 launches a value after the clock edge, that value crawls through the combinational cloud taking , and register R2 must have it stable before the next edge. All three added together must fit inside one clock period .


L1 — Recognition

Exercise 1.1

Which of these Verilog lines creates a register (stored state), and which creates only combinational wires/gates?

(a) assign s = a ^ b;
(b) always @(posedge clk) q <= d;
(c) always @(*) y = sel ? p : n;
(d) wire [3:0] sum = x + y;
Recall Solution 1.1

A register is created only when a signal is assigned inside @(posedge clk) (or has clocked feedback).

  • (a) assign → combinational wire/gate (an XOR gate). Not a register.
  • (b) q <= d inside @(posedge clk)register (a D flip-flop). ✅
  • (c) always @(*) → combinational (a 2-to-1 mux). Not a register.
  • (d) wire ... = x+y → combinational (an adder). Not a register. Answer: only (b) is a register.

Exercise 1.2

In the equations and , name what each of , , , is in plain words.

Recall Solution 1.2
  • = current register contents (the machine's memory right now).
  • = inputs arriving this cycle.
  • = next-state combinational logic — the function that computes what the registers will hold next.
  • = output logic — the function that computes the outputs from state and inputs. The update happens only at the clock edge; and are pure combinational functions with no memory.

L2 — Application

Exercise 2.1

A register-to-register path has ns, ns, ns. Find the minimum clock period and the maximum frequency in GHz.

Recall Solution 2.1

Use the setup rule . What this means: the logic barely settles in 2.70 ns, so you cannot clock faster than ~370 MHz without a setup violation.

Exercise 2.2

An 8-bit accumulator does acc <= acc + data_in;. How many flip-flops does the design need? How many for a 32-bit version?

Recall Solution 2.2

A register stores one bit per flip-flop. Only acc is stored (the adder is combinational gates, not storage).

  • 8-bit acc8 flip-flops.
  • 32-bit acc32 flip-flops. The adder is synthesized as gates and adds zero flip-flops. (See Logic synthesis for how acc + data_in becomes an adder.)

Exercise 2.3

Complete this module so that y holds (a + b) * c registered on the clock. Fill the two blanks (___).

wire [15:0] prod = ___ ;
always @(posedge clk) y ___ prod;
Recall Solution 2.3
wire [15:0] prod = (a + b) * c;   // combinational: adder + multiplier
always @(posedge clk) y <= prod;  // sequential: latch with non-blocking <=
  • The wire is pure combinational math — it re-computes every instant.
  • The register uses <= (non-blocking) because it is inside @(posedge clk) (see the L3 trap for why).

L3 — Analysis

Exercise 3.1

This block is meant to swap a and b every clock, but it fails. Explain why, then fix it.

always @(posedge clk) begin
  a = b;
  b = a;
end
Recall Solution 3.1

Why it fails: = is a blocking assignment — statements run in order, and each sees the results of the previous one immediately.

  1. a = b;a now equals old b.
  2. b = a;a was already updated, so b also gets old b. Result: both end up as old b. No swap. Fix — use non-blocking <=:
always @(posedge clk) begin
  a <= b;
  b <= a;
end

Non-blocking reads all right-hand sides using the pre-edge (old) values first, then updates both simultaneously — exactly how real flip-flops fire in parallel. Now ab truly swap.

Exercise 3.2

Two flip-flops sit back-to-back with no logic between them (a shift register). Given ns and ns, does this pass the hold constraint? Show the check.

Recall Solution 3.2

With no logic, . Hold rule: . Passes. The new data reaches R2 no earlier than ns after the edge, which is after R2's ns hold window closes, so the old value latches safely. (Notice never appeared — hold is edge-local.)

Exercise 3.3

A path has ns, ns, ns. Is there a hold violation? If so, by how much, and what fix works?

Recall Solution 3.3

Check: ns. Required: ns. The data arrives too early and corrupts the same-edge capture. Fix: add delay (buffers) on the short path so rises by at least ns → ns, just meeting hold. Slowing the clock does nothing is not in the hold equation.


L4 — Synthesis

Exercise 4.1

A single combinational block computes out = ((a+b) + c) + d (three chained adds) between two registers. Each adder has ns; ns, ns. (a) Find as one flat block. (b) Split it into 2 pipeline stages (register after two adders, then one adder). New critical path? New ? Use the figure below.

Figure — RTL (register transfer level) design
Recall Solution 4.1

(a) Flat: three adders in series → ns. (b) Pipelined (2 stages): longest stage now holds two adders → ns (the other stage has 1 adder = 0.9 ns; the longest stage sets the clock). Payoff: cutting the critical path from 3 adders to 2 raised throughput from ~323 MHz to ~455 MHz — a speedup, at the cost of extra pipeline registers and 1 cycle of latency. See Pipelining.

Exercise 4.2

Sketch (in words + code skeleton) an RTL description of a machine with states IDLE → LOAD → DONE, advancing one state per clock, that asserts ready in DONE. Identify (next-state) and (output) parts.

Recall Solution 4.2

This is a finite state machine: a state register plus two combinational functions. Here clk, rst are module inputs; ready is a module output.

module fsm(input clk, input rst,        // rst = synchronous reset input
           output ready);
  reg [1:0] state, next;                // 'reg' is a Verilog storage TYPE, not
                                        // a promise of a flip-flop (see note below)
  localparam IDLE=0, LOAD=1, DONE=2;
 
  always @(*) begin                     // δ: next-state logic (combinational)
    case (state)
      IDLE: next = LOAD;
      LOAD: next = DONE;
      DONE: next = DONE;
      default: next = IDLE;
    endcase
  end
 
  always @(posedge clk) begin           // the register: latch next state
    if (rst) state <= IDLE;             // synchronous reset: only acts on an edge
    else     state <= next;
  end
 
  assign ready = (state == DONE);       // λ: output logic (combinational)
endmodule
  • = the always @(*) case → next-state combinational function.
  • = the assign ready = ... → output combinational function.
  • reg ≠ hardware register. In Verilog, reg merely means "a variable that may be assigned inside a procedural block." Whether it becomes flip-flops depends on how it is assigned: state is written inside @(posedge clk), so it synthesizes to 2 flip-flops; next is written inside @(*) and fully re-computed every case, so it synthesizes to pure combinational logic (a mux), no flip-flops. Only state stores anything.
  • rst here is a synchronous reset: it is tested inside @(posedge clk), so it only takes effect on a rising edge (feeding the D input), exactly like ordinary logic. An asynchronous reset would instead appear in the sensitivity list, e.g. always @(posedge clk or posedge rst), and act the instant rst rises regardless of the clock.

L5 — Mastery

Exercise 5.1

You are handed a design that fails setup at the target 1.0 GHz ( ns). Measured on the critical path: ns, ns, ns. (a) By how much does it violate (the slack)? (b) If you pipeline the combinational cloud into two equal halves (register in the middle), what is the new critical-path , the new , and does it now meet 1.0 GHz?

Recall Solution 5.1

(a) Required arrival budget is ns; actual path needs ns. Negative slack ⇒ fails by 0.35 ns. (b) Split ns into two equal halves → each stage ns. Since ns ns, it now meets 1.0 GHz with slack ns to spare. (See Static Timing Analysis for how tools report slack.)

Exercise 5.2

Two registers are clocked by different, unrelated clocks (a clock-domain crossing). Explain why the timing equations on this page do not apply directly, and what mechanism you must add.

Recall Solution 5.2

Our setup/hold equations assume one clock: R1 launches and R2 captures relative to the same periodic edge, so the phase relationship is fixed and is well-defined. Across two unrelated clocks, the launching edge and capturing edge can land arbitrarily close — there is no fixed between them. A signal can be sampled while it is still changing, driving the flip-flop into a metastable state (output hovering between 0 and 1 for an unbounded time). What you must add: a synchronizer — typically two (or more) flip-flops in series in the destination clock domain. The first may go metastable but is given a full cycle to resolve before the second samples it, making the probability of failure vanishingly small. See Clock domains and metastability. Key point: you cannot fix this by tweaking or — the single-clock model simply does not describe two independent clocks.


Recall One-line self-test

Fastest clock a single-clock path allows is set by which sum? ::: — the critical (slowest) path. Which timing constraint has no in it, so a slower clock cannot fix it? ::: The hold constraint, . What is slack? ::: — leftover time in the period; negative means the path violates timing.