I am trying to get correct timing constraints for a ULPI interface, where the PHY is an external chip and the link is an FPGA. The clock is generated by the PHY.

IO configuration diagram

The timing constraints from internal FFs to the output pins of the FPGA are straightforward:

# There is an external 2.4ns delay on the clock between the PHY and the link. 
# Model this as a virtual clock with negative 2.4ns latency...

create_clock -name {ulpi_clk} -period 16.600 [get_ports {ulpi_clk}]
create_clock -name {ulpi_clk_phy} -period 16.600 
set_clock_latency -source -2.4 [get_clocks {ulpi_clk_phy}]

# The ULPI specification has a 6ns input delay on signals from the link
# to the PHY. This becomes a 6ns output delay for the link.

set_output_delay -add_delay  -clock [get_clocks {ulpi_clk_phy}]  6 [get_ports {ulpi_data[*]}] -max

So far so good: when I run this through Quartus, everything works.

There is also a ulpi_dir signal that goes from the phy to the link. It goes to FFs inside the link but also to the output enable of the bidirectional ulpi_data pins.

Every time there is a change in bus direction, there is a turn-around cycle during which the PHY won't drive the bus to avoid bus contention.

The output delay of the PHY is 9ns, which translates into a 9ns input delay on the link:

set_input_delay -add_delay  -clock [get_clocks {ulpi_clk_phy}]  9.0 [get_ports {ulpi_dir}] -max
set_input_delay -add_delay  -clock [get_clocks {ulpi_clk_phy}]  0.0 [get_ports {ulpi_direction}] -min

There is a combinatorial path from the ulpi_dir input to the ulpi_data pins through the output enable. When I run timing analysis with this 9ns input delay constraint, the Timing Analyzer applies a 9ns input delay on ulpi_dir, and it applies the 6ns output delay of ulpi_data for a total of 15ns and a 16.6ns clock. This results in a 4ns timing violation on ulpi_data:

Timing Violation Waveform

In reality, the 6ns output delay should only be used for the internal FFs of the link to ulpi_data, not for ulpi_dir to ulpi_data: we want ulpi_data to stop driving the bus before the rising edge of the next clock, but since it's turn-around cycle, we don't care about the input delay during that cycle.

How do I do this?

Ideally, I want to set_output_delay only for paths from internal FFs to ulpi_data, but it only supports targets, not sources?

  • \$\begingroup\$ Are you familiar with set_max_delay. I think what you need is something like: set_max_delay -from [get_registers *] -to [get_ports ulpi_data] 10.000 \$\endgroup\$
    – Mitu Raj
    Jun 10, 2021 at 20:06
  • \$\begingroup\$ Wasn't that a typo: "internal FFs to ulpi_dir", I think you meant "internal FFs to ulpi_data" \$\endgroup\$
    – Mitu Raj
    Jun 10, 2021 at 20:22
  • \$\begingroup\$ @MituRaj It's one option, but it has the problem that it removes all notion of the clock and the delays related to the clock input path and clock tree to these FFs. You'd have to use a delay of (16.6 - 6.0 - 2.4 (external clock delay) - ??? (internal clock delay). I was hoping that there's way to make the timing analyzer do all that work for me. Especially since some of the internal clock delay can be synthesis dependent, so it would change each run. \$\endgroup\$ Jun 10, 2021 at 20:22
  • \$\begingroup\$ @MituRaj Yes, that was a typo. Fixed. \$\endgroup\$ Jun 10, 2021 at 20:27
  • 1
    \$\begingroup\$ The board designer added a voltage level shifter on ulpi_clk only. This introduces a 2.4ns delay. (Sigh) \$\endgroup\$ Jun 11, 2021 at 13:15

1 Answer 1


Ideally, I want to set_output_delay only for paths from internal FFs to ulpi_dir, but it only supports targets, not sources?

Yes, it's possible in SDC. You can use the set_max_delay and set_min_delay instead. For e.g, if I really understood your requirement on ulpi_data:

set_max_delay -from [get_registers *] -to [get_ports ulpi_data] 8.200

Where \$8.200\$ is obtained as the timing window available: clock period - input delay + skew at destination flop: \$16.600 - 6.00 + (-2.400) = 8.200 \text{ ns}\$

This constraint will be used for setup analysis of all timing paths from flops to the output port ulpi_data.

Similarly for input-to-output delay from ulpi_dir to ulpi_data:

set_max_delay -from [get_ports ulpi_dir] -to [get_ports ulpi_data] 14.200

Where \$14.200\$ is obtained as the timing window available: clock period + skew at destination flop: \$16.600 + (-2.400) = 14.200 \text { ns}\$


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.