Clocks in SDC

Declare clocks, divided clocks and asynchronous clock groups in SDC, read which edges the tool pairs, and tell an ideal clock from a propagated one.

Lesson
L2.6
Time
30 min
Runs on
OpenROAD
Check
5 questions

The asynchronous FIFO of R6.4 writes on a 10 ns clock and reads on a 7 ns clock. Its first timing run listed the read-data path failing by 0.1605 ns. The tool launched the word at 20 ns and wanted it at the read register by 21 ns: one nanosecond for a path that the FIFO's pointers already keep safe.

Timing pathA memory word read across the two clocksThe word mem5 is written on wclk and read through the mux tree into rdata on rclk. The SDC has two create_clock lines and nothing else.

mem5 → rdatasetup check, latest arrival3 cells

  • Clock latency
  • Cell delay
  • Setup time
A memory word read across the two clocks2020.120.220.320.420.520.620.720.820.92121.1time (ns)launch wclk ↑capture rclk ↑Data arrivesRequired bymem5/CLK → mem5/Q (dfxtp_1): 0.3040 ns1 dfxtp_1rmux_hi/A1 → rmux_hi/X (mux4_1): 0.4680 ns2 mux4_1rmux/A1 → rmux/X (mux2_1): 0.2886 ns3 mux2_1setup −0.0999 nsslack −0.1605 ns · violatedarrival 21.0606required 20.9001A memory word read across the two clocks2020.220.420.620.821time (ns)launch wclk ↑capture rclk ↑Data arrivesRequired bymem5/CLK → mem5/Q (dfxtp_1): 0.3040 ns1 dfxtp_1rmux_hi/A1 → rmux_hi/X (mux4_1): 0.4680 ns2 mux4_1rmux/A1 → rmux/X (mux2_1): 0.2886 ns3 mux2_1setup −0.0999 nsslack −0.1605 ns · violatedarrival 21.0606required 20.9001
  1. Launch at 20 ns

    The tool picked the third wclk edge, at 20 ns.

  2. Capture at 21 ns

    The next rclk edge after it is at 21 ns. That pair is the closest the two clocks ever come.

  3. Violated

    Clock-to-Q and two mux levels take 1.0606 ns, so the slack is -0.1605 ns.

Read the path as a table

Launch: wclk rise edge at 20.0000 ns, clock latency 0.0000 ns (ideal). Capture: rclk rise edge at 21.0000 ns, latency 0.0000 ns, library setup time −0.0999 ns.

Arrival 21.0606 ns, required 20.9001 ns, slack −0.1605 ns (violated).

CellArcThroughEdgeDelay (ns)Time (ns)Slew (ns)
1mem5/CLK → mem5/Qdfxtp_1fall0.304020.30400.0213
mem5/Q → rmux_hi/A1wire m5fall0.000020.30400.0213
2rmux_hi/A1 → rmux_hi/Xmux4_1fall0.468020.77200.0797
rmux_hi/X → rmux/A1wire hifall0.000020.77200.0797
3rmux/A1 → rmux/Xmux2_1fall0.288621.06060.0500
rmux/X → rdata/Dwire rdfall0.000021.06060.0500
The report
Startpoint: mem5 (rising edge-triggered flip-flop clocked by wclk)
Endpoint: rdata (rising edge-triggered flip-flop clocked by rclk)
Path Group: rclk
Path Type: max

Fanout       Cap      Slew     Delay      Time   Description
-------------------------------------------------------------------------------------
                    0.1000   20.0000   20.0000   clock wclk (rise edge)
                              0.0000   20.0000   clock network delay (ideal)
                    0.1000    0.0000   20.0000 ^ mem5/CLK (sky130_fd_sc_hd__dfxtp_1)
     1    0.0014    0.0213    0.3040   20.3040 v mem5/Q (sky130_fd_sc_hd__dfxtp_1)
                                                 m5 (net)
                    0.0213    0.0000   20.3040 v rmux_hi/A1 (sky130_fd_sc_hd__mux4_1)
     1    0.0018    0.0797    0.4680   20.7720 v rmux_hi/X (sky130_fd_sc_hd__mux4_1)
                                                 hi (net)
                    0.0797    0.0000   20.7720 v rmux/A1 (sky130_fd_sc_hd__mux2_1)
     1    0.0017    0.0500    0.2886   21.0606 v rmux/X (sky130_fd_sc_hd__mux2_1)
                                                 rd (net)
                    0.0500    0.0000   21.0606 v rdata/D (sky130_fd_sc_hd__dfxtp_1)
                                       21.0606   data arrival time

                    0.1000   21.0000   21.0000   clock rclk (rise edge)
                              0.0000   21.0000   clock network delay (ideal)
                              0.0000   21.0000   clock reconvergence pessimism
                                       21.0000 ^ rdata/CLK (sky130_fd_sc_hd__dfxtp_1)
                             -0.0999   20.9001   library setup time
                                       20.9001   data required time
-------------------------------------------------------------------------------------
                                       20.9001   data required time
                                      -21.0606   data arrival time
-------------------------------------------------------------------------------------
                                       -0.1605   slack (VIOLATED)

OpenSTA 3.1.0 on the sky130 tt library, ideal clocks with a 0.1 ns clock slew, no wires.

The tool timed exactly what the SDC said, and the SDC was wrong about the clocks.

What create_clock declares

create_clock -name wclk -period 10 [get_ports wclk] gives a clock four things. It has a name and a period. It has a waveform: it rises at 0 and falls at half the period, unless -waveform says otherwise. It also has a source, the port or pin where it starts.

From the source, the tool follows the clock through buffers and inverters to every flop clock pin. It stops at a flop. A clock never passes through a CLK→Q arc, so a flop that divides a clock makes a net with no clock on it.

SDC commandWhat it setsTerm in the checks of L2.4
create_clock -period Tname, period, waveform, sourceT, and the launch and capture edges
set_clock_latency Lexpected clock delay to the flops (ideal clock)Llaunch, Lcapture
set_clock_latency -source Ldelay from the clock's origin to the block's portadded to both latencies
set_clock_transition Sslew at the flop clock pins (ideal clock)the index of tcq, tsetup and thold tables
set_clock_uncertainty Umargin for jitter and skew not yet builtUsetup, Uhold
set_propagated_clocktime the clock through the real bufferseach flop's own L, so skew appears

The clock commands of OpenSTA 3.1.0 and where each lands in the setup and hold equations of L2.4.

Before clock tree synthesis the clock is ideal. Every flop sees the edge at the latency from set_clock_latency, zero by default, with no skew. After the tree is built, set_propagated_clock makes the tool add up the real buffer delays instead, and the ideal latency is ignored.

A divided clock is a new clock

Lesson R2.3 warned that a flop dividing a clock makes a new clock domain. In div2, flop dv toggles on clk, and flops rb and rc run on its output. With only create_clock on clk, check_setup lists rb/CLK and rc/CLK as unclocked: no clock reaches them, so nothing they capture is timed.

div2: the clock stops at the dividerArrows are signals. clk reaches dv and ra; the divided net clkd clocks rb and rc.
div2: the clock stops at the dividerArrows are signals. `clk` reaches `dv` and `ra`; the divided net `clkd` clocks `rb` and `rc`. component clk port create_clock, 1 ns component dv (dfxtp_1) toggles every edge component ra (dfxtp_1) on clk generated clkd net create_generated_clock component rb, rc (dfxtp_1) on clkd clockclockQclockdata
  1. The clock stops at dv

    The tool follows clk to the CLK pins of dv and ra. It does not cross dv.

  2. Declare the divided clock

    create_generated_clock -divide_by 2 -source [get_ports clk] on dv/Q names a 2 ns clock tied to clk.

  3. Crossings are timed

    Now ra → rb is a path from clk to clkd, checked with edges of both clocks.

Read the diagram as text
  • clk port: create_clock, 1 ns
  • dv (dfxtp_1): toggles every edge
  • ra (dfxtp_1): on clk
  • clkd net: create_generated_clock
  • rb, rc (dfxtp_1): on clkd
  • clk port → dv (dfxtp_1): clock
  • clk port → ra (dfxtp_1): clock
  • dv (dfxtp_1) → clkd net: Q
  • clkd net → rb, rc (dfxtp_1): clock
  • ra (dfxtp_1) → rb, rc (dfxtp_1): data

A generated clock keeps its master, so the tool knows where its edges fall relative to clk.

The options follow the circuit. Use -divide_by for a counter, -multiply_by for a clock multiplier such as a PLL, and -edges when the new waveform is irregular. -source names where the master is measured: its port, or the divider's own clock pin.

The generated clock also carries the divider's delay once the clock is propagated. Its edge reaches rb a clock-to-Q after the clk edge: 0.3425 ns. That makes the hold check from ra to rb fail by 0.0053 ns.

Timing pathHold from ra (clk) to rb (clkd), propagated clocksThe capture clock is the generated clkd. Its latency is the delay through dv from clk.

ra → rbhold check, earliest arrival1 cell

  • Clock latency
  • Cell delay
  • Hold time
Hold from ra (clk) to rb (clkd), propagated clocks00.050.10.150.20.250.30.35time (ns)launch and capture clk ↑Data arrivesRequired afterra/CLK → ra/Q (dfxtp_1): 0.3119 ns1 dfxtp_1clock 0.3425 nshold −0.0253 nsslack −0.0053 ns · violatedarrival 0.3119required 0.3172Hold from ra (clk) to rb (clkd), propagated clocks00.10.20.3time (ns)launch and capture clk ↑Data arrivesRequired afterra/CLK → ra/Q (dfxtp_1): 0.3119 ns1 dfxtp_1clock 0.3425 nshold −0.0253 nsslack −0.0053 ns · violatedarrival 0.3119required 0.3172
  1. New data from ra

    ra launches on clk with a clock-to-Q of 0.3119 ns.

  2. The late divided edge

    clkd reaches rb 0.3425 ns after the same clk edge. With a hold time of -0.0253 ns, rb needs its old D until 0.3172 ns.

  3. Hold violated

    Slack -0.0053 ns: the data changes before the late edge has finished sampling.

Read the path as a table

Launch: clk rise edge at 0.0000 ns, clock latency 0.0000 ns. Capture: clkd rise edge at 0.0000 ns, latency 0.3425 ns, library hold time −0.0253 ns.

Arrival 0.3119 ns, required 0.3172 ns, slack −0.0053 ns (violated).

CellArcThroughEdgeDelay (ns)Time (ns)Slew (ns)
1ra/CLK → ra/Qdfxtp_1rise0.31190.31190.0329
ra/Q → rb/Dwire arise0.00000.31190.0329
The report
Startpoint: ra (rising edge-triggered flip-flop clocked by clk)
Endpoint: rb (rising edge-triggered flip-flop clocked by clkd)
Path Group: clkd
Path Type: min

Fanout       Cap      Slew     Delay      Time   Description
-------------------------------------------------------------------------------------
                              0.0000    0.0000   clock clk (rise edge)
                              0.0000    0.0000   clock source latency
     2    0.0038    0.1000    0.0000    0.0000 ^ clk (in)
                                                 clk (net)
                    0.1000    0.0000    0.0000 ^ ra/CLK (sky130_fd_sc_hd__dfxtp_1)
     1    0.0017    0.0329    0.3119    0.3119 ^ ra/Q (sky130_fd_sc_hd__dfxtp_1)
                                                 a (net)
                    0.0329    0.0000    0.3119 ^ rb/D (sky130_fd_sc_hd__dfxtp_1)
                                        0.3119   data arrival time

                              0.0000    0.0000   clock clkd (rise edge)
                              0.0000    0.0000   clock source latency
     2    0.0038    0.1000    0.0000    0.0000 ^ clk (in)
                                                 clk (net)
                    0.1000    0.0000    0.0000 ^ dv/CLK (sky130_fd_sc_hd__dfxtp_1)
     3    0.0061    0.0713    0.3425    0.3425 ^ dv/Q (sky130_fd_sc_hd__dfxtp_1)
                                                 clkd (net)
                    0.0713    0.0000    0.3425 ^ rb/CLK (sky130_fd_sc_hd__dfxtp_1)
                              0.0000    0.3425   clock reconvergence pessimism
                             -0.0253    0.3172   library hold time
                                        0.3172   data required time
-------------------------------------------------------------------------------------
                                        0.3172   data required time
                                       -0.3119   data arrival time
-------------------------------------------------------------------------------------
                                       -0.0053   slack (VIOLATED)

OpenSTA 3.1.0, propagated clocks with a 0.1 ns slew at the clk port.

The same check with ideal clocks
Timing pathHold from ra to rb, ideal clocks

ra → rbhold check, earliest arrival1 cell

  • Clock latency
  • Cell delay
  • Hold time
Hold from ra to rb, ideal clocks00.050.10.150.20.250.3time (ns)launch and capture clk ↑Data arrivesRequired afterra/CLK → ra/Q (dfxtp_1): 0.3119 ns1 dfxtp_1hold −0.0215 nsslack +0.3334 ns · metarrival 0.3119required −0.0215Hold from ra to rb, ideal clocks00.10.20.3time (ns)launch and capture clk ↑Data arrivesRequired afterra/CLK → ra/Q (dfxtp_1): 0.3119 ns1 dfxtp_1hold −0.0215 nsslack +0.3334 ns · metarrival 0.3119required −0.0215
Read the path as a table

Launch: clk rise edge at 0.0000 ns, clock latency 0.0000 ns (ideal). Capture: clkd rise edge at 0.0000 ns, latency 0.0000 ns, library hold time −0.0215 ns.

Arrival 0.3119 ns, required −0.0215 ns, slack 0.3334 ns (met).

CellArcThroughEdgeDelay (ns)Time (ns)Slew (ns)
1ra/CLK → ra/Qdfxtp_1rise0.31190.31190.0329
ra/Q → rb/Dwire arise0.00000.31190.0329
The report
Startpoint: ra (rising edge-triggered flip-flop clocked by clk)
Endpoint: rb (rising edge-triggered flip-flop clocked by clkd)
Path Group: clkd
Path Type: min

Fanout       Cap      Slew     Delay      Time   Description
-------------------------------------------------------------------------------------
                    0.1000    0.0000    0.0000   clock clk (rise edge)
                              0.0000    0.0000   clock network delay (ideal)
                    0.1000    0.0000    0.0000 ^ ra/CLK (sky130_fd_sc_hd__dfxtp_1)
     1    0.0017    0.0329    0.3119    0.3119 ^ ra/Q (sky130_fd_sc_hd__dfxtp_1)
                                                 a (net)
                    0.0329    0.0000    0.3119 ^ rb/D (sky130_fd_sc_hd__dfxtp_1)
                                        0.3119   data arrival time

                    0.1000    0.0000    0.0000   clock clkd (rise edge)
                              0.0000    0.0000   clock network delay (ideal)
                              0.0000    0.0000   clock reconvergence pessimism
                                        0.0000 ^ rb/CLK (sky130_fd_sc_hd__dfxtp_1)
                             -0.0215   -0.0215   library hold time
                                       -0.0215   data required time
-------------------------------------------------------------------------------------
                                       -0.0215   data required time
                                       -0.3119   data arrival time
-------------------------------------------------------------------------------------
                                        0.3334   slack (MET)

Ideal clocks with a 0.1 ns clock slew: both edges at 0 ns.

An ideal clock puts both edges at 0 ns, so this hold check passes with 0.3334 ns. Clock tree synthesis must later balance clkd against clk, or this crossing breaks.

Two clocks in one SDC are related unless you say otherwise. The tool lines up both waveforms over their common period, here 70 ns. For each launch edge it takes the next capture edge, and it checks the tightest pair. For 10 ns and 7 ns, that pair is 20 ns and 21 ns.

Rising edges of wclk and rclk, 0 to 24 nsOne column per nanosecond; a 1 marks a rising edge.
0123456789101112131415161718192021222324wclk ↑ (10 ns)rclk ↑ (7 ns)launchcapture
  1. Cycle 7

    Launch at 0 ns, capture at 7 ns: 7 ns for the path.

  2. Cycle 14

    Launch at 10 ns, capture at 14 ns: 4 ns for the path.

  3. Cycle 21

    Launch at 20 ns, capture at 21 ns: 1 ns for the path.

The tool times a wclk-to-rclk path against the smallest of these gaps.

Launch (wclk)Next capture (rclk)Time for the path
0 ns7 ns7 ns
10 ns14 ns4 ns
20 ns21 ns1 ns
30 ns35 ns5 ns
40 ns42 ns2 ns
50 ns56 ns6 ns
60 ns63 ns3 ns

Every wclk edge in one 70 ns common period. The pattern then repeats.

For clocks with no fixed phase, that 1 ns is meaningless. The edges drift past each other, so every gap occurs, down to zero. The FIFO handles this with Gray pointers and two-flop synchronizers, and the SDC must tell the tool so.

Asynchronous clock groups

set_clock_groups -asynchronous -group [get_clocks wclk] -group [get_clocks rclk] declares that no path between the groups is timed, in either direction. The crossings leave the report, and the worst path is now inside the read domain.

The worst setup path after the clock groups
Timing pathWorst setup path with asynchronous clock groups

rptr0 → rdatasetup check, latest arrival3 cells

  • Clock latency
  • Cell delay
  • Setup time
Worst setup path with asynchronous clock groups01234567time (ns)launch rclk ↑capture rclk ↑Data arrivesRequired byrptr0/CLK → rptr0/Q (dfxtp_1): 0.3559 ns1rmux_hi/S0 → rmux_hi/X (mux4_1): 0.5323 ns2rmux/A1 → rmux/X (mux2_1): 0.2886 ns3setup −0.0999 nsslack +5.7233 ns · metarrival 1.1768required 6.9001Worst setup path with asynchronous clock groups0246time (ns)launch rclk ↑capture rclk ↑Data arrivesRequired byrptr0/CLK → rptr0/Q (dfxtp_1): 0.3559 ns1rmux_hi/S0 → rmux_hi/X (mux4_1): 0.5323 ns2rmux/A1 → rmux/X (mux2_1): 0.2886 ns3setup −0.0999 nsslack +5.7233 ns · metarrival 1.1768required 6.9001
Read the path as a table

Launch: rclk rise edge at 0.0000 ns, clock latency 0.0000 ns (ideal). Capture: rclk rise edge at 7.0000 ns, latency 0.0000 ns, library setup time −0.0999 ns.

Arrival 1.1768 ns, required 6.9001 ns, slack 5.7233 ns (met).

CellArcThroughEdgeDelay (ns)Time (ns)Slew (ns)
1rptr0/CLK → rptr0/Qdfxtp_1rise0.35590.35590.0892
rptr0/Q → rmux_hi/S0wire r0rise0.00000.35590.0892
2rmux_hi/S0 → rmux_hi/Xmux4_1fall0.53230.88820.0797
rmux_hi/X → rmux/A1wire hifall0.00000.88820.0797
3rmux/A1 → rmux/Xmux2_1fall0.28861.17680.0500
rmux/X → rdata/Dwire rdfall0.00001.17680.0500
The report
Startpoint: rptr0 (rising edge-triggered flip-flop clocked by rclk)
Endpoint: rdata (rising edge-triggered flip-flop clocked by rclk)
Path Group: rclk
Path Type: max

Fanout       Cap      Slew     Delay      Time   Description
-------------------------------------------------------------------------------------
                    0.1000    0.0000    0.0000   clock rclk (rise edge)
                              0.0000    0.0000   clock network delay (ideal)
                    0.1000    0.0000    0.0000 ^ rptr0/CLK (sky130_fd_sc_hd__dfxtp_1)
     2    0.0082    0.0892    0.3559    0.3559 ^ rptr0/Q (sky130_fd_sc_hd__dfxtp_1)
                                                 r0 (net)
                    0.0892    0.0000    0.3559 ^ rmux_hi/S0 (sky130_fd_sc_hd__mux4_1)
     1    0.0018    0.0797    0.5323    0.8882 v rmux_hi/X (sky130_fd_sc_hd__mux4_1)
                                                 hi (net)
                    0.0797    0.0000    0.8882 v rmux/A1 (sky130_fd_sc_hd__mux2_1)
     1    0.0017    0.0500    0.2886    1.1768 v rmux/X (sky130_fd_sc_hd__mux2_1)
                                                 rd (net)
                    0.0500    0.0000    1.1768 v rdata/D (sky130_fd_sc_hd__dfxtp_1)
                                        1.1768   data arrival time

                    0.1000    7.0000    7.0000   clock rclk (rise edge)
                              0.0000    7.0000   clock network delay (ideal)
                              0.0000    7.0000   clock reconvergence pessimism
                                        7.0000 ^ rdata/CLK (sky130_fd_sc_hd__dfxtp_1)
                             -0.0999    6.9001   library setup time
                                        6.9001   data required time
-------------------------------------------------------------------------------------
                                        6.9001   data required time
                                       -1.1768   data arrival time
-------------------------------------------------------------------------------------
                                        5.7233   slack (MET)

Read pointer to read data, inside rclk: slack 5.7233 ns.

Clock groups come in three kinds. -asynchronous is for clocks from separate sources. -logically_exclusive and -physically_exclusive are for clocks that never run together, such as two clocks behind one multiplexer. For timing, all three cut the paths between the groups.

Clock groups check nothing on those paths, and that includes one property the FIFO needs. Its Gray pointer works only if the pointer bits reach the synchronizers within about one read period of each other. Real flows bound that skew with a maximum delay on the pointer paths.

Dropped by OpenSTA 3.1.0

set_clock_groups -asynchronous \
  -group [get_clocks wclk] -group [get_clocks rclk]
set_max_delay 7 -from [get_cells {wptr0 wptr1}] \
  -to [get_cells {rq1_0 rq1_1}]

The clock groups win: the pointer paths stay untimed.

Timed

set_max_delay 7 -ignore_clock_latency \
  -from [get_cells {wptr0 wptr1}] -to [get_cells {rq1_0 rq1_1}]
set_false_path -from [get_cells mem*] -to [get_cells rdata]
set_false_path -hold -from [get_clocks wclk] -to [get_clocks rclk]

No clock-level exception: the pointer paths get a 7 ns limit.

In OpenSTA 3.1.0, a max delay is dropped on paths that clock groups or any false path already cut, even a false path written between the two clocks. The version that works names the paths instead: the pointer gets its limit, and the memory paths and the cross-clock hold checks are cut one by one. -ignore_clock_latency bounds the data path alone, leaving out both clocks' latencies. Try it below runs it.

Try it

This is the FIFO with the pointer recipe of the last section. Run it. Paths shows wptr0 → rq1_0 in a group called "path delay": required 6.9121 ns, which is the 7 ns limit minus the flop's setup time, and slack 6.6067 ns. The worst slack overall, 5.7233 ns, now sits inside the read domain.

Now replace the three exception lines with the set_clock_groups line and run again. The pointer paths disappear from the report: nothing checks their skew any more. Delete every exception, and the memory path of the opening figure fails again.

STAOpenSTA in OpenROAD 26Q2 · sky130hd tt_025C_1v80 Liberty · simulator service
Edit the constraints, then run them

          
Expected: path 1 slack 6.6067 ns path 1 required 6.9121 ns WNS 5.7233 ns
Read the netlist: afifo_x.v
module afifo_x (wclk, rclk, wd, wg0, wg1, rp0, rp1, rp2, rdq, wsync0, wsync1);
  input wclk;
  input rclk;
  input wd;
  input wg0;
  input wg1;
  input rp0;
  input rp1;
  input rp2;
  output rdq;
  output wsync0;
  output wsync1;
  wire g0, g1, m0, m1, m2, m3, m4, m5, m6, m7, s0, s1, r0, r1, r2, lo, hi, rd;
  sky130_fd_sc_hd__dfxtp_1 wptr0 (.CLK(wclk), .D(wg0), .Q(g0));
  sky130_fd_sc_hd__dfxtp_1 wptr1 (.CLK(wclk), .D(wg1), .Q(g1));
  sky130_fd_sc_hd__dfxtp_1 mem0 (.CLK(wclk), .D(wd), .Q(m0));
  sky130_fd_sc_hd__dfxtp_1 mem1 (.CLK(wclk), .D(wd), .Q(m1));
  sky130_fd_sc_hd__dfxtp_1 mem2 (.CLK(wclk), .D(wd), .Q(m2));
  sky130_fd_sc_hd__dfxtp_1 mem3 (.CLK(wclk), .D(wd), .Q(m3));
  sky130_fd_sc_hd__dfxtp_1 mem4 (.CLK(wclk), .D(wd), .Q(m4));
  sky130_fd_sc_hd__dfxtp_1 mem5 (.CLK(wclk), .D(wd), .Q(m5));
  sky130_fd_sc_hd__dfxtp_1 mem6 (.CLK(wclk), .D(wd), .Q(m6));
  sky130_fd_sc_hd__dfxtp_1 mem7 (.CLK(wclk), .D(wd), .Q(m7));
  sky130_fd_sc_hd__dfxtp_1 rq1_0 (.CLK(rclk), .D(g0), .Q(s0));
  sky130_fd_sc_hd__dfxtp_1 rq2_0 (.CLK(rclk), .D(s0), .Q(wsync0));
  sky130_fd_sc_hd__dfxtp_1 rq1_1 (.CLK(rclk), .D(g1), .Q(s1));
  sky130_fd_sc_hd__dfxtp_1 rq2_1 (.CLK(rclk), .D(s1), .Q(wsync1));
  sky130_fd_sc_hd__dfxtp_1 rptr0 (.CLK(rclk), .D(rp0), .Q(r0));
  sky130_fd_sc_hd__dfxtp_1 rptr1 (.CLK(rclk), .D(rp1), .Q(r1));
  sky130_fd_sc_hd__dfxtp_1 rptr2 (.CLK(rclk), .D(rp2), .Q(r2));
  sky130_fd_sc_hd__mux4_1 rmux_lo (.A0(m0), .A1(m1), .A2(m2), .A3(m3), .S0(r0), .S1(r1), .X(lo));
  sky130_fd_sc_hd__mux4_1 rmux_hi (.A0(m4), .A1(m5), .A2(m6), .A3(m7), .S0(r0), .S1(r1), .X(hi));
  sky130_fd_sc_hd__mux2_1 rmux (.A0(lo), .A1(hi), .S(r2), .X(rd));
  sky130_fd_sc_hd__dfxtp_1 rdata (.CLK(rclk), .D(rd), .Q(rdq));
endmodule

Check yourself

Predict the outputThe same FIFO netlist as the opening figure, now with a 6 ns wclk and a 4 ns rclk. The read-data path itself is unchanged. What worst setup slack (WNS) does OpenSTA report, in ns?
create_clock -name wclk -period 6 [get_ports wclk]
create_clock -name rclk -period 4 [get_ports rclk]
set_clock_transition 0.1 [all_clocks]
Read the netlist: design.v
module afifo_x (wclk, rclk, wd, wg0, wg1, rp0, rp1, rp2, rdq, wsync0, wsync1);
  input wclk;
  input rclk;
  input wd;
  input wg0;
  input wg1;
  input rp0;
  input rp1;
  input rp2;
  output rdq;
  output wsync0;
  output wsync1;
  wire g0, g1, m0, m1, m2, m3, m4, m5, m6, m7, s0, s1, r0, r1, r2, lo, hi, rd;
  sky130_fd_sc_hd__dfxtp_1 wptr0 (.CLK(wclk), .D(wg0), .Q(g0));
  sky130_fd_sc_hd__dfxtp_1 wptr1 (.CLK(wclk), .D(wg1), .Q(g1));
  sky130_fd_sc_hd__dfxtp_1 mem0 (.CLK(wclk), .D(wd), .Q(m0));
  sky130_fd_sc_hd__dfxtp_1 mem1 (.CLK(wclk), .D(wd), .Q(m1));
  sky130_fd_sc_hd__dfxtp_1 mem2 (.CLK(wclk), .D(wd), .Q(m2));
  sky130_fd_sc_hd__dfxtp_1 mem3 (.CLK(wclk), .D(wd), .Q(m3));
  sky130_fd_sc_hd__dfxtp_1 mem4 (.CLK(wclk), .D(wd), .Q(m4));
  sky130_fd_sc_hd__dfxtp_1 mem5 (.CLK(wclk), .D(wd), .Q(m5));
  sky130_fd_sc_hd__dfxtp_1 mem6 (.CLK(wclk), .D(wd), .Q(m6));
  sky130_fd_sc_hd__dfxtp_1 mem7 (.CLK(wclk), .D(wd), .Q(m7));
  sky130_fd_sc_hd__dfxtp_1 rq1_0 (.CLK(rclk), .D(g0), .Q(s0));
  sky130_fd_sc_hd__dfxtp_1 rq2_0 (.CLK(rclk), .D(s0), .Q(wsync0));
  sky130_fd_sc_hd__dfxtp_1 rq1_1 (.CLK(rclk), .D(g1), .Q(s1));
  sky130_fd_sc_hd__dfxtp_1 rq2_1 (.CLK(rclk), .D(s1), .Q(wsync1));
  sky130_fd_sc_hd__dfxtp_1 rptr0 (.CLK(rclk), .D(rp0), .Q(r0));
  sky130_fd_sc_hd__dfxtp_1 rptr1 (.CLK(rclk), .D(rp1), .Q(r1));
  sky130_fd_sc_hd__dfxtp_1 rptr2 (.CLK(rclk), .D(rp2), .Q(r2));
  sky130_fd_sc_hd__mux4_1 rmux_lo (.A0(m0), .A1(m1), .A2(m2), .A3(m3), .S0(r0), .S1(r1), .X(lo));
  sky130_fd_sc_hd__mux4_1 rmux_hi (.A0(m4), .A1(m5), .A2(m6), .A3(m7), .S0(r0), .S1(r1), .X(hi));
  sky130_fd_sc_hd__mux2_1 rmux (.A0(lo), .A1(hi), .S(r2), .X(rd));
  sky130_fd_sc_hd__dfxtp_1 rdata (.CLK(rclk), .D(rd), .Q(rdq));
endmodule
ConceptFour ways to constrain the divided clock of div2. Which one loses the relation between clkd and clk?
ConceptAfter set_clock_groups -asynchronous between wclk and rclk, what happens to the hold checks of the crossings?
ConceptA flop's clock passes through three clkbuf_1 cells in the netlist. The clock is ideal, with no set_clock_latency. What capture latency does the report show?
ConceptThe two FIFO clocks are left related. Why is the 1 ns pair of the opening figure the wrong number to design for?

Remember

  • create_clock gives a name, a period, a waveform and a source; the clock stops at every flop.
  • A clock divided by a flop needs create_generated_clock, which keeps its relation to the master clock.
  • Related clocks are timed against their tightest launch-capture pair over the common period.
  • Asynchronous clock groups cut every check between the groups; a max delay on the Gray pointer needs path-level exceptions.
  • Ideal clocks use the SDC latency with no skew; set_propagated_clock times the real buffers.