Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
15 years ago

timing constraints for EHPI DSP to FPGA asynchronous interface

Hi, I am trying to write timing constraints for connecting a TI DSP, TMS320VC5510A, to a Cyclone IV FPGA. The bus used is EHPI in Multiplexed mode. It looks confusing because the interface is asynchronous, based on HDS / ADS {data and address strobes} which time the latching of data / addresses / control information to/from the DSP/FPGA. I am not sure yet how best to implement the SDC constraints. Does anybody have experience doing this ?

I have been using Rsycs excellent User Guide for TimeQuest, but it hasnt yet become clear how to optimally constrain such an asynchronous interface !

Many thanks, DrPositiveLogic

20 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Is it a top-level register? I would normally assume there is a hierarchy path to it. (Note that I recommend get_keepers over get_registers. Either should work, but get_registers isn't a true .sdc command and was added by Altera, where get_keepers is more standardized). In TimeQuest go to View -> Name Finder and use that try and whittle down why it isn't matching. Or go to the Technology Map viewer and look for it there. There's a chance it got synthesized out or something, but most likely it's just a name matching issue. Another thought is to run:

    report_path -to [get_ports hds_n] -panel_name test

    and see what is driving it.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc....i'm getting there (I think !)....but i see this warning during project compilation fro Quartus:

    Warning: Ignored filter at AlteraIOTiming_Strobed_TestProject.sdc(35): hds_ni could not be matched with a register

    # Create Generated Clock for STROBE from PLL driving REG

    create_generated_clock -name HAD_STROBE_REG -source EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0] [get_registers hds_ni]

    Even though hds_ni is a register in my design driving output pin : hds_n

    Not sure what is happening here !

    cheers
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Looks correct. Look at the messages when reading in the .sdc and updating the netlist. I'm guessing there's a warning or two.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc, Thanks again for your brilliant help :)

    I see what you mean about my generated clock error ( although i

    didnt quite get what you meant about a space in the name ?)...i see i have missed off the get_registers / get_ports commands).

    In the design the REG hds_ni is driven from the PLL clock output :

    EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0]

    The output pin is : hds_n, which is fed by the REG output. hds_ni ...so

    now i have created the following constaints :

    # Create Generated Clock for STROBE from PLL driving REG

    create_generated_clock -name HAD_STROBE_REG -source EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0] [get_registers hds_ni]# Create Generated Clock for STROBE to output pin

    create_generated_clock -name HAD_STROBE -source HAD_STROBE_REG [get_ports hds_n]

    Does this look remotley correct ?

    When i run your report commands though i still get zero setup and hold paths for these paths.

    many thanks
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Are your generated clocks working? I see a space in the -source clock name, which would break it, and I don't see it applied to anything. I would expect something like:

    create_generated_clock -name HAS_STROBE -source EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0] [get_ports HAS_STROBE]

    (I don't know the name of the port, but guessing HAS_STROBE)

    If the generated clock isn't correct, then it all falls apart and I would expect it to not have any timing, since you use those clocks for the rest of the design.

    Does the PLL drive the strobes directly, or does it drive a register that drives the strobe? If the latter, you need to put a generated clock on the register from the PLL, and then one on the output port where the source is the register.

    When you run

    report_timing -setup -npaths 100 -detail full_path -to_clock HAS_STROBE -panel_name "HAS_STROBE||setup"

    report_timing -hold -npaths 100 -detail full_path -to_clock HAS_STROBE -panel_name "HAS_STROBE||hold"

    Make sure the data required path shows the entire clock path from inclk0, through the PLL, through the register(if there is one) and out the port. If it doesn't, that needs to be fixed before worrying about multicycles and what values for -min/-max.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc, thanks for your second response, which i have been trying to implement...here s my SDC file so far, copied below. The HAS_STROBE and HAD_STROBE are both defined as clocks, HAS is the address strobe and clocks out HAD pins 0 and 1, a 2 bit address reg select to the DSP. HAD strobe clocks out the 16 bit data bus.

    When i compile my design and then run 'report all I/O timings' i get the follwoing messagese for TimeQutes:

    Info: Report Timing: No setup paths were found

    Info: Report Timing: No hold paths were found

    Info: Report Timing: No recovery paths were found

    Info: Report Timing: No removal paths were found

    Info: Report Timing: No setup paths were found

    Info: Report Timing: No hold paths were found

    Info: Report Timing: No setup paths were found

    Info: Report Timing: No hold paths were found

    ...i wonder what i am doing wrong ! It seems just about everything so far !

    thanks for your help:oops:

    # Define TMS320TLV5510 Timing Parameters

    set DSP_Tsu 4

    set DSP_Th 4

    set DSP_TcoMax 16

    set DSP_TcoMin 6# set max and min est DSP to FPGA delays

    set Max_fpga2dsp 2

    set Min_fpga2dsp 1# set max / min OUTPUT delays

    set OutputDelayMax [expr $DSP_Tsu + $Max_fpga2dsp]

    set OutputDelayMin [expr $DSP_TcoMin + $Min_fpga2dsp]# set max / min INPUT delays

    set InputDelayMax [expr $DSP_TcoMax + $Max_fpga2dsp]

    set InputDelayMin [expr -1*$DSP_Th + $Min_fpga2dsp]# Set period for EHPI base clock

    set ehpi_base_period 12.82# create constraint for input clock pin to PLL

    create_clock -name inclk0 -period $ehpi_base_period [get_ports inclk0]

    derive_pll_clocks

    derive_clock_uncertainty

    set_clock_groups -asynchronous

    -group {inclk0

    EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0]

    }# Create Generated Clock for STROBE write output HAS

    create_generated_clock -name HAS_STROBE -source EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0]# Create Generated Clock for STROBE write output HAD

    create_generated_clock -name HAD_STROBE -source EHPI_PLL_inst|altpll_component|auto_generated|pll1|clk[0]

    set_multicycle_path -setup 0 -to [get_clocks HAS_STROBE]

    set_multicycle_path -setup 0 -to [get_clocks HAD_STROBE]# *************************************************************************************************************# Set Multicycles on EHPI to DSP data output bus : 2 clocks# *************************************************************************************************************

    set_multicycle_path -from [get_ports {had

    [*]}] -to [get_registers {bidir_interface:uut|hdata

    [*]}] -setup -end 2

    set_multicycle_path -from [get_ports {had

    [*]}] -to [get_registers {bidir_interface:uut|hdata

    [*]}] -hold -end 1# *************************************************************************************************************# Set Multicycles on DSP to EHPI data input bus : 2 clocks# *************************************************************************************************************

    set_multicycle_path -from [get_registers {bidir_interface:uut|hdout

    [*]}] -to [get_ports {had

    [*]}] -setup -start 2

    set_multicycle_path -from [get_registers {bidir_interface:uut|hdout

    [*]}] -to [get_ports {had

    [*]}] -hold -start 1

    # *************************************************************************************************************# Constrain DSP to EHPI Input ports# *************************************************************************************************************# input MAX delay on HAD bus : using EHPI Virtual Data Strobe

    set_input_delay -clock { HAD_STROBE } -max $InputDelayMax [get_ports {had

    [*]}]# input MIN delay on HAD bus : using EHPI Virtual Data Strobe

    set_input_delay -clock { HAD_STROBE } -min $InputDelayMin [get_ports {had

    [*]}]# input MAX delay on HAS bus : using EHPI Virtual Address strobe

    set_input_delay -clock { HAS_STROBE } -max $InputDelayMax [get_ports {had[0] had[1]}]# input MIN delay on HAD bus : using EHPI Virtual Address strobe

    set_input_delay -clock { HAS_STROBE } -min $InputDelayMin [get_ports {had[0] had[1]}]# input MAX delay on RDY, D2H ACK and D2H REQ lines : using EHPI Data Strobe

    set_input_delay -clock { HAD_STROBE } -max $InputDelayMax [get_ports {h2dack_n[0] h2dack_n[1] d2hreq[0] d2hreq[1] hrdy[0] hrdy[1]}]# input MAX delay on RDY, D2H ACK and D2H REQ lines : using EHPI Data Strobe

    set_input_delay -clock { HAD_STROBE } -min $InputDelayMin [get_ports {h2dack_n[0] h2dack_n[1] d2hreq[0] d2hreq[1] hrdy[0] hrdy[1]}]# *************************************************************************************************************# Constrain DSP to EHPI Output ports# *************************************************************************************************************# Output MAX delay on HAD bus : using EHPI Virtual clock

    set_output_delay -clock { HAD_STROBE } -max $OutputDelayMax [get_ports {had

    [*]}]# Output MIN delay on HAD bus : using EHPI Virtual clock

    set_output_delay -clock { HAD_STROBE } -min $OutputDelayMin [get_ports {had

    [*]}]# Output MAX delay on control signals hds,has,hcs : using EHPI Data Strobe

    set_output_delay -clock { HAD_STROBE } -max $OutputDelayMax [get_ports {has_n hcs_n[0] hcs_n[1] hds_n hrnw d2hack_n[0] d2hack_n[1]}]# Output MIN delay on control signals hds,has,hcs : using EHPI Data Strobe

    set_output_delay -clock { HAD_STROBE } -min $OutputDelayMin [get_ports {has_n hcs_n[0] hcs_n[1] hds_n hrnw d2hack_n[0] d2hack_n[1]}]# Output MAX delay on HAS bus : using EHPI Virtual Address strobe

    set_output_delay -clock { HAS_STROBE } -max $OutputDelayMax [get_ports {had[0] had[1]}]# Output MIN delay on HAD bus : using EHPI Virtual Address strobe

    set_output_delay -clock { HAS_STROBE } -min $OutputDelayMin [get_ports {had[0] had[1]}]
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I probably won't be able to do that, but...

    1) The first thing you need to get is your clocks correct. If the FPGA is sending a clock, then you don't want a virtual clock. You put a generated clock on the output port, where the -source is the output of the PLL. If a register drives the strobe off chip, then you need a generated clock on the register(and the -source of that is the PLL output), and then another generated clock on the output port, where the -source is the register. This tells how the clock gets off chip, and the entire path will be used in timing analysis.

    2) For your set_output_delays, the -clock option will use the generated clock you created on the output port.

    3) You will have a default setup and hold relationship. For example, let's say both clocks are 80MHz, so you have a 12.5ns setup relationship and 0ns hold relationship. Taking the setup side first, your logic will not send data and strobe it on every cycle. Let's say you send data out on a cycle and the strobe out 3 cycles later. You would need:

    set_multicycle_path -setup 3 -from [get_clocks {PLL|clk[0]}] -to [get_clocks {strobe_clk}]

    In this case the -from clock is the PLL driving the 80MHz clock that creates your logic and the strobe_clk would be the name of the generated clock you put on the output port. This would make the setup relationship 37.5ns(I have no idea if this is what you want, it depends on the logic). Finally you would change the -max value on the set_output_delay to account for the Tsu of the other device, as well as board skew.

    4) Now do the same for the hold. Since you modified the setup relationship, the default hold is now 25ns. Let's say your system works that the data doesn't change until 1 cycle after the previous strobe. If you add:

    set_multicycle_path -hold 3 -from [get_clocks {PLL|clk[0]}] -to [get_clocks {strobe_clk}]

    I did 3, because it takes 2 cycles to get it back to a 0ns, and a third one to get a -12.5ns hold relationship(the user guide section on multicycles covers all this)

    5) Again, change the -min value to account for board delays and Th of the other device.

    On the input side, does the clock being sent by the FPGA out the strobe port generate the data coming back, or does something else? If the FPGA's strobe output generates the returning data, then you would use that strobe clock on your set_input_delay constraints, and the -max and -min values would be represent the longest and shortest round-trip delays from the strobe going out to data coming back.

    If the input data is coming from another source(say the DSP is driven by an oscillator), then you would use a virtual clock.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Rysc...what might prove rally helpfull to me would be an example in SDC syntax of constraining a simple sort of async interface ....such as what constraints to apply to the HAD I/O bus (which is Tristatable), how to create the clocks (HAS and HDS) based on the strobes....i assume i would create a couple of Virtual clocks here.....and what sort of MC constrainst i need ?

    many thanks, Dr+VLogic !
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello there and thanks for the reply. I think your analys is spot on. There are two strobes: HAS and HDS. The falling edge of HAS is intended to latch in the HAD (16 bit Multiplexed data bus) on its falling edge. The HDS strobe is intended to latch in the HAD bus (data this time) on its rising edge. There are setup and hold timings given in the TI datasheet for everything, HAS to HDS setup/hold, HAS to HAD setup/hold, HDS to HAD setup/hold etc.

    My problem is that i dont know really how to implement these constraints in TimeQuest SDC format. I believe i would need to apply :

    set_input_delay and set_output_delay (i have been reading your excellent UserGuide here to help: pages 14-29 so far are an aid !)....but should i create a Virtual clock for the HAS and HDS strobe outputs (output from the FPGA) and time all I/O with respcet to them ?

    The set_multicycle_path constaint will be needed i think, because the FPGA runs at about 80MHz, and the maximum TCO from the DSP is around 16 ns...ie > 1 clock.

    The actual interface inside the FPGA is driven by an FSM, which inherently adds delays (ie one clock wide minimum) to each of the drievn and read signal paths...ie it delays the HDS by a clock after the HAS signal is driven low....and sets up the HAD bus for a write a clock earlye etc. In a way its self timed and self constrained i suppose. BUT this doest help Quartus and TimeQuest, which is why i still need to apply some sensible SDC timing constraints i think.

    Many thanks for your help, DR Positive Logic !
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I haven't looked at the actual device or constraints, but generally with "asynchronous logic", the strobe should be treated as a clock. Note that if it were truly asynchronous, you wouldn't time it. Just because the clock isn't always periodic, you have a max and min relationship between the data and that strobe.

    More often than not, even with the clocks set up, you have setup and hold relationships that are too restrictive, since they assume data is sent on ever edge. So you most likely need to add multicycles to the interface to get the setup relationship and hold relationship correct. (Note that you need to know what it should be before adding multicycles. Then add the MCs to match the requirement).

    The final thing is adding the -max and -min external delays, which are usually a small component.

    I "think" this will help, but not having tread the datasheet, may be way off base.