Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
    • STA Foundations
    • Setup, Hold and Slack
    • Skew and Variation
    • Timing Exceptions
    • Clock Gating
    • RTL for Timing
    • Clock Architecture
      • Clock-Domain Plan
      • Glitch-Free Clock Mux
      • Generated and Virtual Clocks
      • PLL Lock and Reset Coordination
      • Source-Synchronous Interfaces
      • DVFS Transition Protocol
      • Clock Constraint Examples
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Clock Architecture
  1. Topics
  2. RTL Design
  3. Timing & Clocking
  4. Clock Architecture
  5. Clock Constraint Examples

Part 5 · Timing & Clocking · Intermediate

Clock Constraint Examples

Apply concrete SDC to the worked PLL, mux, gated clock, divider, virtual IO reference, and source-synchronous boundary.

On this page

    Why this matters

    A set of clock definitions that look right can still leave a divider output without its clock, or an input bus with only a max delay. You find that out by reporting the resolved clocks and endpoints, not by reading the SDC.

    After this lesson you can: write the SDC for primary, generated, muxed, virtual and forwarded-strobe clocks, and list the reports that prove the clocks and endpoints are covered.

    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.

    Primary and generated clocks

    Diagram
    # 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.

    Mux alternatives and exclusivity

    Diagram
    # 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.

    Warning

    This example assumes the library ICG transparently propagates each mux clock while enabled. If the flow requires explicit clocks at the gate output, define both alternatives there first and use those names as the divider masters. Resolve both masters at the divider input; do not let a single ambiguous generated-clock command choose one.

    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.

    Virtual clock and IO delays

    Diagram
    # 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.

    Forwarded-strobe receive boundary

    Diagram
    # 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.

    Resolved coverage checks

    Diagram
    # 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.

    Constraint review and signoff

    • 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.

    Interview

    Use a concrete clock tree when discussing constraints: identify each source and transformation, show the SDC relationship, explain mode exclusivity, and finish with coverage reports that prove endpoints are constrained.

    Check yourself Why are both minimum and maximum IO delays required?

    Maximum delay participates in setup analysis; minimum delay participates in hold analysis. Supplying only one side leaves part of the boundary timing contract unmodeled.

    Remember

    • A generated clock at the PLL, then core and peripheral alternatives through the mux. Report both peripheral clocks with their periods and masters.

    • Supply both -max and -min input delays: max feeds setup and min feeds hold.

    • Audit unconstrained endpoints, check every legal mode independently, and review clock groups against CDC results.

    Rule of thumb: show the SDC relationship for each clock, then close with coverage reports that prove the endpoints are constrained.

    How this was checked

    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.

    Keep going

    • Code lab: SDC clock groups

    • Interview: run a mock interview on this topic

    Related topics

    • Clock definition and uncertainty

    • IO timing and boundary contracts

    Previous

    154 / 350

    Next: Reset & CDC

    Up next

    Up nextReset & CDC

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Clock-Domain Plan
    • Glitch-Free Clock Mux
    • Generated and Virtual Clocks