The architectural inventory now becomes an SDC draft. Assume the STA session uses ns; confirm with the tool's unit report before sourcing. Object names and some options vary by tool, but each command below has one reviewable purpose and maps to a clock-tree element already introduced.
# 100 MHz reference and unrelated 25 MHz debug source
create_clock -name ref_clk -period 10.000 [get_ports ref_clk_i]
create_clock -name dbg_clk -period 40.000 [get_ports dbg_clk_i]
# PLL output; downstream clocks are defined after their mux masters
create_generated_clock -name pll_clk \
-source [get_ports ref_clk_i] -multiply_by 4 \
[get_pins u_pll/clk_o]The generated clocks preserve edge relationships instead of creating unrelated primary clocks. Review the PLL model and divider implementation to confirm that the stated multiplication, division, phase, and duty cycle match hardware.
# Two possible clocks reach the same mux output; -add preserves both views
create_generated_clock -add -name core_from_pll \
-master_clock pll_clk -source [get_pins u_clk_mux/clk_a_i] \
-divide_by 1 \
[get_pins u_clk_mux/clk_o]
create_generated_clock -add -name core_from_dbg \
-master_clock dbg_clk -source [get_pins u_clk_mux/clk_b_i] \
-divide_by 1 \
[get_pins u_clk_mux/clk_o]
# The ICG propagates both mux clocks; the downstream divider needs both masters.
create_generated_clock -add -name periph_from_pll \
-master_clock core_from_pll \
-source [get_pins u_periph_div/clk_i] -divide_by 4 \
[get_pins u_periph_div/clk_o]
create_generated_clock -add -name periph_from_dbg \
-master_clock core_from_dbg \
-source [get_pins u_periph_div/clk_i] -divide_by 4 \
[get_pins u_periph_div/clk_o]
set_clock_groups -logically_exclusive \
-group {core_from_pll periph_from_pll} \
-group {core_from_dbg periph_from_dbg}Depending on the tool, the master clocks pll_clk and dbg_clk may also keep propagating through the mux arcs next to the generated clocks. Many flows stop them at u_clk_mux/clk_o (for example with set_clock_sense -stop_propagation); check your tool's documentation and the resolved-clock report below. Some flows use -physically_exclusive for alternatives defined on the same pin; -logically_exclusive keeps crosstalk analysis between them, which is pessimistic rather than wrong.
Logical exclusivity says the two propagated alternatives cannot be active together in one mode; it does not declare the unrelated roots physically related. Separate asynchronous relationships and test-mode exceptions belong in their corresponding analysis views.
Clock coverage contract | Expected period / master |
|---|---|
core_from_pll | 2.5 ns / pll_clk |
core_from_dbg | 40 ns / dbg_clk |
periph_from_pll | 10 ns / core_from_pll |
periph_from_dbg | 160 ns / core_from_dbg |
Before signoff, report clocks at the divider output and require both peripheral alternatives with these periods and masters. Report clock interactions and require exclusivity across the two families, while retaining timing between each core clock and its own peripheral clock. A flow using separate case-analysis views must establish the same coverage across those views.
# External device timing reference: no physical design object
create_clock -name ext_io_clk -period 8.000
set_input_delay -clock ext_io_clk -max 2.10 [get_ports ext_rx_data_i*]
set_input_delay -clock ext_io_clk -min 0.35 [get_ports ext_rx_data_i*]
set_output_delay -clock ext_io_clk -max 1.80 [get_ports ext_tx_data_o*]
set_output_delay -clock ext_io_clk -min -0.20 [get_ports ext_tx_data_o*]These virtual-clock ports are a separate hypothetical system-synchronous IO interface; its internal launch/capture clock relation must be supplied by integration. They are not the eight forwarded-strobe receive pins. These illustrative numbers require an external device/board/package/jitter budget before use; the virtual-clock snippet alone does not close an interface.
# SDR receive: launch on falling strobe, capture on next rising edge.
# Matches the source-synchronous lesson's 8 ns paper budget.
create_clock -name rx_strobe -period 8.000 -waveform {0.000 4.000} \
[get_ports rx_strobe_i]
set_input_delay -clock rx_strobe -clock_fall -max 2.10 [get_ports rx_data_i*]
set_input_delay -clock rx_strobe -clock_fall -min 0.35 [get_ports rx_data_i*]
set_clock_uncertainty -setup 0.15 [get_clocks rx_strobe]
set_clock_uncertainty -hold 0.15 [get_clocks rx_strobe]
# u_rx_capture/D* are eight positive-edge IO capture data pins.
# Library setup/hold and internal clock/data paths are analyzed by STA.
# Do not also apply ext_io_clk delays to rx_data_i*.The received strobe is a primary clock at the input port. A transmitted forwarded clock would instead need a generated clock at its output and output-delay budgets; that is a different direction. No PLL relationship is asserted for rx_strobe. Review the FIFO CDC boundary separately; any asynchronous exceptions must preserve these pin-to-capture setup/hold paths.
# Synopsys-style collection/attribute API draft; adapt for the STA tool.
# Run after netlist linking and all clock definitions; errors must fail the job.
proc require_count {objects expected label} {
if {[sizeof_collection $objects] != $expected} { error "$label: unexpected object count" }
}
proc require_clock_names {objects expected label} {
set actual [lsort [get_object_name [get_clocks -of_objects $objects]]]
if {$actual ne [lsort $expected]} { error "$label: resolved clocks $actual" }
}
require_count [get_ports rx_strobe_i] 1 rx_strobe_port
require_count [get_ports rx_data_i*] 8 rx_data_ports
require_count [get_pins u_rx_capture/D*] 8 rx_capture_data
require_count [get_pins u_rx_capture/CK*] 8 rx_capture_clocks
require_count [get_pins u_clk_mux/clk_o] 1 mux_output
require_count [get_pins u_periph_div/clk_i] 1 divider_input
require_count [get_pins u_periph_div/clk_o] 1 divider_output
require_clock_names [get_ports rx_strobe_i] {rx_strobe} strobe_port
foreach_in_collection ck [get_pins u_rx_capture/CK*] {
require_clock_names $ck {rx_strobe} [get_object_name $ck]
}
# Fails if the master clocks also propagate through the mux: stop them or extend the expected list.
require_clock_names [get_pins u_clk_mux/clk_o] {core_from_pll core_from_dbg} mux
require_clock_names [get_pins u_periph_div/clk_i] {core_from_pll core_from_dbg} divider_input
require_clock_names [get_pins u_periph_div/clk_o] {periph_from_pll periph_from_dbg} divider_output
foreach {name period master} {
core_from_pll 2.5 pll_clk
core_from_dbg 40.0 dbg_clk
periph_from_pll 10.0 core_from_pll
periph_from_dbg 160.0 core_from_dbg
rx_strobe 8.0 {}
} {
set c [get_clocks $name]
require_count $c 1 $name
if {abs([get_attribute $c period] - $period) > 0.000001} {
error "$name: wrong period"
}
if {$master ne ""} {
set actual_master [get_object_name [get_attribute $c master_clock]]
if {$actual_master ne $master} { error "$name: wrong master $actual_master" }
}
}
report_clock [get_clocks rx_strobe]
report_port -input_delay [get_ports rx_data_i*]
foreach_in_collection bit_port [get_ports rx_data_i*] {
report_timing -from $bit_port -to [get_pins u_rx_capture/D*] -delay_type max
report_timing -from $bit_port -to [get_pins u_rx_capture/D*] -delay_type min
}Expected coverage, not observed output | Required report content |
|---|---|
rx_data_i[7:0] -> IO capture | All eight bits; rx_strobe falling launch at 4 ns, rising setup capture at 8 ns; next falling launch at 12 ns for hold around capture at 8 ns |
Strobe port and eight IO clock pins | rx_strobe, period 8 ns, waveform {0 4}; no ext_io_clk on these pins |
Mux / divider input | Both core_from_pll and core_from_dbg |
Divider output | Both peripheral alternatives, periods and masters from coverage table |
Unconstrained/excepted endpoints | Audit full design, including both IO directions and FIFO crossing; zero unexplained endpoints |
Pin names assume eight scalar IO cells; adapt and check exact cardinalities for the linked design. The separate virtual interface needs its own port counts and timing reports. Confirm the reported input delays, launch/capture edges, all-bit min/max coverage and absence of unintended exceptions; hold reports may show the equivalent launch 4 ns / capture 0 ns pair after shifting both edges by one period. A missing per-bit path is a review failure, not a passing margin. Name/period checks alone do not establish timing closure. Real timing closure needs real libraries, extracted paths, corners, modes and clock interactions.
Resolve every get_ports and get_pins collection to the intended object.
Report all clocks and confirm period, waveform, master, and propagation.
Audit unconstrained endpoints and generated-clock reachability.
Check every legal mux, DVFS, functional, and test scenario independently.
Review clock groups and exceptions against CDC results so one flow does not hide paths expected by another.
Maximum delay participates in setup analysis; minimum delay participates in hold analysis. Supplying only one side leaves part of the boundary timing contract unmodeled.
The SDC is a draft and was not run. The coverage checker and expected-coverage table are source, not resolved netlist output. Pending STA must use real libraries, extracted paths, corners, modes and clock interactions.
Delays and uncertainty values are illustrative and need an external device, board, package and jitter budget before use.