Electrical – Initialising input signals in VHDL

vhdl

Take this example:

port(clk        : in  std_logic; 
 areset_n       : in  std_logic; 
 ena            : in  std_logic; 
 load           : in  std_logic;
 load_val       : in  unsigned(cnt_width-1 downto 0) := (others => '0');  
 counter_value  : out unsigned(cnt_width-1 downto 0) := (others => '0')  
);

counter_value should be initialised to some value since it's my output, but is it neccessary to initialise the input values too?

Should all the signals be initialised to 0, including clk and reset?

Best Answer

Do not use initial values in synthesizable VHDL i.e. VHDL which creates a logic circuit in your target FPGA/CPLD/ASIC. Use a reset term, controlled by the reset input you have.

This makes your design far more portable other devices and lets you drop in other IP more easily. In my experience, the vast majority of IP you'll encounter uses reset terms, for the same reason of portability.

In a RAM-based FPGA, initial values are typically added into the configuration file during synthesis and therefore loaded into the relevant registers during device configuration. This is not true of flash-based FPGAs or many CPLDs, as well as ASICs, so the same design put into these devices now won't work and the source can be hard to track down.

Using a reset term removes all these problems. You want to have design modules that you can pull into other designs in the future and you don't know what you'll be working with by then.

You can use initial values safely enough in testbenches.

Remember that this is a digital logic circuit, not a computer program. The inputs do not need a reset value here - the logic gate driving them needs one.

If you have an external reset, don't forget to synchronise it to your clock before use. This is in case the reset input changes just as your clocked register sees its active edge on its clock and possibly goes metastable. Use a shift register to produce a reset at least (say) 4 clocks long which is asynchronously asserted and synchronously negated, such as:

  signal resetSR : std_logic_vector(3 downto 0);

  process(RESET_N, CLK) is
  begin
    if (RESET_N = '0') then
      resetSR  <=  "1111";
    elsif rising_edge(CLK) then
      resetSR  <=  resetSR(2 downto 0) & '0';
    end if;
  end process;
  rst  <=  resetSR(3);

If you don't have an external reset to use for your internal reset, you can produce one in a RAM-based FPGA using (dare I say it) one solitary instance of an initial value. With big comments all over it, drawing the attention of other engineers who may migrate your design in the future. You can create a (say) 4-bit shift register with the initial value of "1111" and shift a '0' into it at clock rate. Use the last bit of this shift register as your reset. It will be '1' for the first four clocks after reset, then '0' thereafter.

Avoid doing this if you have an external reset signal.

  -- THIS SIGNAL IS THE ONLY USE OF AN INITIAL VALUE.
  -- THIS MAY NEED TO CHANGE WHEN MIGRATING THIS DESIGN TO OTHER DEVICES.
  signal resetSR : std_logic_vector(3 downto 0) := "1111";

  process(CLK) is
  begin
    if rising_edge(CLK) then
      resetSR  <=  resetSR(2 downto 0) & '0';
    end if;
  end process;
  rst  <=  resetSR(3);