【问题标题】:Implementing a FSM in VHDL在 VHDL 中实现 FSM
【发布时间】:2011-08-25 10:53:55
【问题描述】:

只是想知道我是否在 VHDL 中实现了一个有限状态机,我是否需要说明 所有 的输出处于每种可能的状态?即使我知道某些输出不会从一种状态更改为另一种状态,并且我知道状态的顺序也将保持相同的顺序?

例如,在这个(强制)示例中:

entity test is
    port (
        clk : in std_logic;
        a : in std_logic;
        b: out std_logic;
        c: out std_logic;
    );
end test;

architecture Behavioral of test is

type executionStage is (s1,s2,s3);
signal currentstate, nextstate: executionStage;

begin
    process (clk)
    begin
          if(rising_edge(clk)) then
                 currentstate <= nextstate;
          else 
                 currentstate <= currentstate;
          end if;
    end process;

    process(currentstate)
    begin
        case currentstate is
            when s1 =>
                if (a = '1') then
                    b <= '1';
                    c <= '0';
                else
                    b <= '1';
                    c <= '1';
                end if;

                nextstate <= s2;

            when s2 =>
                -- b doesnt change state from s1 to here, do I need to define what it is here?
                if (a = '1') then
                    b <= '1';
                    c <= '1';
                else
                    b <= '1';
                    c <= '0';
                end if;

                nextstate <= s3;

            when s3 =>
                if (a = '1') then
                    b <= '0';
                    c <= '0';
                else
                    b <= '1';
                    c <= '1';
                end if;

                nextstate <= s1;
        end case;
    end process;
end Behavioral;

据我了解,如果我不这样做,就会创建闩锁?

在类似的例子中这没什么大不了的,但是如果我的机器有超过 10 个输出和超过 10 个状态,那么我的 VHDL 文件开始看起来非常混乱,我确信复制它一定是不好的做法并一遍又一遍地粘贴相同的东西。有更好的方法吗?

编辑:我可以为输出定义“默认”状态吗? IE 在所有进程之外将 b 设置为 1,然后仅在它为 0 的 case 语句中定义它是什么?这行得通吗?

【问题讨论】:

    标签: vhdl fsm


    【解决方案1】:

    是的,如果您只驱动打算在过程的某些分支中组合的信号,您将推断出锁存器。

    但是,您可以简单地通过在case 语句之前为信号分配一个值来为信号定义一个“默认”状态(但在同一进程中)。例如:

    process(currentstate, a)
    begin
        b <= '1';
        c <= '1';
        case currentstate is
            when s1 =>
                if (a = '1') then
                    c <= '0';
                end if;
    
                nextstate <= s2;
    
            when s2 =>
                -- b doesnt change state from s1 to here, do I need to define what it is here?
                if (a /= '1') then
                    c <= '0';
                end if;
    
                nextstate <= s3;
    
            when s3 =>
                if (a = '1') then
                    b <= '0';
                    c <= '0';
                end if;
    
                nextstate <= s1;
        end case;
    end process;
    

    【讨论】:

    • 谢谢托米!所以在我的例子中,我可以在 process(currentstate) 中设置 b
    • 基本上我想知道我可以设置一个默认值,该默认值可以被第一个 case 语句中的所有其他 case/if 语句“继承”。还是我需要在所有 case/if 语句中设置一个新的默认值?
    • 您只需要确保在分支的每个分支中都为信号分配了一个值(即,在没有为信号分配值的过程中没有路径)。这最容易通过在 case 语句之外分配一个合理的默认值来实现。在 case 语句中没有办法做到这一点。
    • 我更新了我的回复以包含一个示例。在这样做时,我意识到我可能误解了你的评论。是的,可以在 when 语句中分配值,但在其中包含的 if 语句之外。 when 中不需要只有一个语句(这在您的代码中已经很明显了,因为您在 if 语句之外分配了nextstate。
    【解决方案2】:

    您的示例代码存在三个问题:

    端口列表中的最后一个端口不应有分号:

    port (
        clk : in std_logic;
        a : in std_logic;
        b: out std_logic;
        c: out std_logic -- no semicolon here!!!
        );
    

    在您的注册过程中,您不应该有“else”语句。虽然这可能会被工具接受,但它会让您的 VHDL 设计人员感到困惑。

    process (clk)
    begin
        if(rising_edge(clk)) then
            currentstate <= nextstate;
        end if;
    end process;
    

    在您的组合逻辑中,敏感度列表应包含您读取的所有信号:process(a, currentstate)。在这种特殊情况下(再次),事情可能会很好,但如果您的敏感度列表不正确,您必然会推断出闩锁或导致其他问题。

    至于你的问题:

    1. 是的,您需要为组合过程中的每个信号分配一个值(针对每个状态)。
    2. 正如 Tomi 所提到的,您可以通过在流程开始时分配一个默认值轻松地做到这一点。
    3. 但您也可以在一个同步进程中编写整个状态机。这样,您就不必为每个状态的每个信号分配一个值。

    【讨论】:

    • 谢谢菲利普!真的很感激这些信息。 :)
    【解决方案3】:

    只是对 Philippe 回复的注释(不能直接评论吗?)..

    我更喜欢以两种进程的方式编写状态机。它非常清楚您期望推断的触发器和不期望的触发器。它也有点像 描述硬件——例如,想象一下用板级逻辑构建一个状态机。 注册的设备匹配 state

    话虽如此,我通常将一个进程状态机用于小型简单任务,而转移到两个进程状态机用于更大的任务。 我什至有时会使用第三个过程将状态输出组织到不同的“任务”组中......但不经常。一个非常大的状态机往往会告诉我架构需要工作..

    【讨论】:

      【解决方案4】:
      process (clk)
      begin
        if(rising_edge(clk)) then
          currentstate <= nextstate;
        end if;
      end process;
      

      嗨

      上述过程有问题,但不是由于敏感列表。只为顺序进程声明 clk 是可以的。仿真和综合工具都不会出现问题。毕竟在你的代码中,clk 是最快的变化/转换信号。

      但是,您应该使用(最好)异步重置。当然,现在的厂商都说,对于 FPGA 设计,甚至不需要复位。它们发生在启动时。或者他们建议同步重置。

      不过,异步复位对于基于板的环境还是很有价值的。

      简而言之:为您的设计添加一个重置并正确修复其行为。

      亲切的问候 尼古拉斯·卡夫瓦迪亚斯

      【讨论】:

        【解决方案5】:

        以下 VHDL 代码是边缘敏感状态机。 本例中的边缘敏感过程将使“out1”和“out2”都与“clk”同相。

        entity main_code is
            Port ( clk : in  STD_LOGIC;
                   in1 : in  STD_LOGIC;
                   in2 : in  STD_LOGIC;
                   out1 : out  STD_LOGIC;
                   out2 : out  STD_LOGIC);
        end main_code;
        
        architecture Behavioral of main_code is
        
        -- here are temp signals to associate or assign output (out1 and out2) values indirectly
        signal out1_temp : std_logic := '0';  
        signal out2_temp : std_logic := '0';
        
        -- counter registers 
        signal counter : integer range 0 to 255 := 0;
        signal counter_8th_clk : integer range 0 to 255 := 0;
        -- state machines definition
        type state_machine_type is (s0,s1);
        signal state : state_machine_type := s0;
        begin
        -- concurrent assignments
        out1 <= out1_temp;
        out2 <= out2_temp;
        
        --half clock generator process
        half_clock : process (clk) is
        begin
        if rising_edge(clk) then
        --out1_temp <= not out1_temp;
        end if;
        end process half_clock;
        
        -- max counter = ndiv -1; here ndiv=4; counter starts from zero;
        one_fourth_clock : process (clk)
        begin
        if rising_edge(clk) then
        counter <= counter + 1;
            if (counter >= 3) then 
                counter <= 0;
        --      out2_temp <= not out2_temp;
            end if;
        end if;
        end process one_fourth_clock;
        
        
        one_eighth_clock : process (clk)
        begin
        if rising_edge(clk) then
        counter_8th_clk <= counter_8th_clk + 1;
            if (counter_8th_clk>=7) then
                counter_8th_clk <= 0;
        --      out2_temp <= not out2_temp;
            end if;
        end if;
        end process one_eighth_clock;
        
        -- state_process creates two half clock (speed) with out1 out of phase with clk
        -- and out2 in-phase with clk
        -- following process is sensitive to clk level not edge
        state_process_edge_sensitive : process (clk)
        begin
        if rising_edge (clk) then
        case state  is
        
            when s0 =>
                out1_temp <= not out1_temp;
                state <= s1;
            when s1 =>
                out2_temp <= not out2_temp;
                state <= s0;
        end case;
        end if;
        
        end process state_process_edge_sensitive;
        
        
        
        end Behavioral;
        

        这里是测试台

        LIBRARY ieee;
        USE ieee.std_logic_1164.ALL;
        
        -- Uncomment the following library declaration if using
        -- arithmetic functions with Signed or Unsigned values
        --USE ieee.numeric_std.ALL;
        
        ENTITY my_test_bench IS
        END my_test_bench;
        
        ARCHITECTURE behavior OF my_test_bench IS 
        
            -- Component Declaration for the Unit Under Test (UUT)
        
            COMPONENT main_code
            PORT(
                 clk : IN  std_logic;
                 in1 : IN  std_logic;
                 in2 : IN  std_logic;
                 out1 : OUT  std_logic;
                 out2 : OUT  std_logic
                );
            END COMPONENT;
        
        
           --Inputs
           signal clk : std_logic := '0';
           signal in1 : std_logic := '0';
           signal in2 : std_logic := '0';
        
            --Outputs
           signal out1 : std_logic;
           signal out2 : std_logic;
        
           -- Clock period definitions
           constant clk_period : time := 10 ns;
        
        BEGIN
        
            -- Instantiate the Unit Under Test (UUT)
           uut: main_code PORT MAP (
                  clk => clk,
                  in1 => in1,
                  in2 => in2,
                  out1 => out1,
                  out2 => out2
                );
        
           -- Clock process definitions
           clk_process :process
           begin
                clk <= '0';
                wait for clk_period/2;
                clk <= '1';
                wait for clk_period/2;
           end process;
        
        
           -- Stimulus process
           stim_proc: process
           begin        
              -- hold reset state for 100 ns.
        --      wait for 100 ns;    
        --
        --      wait for clk_period*10;
        
              -- insert stimulus here 
        
              wait;
           end process;
        
        END;
        

        【讨论】:

          【解决方案6】:

          以下 VHDL 代码是电平敏感状态机。 本例中的电平敏感过程将使“out1”与“clk”异相,“out2”与“clk”同相。

          entity main_code is
              Port ( clk : in  STD_LOGIC;
                     in1 : in  STD_LOGIC;
                     in2 : in  STD_LOGIC;
                     out1 : out  STD_LOGIC;
                     out2 : out  STD_LOGIC);
          end main_code;
          
          architecture Behavioral of main_code is
          
          -- here are temp signals to associate or assign output (out1 and out2) values indirectly
          signal out1_temp : std_logic := '0';  
          signal out2_temp : std_logic := '0';
          
          -- counter registers 
          signal counter : integer range 0 to 255 := 0;
          signal counter_8th_clk : integer range 0 to 255 := 0;
          -- state machines definition
          type state_machine_type is (s0,s1);
          signal state : state_machine_type := s0;
          begin
          -- concurrent assignments
          out1 <= out1_temp;
          out2 <= out2_temp;
          
          --half clock generator process
          half_clock : process (clk) is
          begin
          if rising_edge(clk) then
          --out1_temp <= not out1_temp;
          end if;
          end process half_clock;
          
          -- max counter = ndiv -1; here ndiv=4; counter starts from zero;
          one_fourth_clock : process (clk)
          begin
          if rising_edge(clk) then
          counter <= counter + 1;
              if (counter >= 3) then 
                  counter <= 0;
          --      out2_temp <= not out2_temp;
              end if;
          end if;
          end process one_fourth_clock;
          
          
          one_eighth_clock : process (clk)
          begin
          if rising_edge(clk) then
          counter_8th_clk <= counter_8th_clk + 1;
              if (counter_8th_clk>=7) then
                  counter_8th_clk <= 0;
          --      out2_temp <= not out2_temp;
              end if;
          end if;
          end process one_eighth_clock;
          
          -- state_process creates two half clock (speed) with out1 out of phase with clk
          -- and out2 in-phase with clk
          -- following process is sensitive to clk level not edge
          state_process_level_sensitive : process (clk)
          begin
          case state  is
          
              when s0 =>
                  out1_temp <= not out1_temp;
                  state <= s1;
              when s1 =>
                  out2_temp <= not out2_temp;
                  state <= s0;
          end case;
          end process state_process_level_sensitive;
          
          
          
          end Behavioral;
          

          这里是测试台

          LIBRARY ieee;
          USE ieee.std_logic_1164.ALL;
          
          -- Uncomment the following library declaration if using
          -- arithmetic functions with Signed or Unsigned values
          --USE ieee.numeric_std.ALL;
          
          ENTITY my_test_bench IS
          END my_test_bench;
          
          ARCHITECTURE behavior OF my_test_bench IS 
          
              -- Component Declaration for the Unit Under Test (UUT)
          
              COMPONENT main_code
              PORT(
                   clk : IN  std_logic;
                   in1 : IN  std_logic;
                   in2 : IN  std_logic;
                   out1 : OUT  std_logic;
                   out2 : OUT  std_logic
                  );
              END COMPONENT;
          
          
             --Inputs
             signal clk : std_logic := '0';
             signal in1 : std_logic := '0';
             signal in2 : std_logic := '0';
          
              --Outputs
             signal out1 : std_logic;
             signal out2 : std_logic;
          
             -- Clock period definitions
             constant clk_period : time := 10 ns;
          
          BEGIN
          
              -- Instantiate the Unit Under Test (UUT)
             uut: main_code PORT MAP (
                    clk => clk,
                    in1 => in1,
                    in2 => in2,
                    out1 => out1,
                    out2 => out2
                  );
          
             -- Clock process definitions
             clk_process :process
             begin
                  clk <= '0';
                  wait for clk_period/2;
                  clk <= '1';
                  wait for clk_period/2;
             end process;
          
          
             -- Stimulus process
             stim_proc: process
             begin        
                -- hold reset state for 100 ns.
          --      wait for 100 ns;    
          --
          --      wait for clk_period*10;
          
                -- insert stimulus here 
          
                wait;
             end process;
          
          END;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-01-16
            • 2013-11-30
            • 2018-11-01
            • 1970-01-01
            • 2015-07-29
            • 1970-01-01
            • 2014-10-03
            • 2019-04-23
            相关资源
            最近更新 更多