1
\$\begingroup\$

I am working with VHDL for Xilinx FPGAs and I am trying to create some hierarchical components. When instantiating a component B inside another component A, what clk is expected to pass to the component B, a direct reference to the clk input port or is a bad practice assigning it to a signal before?

By the simulation a can guess that assigning the clk to a signal before can add some delay, which makes me think this is an valid trick or it could add some unexpected behaviour to the system.

Here is some Dummy operation over a std_logic_vector for example. I created a simple component and a combo component that uses two of simple component. I compared the behaviour of the simple component alone and the combo component in a simulation. Further in the bottom is shown the difference between assigning or not the clk to a signal during the simulation.

library ieee;                                                                                                                                
use ieee.std_logic_1164.all;                                                                                                                 
use ieee.numeric_std.ALL;                                                                                                                   

entity SimpleComponent is                                                                                                                    
    generic(                                                                                                                                 
        SC_IN_SIZE : NATURAL := 10                                                                                                           
    );                                                                                                                                       
    port(                                                                                                                                    
        in_clk  : in  std_logic := '0';                                                                                                      
        in_data : in  std_logic_vector(SC_IN_SIZE - 1 downto 0);                                                                             
        out_op  : out std_logic_vector(SC_IN_SIZE - 1 downto 0)                                                                              
    );                                                                                                                                       
end entity;                                                                                                                                  

architecture RTL of SimpleComponent is                                                                                                       

begin                                                                                                                                        

    COUNT_BITS : process(in_clk) is                                                                                                          
    begin                                                                                                                                    
        if rising_edge(in_clk) then                                                                                                          

            out_op <= not in_data;                                                                                                           

        end if;                                                                                                                              
    end process COUNT_BITS;                                                                                                                  

end architecture RTL;                                                                                                                        

Here comes the combo component (note the marked lines 59 and 60):

library ieee;                                                                                                                                
use ieee.std_logic_1164.all;                                                                                                                 
use ieee.numeric_std.all;                                                                                                                    

entity ComboComponent is                                                                                                                     
    generic(                                                                                                                                 
        CB_IN_SIZE : natural := 10;                                                                                                          
        COMB       : natural := 2                                                                                                            
    );                                                                                                                                       
    port(                                                                                                                                    
        in_clk  : in  std_logic                                 := '0';                                                                      
        in_data : in  std_logic_vector(CB_IN_SIZE - 1 downto 0) := (others => '0');                                                          
        out_op  : out std_logic_vector(CB_IN_SIZE - 1 downto 0) := (others => '0')                                                           
    );                                                                                                                                       
end entity ComboComponent;                                                                                                                   

architecture RTL of ComboComponent is                                                                                                        

    constant SPLITED_BITS : natural := CB_IN_SIZE / COMB;                                                                                    

    component SimpleComponent                                                                                                                
        generic(                                                                                                                             
            SC_IN_SIZE : NATURAL := SPLITED_BITS                                                                                             
        );                                                                                                                                   
        port(                                                                                                                                
            in_clk  : in  std_logic;                                                                                                         
            in_data : in  std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0');                                                    
            out_op  : out std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0')                                                     
        );                                                                                                                                   
    end component SimpleComponent;                                                                                                           

    type TY_SPLIT is array (COMB - 1 downto 0) of std_logic_vector(SPLITED_BITS - 1 downto 0);                                               

    signal SN_SPLIT_IN  : TY_SPLIT := (others => (others => '0'));                                                                           
    signal SN_SPLIT_OUT : TY_SPLIT := (others => (others => '0'));                                                                           

    signal SN_in_clk : std_logic := '0';                                                                                                     

begin                                                                                                                                        

    SN_in_clk <= in_clk;                                                                                                                     

    GEN_COMP : for I in COMB - 1 downto 0 generate                                                                                           

        GEN_SPLIT_BITS : for B in SPLITED_BITS - 1 downto 0 generate                                                                         

            SN_SPLIT_IN(I)(B)            <= in_data(SPLITED_BITS * I + B);                                                                   
            out_op(SPLITED_BITS * I + B) <= SN_SPLIT_OUT(I)(B);                                                                              

        end generate;                                                                                                                        

        SC_I : component SimpleComponent                                                                                                     
            port map(                                                                                                                        
                in_clk  => in_clk, --LINE 59                                                                                                 
--              in_clk  => SN_in_clk, --LINE 60                                                                                              
                in_data => SN_SPLIT_IN(I),                                                                                                   
                out_op  => SN_SPLIT_OUT(I)                                                                                                   
            );                                                                                                                               
    end generate;                                                                                                                            
end architecture RTL;                                                                                                                        

Test bench:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ComboComponentSim is
    generic(
        CB_IN_SIZE : natural := 20;
        COMB       : natural := 2
    );
end entity ComboComponentSim;

architecture RTL of ComboComponentSim is

    constant SPLITED_BITS : natural := CB_IN_SIZE / COMB;

    component SimpleComponent
        generic(
            SC_IN_SIZE : NATURAL := SPLITED_BITS
        );
        port(
            in_clk  : in  std_logic;
            in_data : in  std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0');
            out_op  : out std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0')
        );
    end component SimpleComponent;

    component ComboComponent
        generic(
            CB_IN_SIZE : natural := CB_IN_SIZE;
            COMB       : natural := COMB
        );
        port(
            in_clk  : in  std_logic;
            in_data : in  std_logic_vector(CB_IN_SIZE - 1 downto 0) := (others => '0');
            out_op  : out std_logic_vector(CB_IN_SIZE - 1 downto 0) := (others => '0')
        );
    end component ComboComponent;

    signal in_clk    : std_logic                                   := '0';
    signal in_dataCC : std_logic_vector(CB_IN_SIZE - 1 downto 0)   := (others => '0');
    signal in_dataSC : std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0');
    signal out_opCC  : std_logic_vector(CB_IN_SIZE - 1 downto 0)   := (others => '0');
    signal out_opSC  : std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0');

begin
    CC : component ComboComponent
        port map(
            in_clk  => in_clk,
            in_data => in_dataCC,
            out_op  => out_opCC
        );

    SC : component SimpleComponent
        port map(
            in_clk  => in_clk,
            in_data => in_dataSC,
            out_op  => out_opSC
        );
    stimuls : process
        variable tmp : std_logic_vector(SPLITED_BITS - 1 downto 0) := (others => '0');
    begin
        wait for 5 ns;

        tmp       := "0000000001";
        in_dataSC <= tmp;
        in_dataCC <= tmp & tmp;
        in_clk    <= '1';

        wait for 5 ns;
        in_clk <= '0';
        wait for 5 ns;

        tmp       := "0000000010";
        in_dataSC <= tmp;
        in_dataCC <= tmp & tmp;
        in_clk    <= '1';

        wait for 5 ns;
        in_clk <= '0';
        wait for 5 ns;

        tmp       := "0000000100";
        in_dataSC <= tmp;
        in_dataCC <= tmp & tmp;
        in_clk    <= '1';

        wait for 5 ns;
        in_clk <= '0';

    end process;
end architecture RTL;

Passing the clk port reference to component instantiation (LINE 60 commented):

enter image description here Assigning the clk to a signal and passing the signal to component instantiation (LINE 59 commented):

enter image description here

The clk assignment to a signal gives me the behaviour that I wanted, but I guess I'm break the clk synchronism along the system, since it is adding a unknown (unknown for me at least) delay to clks in some components. Is this a real problem?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Assigning the clock via a signal adds one delta cycle to the clock seen via that signal. If that "fixes" your simulation, you have a race condition (possibly clock assigned to a signal in somebody elses memory model) that may or may not appear in actual hardware. Thah's something worth understanding rather than burying under the carpet. \$\endgroup\$
    – user16324
    Apr 28, 2018 at 21:18
  • 1
    \$\begingroup\$ Considering what you sad, I realised that my test bench is not a realist one, since I set 1 to clk at same time that I set the values to my signals. This is a very unusual situation because usually the signals are assigned right after the clk edge, not at same time. Here is where I create the race condition. In this case, assigning the clk to a signal in ComboComponent was not the most important point, it just revealed a weird situation that was the concurrent definition of the clk and signals generated for test. Thanks @BrianDrummond ! \$\endgroup\$ May 1, 2018 at 1:05

1 Answer 1

0
\$\begingroup\$

Every element in real hardware has a delay, wire delay, or logic gate delay. Every FF flips with a certain delay after clock edge is applied, which is called "TCQ", clock to "Q" delay. However, in simplified behavioral simulations this delay is often neglected in synthesis tool. As result, the behavioral simulation would show instantaneous flip of all bits in a register with clock edge. This might create some false and unexpected states if the design is not done right. After realistic map and route, when all delays are realistically back annotated, the behavior might be different. The most notorious example is an asynchronous "ripple" counter, where the mere fact of TCQ creates ugly state transitions, which would be seen as simultaneous transitions in simple behavioral simulations.

To avoid the false behavior in first-round simulations, it is recommended to include explicit (small, arbitrary) delays in all clock-to-flop VHDL models/statements. Then the behavioral simulations will be no different form back-annotated ones.

\$\endgroup\$
1
  • \$\begingroup\$ The problem in this case was in the test bench signal generation. I set 1 to clk at same time I set the values passed to the input ports. This creates a race condition as mentined by @BrianDrummond . What I should have done, as you suggested, is have assigned values to the input signals some time after setting the clk (using wait for...) or created in the test bench a process that is clk sensitive and set the values to the input signals inside this clk sensitive process. \$\endgroup\$ May 1, 2018 at 1:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.