在VHDL中实施FSM

问题描述 投票:6回答:6

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

例如,在此(强制)示例中:

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时将其定义为1?那行得通吗?

vhdl fsm
6个回答
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;

7
投票

示例代码的三个问题:

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

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;

在您的组合逻辑中,灵敏度列表应包含您读取的all信号:process(a, currentstate)。在这种特定情况下(再一次),可能会很好地解决问题,但是如果您的敏感度列表不正确,您势必会推断出闩锁或引起其他问题。

关于您的问题:

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

3
投票

只是对Philippe的回复的注释(无法直接评论?)。

我更喜欢以两种处理方式编写状态机。它非常清楚地说明了在何处可以推断出触发器,在何处没有。沿着描述硬件-想象一下用板级逻辑构建状态机。已注册的设备符合状态<= next_state进程,并且case语句映射到状态寄存器前面的and和/或数组。]

话虽如此,我通常使用一台进程状态机来完成小的简单任务,然后移到两台进程机上进行更大的任务。我什至有时会使用第三种方法将状态输出组织到不同的“任务”组中,但不是很常见。一个非常大的状态机倾向于告诉我架构需要工作。.


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

上述过程是有问题的,但不是由于敏感度列表所致。可以只为顺序处理声明clk是可以的。模拟和综合工具都不会有问题。毕竟,clk是最快的更改/转换信号。

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

仍然,异步复位对于基于板的环境非常有用。

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

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


0
投票

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

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;
© www.soinside.com 2019 - 2024. All rights reserved.