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
      • The timing-closure loop in practice
      • ECO levers: sizing and buffering
      • When an RTL change is the right call
      • Senior closure checklist
    • RTL-to-Implementation Closure
    • DFT-Ready RTL
    • Capstone: Resilient Streaming Peripheral
    • Principal Design Review
    • Senior RTL Interview Questions & Model Answers
  • Glossary and Notation
Loading lesson

‹STA and ECO Hub
  1. Topics
  2. RTL Design
  3. Senior & Interview
  4. STA and ECO Hub
  5. When an RTL change is the right call

Part 9 · Senior · Senior

When an RTL change is the right call

Split a structural timing path across a pipeline stage and carry its select with it.

On this page

    Why this matters

    Repeated ECOs on a structural violation get fragile: too many logic levels, impossible fanout or heavy same-cycle compute. A pipeline cut then costs a cycle, and cutting the data without its select scrambles every answer.

    After this lesson you can: decide when to stop ECOing and cut the path, align select and valid with the data, and update the latency contract.

    When ECOs stop working

    If violations are structural, repeated ECOs become fragile. Too many logic levels, impossible fanout, and same-cycle heavy compute all qualify.

    That is when an RTL or micro-architecture change is justified. The usual cut is a pipeline stage across the deep cone.

    Splitting the path across a register

    The listing registers complete branch results and the select before the final mux. Multiply plus both additions remain before the registers; only selection moves after them. This can help a mux-dominated boundary, but it does not split arithmetic depth or promise a balanced path.

    Before the cut, multiply, adds and the select mux share one path. After it, sum0, sum1 and sel_q register in front of the mux: the arithmetic depth is unchanged and only the mux moves into the next cycle.

    Read the two panels top to bottom. The shaded boxes with a clock notch are the new registers.

    • sel_q is registered with the sums, so the select still matches its data.

    • The left bracket is the same length in both panels: the multiply and adds are not split.

    • The right bracket is the only new stage: one more cycle of latency.

    eco_before.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
    `timescale 1ns/1ps
    // Before: long same-cycle multiply-add and mux chain
    module eco_before (
      input  logic [3:0] a, b, c, d, e, f, g, h,
      input  logic       sel,
      output logic [7:0] y
    );
      always_comb begin
        if (sel) y = a * b + c + d;
        else     y = e * f + g + h;
      end
    endmodule
    
    // After: register complete branches before selection; arithmetic is unsplit
    module eco_after (
      input  logic       clk, rst_n,
      input  logic [3:0] a, b, c, d, e, f, g, h,
      input  logic       sel,
      output logic [7:0] y
    );
      logic [7:0] sum0 = 8'h00, sum1 = 8'h00;
      logic sel_q = 1'b0;
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
          sum0 <= 8'h00;
          sum1 <= 8'h00;
          sel_q <= 1'b0;
        end else begin
          sum0 <= a * b + c + d;
          sum1 <= e * f + g + h;
          sel_q <= sel;
        end
      end
      assign y = sel_q ? sum0 : sum1;
    endmodule

    Throughput remains one result per cycle for an always-accepting same-clock interface. Compared with the combinational branch output, availability moves to after the next capture edge. Timing gain is hypothetical until mapped/routed reports show that moving the mux helps; an arithmetic-dominated path may instead require registering the product and aligning addends/select for a later add stage.

    Latency changes the contract

    The waveform uses the same cut with constant sums, so only the select moves. Each y_o answers the previous slot's sel.

    • Slot 0: reset holds sel at 0 and y_o at 00.

    • Slot 1: sel rises to 1 while y_o shows B2, the answer to slot 0's sel.

    • Slot 2: sel falls to 0 while y_o shows A1, the answer to slot 1's sel.

    • Slot 3: sel rises to 1 while y_o shows B2, the answer to slot 2's sel.

    • Slot 4: sel falls to 0 while y_o shows A1, the answer to slot 3's sel.

    The select is delayed with the data on purpose. Pairing this cycle's select with last cycle's sums scrambles the answers on every select change.

    Use an explicit convention: inputs launch just after E0, branch registers capture at E1, y settles after E1, and a downstream flop consumes at E2. Falling-edge stimulus is also valid when the checker verifies output hold before capture as well as the post-update value. The constant-sum waveform illustrates select alignment only; the finite bench below also varies arithmetic and tests hold between edges.

    Common mistakes

    Common pitfall

    Cutting the data path but not its select or valid. Simulation with a steady select hides the mix-up until system test, where it looks like random corruption.

    Interview

    “When do you stop ECOing and cut the path, and what does the cut cost?”

    • Escalates when report-based local or shared gate repairs cannot robustly meet the budget.

    • Costs one cycle of latency on that path.

    • Forces a shift of valid bits and downstream selects.

    Check yourself The pipelined output answers the previous cycle's inputs. Which surrounding logic must change with the cut?

    Align forward valid, tags and selects with data, and update the consumer latency contract. This example always accepts work and has no READY. For stalls, use an elastic stage with storage and coordinated enables; never just delay READY, since work accepted before backpressure arrives must have reserved capacity. See elastic stages.

    Check yourself After this change, simulation matches but STA still fails into the new registers. What does that indicate?

    The complete multiply-plus-two-add cone is still before the registers. Diagnose its mapped arcs and budget; consider an actual arithmetic split with aligned addends and select. Registering branch results only moved the final mux.

    Testbench

    This finite temporal regression checks reset, output hold before capture, independently varied select/arithmetic, captured values and reset cancellation. A combinational replacement must fail the hold checks whenever the selected result changes.

    eco_before.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
    `timescale 1ns/1ps
    // Before: long same-cycle multiply-add and mux chain
    module eco_before (
      input  logic [3:0] a, b, c, d, e, f, g, h,
      input  logic       sel,
      output logic [7:0] y
    );
      always_comb begin
        if (sel) y = a * b + c + d;
        else     y = e * f + g + h;
      end
    endmodule
    
    // After: register complete branches before selection; arithmetic is unsplit
    module eco_after (
      input  logic       clk, rst_n,
      input  logic [3:0] a, b, c, d, e, f, g, h,
      input  logic       sel,
      output logic [7:0] y
    );
      logic [7:0] sum0 = 8'h00, sum1 = 8'h00;
      logic sel_q = 1'b0;
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
          sum0 <= 8'h00;
          sum1 <= 8'h00;
          sel_q <= 1'b0;
        end else begin
          sum0 <= a * b + c + d;
          sum1 <= e * f + g + h;
          sel_q <= sel;
        end
      end
      assign y = sel_q ? sum0 : sum1;
    endmodule
    

    Remember

    • Escalate to RTL when local or shared gate repairs cannot robustly meet the budget.

    • The cut costs one cycle of latency on that path; the consumer must expect data one cycle later.

    • Delay the select and valid with the data; a steady select in simulation hides the mix-up.

    How this was checked

    Finite temporal regression, not formal equivalence. Run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It checks reset, output hold before capture, independently varied select and arithmetic, captured values and reset cancellation. A combinational replacement must fail the hold checks whenever the selected result changes.

    Keep going

    • Practice: Pipelined arbiter for timing closure

    • Interview: run a mock interview on this topic

    Related topics

    • ECO levers: sizing and buffering

    • Senior closure checklist

    Previous

    293 / 350

    Next: Senior closure checklist

    Up next

    Up nextSenior closure checklist

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The timing-closure loop in practice
    clksely_o0b2a1b2a1
    A pipelined select answering one cycle later