• 0

Nexys4 DDR: Fix hold time violation

Go to solution Solved by artvvb,



I am using Vivado 2016.4 to program the Nexys4 DDR 7-segment display.

I have a very simple VHDL project, which works as follows:

  • 100 MHz clock is used to increment an 8-bit counter
  • when this counter overflows, it inverts the value of a local signal called "slowclk". Hence, "slowclk" is "clk" divided by 512.
  • the "slowclk" is used to increment another 8-bit counter, the output of which is assigned to the 7-segment display segment selector pins on the board.

Complete VHDL source:


library IEEE;


entity segdisp is

    port (    clk    : in    std_logic;
        seg_en    : out    std_logic_vector(7 downto 0);
        seg_cs    : out    std_logic_vector(7 downto 0) );

architecture top of segdisp is
    signal r_count: natural range 0 to 255 := 0;
    signal disp_next: std_logic := '0';

    signal seg_cs_int: natural range 0 to 255;

    signal clkdiv: natural range 0 to 255 := 0;
    signal slowclk: std_logic := '0';
    function int2slv(arg: integer; length: positive) return std_logic_vector is
        return std_logic_vector(to_unsigned(arg, length));
    end function;
    seg_cs <= int2slv(seg_cs_int, seg_cs'length);
    seg_en <= not X"80";

    divider: process (clk)
        if rising_edge(clk) and clk = '1' then
            if clkdiv = 255 then
                clkdiv <= 0;
                slowclk <= not slowclk;
                clkdiv <= clkdiv + 1;
            end if;
        end if;
    end process;

    main: process (slowclk)
        if rising_edge(slowclk) and slowclk = '1' then
            seg_cs_int <= seg_cs_int + 1;
        end if;
    end process;
end architecture top;

Note: I understand that given such division, the effect on the digit segments will still not be visible - I just want to demonstrate the timing problem.

However, the design fails to meet timing constraints as follows in attached pictures:



Timing constraint failures in more detail, including the full source VHDL:


Clock routing on the FPGA:


The following is the .xdc constraints file (commented-out definitions are omitted):



## Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports { clk }]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0.000 5.000} [get_ports { clk }]


set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {seg_cs[7]}]
set_property -dict {PACKAGE_PIN R10 IOSTANDARD LVCMOS33} [get_ports {seg_cs[6]}]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {seg_cs[5]}]
set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports {seg_cs[4]}]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {seg_cs[3]}]
set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports {seg_cs[2]}]
set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {seg_cs[1]}]

set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {seg_cs[0]}]

set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {seg_en[0]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {seg_en[1]}]
set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports {seg_en[2]}]
set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {seg_en[3]}]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {seg_en[4]}]
set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {seg_en[5]}]
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {seg_en[6]}]
set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {seg_en[7]}]


set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]

set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]


From what little I know about FPGA clock routing and resources, I understand this to be due to the high-frequency clock and associated logic being in different regions to each other, thus requiring the implementation run to route the clock signal through awkward paths; as a consequence, the total signal propagation time is such, that before the logic relevant to the current clock pulse is evaluated, the next clock front is already present.

Am I correct in this thinking? And in either case, how can I fix the timing issues that Vivado warns about?

Edited by maximb
Amend formatting
Link to post
Share on other sites

2 answers to this question

Recommended Posts

  • 1
  • Solution


This type of issue is typical of a logic-gated clock. Usually you can get around it by replacing slowclk with an enable strobe and clocking all of your processes on the main fast clock signal.

Pseudocode of what I mean follows:

generate_strobe: process (clk)
    if rising_edge(clk) then
        if <statement> then --however you would normally toggle slowclk froom low to high
            slowclk_strb <= 1;
            slowclk_strb <= 0;
        end if;
    end if;
end process;

using_the_strobe: process (clk)
    if rising_edge(clk) then
        if slowclk_strb = 1 then
            <do stuff>;
        end if;
    end if;
end process;

Hope this helps,


Edited by artvvb
formatting of code block
Link to post
Share on other sites
  • 0


The logic clock issue is one of the several common digilent forum requests I've come across.

This article discusses several different approaches for demonstrating timing, different from the logic clock you've outlined above.  You might find that some of these reiterate what @artvvb commented above.

Crossing clock domains is also a very difficult issue to deal with.  This paper discusses many of the solutions, together with some of the reasons why crossing clock domains is generally a bad idea.


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now