VHDL FSM中的状态管理

时间:2013-01-10 10:46:18

标签: vhdl fsm

我在VHDL中看到的很多FSM都是通过在FSM逻辑中设置变量“next_state”然后将其单独分配给流程外的状态变量来实现的。

如果只是写“state <= state_five;”有什么不对改为设置下一个状态? 我假设这么多人使用单独的下一个状态变量的原因,而不是直接分配到我一直看到的状态,但据我所知,没有区别在于它使代码更长,更复杂。

我错过了什么吗?或者只是一个风格问题?如果是这样,为什么这种风格更好,对我来说似乎没必要。

3 个答案:

答案 0 :(得分:6)

“简单地写state <= state_five;会有什么问题吗?”

什么都没有 - 提供状态分配是在一个定时的过程中完成的。

这导致了简洁可靠的“单进程状态机”风格,而不是不可靠(因为它很容易让灵敏度列表错误)两种过程风格,在太多的教科书和在线教程中教授。 / p>

搜索“单进程状态机”,您应该能够找到很好的示例材料并进一步讨论。

历史记录:上个世纪可能有一些综合工具存在单一过程风格的问题;但现在没有理由避免它。

答案 1 :(得分:3)

有些人总是编写双进程状态机(即一个同步进程和一个并发进程)的原因可能主要是因为他们学会在学校这样做,就像其他人所说的那样。

但是,在某些情况下,这种编码风格实际上可能比单个同步过程更好。简而言之,它允许您在同一上下文中混合同步和并发分配。考虑以下两段代码,两者都完成相同的事情:

双进程状态机:

process (clk)
begin
  if rising_edge(clk) then
    state <= state_next;
  end if;
end process;  

process (all)
begin 
  state_next <= state;
  case state is 
    when s_idle => 
      if req_i = '1' then 
        fifo_read <= '1'; -- Concurrent assignment
        state_next <= s_check_data; -- "Synchronous" assignment 
      end if; 
    when s_check_data =>
      if fifo_out = x"1234" then
        (...)
      end if;
    (...) 
  end case; 
end process;

单进程状态机:

process (clk)
begin 
  if rising_edge(clk) then
    case state is 
      when s_idle => 
        if req_i = '1' then 
          fifo_read <= '1';
          state <= s_wait_for_data;
        end if;
      when s_wait_for_data =>
        state <= s_check_data;
      when s_check_data =>
        -- Data word from FIFO now available.
        if fifo_out = x"1234" then
          (...)
        end if;
      (...) 
    end case;
  end if;
end process;

注意第二个例子中的额外状态。因为无法在VHDL中的同步进程中进行并发分配(我希望有!),寄存器将被添加到fifo_read信号中,将其延迟一个周期。虽然这个例子很简单,但始终坚持使用单进程状态机有时会导致代码变得非常混乱并且难以遵循这个原因。它还可能导致您的状态机在硬件上花费更多资源,甚至使代码更长。这两种风格都不是正确的选择,但我通常更喜欢单一流程变体。

答案 2 :(得分:2)

甚至使用变量:

state := state_five

使用变量存储状态意味着它保持完全本地的进程,并且不会污染整个architecture的命名空间。

这也意味着如果您习惯使用printf(抱歉report)来跟踪调试状态机的进度(有时候比波形查看器更好),您可以报告预期的<在状态机进程结束时的em> next 状态,这可能很方便。

添加了: 如注释中所述,变量赋值“立即”发生(要清楚 - 这不会导致case语句立即切换到下一个状态!)

如果您需要提前一个周期输出,则可以利用此效果(偶尔) - 通过根据过程结束时的下一个状态分配所述信号。如果我最终需要这样做,我倾向于使用一个明确的next_state变量,我将其用于除case语句和state := next_state;之外的所有内容(正好在时钟的末尾)处理)。它向代码审查员证明了你打算这样做!