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.
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
:
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?
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\$ulpi_clk
only. This introduces a 2.4ns delay. (Sigh) \$\endgroup\$