How do I solve this delta cycle clock delay issue

Viewed 3726

I have the following simplified example of my code, where the DeltasTest entity can be simulated to show the issue. The clock in the real design is inverted or not based on a generic, and feeds several other entities below this one.

The problem is that the simple edge detector does not work (data_out is just a glitch) in behavioral simulation, due to the delta cycle delay introduced on the clock by the inversion stage. Is there a standard or otherwise elegant way to solve this?

So far my best solution is to assign the data_in signal to another signal, to give it the same delta cycle delay as clk. I thought of using a function to invert the clock as necessary based on the generic as a second parameter to the function, but the clock is used in many places and this did not seem very elegant, and I was note sure it would even solve the problem. Clutching at straws, I also tried making the clock inversion assignment a transport assignment, but, as expected, this made no difference.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Deltas is
    Generic (
        CLK_INVERT : boolean := false
    );
    Port (
        clk : in std_logic;
        data_in : in std_logic
    );
end Deltas;

architecture Behavioral of Deltas is

    -- Signals
    signal data_reg : std_logic := '0';
    signal clk_inverted : std_logic := '0';
    signal data_out : std_logic := '0';

begin

    ClkInvert : if (CLK_INVERT) generate
        clk_inverted <= not clk;
    else generate
        clk_inverted <= clk;
    end generate;

    process (clk_inverted)  
    begin
        if (rising_edge(clk_inverted)) then
            data_reg <= data_in;
        end if;
    end process;

    process (data_reg, data_in) 
    begin
        if (data_reg /= data_in) then
            data_out <= '1';
        else
            data_out <= '0';
        end if;
    end process;

    -- Other entities use `clk_inverted`. Commented out so that this example compiles
    --LowerEntity : entity work.Counter
    --port map (
    --  clk => clk_inverted
    --);

end Behavioral;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity DeltasTest is
end DeltasTest;

architecture Behavioral of DeltasTest is

    signal clk : std_logic := '0';
    signal data_in : std_logic := '0';

begin

    clk <= not clk after 10 ns;

    process (clk)
        variable count : integer := 0;
    begin
        if (rising_edge(clk)) then
            count := count + 1;
            if (count = 4) then
                count := 0;
                data_in <= not data_in;
            end if;
        end if;
    end process;

    uut : entity work.Deltas
    Port map (
        clk => clk,
        data_in => data_in
    );

end Behavioral;
3 Answers

How about using the older style of clock and replacing CLK_INVERT with CLK_POLARITY. Haven't done it myself, but I am pretty sure I have seen it somewhere.

entity Deltas is
    Generic (
        CLK_POLARITY : std_logic := '1'
    );
    Port (
        clk : in std_logic;
        data_in : in std_logic
    );
end Deltas;
architecture Behavioral of Deltas is
    signal data_reg : std_logic;
    signal data_out : std_logic;

begin

    process (clk)  
    begin
        if clk = CLK_POLARITY and clk'event then
            data_reg <= data_in;
        end if;
    end process;

This raises a bigger issue, how does one write IP that may for different designs need different clock polarity (as done here), different reset polarity, and different reset styles (asynchronous reset vs synchronous reset). I think we need a package of procedures that implements flip-flops. In addition to purpose built ones DFF with asynchronous reset, I think we could also have things like DFFR (DFF with reset) whose implementation is determined by the package body used.

-- In package body asynchronous resets
procedure DFFR (
  signal Clk   : std_logic ; 
  signal Reset : std_logic ; 
  signal DataIn : std_logic ;
  signal DataOut : std_logic ;
  constant ResetValue : std_logic 
) is
begin
  if Reset = RESET_POLARITY then 
    DataOut <= ResetValue ; 
  elsif Clk = CLOCK_POLARITY and Clk'event then 
    DataOut <= DataIn ; 
  end if ;
end procedure DFFR ; 

-- In package body synchronous resets
procedure DFFR (
  signal Clk   : std_logic ; 
  signal Reset : std_logic ; 
  signal DataIn : std_logic ;
  signal DataOut : std_logic ;
  constant ResetValue : std_logic 
) is
begin
  if Clk = CLOCK_POLARITY and Clk'event then 
    if Reset = RESET_POLARITY then 
      DataOut <= ResetValue ; 
    else
      DataOut <= DataIn ; 
    end if ;
  end if ; 
end procedure DFFR ; 

-- In package body power on reset by initialization
procedure DFFR (
  signal Clk   : std_logic ; 
  signal Reset : std_logic ; 
  signal DataIn : std_logic ;
  signal DataOut : std_logic ;
  constant ResetValue : std_logic 
) is
begin
  if Clk = CLOCK_POLARITY and Clk'event then 
    DataOut <= DataIn ; 
  end if ;
end procedure DFFR ; 

Designs that make different decisions for different clock domains would need a separate library for each clock domain.

The upcoming IEEE 1076-2018 is doing a pilot for IEEE open source to open source the current VHDL packages. Maybe we can get this in the next revision - however, currently I have more ideas than I have time, so we need more participants.

Related