在VHDL中实现FSM

时间:2011-05-14 09:47:40

标签: vhdl fsm

只是想知道我是否在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,然后只定义它在case语句中的0是什么?那会有用吗?

6 个答案:

答案 0 :(得分:7)

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

但是,您可以通过在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;

答案 1 :(得分:7)

您的示例代码有三个问题:

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

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

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

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

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

至于你的问题:

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

答案 2 :(得分:3)

请注意Philippe的回复(不能直接评论?)..

我更喜欢以两种流程样式编写状态机。它非常清楚地表明您期望推断的触发器在哪里以及您不在哪里。它也有点多了 描述硬件 - 想象一下如何构建具有板级逻辑的状态机。 注册的设备匹配状态&lt; = next_state进程, case语句映射到状态寄存器前面的和/或数组。

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

答案 3 :(得分:0)

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

您好

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

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

但是,异步复位对于基于电路板的环境很有价值。

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

亲切的问候 Nikolaos Kavvadias

答案 4 :(得分:0)

以下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;

答案 5 :(得分:0)

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

RandomForestRegressor()

这是测试台

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;