After placement, wire lengths are known well enough to compute real loads and delays. Some nets now break the electrical rules of the library: a driver sees more capacitance than it may drive, or its output rises and falls too slowly. Some paths miss timing. Design repair fixes both by changing the netlist: it inserts buffers, resizes cells and swaps pins. This article shows OpenROAD's two repair commands, repair_design and repair_timing, at work on a high-fanout enable net and on the 16x16 multiplier at a clock it cannot meet.
8 min read | Intermediate
What You'll Learn
- Explain max slew, max capacitance and max fanout limits
- Read a
report_check_typesviolation report - Describe the moves of
repair_designandrepair_timing - Read the repair tables in the OpenROAD log
Electrical Rules
A standard cell library characterizes every cell only within a range of conditions. Outside it, the delay tables have no data and the cell may not work reliably. The limits come from the Liberty file:
- Max transition (slew): the slowest rise or fall time allowed at any pin. In the sky130 hd typical library it is 1.5 ns.
- Max capacitance: the largest load an output pin may drive. It depends on the cell and its drive strength: 0.16 pF for the Q output of a
dfxtp_1flip-flop. - Max fanout: the number of loads a pin may drive. Libraries and designs can set it; it is a rule of thumb rather than an electrical limit.
These are design rule constraints. They are checked before timing, because delays computed outside the characterized range are not trustworthy.
A Net With 64 Loads
A small test design registers an enable signal and uses it to enable 64 flip-flops:
module fanout64r (
input clk,
input en,
input [63:0] d,
output reg [63:0] q
);
reg en_q;
always @(posedge clk) begin
en_q <= en;
end
always @(posedge clk) begin
if (en_q)
q <= d;
end
endmodule
Synthesis maps the 64 enabled flip-flops to edfxtp_1 cells, so one dfxtp_1 drives all 64 DE pins. After global placement, before any repair:
report_check_types -max_slew -max_capacitance -max_fanout -violators max slew Pin Limit Slew Slack ------------------------------------------------------------ _43_/Q 1.50 2.27 -0.77 (VIOLATED) _45_/DE 1.50 2.27 -0.77 (VIOLATED) ... max capacitance Pin Limit Cap Slack ------------------------------------------------------------ _43_/Q 0.16 0.25 -0.09 (VIOLATED)
The net carries 0.25 pF: 0.20-0.22 pF of pin capacitance from the 64 DE inputs and 0.03 pF of wire. That is too much for a size-1 flip-flop, and its output edge takes 2.27 ns. All 65 pins on the net, the driver and every load, violate the slew limit.
repair_design
repair_design fixes slew, capacitance, fanout and long-wire violations. The lab's flow runs it right after global placement:
[INFO RSZ-0034] Found 1 slew violations. [INFO RSZ-0039] Resized 1 instances. [INFO RSZ-0038] Inserted 1 buffers in 1 nets.
It made two changes. It upsized the driver from dfxtp_1 to dfxtp_2, and it split the loads with a large buffer, a buf_12 named load_slew1: the flip-flop now drives 30 DE pins and the buffer, and the buffer drives the other 34. The net report after repair shows half the load on the original net:
Net en_q Total capacitance: 0.12-0.12 Number of loads: 31
The second check finds no violations. Repair counts the problem per net, not per pin: one net, 65 violating pins, fixed with one buffer and one resize.
Adding set_max_fanout 16 [current_design] before repair_design gave the same result, one buffer with 30 and 34 loads per net. The reason is in the library, and the log warns about it when the Liberty file is read:
[WARNING STA-1171] .../sky130_fd_sc_hd__tt_025C_1v80.lib line 23, default_fanout_load is 0.0.
The timer does not count load pins directly. It adds up the fanout_load of each load pin, and the sky130 Liberty files give every pin a fanout load of 0. With a fanout limit of 16, report_check_types -max_fanout reports a fanout of 0 on every net, including the one with 64 loads, so the limit can never be violated. In sky130 flows, the slew and capacitance limits are what make repair_design split large nets. A fanout limit only works with a library that defines fanout loads.
Quick Check
Q: Why does every load pin on the overloaded net report the same slew violation as the driver?
Show Answer
The slow edge is created by the driver charging the whole net. It arrives at every load pin almost unchanged, because the wire resistance is small. Fixing the driver side fixes all the pins at once.
Input Ports Are Different
An earlier version of the test design used the en input port directly to drive the 64 flip-flops. repair_design found nothing to repair. Without constraints, an input port is an ideal driver: its edges are instant and it can drive any load, so the net never breaks a slew or capacitance limit. The real driver sits outside the block. Constraints such as set_driving_cell or set_input_transition on the port describe it, and buffer_ports -inputs inserts a buffer behind every input so the block always has a real driver of its own.
repair_timing
repair_timing -setup works on paths that miss timing. The lab's flow runs it after clock tree synthesis, with the clock propagated, when the clock latencies are real. The multiplier at a 6 ns clock:
[INFO RSZ-0094] Found 18 endpoints with setup violations.
Iter | Removed | Resized | Inserted | Cloned | Pin | Area | WNS | StTNS | Viol
| Buffers | Gates | Buffers | Gates | Swaps | | | | Endpts
0* | 0 | 0 | 0 | 0 | 0 | +0.0% | -3.859 | -86.0 | 18
final | 0 | 95 | 67 | 0 | 52 | +7.7% | -1.018 | -26.1 | 8
[INFO RSZ-0045] Inserted 67 buffers, 8 to split loads.
[INFO RSZ-0051] Resized 95 instances: 95 up, 0 up match, 0 down, 0 VT
[INFO RSZ-0043] Swapped pins on 52 instances.
[WARNING RSZ-0062] Unable to repair all setup violations.
The moves, in the order the log lists them (RSZ-0100):
- Unbuffer: remove a buffer on a critical path when it adds more delay than it saves.
- Size up: replace a gate with a stronger version of the same function. 95 gates were upsized.
- Swap pins: connect the late signal to the faster input of a gate with equivalent inputs, for example the A and B inputs of a NAND. 52 swaps.
- Buffer: insert a buffer to isolate a critical path from heavy non-critical loads. 67 buffers, 8 of them to split loads.
- Clone: duplicate a gate so that each copy drives part of the loads. None here.
The worst slack improved from -3.86 to -1.02 ns, and 10 of the 18 failing endpoints were fixed, for 7.7 % more cell area. The remaining paths are too long in logic for 6 ns, which repair cannot change: the warning RSZ-0062 says so.
Quick Check
Q: Both commands insert buffers. What is the difference in what they look at?
Show Answer
repair_design looks at electrical rules on each net (slew, capacitance, fanout, wire length) regardless of timing. repair_timing looks at timing paths with negative slack and changes cells only where it improves the slack.
Running It in ChipVerify Lab
Run Place and Route on the multiplier with a 6 ns clock and find the two repair tables: the repair_design table right after global placement (for the multiplier, nothing to repair) and the repair_timing table after CTS. Note the number of resized gates and inserted buffers, and the worst slack before and after.
Common Mistakes
Mistake #1: Ignoring slew and capacitance violations because timing passes
The delays of an overloaded net are computed outside the library's tables, so a passing timing report on such a net is not reliable. Fix the design rule violations first.
Mistake #2: Expecting repair to close any timing gap
Sizing and buffering recovered 2.8 ns on the multiplier, not the 3.9 ns it needed. Large gaps need changes in synthesis, the architecture or the clock period.
Mistake #3: Forgetting to legalize after repair
Repair inserts and resizes cells at ideal positions. A detailed placement must follow, as it does in the lab's flow.
Practice Exercise
Challenge: Load per Pin
The enable net had 0.20-0.22 pF of pin capacitance from 64 DE inputs. What is the capacitance of one DE pin? How many such pins can a dfxtp_1 drive within its 0.16 pF limit, ignoring the wire?
Hint
Divide the pin capacitance by the number of pins, then divide the limit by the result.
Solution
About 0.21 / 64 = 3.3 fF per DE pin. 0.16 pF / 3.3 fF is about 48 pins, before any wire capacitance. With the wire, and to keep the slew well inside 1.5 ns, the practical number is lower, which is why repair split the 64 loads into 30 and 34.
Open the ready-made example in the lab, synthesize it and run Place and Route.
Summary
- Max slew, max capacitance and max fanout keep every cell inside its characterized range.
repair_designfixed a 64-load net (2.27 ns slew, 0.25 pF) with one upsized driver and one buffer.- An unconstrained input port is an ideal driver; describe the real driver with constraints or buffer the ports.
repair_timingsizes up gates, swaps pins, buffers and clones; on the multiplier at 6 ns it recovered 2.3 ns of 3 ns.- Always legalize after repair.