Problem Description
I am trying to figure out the "correct" way to constrain (in .xdc format - this is in Vivado) a forwarded source-synchronous clock that is generated (by division) from the system clock and center-sampled at the receiving module. The situation is as follows:
We have an ADC that our FPGA is sending data to. The interface to the ADC is source-synchronous: we forward a clock along with the data. It is also center-sampled in that we generate the data (at the FPGA) on the falling edge of the forwarded clock, and capture the data on the rising edge of the forwarded clock. To add to the complexity, this forwarded clock is generated by dividing the system clock. We want to be able to set the output delay of this forwarded clock/data so we can specify the setup and hold times of the ADC. The issue is that we are unsure how to specify the multicycle constraints such that Vivado figures out the correct launch and capture edge.
In real life, our forwarded clock is only divided by two from the system clock, but we want to know how to do this in the most general case, and so we'll set the division rate to eight for the sake of example.
Visualization
Waveform showing clk, generated (/8) clock, and data. Data is launched on falling edge of generated clock, and captured on rising edge of generated clock:
The big issue is figuring out the correct multicycle constraints. There seems to be no intuitive way to specify that data is launched on the falling edge of the generated clock and captured by the rising edge. The main issue is that the data is actually generated by the system clock - an FSM (that creates the generated clock) ensures that new data is only launched on edges where the generated clock falls. The "launch clock" is thus the system clock, while the "capture clock" is SCKO.
Below is a drawing of the system; SDO and SCKO are outputs of the FPGA:
Attempted Solutions
We were able to quite easily solve the question of multicycling with regards to setup; in this case we set:
set_multicycle_path 4 -setup -from [get_clocks sys_clk] -to [get_clocks SCKO] -start
This makes sense - our capture edge is 4 cycles from our launch edge, so we push the setup time forward hold cycles. These 4 cycles are in terms of the system clock, so we make sure to use the -start flag so that the setup multiplier is in terms of the launch clock.
The question is: what should we do for the hold multicycle path, and why?
Research
For research, we can consult Vivado's UG903: Using Constraints. Of particular use is the section on multicycle paths - specifically the "Multicycles Between FAST-to-SLOW Clocks" section on page 117. But this only tells us how to handle an extended datapath - we don't understand how to apply this to our project, where we need to make sure Vivado knows that data is only launched on the falling edge of SCKO (which is NOT the clock that generates it - sys_clk generates it, but only certain rising edges of sys_clk).
We've tried cycling through different hold multipliers, but we're not sure what the correct way of doing this is. For our "divide by 2" example, we found that setting a hold multiplier of 1 would work - the path report seemed to indicate something we could convince ourselves was the right answer (namely, it started the "source clock" at one period after the "launch clock" - this would correspond to the launch path starting at the falling edge of the forwarded clock and the capture path starting at the rising edge of the forwarded clock.
We've also looked at several parameters for our generated clock, output delay, and set multicycle path constraints. We've looked at the "-clock_fall" flag, but this tells the tool that we want to capture on the falling edge (when we actually need to tell it to launch on the falling edge, but of a different clock). We've also looked at "-rise" and "-fall", but haven't been able to really figure out what those do or what effect they have.
Question
In short: what is the correct multi-cycle constraint to put here, and why?