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.
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.
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.
`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;
endmoduleThroughput 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.
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.
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.
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.
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.
`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
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.