alexforencich / verilog-axis

Verilog AXI stream components for FPGA implementation
MIT License
747 stars 229 forks source link

async FIFO timing constraints for Vivado #6

Open caryan opened 8 years ago

caryan commented 8 years ago

I'm not sure where these should be documented but it would be nice for the user to have a template to get the constraints right for Vivado. After, poking around in the FIFO from Xilinx and Xilinx forums, this works for me:

#grey coded counter synchronizers in  get a max_delay -datapath only
set wrclk [get_clocks -of_objects [get_ports input_clk]]
set rdclk [get_clocks -of_objects [get_ports output_clk]]
set_max_delay -from [get_cells fifo_inst/wr_ptr_gray_reg_reg[*]] -to [get_cells fifo_inst/wr_ptr_gray_sync1_reg_reg[*]] -datapath_only [get_property -min PERIOD $wrclk]
set_max_delay -from [get_cells fifo_inst/rd_ptr_gray_reg_reg[*]] -to [get_cells fifo_inst/rd_ptr_gray_sync1_reg_reg[*]] -datapath_only [get_property -min PERIOD $rdclk]

#set ASYNC_REG property for all registers in the grey code synchronizer chain
set_property ASYNC_REG TRUE [get_cells -regexp {fifo_inst/(wr|rd)_ptr_gray_sync[12]_reg_reg\[\d+\]}]

#ASYNC_REG property and false path to the reset synchronizer
set_property ASYNC_REG TRUE [get_cells -regexp {fifo_inst/(input|output)_rst_sync[123]_reg_reg}]
set_false_path -to [get_cells -regexp {fifo_inst/(input|output)_rst_sync[123]_reg_reg}]
set_false_path -from [get_cells fifo_inst/output_rst_sync1_reg_reg] -to [get_cells fifo_inst/input_rst_sync2_reg_reg]
alexforencich commented 8 years ago

Yeah, that sort of stuff should probably go in the readme somewhere. And possibly in an example design of some sort. What I do in ISE is constrain the top-level clocks and then let those constraints propagate down to the instances. That seems to be all that is necessary to make it work. However, Vivado may need a bit more.

caryan commented 8 years ago

FWIW I now use a tcl script for the Vivado constraints:

set async_fifos [get_cells -hier -filter {(ORIG_REF_NAME == axis_async_fifo || REF_NAME == axis_async_fifo || ORIG_REF_NAME == axis_async_frame_fifo || REF_NAME == axis_async_frame_fifo)}]

foreach fifo $async_fifos {
    puts $fifo
    # ASYNC_REG property on the reset synchronizer flip-flops
    set reset_ffs [get_cells -hier -regexp {.*/(in|out)put_rst_sync[123]_reg_reg} -filter "PARENT == $fifo"]
    set_property ASYNC_REG TRUE $reset_ffs

    # false path to reset pins on the reset synchronizer flip-flops
    set_false_path -to [get_pins -of_objects $reset_ffs -filter {IS_PRESET || IS_RESET}]

    # false path to the second stage reset synchronizer flip-flops data
    set_false_path -to [get_pins $fifo/input_rst_sync2_reg_reg/D]
    set_false_path -to [get_pins $fifo/output_rst_sync2_reg_reg/D]

    # max delayto 2ns to maximize metastability settle time
    set_max_delay -from [get_cells $fifo/input_rst_sync2_reg_reg] -to [get_cells $fifo/input_rst_sync3_reg_reg] 2
    set_max_delay -from [get_cells $fifo/output_rst_sync2_reg_reg] -to [get_cells $fifo/output_rst_sync3_reg_reg] 2

    # set ASYNC_REG property for all registers in the grey code synchronizer chain
    set_property ASYNC_REG TRUE [get_cells -hier -regexp {.*/(wr|rd)_ptr_gray_sync[12]_reg_reg\[\d+\]} -filter "PARENT == $fifo"]

    # extract write/read clocks from the grey code registers
    set read_clk [get_clocks -of_objects [get_pins $fifo/rd_ptr_reg_reg[0]/C]]
    set write_clk [get_clocks -of_objects [get_pins $fifo/wr_ptr_reg_reg[0]/C]]

    # rd_ptr_gray_sync is synchronized from the read clock to the write clock so
    # we use the read clock (launch clock) period to constrain the max_delay
    set_max_delay -from [get_cells $fifo/rd_ptr_gray_reg_reg[*]] -to [get_cells $fifo/rd_ptr_gray_sync1_reg_reg[*]] -datapath_only [get_property -min PERIOD $read_clk]
    # similarly we uuse the write clock period to constrain the max_delay for the wr_ptr_gray_sync
    set_max_delay -from [get_cells $fifo/wr_ptr_gray_reg_reg[*]] -to [get_cells $fifo/wr_ptr_gray_sync1_reg_reg[*]] -datapath_only [get_property -min PERIOD $write_clk]

    # for async_frame_fifos there are a few more status synchronization registers
    if {[string match [get_property ORIG_REF_NAME [get_cells $fifo]] axis_async_frame_fifo] || [string match [get_property REF_NAME [get_cells $fifo]] axis_async_frame_fifo]} {
        set status_sync_regs [get_cells -quiet -hier -regexp {.*/(?:overflow|bad_frame|good_frame)_sync[1234]_reg_reg} -filter "PARENT == $fifo"]
        foreach reg $status_sync_regs {
            set_property ASYNC_REG TRUE $reg
        }
    }
}