This is the last practical article of the tutorial. The UART transmitter of the previous articles fails at 3.4 ns, on the slow corner, with two violations: a setup violation of -0.3165 ns in the baud counter logic, and a removal violation of -0.1148 ns on the asynchronous reset. Here both are fixed with changes in the RTL, one at a time. After each change the design is run again at all three corners, so that you see what the change did and what it did not do.

11 min read | Intermediate

What You'll Learn

  • Close a setup violation by shortening the logic between two registers
  • Close a removal violation with a reset synchronizer, and constrain the external reset correctly
  • Check the result at all corners and confirm that the function did not change
  • Estimate the smallest clock period of a design from its worst slack

The Starting Point

The constraints are the 3.4 ns SDC of the previous article, and the results of the original design are:

CornerWorst setup slack (ns)Removal slack (ns)
ss-0.3165-0.1148
tt1.64770.2044
ff2.33140.2852

The worst setup path starts at a bit of the baud counter, goes through the compare cnt == 867 and ends at the shift register. Its five cells take 3.5677 ns, and the capture flop needs the data by 3.2513 ns.

Change 1: Shorten the Compare

The old counter is one 10-bit register that counts to 867. The compare that makes the tick looks at all 10 bits, and its result drives the logic of the shift register in the same clock cycle. There are two ideas, and the design uses both:

  • Split the counter. 868 is 28 x 31. A counter ca that counts 0 to 27, and a second counter cb that advances when ca wraps and counts 0 to 30, give one full turn every 28 x 31 = 868 clock cycles. Each counter has 5 bits, and each compare looks at only 5 bits.
  • Register the tick. Instead of computing the tick and using it in the same cycle, compute it one cycle early and store it in a flip-flop. The logic that moves the shift register then starts at a flip-flop output, with no compare in front of it.

The registered tick is high in the cycle where ca is 27 and cb is 30. It is computed in the cycle before, when ca is 26 and cb is 30:


reg [4:0] ca, cb;
reg       tick;                      // registered: high while ca == 27 and cb == 30
...
tick <= active && (ca == 5'd26) && (cb == 5'd30);
...
if (ca == 5'd27) begin
  ca <= 5'd0;
  cb <= (cb == 5'd30) ? 5'd0 : cb + 5'd1;
end else ca <= ca + 5'd1;

The data path of the old design is the first row in the diagram below, and the worst path of the new one the second row, again on the slow corner at 3.4 ns:

The new worst path has four cells (nor4bb, nor3, nor2 and a22o) and arrives at 3.0150 ns. Its capture flop has a larger setup time of 0.2926 ns, so the required time is 3.1074 ns. The slack is 3.1074 - 3.0150 = +0.0923 ns, a change of +0.4088 ns from the old value. The margin is small, but it is positive.

The Results After Change 1

CornerWorst setup slack (ns)Removal slack (ns)
ss+0.0923-0.1148
tt1.73650.2044
ff2.28180.2709

Setup is met at all the corners. The removal violation did not change, as expected: the reset was not touched. Look at the fast corner, too: the setup slack went down a little, from 2.3314 to 2.2818 ns. The change was made for the slow corner, and the extra register and the second counter do not give a gain everywhere. A fix has to be judged at every corner.

Change 2: Synchronize the Reset Release

The removal check fails because the external reset can be released at any time, and in the constraints it was given an input delay of 0.5 ns, which is shorter than the 0.6148 ns that the flip-flop needs at the slow corner. The cure is not to add delay but to release the reset from a flip-flop. Two flip-flops in a row make a reset synchronizer: the reset asserts at once when the port goes low, and it releases only on a clock edge:


reg rs1, rs2;
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin rs1 <= 1'b0; rs2 <= 1'b0; end
  else begin rs1 <= 1'b1; rs2 <= rs1; end
end
wire rst_s = rs2;                    // the reset used by the rest of the design
always @(posedge clk or negedge rst_s) begin
  ...                                // the same logic as before, with rst_s
end

When the port goes high, the first flop takes a 1 at the next clock edge, and the second flop one edge later. The reset of the design, rst_s, rises shortly after a clock edge, and has the rest of the clock period to settle before the next edge. A reset that changes only after the clock edge, with a delay that is the clock-to-Q of a flip-flop, can meet the removal time, because the clock-to-Q of the synchronizer flop is a real delay: 1.3632 ns at the slow corner.

Constrain the External Reset

The port rst_n now drives only the reset pins of the two synchronizer flops. It comes from outside, and it is not related to the clock. A timing check for it makes no sense: the removal check of the first flop against the clock would say that the reset must be released at some distance from the clock edge, and nobody can promise that. The right constraint is to tell STA that the port is not timed:


create_clock -name clk -period 3.4 [get_ports clk]
set_input_delay 0.5 -clock clk [get_ports {start data*}]
set_output_delay 0.5 -clock clk [get_ports {tx busy}]
set_false_path -from [get_ports rst_n]

The input delay of the reset is gone, and a false path starts at the port. check_setup -verbose still prints that rst_n is missing an input delay. This is expected here: the port has no timing check on purpose. The article about what STA cannot see explains why the safe release of an asynchronous reset is the job of the synchronizer and not of the static timing analysis, and the article about false paths covers the command.

Once the reset comes from a flip-flop, STA can check it. The path from the second synchronizer flop to the reset pins of the rest of the design is a normal recovery and removal check, and it passes at every corner:

CornerRecovery slack (ns)Removal slack (ns)
ss2.09110.4088
tt2.59560.3199
ff2.84680.2494

The reset flop drives about 25 reset pins, so its output has a load of 0.0816 pF and a slew of 1.1043 ns at the slow corner. The slack is large enough for that today. In a bigger design, a reset that fans out to thousands of flops needs a buffer tree, and this check is where its effect shows up.

Final Results

With both changes, every check passes at every corner. The worst slack of each type is:

CornerWorst setup (ns)Worst hold (ns)Hold endpoint
ss0.09230.4088reset removal
tt1.73650.3199reset removal
ff2.28180.2041_176_/D

The total negative slack is 0.00 at all three corners.

Did the Function Change?

STA does not know what the circuit does. A change in the RTL has to be checked in simulation, or with an equivalence check. For this UART, the two versions were simulated side by side with the same reset and the same start pulses, sending the data 0xA5 and then 0x3C, with a comparison of the outputs tx and busy in every clock cycle. There were no mismatches in 20,000 cycles. The transmitted frame also has the right timing: the output edges of the first frame are 868 clock cycles apart (cycles 18, 886, 1754, 2622, 3490), which is one bit time at 100 MHz and 115200 baud.

How Fast Can It Go Now?

For a path between registers, the slack changes by the same amount as the period, so the smallest period is the current period minus the worst slack. At the slow corner:

DesignWorst setup slack at 3.4 ns (ns)Smallest period (ns)
original-0.3165about 3.72
final+0.0923about 3.31

This is an estimate. The input delay and output delay were kept at 0.5 ns for both designs, and the worst path can change when the clock is faster. The change in the RTL took the design from about 269 MHz to about 302 MHz at the slow corner, a gain of about 12 percent.

The same difference shows at the typical corner, which does not need PRO. There the original design needs more than 1.7 ns (setup -0.0523 ns, with removal -0.0956 ns when the reset has an input delay of 0.2 ns), and the final design meets 1.7 ns with +0.0365 ns and fails at 1.6 ns with -0.0635 ns.

The Method in Short

  1. Write the SDC from the specification, and check that every port is constrained.
  2. Run all the corners, and list the failing checks and their groups.
  3. For each failing path, find why it is slow and choose a change that matches the cause.
  4. Make one change at a time, and run all corners again. A change can help one corner and cost another.
  5. Check the function after every change in the RTL.
  6. When all checks pass, estimate the margin and the smallest period.

Common Mistakes

Mistake #1: Fixing the removal violation by adding delay to the reset

A delay cell would pass the number at the corner you looked at, and break it at another. The release of the reset must come from a clock edge, and then the check is met by the clock-to-Q of a flop at every corner.

Mistake #2: Declaring the external reset a false path without a synchronizer

The false path only removes the check, it does not make the design safe. Without the synchronizer, the reset can be released too close to a clock edge, and flip-flops can end up in different states. The two go together.

Quick Check: A design has a worst setup slack of 0.20 ns at 4.0 ns. About what is its smallest clock period?

The smallest period is about 4.0 - 0.20 = 3.8 ns, if the worst path is a path between registers and it does not change when the clock gets faster.

Practice Exercise

Challenge: Take It Further

Paste the final design into the lab with the 3.4 ns SDC and set the corner to the slow library. Then lower the period to 3.2 ns. Predict the worst setup slack first, then run it. Which path is the worst now, and what would you change next?

Open the ready-made example in the lab, run synthesis, and then run STA. Editing constraints.sdc and re-running only STA, and choosing another library or corner, are PRO features.

Hint

The slack should drop by the same amount as the period, 0.2 ns. Read the cells of the new worst path and look at their load and slew, as in the previous article.

Solution

The prediction is 0.0923 - 0.2 = -0.1077 ns. The worst path will still be a path through the tick logic or the bit counter, which is the longest remaining logic. A possible next step is to look at the four cells of the new worst path and apply the same idea again, for example by registering another intermediate signal, or by changing the counter bit widths. The point of the exercise is the method: predict, run, read the path, and choose the change that matches the cause.

Summary

  • The original UART fails at 3.4 ns on the slow corner: setup -0.3165 ns and removal -0.1148 ns. It passes at the typical and fast corners.
  • Splitting the counter into two 5-bit counters and registering the tick shortens the worst path from five cells to four, and the setup slack becomes +0.0923 ns.
  • A two-flop reset synchronizer releases the reset from a clock edge. The removal slack at the slow corner changes from -0.1148 ns to +0.4088 ns.
  • The external reset is constrained with set_false_path -from, not with an input delay, and the synchronizer makes it safe.
  • A simulation of both designs showed no difference at the outputs. The bit time is 868 clock cycles.
  • The smallest period at the slow corner moved from about 3.72 ns to about 3.31 ns.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.