Level 5 — MasteryHDL & Digital Design Flow

HDL & Digital Design Flow

90 minutes60 marksprintable — key stays hidden on paper

Level 5 — Mastery (cross-domain: coding + timing math + digital design) Time limit: 90 minutes Total marks: 60

Instructions: Answer all three questions. Verilog code must be synthesizable unless a testbench is explicitly requested. Show timing arithmetic in full. Use $...$ conventions for math where helpful.


Question 1 — RTL Design, Blocking vs Non-blocking, and Synthesis (22 marks)

You are to design a synchronous 4-bit accumulator with saturation and parity output. Specification:

  • Inputs: clk, rst_n (active-low async reset), en, din[3:0].
  • Output: acc[3:0], ovf (sticky saturation flag), par (even parity of acc).
  • On each rising clock edge with en=1, compute acc + din. If the true sum ≥ 16 (would overflow 4 bits), clamp acc to 4'b1111 and set ovf=1 (sticky until reset). Otherwise store the sum.
  • par is combinational: XOR-reduction of acc.

(a) Write synthesizable Verilog for this module. Use correct reset style, correct assignment type (blocking vs non-blocking) in each block, and separate the combinational par logic. (10)

(b) A colleague writes the accumulator update as:

always @(posedge clk) begin
    sum = acc + din;      // 5-bit temp
    acc = sum[3:0];
end

inside a single always block that also drives another register from acc. Explain precisely what functional bug the use of blocking assignments introduces here versus non-blocking, and state the RTL rule for register inference. (6)

(c) After synthesis, the tool reports your saturating adder maps to a 5-bit carry-ripple adder plus a comparator. Sketch (in words + a gate/logic count estimate) the combinational cone that feeds acc, and identify which signal path is likely the critical path into the acc register. (6)


Question 2 — Static Timing Analysis (20 marks)

A register-to-register path in a synchronous design has these parameters:

Parameter Value
Clock period target TT to be found
Launch clock-to-Q, tcqt_{cq} 0.30 ns
Combinational logic delay, tcombt_{comb} 3.10 ns
Setup time, tsut_{su} 0.25 ns
Hold time, tht_{h} 0.15 ns
Clock skew (capture − launch), tskewt_{skew} +0.20 ns
Clock jitter (uncertainty), tjitt_{jit} 0.10 ns

(a) Write the setup timing inequality including skew and jitter, then compute the minimum clock period TminT_{min} and the corresponding maximum frequency. (8)

(b) Write the hold timing inequality. Given the shortest combinational path from launch to capture is tcomb,min=0.20t_{comb,min}=0.20 ns, determine whether a hold violation exists (show the slack). If it violates, state one concrete fix. (7)

(c) The design is retargeted from an FPGA to an ASIC. Explain two reasons the same RTL typically achieves a higher fmaxf_{max} on the ASIC, referencing the physical delay model behind tcombt_{comb}. (5)


Question 3 — Testbench, Simulation & Critical Path Proof (18 marks)

(a) Write a self-checking Verilog testbench for the accumulator of Q1 that: generates a 10 ns clock, applies async reset, then drives at least three din values including one that forces saturation, and uses $error/$display to flag any mismatch against a reference model computed in the testbench. (10)

(b) Consider the ripple-carry critical path of an NN-bit adder where each full-adder carry stage has delay tct_c and the sum XOR has delay tst_s. Derive the worst-case propagation delay Tadder(N)T_{adder}(N) as a function of NN, and compute it for N=4N=4, tc=0.18t_c = 0.18 ns, ts=0.12t_s = 0.12 ns. State how a carry-lookahead structure changes the asymptotic delay order. (8)

Answer keyMark scheme & solutions

Question 1

(a) Synthesizable module (10 marks)

module sat_acc (
    input        clk, rst_n, en,
    input  [3:0] din,
    output reg [3:0] acc,
    output reg   ovf,
    output       par
);
    wire [4:0] sum = {1'b0, acc} + {1'b0, din};   // 5-bit true sum
 
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            acc <= 4'b0000;
            ovf <= 1'b0;
        end else if (en) begin
            if (sum >= 5'd16) begin
                acc <= 4'b1111;   // saturate/clamp
                ovf <= 1'b1;      // sticky
            end else begin
                acc <= sum[3:0];
            end
        end
    end
 
    assign par = ^acc;            // combinational even-parity XOR reduction
endmodule

Mark scheme:

  • Async active-low reset in sensitivity list + if(!rst_n) first: 2
  • Non-blocking (<=) for all sequential outputs: 2
  • Correct 5-bit sum / overflow detection (sum>=16): 2
  • Saturation clamp to 4'hF and sticky ovf (not cleared except reset): 2
  • par as separate combinational assign ^acc: 2 Why: sequential state must use non-blocking to model true register behaviour; parity is purely combinational so it belongs in assign, not the clocked block.

(b) Blocking-assignment bug (6 marks)

  • With blocking =, statements execute in order within the same delta cycle: sum and acc update immediately, so a second register that reads acc in the same block sees the new (already-updated) value instead of the old value — collapsing what should be two pipeline stages into one, or creating a race/wrong data. (3)
  • With non-blocking <=, all RHS are evaluated first, then updates commit at end of the time step, so every register samples the pre-edge value — correctly modelling parallel flip-flops. (2)
  • RTL rule: use non-blocking <= for sequential (clocked) logic, blocking = for combinational (always @*) logic. (1)

(c) Critical-path cone (6 marks)

  • Cone feeding acc: 5-bit ripple-carry adder (acc+din) → comparator sum>=16 (effectively sum[4] OR-detect since any value ≥16 sets bit4, so really just sum[4]) → 4×2:1 mux selecting between sum[3:0] and 1111. (3)
  • Gate estimate: ~5 full adders (≈5×5=25 gates), overflow test ≈1 gate (sum[4]), 4 muxes (≈4×3=12 gates) → ~40 gates. (1)
  • Critical path: carry chain of the 5-bit adder (LSB carry-in rippling to sum[4]), which then drives the mux-select — i.e. acc[0]/din[0] → carry ripple → sum[4] → mux → acc[3]. (2)

Question 2

(a) Setup analysis (8 marks)

Setup inequality (skew and jitter degrading the budget): tcq+tcomb+tsuT+tskewtjitt_{cq} + t_{comb} + t_{su} \le T + t_{skew} - t_{jit}

Rearranged: Tmin=tcq+tcomb+tsutskew+tjitT_{min} = t_{cq} + t_{comb} + t_{su} - t_{skew} + t_{jit} Tmin=0.30+3.10+0.250.20+0.10=3.55 nsT_{min} = 0.30 + 3.10 + 0.25 - 0.20 + 0.10 = 3.55\ \text{ns}

fmax=13.55 ns=281.7 MHzf_{max} = \frac{1}{3.55\text{ ns}} = 281.7\ \text{MHz}

Marks: inequality with correct sign of skew/jitter 3, arithmetic 3, frequency 2. Why: positive skew (capture later than launch) relaxes setup, jitter always tightens it.

(b) Hold analysis (7 marks)

Hold inequality: tcq+tcomb,minth+tskew+tjitt_{cq} + t_{comb,min} \ge t_h + t_{skew} + t_{jit}

Compute both sides:

  • LHS =0.30+0.20=0.50= 0.30 + 0.20 = 0.50 ns
  • RHS =0.15+0.20+0.10=0.45= 0.15 + 0.20 + 0.10 = 0.45 ns

Hold slack =LHSRHS=0.500.45=+0.05= \text{LHS} - \text{RHS} = 0.50 - 0.45 = +0.05 ns 0\ge 0no hold violation (passes, marginally). (5) Fix if it had failed: insert buffer/delay cells on the data path to increase tcomb,mint_{comb,min}, or reduce clock skew via clock-tree balancing. (2) Why: hold is independent of TT; positive skew hurts hold (opposite of setup), so skew is added to the required side.

(c) FPGA → ASIC fmaxf_{max} (5 marks)

  • Routing: FPGA logic goes through programmable interconnect (switch boxes, pass transistors) adding large RC delay; ASIC uses dedicated custom metal routing → smaller tcombt_{comb}. (2.5)
  • Logic mapping: FPGA implements logic in LUTs (fixed delay per lookup) whereas ASIC standard cells give optimally sized gates/transistors; tcombt_{comb} is the sum of intrinsic gate delay + interconnect RC, both lower on ASIC. (2.5)

Question 3

(a) Self-checking testbench (10 marks)

module tb_sat_acc;
    reg clk, rst_n, en;
    reg  [3:0] din;
    wire [3:0] acc;
    wire ovf, par;
    reg  [4:0] model_acc;   // reference (5-bit to see overflow)
    reg        model_ovf;
 
    sat_acc dut(.clk(clk), .rst_n(rst_n), .en(en),
                .din(din), .acc(acc), .ovf(ovf), .par(par));
 
    initial clk = 0;
    always #5 clk = ~clk;   // 10 ns period
 
    // reference model
    task ref_update;
        input [3:0] d;
        reg [4:0] s;
        begin
            s = model_acc[3:0] + d;
            if (s >= 16) begin model_acc = 5'd15; model_ovf = 1; end
            else            model_acc = s;
        end
    endtask
 
    task check;
        begin
            if (acc !== model_acc[3:0])
                $error("acc mismatch: dut=%0d exp=%0d", acc, model_acc[3:0]);
            if (ovf !== model_ovf)
                $error("ovf mismatch: dut=%b exp=%b", ovf, model_ovf);
            else $display("OK acc=%0d ovf=%b par=%b", acc, ovf, par);
        end
    endtask
 
    initial begin
        en=0; din=0; model_ovf=0; model_acc=0;
        rst_n=0; @(negedge clk); rst_n=1;  // async reset release
        en=1;
        din=4'd5;  ref_update(5); @(negedge clk); check;
        din=4'd7;  ref_update(7); @(negedge clk); check;
        din=4'd9;  ref_update(9); @(negedge clk); check; // forces saturation
        $finish;
    end
endmodule

Marks: clock gen 2, async reset apply/release 2, ≥3 stimuli incl. saturation case 2, reference model 2, self-check with $error 2.

(b) Ripple-carry delay derivation (8 marks)

The worst case propagates a carry from bit 0 through all NN carry stages, then the final sum XOR: Tadder(N)=Ntc+ts\boxed{T_{adder}(N) = N\,t_c + t_s}

For N=4N=4: T=4(0.18)+0.12=0.72+0.12=0.84 nsT = 4(0.18) + 0.12 = 0.72 + 0.12 = 0.84\ \text{ns}

Carry-lookahead reduces the carry generation to a tree, giving delay order O(logN)O(\log N) instead of O(N)O(N). (2 for order statement) Mark scheme: derivation/formula 3, N=4N=4 arithmetic 3, CLA order 2.

[
  {"claim":"Setup Tmin = 0.30+3.10+0.25-0.20+0.10 = 3.55 ns",
   "code":"Tmin = 0.30+3.10+0.25-0.20+0.10; result = abs(Tmin-3.55)<1e-9"},
  {"claim":"fmax = 1/3.55 ns approx 281.69 MHz",
   "code":"f = 1/(3.55e-9); result = abs(f-2.81690e8) < 1e5"},
  {"claim":"Hold slack = (0.30+0.20)-(0.15+0.20+0.10) = +0.05 ns (pass)",
   "code":"slack = (0.30+0.20)-(0.15+0.20+0.10); result = abs(slack-0.05)<1e-9 and slack>=0"},
  {"claim":"Ripple adder N=4: 4*0.18+0.12 = 0.84 ns",
   "code":"T = 4*0.18+0.12; result = abs(T-0.84)<1e-9"}
]