Bimo
Bimo

Reputation: 6647

What's the VHDL equivalent of Verilog $setup

I need a VHDL entity/architecture that does the exact same thing as this Verilog module below that uses the $setup keyword to check the timing on the inputs. Is there a way to do this natively in VHDL without using mixed VHDL-Verilog simulation?

`timescale 1ns/10ps

module sim_check_setup_posedge(
    input wire data_event,
    input wire ref_event
);

reg notifier;

specify
    specparam tSU = 1;    // 1 ns
    $setup(data_event, posedge ref_event, tSU, notifier);
endspecify

endmodule

Here's what I have so far for VHDL code:

library ieee;
use ieee.std_logic_1164.all;

entity sim_check_setup_posedge is
   port(
       data_event :in std_logic;
       ref_event  :in std_logic
    );
end entity;

architecture beh of sim_check_setup_posedge is
begin

-- ?? how to implement $setup here?

end architecuture;

Upvotes: 0

Views: 223

Answers (1)

scary_jeff
scary_jeff

Reputation: 4384

You can easily implement basic timing checks for simulation in VHDL using a combination of predefined attributes (last_event here) and either checker entities as per your example, or procedures as per a comment. Here's an example setup time checker:

library ieee;
use ieee.std_logic_1164.all;

entity SetupCheckEntity is
  generic (
    tSU : time
  );
  port (
    data_event :in std_logic;
    ref_event  :in std_logic
  );
end entity;

architecture a of SetupCheckEntity is
begin
  SetupCheck : process (ref_event)
  begin
    if (rising_edge(ref_event)) then
      -- Warn if setup time not met or data not valid ('X'/'U')
      if (data_event'last_event < tSU or data_event = 'X' or data_event = 'U') then
        report "SetupCheckEntity: Setup failure, expected " & time'image(tSU) & ", got " & time'image(data_event'last_event) & "." severity warning;
      end if;
    end if;
  end process;
end a;

You could easily modify this to check relative to either or both ref_event edge (perhaps dependant on another generic), or extend it to also check hold time. I made the setup time a generic but you could just as easily use a constant. You could also call the procedure below in this entity in place of the process.

Roughly same code can be put in a procedure as shown in the test bench below that shows both entity and procedure methods giving the same basic result.

library ieee;
use ieee.std_logic_1164.all;

entity test is
end;

architecture a of test is
  constant tCK : time := 20 ns;
  constant tSU : time := 3 ns;
  signal data : std_logic := '0';
  signal ref : std_logic := '0';
  
  -- This procedure could be in a package with some other similar procedures
  procedure SetupCheckProcedure (signal d,r : in std_logic; constant tSU : in time) is
  begin
    wait until rising_edge(r);
    if (d'last_event < tSU or d = 'X' or d = 'U') then
      report "SetupCheckProcedure: Setup failure, expected " & time'image(tSU) & ", got " & time'image(d'last_event) & "." severity warning;
    end if;
  end procedure;
begin
  ref <= not ref after tCK / 2;
  -- Data toggling out of sync with ref
  data <= not data after (tCK - 1 ns);
  
  SetupChecker : entity work.SetupCheckEntity
  generic map (
    tSU => tSU
  )
  port map (
    data_event => data,
    ref_event => ref
  );
  
  SetupCheckProcedure(data, ref, tSU);
end;

Instead of report you could use some logging package or write to a file.

If you're thinking "wow, all that code to replace one SystemVerilog line", bear in mind that after writing a procedure, you only need SetupCheckProcedure(data, ref, tSU);, which is pretty well identical to the builtin function in the question.

Upvotes: 1

Related Questions