Search code examples
vhdlfpga

VHDL short form to trigger actions on raising edges


I wonder if there is a shorter way to trigger on signal edges that are not the clock.

Consider the following example:

  signal clock               : std_logic;
  signal ready               : std_logic;  -- comes from some slow component
  signal last_ready          : std_logic;
  signal some_rare_condition : std_logic;

  ----------------------------------

  process (clock) is 
  begin

    if rising_edge (clock) then

      if (some_rare_condition = '1') then

        if (ready = '1') and (last_ready = '0') then
          -- do something here, writing data to UART for example.
        end if;

        last_ready <= ready;

      end if;
    end if;
  end process;

Here I want to do something if the signal 'ready' got a raising edge. The raising edge should only be evaluated if some_rare_condition is true.

I currently just remember the last state of the ready signal in a latch and build the edge detection logic myself.

Question: Is there a shorter, more elegant way to do this?

The way I do it right works just fine, but I litter up my code with all these last_ready signals. This seem to be such a common paradigm that I think I miss some language or library construct that helps me to keep my code clean and lean.


Solution

  • You can write a rising or falling edge detection in two lines:

    • a simple D-FF to register the old signal
    • a comparison for the rising edge

    Example code:

    signal MMCM_Locked      : STD_LOGIC;
    signal MMCM_Locked_d    : STD_LOGIC     := '0';
    signal MMCM_Locked_re   : STD_LOGIC;
    
    -- detect rising edge on CMB locked signals
    MMCM_Locked_d   <= MMCM_Locked          when rising_edge(Control_Clock);
    MMCM_Locked_re  <= not MMCM_Locked_d    and MMCM_Locked;
    

    Edit 1

    Of cause, you can also add an enable to this one-liner D-FF by defining some FF functions (this is still synthesizeable !).

    -- d-flipflop with reset and enable
    function ffdre(q : STD_LOGIC; d : STD_LOGIC; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
    begin
        return ((d and en) or (q and not en)) and not rst;
    end function;
    
    function ffdre(q : STD_LOGIC_VECTOR; d : STD_LOGIC_VECTOR; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC_VECTOR is
    begin
        return ((d and (q'range => en)) or (q and not (q'range => en))) and not (q'range => rst);
    end function;
    
    -- d-flipflop with set and enable
    function ffdse(q : STD_LOGIC; d : STD_LOGIC; set : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
    begin
        return ((d and en) or (q and not en)) or set;
    end function;
    
    -- t-flipflop with reset and enable
    function fftre(q : STD_LOGIC; rst : STD_LOGIC := '0'; en : STD_LOGIC := '1') return STD_LOGIC is
    begin
        return ((not q and en) or (q and not en)) and not rst;
    end function;
    
    -- rs-flipflop with dominant rst
    function ffrs(q : STD_LOGIC; rst : STD_LOGIC := '0'; set : STD_LOGIC := '0') return STD_LOGIC is
    begin
        return (q or set) and not rst;
    end function;
    
    -- rs-flipflop with dominant set
    function ffsr(q : STD_LOGIC; rst : STD_LOGIC := '0'; set : STD_LOGIC := '0') return STD_LOGIC is
    begin
        return (q and not rst) or set;
    end function;
    

    Example:

    mySignal_d <= ffdre(q => mySignal_d, d => mySignal, en => myEnable) when rising_edge(Clock);