Search code examples
vhdlresetfsm

VHDL reset during execution


I am developing a Secure Sequence Detector, which is a FSM, by using 3 different processes. It has as input num_in (8 bits) that represents the input number and a first input (1 bit) that has to be '1' only during the first number, otherwise the FSM goes in a state with fixed output. This condition can happen again if the user insert 3 wrong input sequences. The output is composed by an unlock signal (equal to '1' if the sequence is correct) and by a warning signal (equal to '1' if the sequence is wrong), and they both have to be updated every 5 clock cycles, since the sequence is composed by 5 numbers, even if one of the input is wrong. The first process is:

state_register_p : process(rst, clk)
        begin 
            if rst = '0' then   -- initial state, asynchronous rst
                current_state <= S0;
            elsif (clk'EVENT and clk = '1') then
                if(rst = '0') then
                    current_state <= S0;
                    --errors <= -1;
                else
                    current_state <= next_state;
                    five_cycles <= std_logic_vector(to_unsigned((to_integer(unsigned(five_cycles)) + 1), five_cycles'length));
                    if to_integer(unsigned(five_cycles)) = 5 then
                        five_cycles <= "001";
                    end if;
                 end if;
            end if;
    end process state_register_p;

In this FSM I receive each clock a number on 8 bits and I have to check if it is in the right sequence, if it is not, after 5 cycle from the beginnig I set an error. When the error = 3, the FSM goes in another state in which the unlock is fixed at 0 and the warning at 1, until a reset is given as input again and the FSM starts from the initial S0 state. My testbench code is like that:

clk_tb <= (not(clk_tb) and end_sim) after T_CLK / 2; 
rst_tb <= '1' after T_RESET;

d_process: process(clk_tb, rst_tb)
    variable t : integer := 0; 
  begin
    if(rst_tb = '0') then
      num_in_tb <= (others => '0');
      first_tb <= '0';
      t := 0;
    elsif(rising_edge(clk_tb)) then
      case(t) is 
        -- correct
        when 1 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 2 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 3 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 4 => num_in_tb <= "01100101"; first_tb <= '0';  --101
        when 5 => num_in_tb <= "01001001"; first_tb <= '0';  --73

        --invalid because of the num_in (error = 1, but still < 3)
        when 6 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 7 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 8 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 9 => num_in_tb <= "01100100"; first_tb <= '0';  --100
        when 10 => num_in_tb <= "01001001"; first_tb <= '0';  --73

        --invalid because of the two first (blocking condition) 
        when 11=> num_in_tb <= "00100101"; first_tb <= '0';  --37
        when 12=> num_in_tb <= "00100110"; first_tb <= '1';  --38
        when 13=> num_in_tb <= "00100111"; first_tb <= '1';  --39

        --reset is needed
        when 14=> rst_tb <= '0', '1' after T_RESET;  --unknown behavior here

        -- correct
        when 15 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 16 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 17 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 18 => num_in_tb <= "01100101"; first_tb <= '0';  --101
        when 19 => num_in_tb <= "01001001"; first_tb <= '0';  --73

        when 20 => end_sim <= '0';
        when others => null; -- Specifying that nothing happens in the other cases 

      end case;
      t := t + 1;
    end if;
  end process;

I would like to insert something like that when 14=> rst_tb <= '0', '1' after T_RESET; to reset my FMS. How can I do it? Thanks


Solution

  • You currently have rst_tb driven in multiple locations which is a conflict. Remove it from outside of d_process, and remove rst_tb from your sensitivity list. Then your if-statement will be:

    if rising_edge(clk_tb) then ...
    

    You can create a when 0 => clause on your t variable where you perform resetting:

    when 0 =>
      num_in_tb <= (others=>'0');
      first_tb <= '0';
      t := 0;
      rst_tb <= '0', '1' after T_RESET;
    

    Then you can have rst_tb driven again in your when 14 => clause.

    ...
    
    when 14 =>
      rst_tb <= '0', '1' after T_RESET;
    
    ...
    

    You will have to make your T_RESET shorter than a clk_tb period, or your state_register_p process will start missing stimulus from d_process.

    EDIT:

    library IEEE;
    use IEEE.std_logic_1164.all;
    library STD;
    use STD.textio.all;
    
    entity tb is
    end tb;
    
    architecture arch of tb is
    
    constant T_RESET : time := 5 ns;
    constant T_CLK   : time := 10 ns;
    
    signal clk_tb    : std_logic := '0';
    signal rst_tb    : std_logic := '0';
    signal trig_rst  : std_logic := '0';
    signal num_in_tb : std_logic_vector(7 downto 0);
    signal first_tb  : std_logic := '0';
    signal end_sim   : std_logic := '1';
    
    begin
    
    --  rst_tb <= '0','1' after T_RESET;
    clk_tb <= (not(clk_tb) and end_sim) after T_CLK / 2; 
    
    --d_process: process(clk_tb, rst_tb)
    d_process: process(clk_tb)
      variable t : integer := 0; 
    begin
    --    if(rst_tb = '0') then
    --      num_in_tb <= (others => '0');
    --      first_tb <= '0';
    --      t := 0;
    --    elsif(rising_edge(clk_tb)) then
      if(rising_edge(clk_tb)) then
        case(t) is 
        when 0 =>
          num_in_tb <= (others=>'0');
          first_tb <= '0';
          rst_tb <= '0', '1' after T_RESET;
        -- correct
        when 1 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 2 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 3 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 4 => num_in_tb <= "01100101"; first_tb <= '0';  --101
        when 5 => num_in_tb <= "01001001"; first_tb <= '0';  --73
    
        --invalid because of the num_in (error = 1, but still < 3)
        when 6 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 7 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 8 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 9 => num_in_tb <= "01100100"; first_tb <= '0';  --100
        when 10 => num_in_tb <= "01001001"; first_tb <= '0';  --73
    
        --invalid because of the two first (blocking condition) 
        when 11 => num_in_tb <= "00100101"; first_tb <= '0';  --37
        when 12 => num_in_tb <= "00100110"; first_tb <= '1';  --38
        when 13 => num_in_tb <= "00100111"; first_tb <= '1';  --39
    
        --reset is needed
        when 14 => rst_tb <= '0', '1' after T_RESET;  --unknown behavior here
    
        -- correct
        when 15 => num_in_tb <= "00100100"; first_tb <= '1';  --36
        when 16 => num_in_tb <= "00010011"; first_tb <= '0';  --19
        when 17 => num_in_tb <= "00111000"; first_tb <= '0';  --56
        when 18 => num_in_tb <= "01100101"; first_tb <= '0';  --101
        when 19 => num_in_tb <= "01001001"; first_tb <= '0';  --73
    
        when 20 => end_sim <= '0';
        when others => null; -- Specifying that nothing happens in the other cases 
    
        end case;
        t := t + 1;
      end if;
    end process d_process;
    
    end arch;