| # Copyright 2023 Google LLC |
| # Copyright lowRISC contributors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| ## Clock Signal - 100M >> 1/100e6 = 1e-8s = 10ns |
| create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports IO_CLK] |
| |
| ## Rename MMCM outputs for less bug-prone parsing. |
| ## Some auto-derived clocks can have names that include brackets. |
| create_generated_clock -name clk_main [get_pin clkgen/pll/CLKOUT0] |
| create_generated_clock -name clk_usb_48 [get_pin clkgen/pll/CLKOUT1] |
| create_generated_clock -name clk_aon [get_pin clkgen/pll/CLKOUT4] |
| |
| # Store clock periods in variables |
| set clk_main_period [get_property PERIOD [get_clocks clk_main]] |
| set clk_usb_48_period [get_property PERIOD [get_clocks clk_usb_48]] |
| set clk_aon_period [get_property PERIOD [get_clocks clk_aon]] |
| |
| ## Clock Domain Crossings |
| set clks_10_unbuf [get_clocks -of_objects [get_pin clkgen/pll/CLKOUT0]] |
| set clks_48_unbuf [get_clocks -of_objects [get_pin clkgen/pll/CLKOUT1]] |
| set clks_aon_unbuf [get_clocks -of_objects [get_pin clkgen/pll/CLKOUT4]] |
| |
| ## Divided clock |
| ## This is not really recommended per Vivado's guidelines, but hopefully these clocks are slow enough and their |
| ## destination flops few enough. |
| |
| set u_pll clkgen/pll |
| set u_div2 top_*/u_clkmgr_aon/u_no_scan_io_div2_div |
| create_generated_clock -name clk_io_div2 -source [get_pin ${u_pll}/CLKOUT0] -divide_by 2 [get_pin ${u_div2}/u_clk_div_buf/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/O] |
| |
| #Recommended Div4 clock constraints from Xilinx |
| #TODO uncomment below line and integrate u_div4 in path to make constraint more generic |
| set u_div4 top_*/u_clkmgr_aon/u_no_scan_io_div4_div |
| create_generated_clock -name clkDiv4 -divide_by 4 -source [get_pins ${u_div4}/gen_div.clk_int_reg/C] [get_pins ${u_div4}/gen_div.clk_int_reg/Q] |
| |
| # |
| |
| # the step-down mux is implemented with a LUT right now and the mux switches on the falling edge. |
| # therefore, Vivado propagates both clock edges down the clock network. |
| # this implementation is not ideal - but we can at least tell Vivado to only honour the rising edge for |
| # timing analysis. |
| set_clock_sense -positive \ |
| [get_pins -filter {DIRECTION == OUT && IS_LEAF} -of_objects \ |
| [get_nets -segments -of_objects \ |
| [get_pin ${u_div2}/u_clk_div_buf/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/I] \ |
| ] \ |
| ] |
| |
| ## JTAG clocks -- JTAG clock max frequency is set to 500KHz |
| create_clock -add -name lc_jtag_tck -period 2000.00 -waveform {0 1000} [get_pin top_*/u_pinmux_aon/u_pinmux_strap_sampling/u_pinmux_jtag_buf_lc/prim_clock_buf_tck/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/O] |
| create_clock -add -name rv_jtag_tck -period 2000.00 -waveform {0 1000} [get_pin top_*/u_pinmux_aon/u_pinmux_strap_sampling/u_pinmux_jtag_buf_rv/prim_clock_buf_tck/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/O] |
| |
| set clk_spi_period 200 |
| set clk_spi_half_period [expr ${clk_spi_period} / 2] |
| ## SPI clocks |
| set spi_dev_data [get_ports {SPI_DEV_D0 SPI_DEV_D1 SPI_DEV_D2 SPI_DEV_D3}] |
| create_clock -add -name clk_spi -period ${clk_spi_period} -waveform "0 ${clk_spi_half_period}" [get_ports SPI_DEV_CLK] |
| create_clock -add -name clk_cs -period [expr $clk_spi_period * 10] |
| set_input_delay -clock clk_spi 5 ${spi_dev_data} -add_delay |
| set_output_delay -clock clk_spi 5 ${spi_dev_data} -add_delay |
| # set_input_delay -clock clk_spi -clock_fall -min ${spi_dev_in_delay_min} ${spi_dev_data} -add_delay |
| # set_input_delay -clock clk_spi -clock_fall -max ${spi_dev_in_delay_max} ${spi_dev_data} -add_delay |
| |
| ## Camera Clock |
| #8-bit, QVGA 60FPS @ 6MHz > setting to 10M to keep numbers round |
| #create_clock -add -name clk_cam_pclk -period 100.00 -waveform {0 50} [get_ports ISP_DVP_PCLK] |
| |
| ##SPI Host IO Delay |
| ## SPI Passthrough constraints |
| create_generated_clock -name clk_spi_pt -divide_by 1 -source [get_ports SPI_DEV_CLK] [get_ports SPI_HOST_CLK] |
| set spi_pt_data [get_ports {SPI_HOST_D0 SPI_HOST_D1 SPI_HOST_D2 SPI_HOST_D3}] |
| set_input_delay -clock clk_spi_pt -clock_fall 7 ${spi_pt_data} -add_delay |
| |
| set_output_delay -clock clk_spi_pt 7 ${spi_pt_data} -add_delay |
| set_output_delay -clock clk_spi_pt 7 [get_ports SPI_HOST_CS_L] -add_delay |
| |
| |
| |
| ## GPIO IO Delay |
| set ioa_muxed_ports [get_ports IOA*] |
| set iob_muxed_ports [get_ports IOB*] |
| set ioc_muxed_ports [get_ports IOC*] |
| set ioc_muxed_ports [get_ports IOD*] |
| set ior_muxed_ports [get_ports -filter {NAME != IOR8 && NAME != IOR9} IOR*] |
| set all_muxed_ports "${ioa_muxed_ports} ${iob_muxed_ports} ${ioc_muxed_ports} ${ior_muxed_ports}" |
| |
| set_input_delay -clock clkDiv4 5 [get_ports ${all_muxed_ports}] |
| set_output_delay -clock clkDiv4 5 [get_ports ${all_muxed_ports}] |
| |
| create_generated_clock -name clk_i2s_rx -divide_by 22 -source [get_pin ${u_pll}/CLKOUT1] [get_pins top_matcha/u_i2s0/i2s_core/bufg_rx_audio_clk/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/O] |
| create_generated_clock -name clk_i2s_tx -divide_by 22 -source [get_pin ${u_pll}/CLKOUT1] [get_pins top_matcha/u_i2s0/i2s_core/bufg_tx_audio_clk/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufg.bufg_i/O] |
| |
| |
| # set clock sense on the input to spi buffers to help the tool understand the clocks are shifted versions of each other |
| # This can also be accomplished through create_genearted_clocks. |
| |
| ## set clock sense approach |
| ##set_clock_sense -negative \ |
| ## [get_pins -filter {DIRECTION == OUT && IS_LEAF} -of_objects \ |
| ## [get_nets -segments -of_objects \ |
| ## [get_pins top_*/u_spi_device/gen_fpga_buf.gen_bufr.bufr_i_i_1/I] \ |
| ## ] \ |
| ## ] \ |
| ## -clocks clk_spi |
| ## |
| ##set_clock_sense -positive \ |
| ## [get_pins -filter {DIRECTION == OUT && IS_LEAF} -of_objects \ |
| ## [get_nets -segments -of_objects \ |
| ## [get_pins top_*/u_spi_device/gen_fpga_buf.gen_bufr.bufr_i_i_1__0/I] \ |
| ## ] \ |
| ## ] \ |
| ## -clocks clk_spi |
| |
| ## create_generated_clock appraoch |
| ## create_generated_clock is preferred since the buffer cell used here is hand-instantiated, while the set_clock_sense point is simply a LUT |
| create_generated_clock -name clk_spi_in -divide_by 1 -source [get_ports SPI_DEV_CLK] [get_pins top_*/u_spi_device/u_clk_spi_in_buf/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufr.bufr_i/O] |
| create_generated_clock -name clk_spi_out -divide_by 1 -source [get_ports SPI_DEV_CLK] [get_pins top_*/u_spi_device/u_clk_spi_out_buf/gen_xilinx.u_impl_xilinx/gen_fpga_buf.gen_bufr.bufr_i/O] -invert |
| |
| set_clock_groups -asynchronous \ |
| -group ${clks_10_unbuf} \ |
| -group ${clks_48_unbuf} \ |
| -group ${clks_aon_unbuf} \ |
| -group clk_io_div2 \ |
| -group clkDiv4 \ |
| -group lc_jtag_tck \ |
| -group rv_jtag_tck \ |
| -group {clk_spi clk_spi_in clk_spi_out clk_spi_pt} \ |
| -group clk_cs \ |
| -group sys_clk_pin \ |
| -group clk_i2s_rx \ |
| -group clk_i2s_tx |