Level 3 — ProductionHDL & Digital Design Flow

HDL & Digital Design Flow

45 minutes60 marksprintable — key stays hidden on paper

Level 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time limit: 45 minutes Total marks: 60

Instructions: Write Verilog from memory. Show timing derivations fully. Explanations must state the why, not just the what.


Question 1 — Combinational + Sequential HDL from memory (12 marks)

(a) Write a synthesizable Verilog module alu4 for a 4-bit ALU with inputs a[3:0], b[3:0], op[1:0] and output y[3:0]. Ops: 00=add, 01=subtract, 10=bitwise AND, 11=bitwise OR. Use a combinational always block. (6)

(b) Write a Verilog module dff_ar implementing a positive-edge-triggered D flip-flop with asynchronous active-low reset rst_n. (4)

(c) State the two golden rules for choosing between blocking (=) and non-blocking (<=) assignments in combinational vs sequential always blocks, and say why each rule prevents a specific bug. (2)


Question 2 — Blocking vs Non-blocking derivation (10 marks)

Given the two code fragments below, both inside always @(posedge clk) with initial a=1, b=2, c=3:

Fragment X (blocking):

a = b;
b = c;
c = a;

Fragment Y (non-blocking):

a <= b;
b <= c;
c <= a;

(a) Give the values of a, b, c after one clock edge for each fragment. Show your reasoning. (6)

(b) Explain why the two results differ in terms of the Verilog scheduler (evaluation phase vs update phase). (4)


Question 3 — Testbench from scratch (10 marks)

Write a self-checking Verilog testbench for the dff_ar module from Q1(b). It must:

  • generate a 10 ns period clock,
  • apply an asynchronous reset pulse then release it,
  • drive at least 3 input vectors on d,
  • use $display/$error (or equivalent) to report a mismatch against an expected value,
  • terminate with $finish.

(10)


Question 4 — Static Timing Analysis derivation (12 marks)

A register-to-register path has: launch clock-to-Q delay tcq=0.4t_{cq}=0.4 ns, combinational logic delay tlogic=2.1t_{logic}=2.1 ns, capture setup time tsu=0.3t_{su}=0.3 ns, capture hold time th=0.15t_{h}=0.15 ns, and clock skew tskew=+0.2t_{skew}=+0.2 ns (capture clock arrives later than launch). Clock period T=3.0T=3.0 ns.

(a) Write the setup-check inequality and compute the setup slack. Pass or fail? (5)

(b) Write the hold-check inequality and compute the hold slack (assume the fast path delay equals tcq+tlogic,mint_{cq}+t_{logic,min} with tlogic,min=0.5t_{logic,min}=0.5 ns). Pass or fail? (4)

(c) The design fails setup at a higher clock frequency. Give the maximum clock frequency (in MHz) this path can run at, and explain why skew helps or hurts here. (3)


Question 5 — RTL, Synthesis & Critical Path (10 marks)

(a) Explain what "RTL" means and describe the two-phase transformation a synthesis tool performs to get from RTL to a gate-level netlist. (4)

(b) Given a datapath with these gate delays along four parallel paths to the same capture register: Path A: 1.2 ns, Path B: 2.8 ns, Path C: 2.6 ns, Path D: 0.9 ns. Identify the critical path and explain why it, not the others, determines the clock period. (3)

(c) State two distinct techniques to shorten a critical path, and explain the mechanism of each. (3)


Question 6 — FPGA vs ASIC flow (6 marks)

Compare FPGA and ASIC design flows across three axes: (i) the physical realization step, (ii) non-recurring engineering cost / turnaround, and (iii) how timing closure is achieved. One sentence of justification per axis. (6)

Answer keyMark scheme & solutions

Question 1 (12)

(a) ALU (6) — 2 for correct port/module header, 2 for combinational always @(*) with blocking =, 2 for correct 4 ops.

module alu4(
  input  [3:0] a, b,
  input  [1:0] op,
  output reg [3:0] y
);
  always @(*) begin
    case (op)
      2'b00: y = a + b;
      2'b01: y = a - b;
      2'b10: y = a & b;
      2'b11: y = a | b;
      default: y = 4'b0000;
    endcase
  end
endmodule

Why: always @(*) + full case (default) → no inferred latch; blocking = models combinational data flow within the block.

(b) DFF async reset (4) — 2 for sensitivity list including negedge rst_n, 2 for reset-priority + non-blocking.

module dff_ar(
  input clk, rst_n, d,
  output reg q
);
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) q <= 1'b0;   // async: reset in sensitivity list
    else        q <= d;
  end
endmodule

Why: negedge rst_n in the list makes reset asynchronous; checking !rst_n first gives reset priority; <= for sequential logic.

(c) Golden rules (2) — 1 each:

  • Combinational blocks → use blocking =. Why: models immediate ordered evaluation; avoids stale intermediate values / simulation-synthesis mismatch.
  • Sequential (clocked) blocks → use non-blocking <=. Why: all RHS sampled before any LHS updates → models parallel register capture, prevents race conditions on shared signals across always blocks.

Question 2 (10)

(a) (6) — 3 marks each fragment.

Fragment X (blocking, sequential execution, values update immediately):

  • a = b → a=2
  • b = c → b=3
  • c = a → c=2 (a already updated to 2)
  • Result: a=2, b=3, c=2 (3)

Fragment Y (non-blocking, all RHS use old values):

  • RHS evaluated: a←2, b←3, c←1 (old a)
  • Result: a=2, b=3, c=1 (3)

(b) (4) — 2 for evaluation/update phase distinction, 2 for applying to result. Non-blocking assignments are processed in two phases within a time step: in the evaluation (active) phase all RHS expressions are computed using current signal values; in the update (NBA) phase the LHS are written. Thus c <= a sees the original a=1. Blocking assignments evaluate and update in-line immediately, so c = a sees the already-modified a=2. This is why non-blocking correctly models simultaneous register clocking.


Question 3 (10)

Marks: clock gen (2), reset pulse (2), ≥3 vectors (2), self-check compare (2), $finish (2).

module tb_dff_ar;
  reg clk, rst_n, d;
  wire q;
  reg expected;
 
  dff_ar dut(.clk(clk), .rst_n(rst_n), .d(d), .q(q));
 
  // clock: 10 ns period
  initial clk = 0;
  always #5 clk = ~clk;
 
  task check;
    begin
      if (q !== expected)
        $display("FAIL: t=%0t d=%b q=%b exp=%b", $time, d, q, expected);
      else
        $display("PASS: t=%0t q=%b", $time, q);
    end
  endtask
 
  initial begin
    rst_n = 0; d = 0; expected = 0;       // async reset asserted
    #12 rst_n = 1;                        // release reset
    // vector 1
    d = 1; @(posedge clk); #1 expected = 1; check;
    // vector 2
    d = 0; @(posedge clk); #1 expected = 0; check;
    // vector 3
    d = 1; @(posedge clk); #1 expected = 1; check;
    #10 $finish;
  end
endmodule

Why: !== catches X/Z; sampling #1 after the edge lets the non-blocking update settle before comparison; reset released off a clock edge to avoid recovery issues.


Question 4 (12)

(a) Setup (5) — inequality (2), computation (2), verdict (1). Setup check (skew added to available time since capture clock is later): tcq+tlogic+tsuT+tskewt_{cq}+t_{logic}+t_{su} \le T + t_{skew} Required data arrival = 0.4+2.1+0.3=2.80.4+2.1+0.3 = 2.8 ns. Available = T+tskew=3.0+0.2=3.2T + t_{skew} = 3.0+0.2 = 3.2 ns. Setup slack =(T+tskew)(tcq+tlogic+tsu)=3.22.8=+0.4= (T+t_{skew}) - (t_{cq}+t_{logic}+t_{su}) = 3.2-2.8 = \mathbf{+0.4} ns → PASS.

(b) Hold (4) — inequality (2), computation (1), verdict (1). Hold check: tcq+tlogic,minth+tskewt_{cq}+t_{logic,min} \ge t_h + t_{skew} LHS =0.4+0.5=0.9= 0.4+0.5 = 0.9 ns. RHS =0.15+0.2=0.35= 0.15+0.2 = 0.35 ns. Hold slack =(tcq+tlogic,min)(th+tskew)=0.90.35=+0.55= (t_{cq}+t_{logic,min}) - (t_h+t_{skew}) = 0.9-0.35 = \mathbf{+0.55} ns → PASS.

(c) Max frequency (3) — 1.5 for value, 1.5 for skew explanation. At the setup limit slack=0: Tmin+tskew=tcq+tlogic+tsuT_{min}+t_{skew} = t_{cq}+t_{logic}+t_{su} Tmin=2.80.2=2.6T_{min} = 2.8 - 0.2 = 2.6 ns. fmax=1/2.6ns=384.6f_{max} = 1/2.6\text{ns} = 384.6 MHz. Why skew helps here: positive skew (capture clock later) adds to the setup-available time, letting the design run faster — but the same positive skew eats into hold margin, so excessive skew endangers hold checks.


Question 5 (10)

(a) (4) — 2 RTL definition, 2 synthesis phases. RTL = Register-Transfer Level: describes design as data transfers between registers each clock, plus the combinational logic between them (abstracting away individual gates). Synthesis: (1) Elaboration/inference + technology-independent optimization — parse HDL, infer registers/logic, build a Boolean/generic gate representation, minimize. (2) Technology mapping — map generic logic onto the target library's actual gates (cells) and optimize for area/timing/power → gate-level netlist.

(b) (3) — 1 identify, 2 explanation. Critical path = Path B (2.8 ns) — the longest delay. Why: the clock period must exceed the slowest path's arrival time (plus setup) so data is stable before every capture edge; shorter paths already meet timing, so the maximum determines fmaxf_{max}.

(c) (3) — 1.5 each.

  • Logic restructuring / flattening — reduce logic depth (fewer gate levels) e.g. tree instead of chain adder, so signal traverses less delay.
  • Pipelining — insert a register mid-path, splitting one long combinational path into two shorter ones, cutting the per-stage delay (at cost of latency). (Also acceptable: gate sizing/buffering, retiming.)

Question 6 (6)

2 marks per axis (correct contrast + justification).

Axis FPGA ASIC
(i) Physical realization Configure pre-fab LUTs/CLBs + routing via bitstream Custom fabricated masks / transistors laid out
(ii) NRE / turnaround Low/near-zero NRE, minutes–hours reprogram Very high NRE (mask sets), weeks–months per spin
(iii) Timing closure Bounded by fixed fabric; achieved via place-&-route + constraints on existing cells Full control of cell sizing/layout → higher achievable clock but must be right first time

Justification examples: FPGA reprogrammability makes iteration cheap but caps peak speed; ASIC's custom silicon yields best speed/power/area at large volume but a bug costs a full re-spin.


[
  {"claim":"Setup slack = 0.4 ns","code":"tcq=0.4;tlogic=2.1;tsu=0.3;T=3.0;skew=0.2;slack=(T+skew)-(tcq+tlogic+tsu);result=(abs(slack-0.4)<1e-9)"},
  {"claim":"Hold slack = 0.55 ns","code":"tcq=0.4;tlmin=0.5;th=0.15;skew=0.2;slack=(tcq+tlmin)-(th+skew);result=(abs(slack-0.55)<1e-9)"},
  {"claim":"Tmin = 2.6 ns and fmax approx 384.6 MHz","code":"tcq=0.4;tlogic=2.1;tsu=0.3;skew=0.2;Tmin=(tcq+tlogic+tsu)-skew;fmax=1/(Tmin*1e-9);result=(abs(Tmin-2.6)<1e-9 and abs(fmax-384615384.6)<1e2)"},
  {"claim":"Blocking fragment X gives c=2, non-blocking Y gives c=1","code":"a,b,c=1,2,3;a=b;b=c;c=a;cx=c;a2,b2,c2=1,2,3;na=b2;nb=c2;nc=a2;result=(cx==2 and nc==1)"}
]