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

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
    • Low-Power RTL Hub
    • DFT and Scan Hub
    • Physical Awareness Hub
    • Waveform Debug Hub
    • STA and ECO Hub
    • RTL-to-Implementation Closure
    • DFT-Ready RTL
    • Capstone: Resilient Streaming Peripheral
    • Principal Design Review
    • Senior RTL Interview Questions & Model Answers
      • Interview: Combinational and Arithmetic
        • The latch inference trap
        • Signed arithmetic and width truncation
        • Parameterized RTL and carry-chain guards
        • Glitches on enables and combinational hazards
      • Interview: Sequential and Pipelines
      • Interview: FSM and Control
      • Interview: Timing and STA
      • Interview: CDC and Reset
      • Interview: Memories and Buses
      • Interview: Low-Power Design
      • Interview: Debug and ECO
      • Interview: Coding and Whiteboard
  • Glossary and Notation
Loading lesson

‹Interview: Combinational and Arithmetic
  1. Topics
  2. RTL Design
  3. Senior & Interview
  4. Senior RTL Interview Questions & Model Answers
  5. Interview: Combinational and Arithmetic
  6. Parameterized RTL and carry-chain guards

Part 9 · Senior · Senior

Parameterized RTL and carry-chain guards

A parameterized adder with safe widths and an optional registered output, distinguished from internal pipelining.

On this page

    Why this matters

    Five 8-bit operands add up to 1275, which needs 11 bits, so a guessed margin truncates. The same adder must also meet setup at large N, where registering the output does not shorten the carry chain.

    After this lesson you can: size a parameterized adder with W plus $clog2(N) bits, separate output registration from internal pipelining, and reject illegal parameters.

    The question

    The interviewer asks for a parameterized N-input adder: what breaks when N is 1 or not a power of two, and what guards the long carry chain at timing closure.

    The question tests two skills at once. Parameters must stay correct at every legal configuration, and the arithmetic cone must still meet setup.

    Model answer

    For positive W and N, W plus $clog2(N) bits is a safe unsigned sum width, including N = 1 and non-powers of two; it is not always the minimum width for very small W. Accumulate into that full width so no configuration truncates.

    The registered output option creates a sampling boundary and adds latency; it does not split the addition cone before that register. If that cone misses its available budget, balance the add tree or insert registers inside it, aligning the other operands and valid bits with each stage. Confirm the mapped topology and timing report.

    N = 4. The loop as written builds a chain of three adders, and REG_OUT registers only after all of them. Balancing the tree and registering inside it leaves one adder per stage at the cost of one cycle.

    Read each panel top to bottom from the inputs. The shaded boxes are registers; the depth that matters is the number of adders between two of them.

    • Left: three adders sit between the input registers and REG_OUT. REG_OUT added latency but removed no depth.

    • Right: the tree has two levels, and a register rank between them cuts each stage to one adder.

    • The cost: one more cycle, so valid and any side-band signals need the same extra stage.

    Configuration

    Width and behaviour

    N = 1

    Sum is W bits; the loop is a single pass

    N a power of two

    No out-of-range case; $clog2(N) is exact

    N = 5, W = 8

    11-bit sum; holds 5 times 255 with margin

    Chain misses setup

    Balance or internally pipeline the cone; an output register alone does not reduce its depth

    Interview

    “Keep the full-width sum, distinguish output registration from internal pipelining, and locate the actual critical cone in STA.”

    Follow-ups

    • Why `$clog2(N)` and not a fixed margin? Five 8-bit operands reach 1275, which needs 11 bits. $clog2(5) is 3, so the margin tracks N instead of guessing.

    • What can fail for large N? Addition depth, input arrival budgets, fanout and routing can all matter. REG_OUT puts the entire cone before one output register; it does not cut that cone in half. A balanced tree or internal pipeline requires a separate implementation and latency-aware checks.

    • How are illegal configurations stopped? Require W >= 1 and N >= 1, and emit a fatal configuration diagnostic. Run illegal configurations as separate expected-failure elaboration/startup jobs. The finite legal matrix below does not prove every parameter value or a tool's handling of malformed port ranges.

    Common wrong answers

    “Keep the W-bit result; the testbench used small values” hides truncation behind weak stimulus. Full-scale vectors are the minimum.

    “Fix the chain at the gate level only” repeats layout pain on every ECO. A structural register slice is the RTL answer when latency allows.

    Common pitfall

    A $clog2(N) width looks safe but is only half the guard. Without a full-scale vector (every operand at maximum), truncation hides behind small stimulus.

    Check yourself W is 8 and N is 5. What is the maximum sum, and how many bits does it need?

    Five times 255 is 1275, which needs 11 bits. The testbench below checks exactly that vector on both paths.

    Check yourself The operands already come from registers, and the addition cone misses setup. Does REG_OUT=1 split that cone?

    No. All additions still lie between the input registers and the output register. Reduce combinational depth or pipeline inside the cone, then verify operand/valid alignment and timing.

    Solution and testbench

    The bench checks 65 vectors per configuration for (W,N) = (1,1), (3,4), (8,5). This covers singleton, power-of-two and non-power-of-two examples, with full-scale inputs on both output modes.

    para_add.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
    78
    79
    80
    81
    module para_add #(
      parameter int W = 8,
      parameter int N = 4,
      parameter int REG_OUT = 0
    ) (
      input  logic                clk,
      input  logic [(N*W)-1:0]    d,
      output logic [W+$clog2(N)-1:0] sum
    );
      localparam int SW = W + $clog2(N);
      if (W < 1 || N < 1) begin : g_bad_config
        initial $fatal(1, "para_add requires W >= 1 and N >= 1");
      end
      logic [SW-1:0] sum_comb, sum_r;
      always_comb begin
        sum_comb = '0;
        for (int i = 0; i < N; i++)
          sum_comb = sum_comb + d[i*W +: W];
      end
      always_ff @(posedge clk) sum_r <= sum_comb;
      assign sum = (REG_OUT != 0) ? sum_r : sum_comb;
    endmodule
    
    module para_add_case #(parameter int W = 8, N = 5) (output logic done = 0);
      timeunit 1ns; timeprecision 1ps;
      localparam int SW = W + $clog2(N);
      logic clk = 0;
      logic [(N*W)-1:0] d;
      logic [SW-1:0] sum_c, sum_r;
      para_add #(.W(W), .N(N), .REG_OUT(0)) dut_c (.clk(clk), .d(d), .sum(sum_c));
      para_add #(.W(W), .N(N), .REG_OUT(1)) dut_r (.clk(clk), .d(d), .sum(sum_r));
      always #5 clk = ~clk;
      int errors = 0;
      int v, acc, prev;
    
      initial begin
        d = '0; prev = 0;
        @(negedge clk);
        @(posedge clk); #1;
        for (int k = 0; k < 64; k++) begin
          acc = 0;
          for (int i = 0; i < N; i++) begin
            v = (k * 13 + i * 29 + 7) % (2**W);
            d[i*W +: W] = v[W-1:0];
            acc = acc + v;
          end
          #1;
          if (sum_c !== acc[SW-1:0]) errors++;
          if (sum_r !== prev[SW-1:0]) errors++;
          @(posedge clk); #1;
          if (sum_r !== acc[SW-1:0]) errors++;
          prev = acc;
        end
        acc = 0;
        for (int i = 0; i < N; i++) begin
          d[i*W +: W] = {W{1'b1}};
          acc = acc + (2**W - 1);
        end
        #1;
        if (sum_c !== acc[SW-1:0]) errors++;
        if (sum_r !== prev[SW-1:0]) errors++;
        @(posedge clk); #1;
        if (sum_r !== acc[SW-1:0]) errors++;
        if (errors != 0) $fatal(1, "FAIL: W=%0d N=%0d errors=%0d", W, N, errors);
        done = 1;
      end
    endmodule
    
    module tb_para_add;
      timeunit 1ns; timeprecision 1ps;
      wire done_single, done_power, done_nonpower;
      para_add_case #(1, 1) singleton_case (done_single);
      para_add_case #(3, 4) power_case (done_power);
      para_add_case #(8, 5) nonpower_case (done_nonpower);
      initial begin
        wait (done_single && done_power && done_nonpower);
        $display("PASS: three legal configurations, 65 vectors each, both output modes");
        $finish;
      end
      initial begin #10000; $fatal(1, "FAIL: parameter matrix timeout"); end
    endmodule

    Remember

    • W + $clog2(N) bits is a safe unsigned sum width for N = 1 and for non-powers of two.

    • REG_OUT puts the whole addition cone before one register; it does not cut the cone.

    • Test full-scale vectors, and run illegal configurations as separate expected-failure jobs.

    Rule of thumb: keep the full-width sum, and find the actual critical cone in the timing report.

    How this was checked

    Bench run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It checks 65 vectors per configuration for (W,N) = (1,1), (3,4), (8,5). This is finite evidence, not proof of the entire legal parameter range.

    Keep going

    • Interview: run a mock interview on this topic

    Related topics

    • Parameterized mux

    • Ripple-carry and carry-lookahead concept

    Previous

    315 / 350

    Next: Glitches on enables and combinational hazards

    Up next

    Up nextGlitches on enables and combinational hazards

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The latch inference trap