我在 VHDL 中看到的许多 FSM 通过next_state
在 FSM 逻辑中设置一个变量“”来工作,然后将其单独分配给进程之外的状态变量。
state <= state_five
如果简单地写“ ;”有什么问题 改为设置下一个状态?我假设有这么多人使用单独的下一个状态变量而不是直接分配给我一直看到的状态的原因,但据我所知,除了它使代码之外没有区别更长更复杂的外观。
我错过了什么吗?还是只是风格问题?如果是这样,为什么这种风格更好,对我来说似乎没有必要。
“单纯写有什么问题state <= state_five;
吗?”
什么都没有——前提是状态分配是在时钟过程中完成的。
这导致了简洁可靠的“单进程状态机”风格,而不是在太多教科书和在线教程中教授的不可靠(因为很容易弄错敏感度列表)的双进程风格。
搜索“单进程状态机”,您应该能够找到很好的示例材料和进一步的讨论。
历史记录:上个世纪可能有一些合成工具存在单进程风格的问题;但这不是现在避免它的理由。
有些人之所以总是写两个进程状态机(即一个同步进程和一个并发进程),可能主要是因为他们在学校就学会了这样做,就像其他人所说的那样。
但是,在某些情况下,这种编码风格实际上可能比单一同步进程更好。简而言之,它允许您在同一上下文中混合同步和并发分配。考虑以下两段代码,它们都完成了同样的事情:
两进程状态机:
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 信号中,将其延迟一个周期。虽然这个例子很简单,但始终坚持使用单进程状态机有时会导致代码变得非常混乱且难以理解。它还可能导致您的状态机在硬件上花费更多资源,甚至使代码更长。这两种风格都不是正确的选择,但我通常更喜欢单进程变体。
甚至使用变量:
state := state_five
使用变量来存储状态意味着它对进程保持完全本地化,并且不会污染整个architecture
.
这也意味着如果你在report
调试时习惯使用 printf(对不起)来跟踪状态机的进度(有时比波形查看器更可取),你可以在状态机结束时报告预期的下一个状态过程,可以很方便。
补充:如评论中所述,变量赋值“立即”发生(要清楚 - 这不会导致case
语句立即切换到下一个状态!)
如果您需要提前一个周期输出,则可以(偶尔)使用此效果 - 通过在过程结束时根据下一个状态分配给所述信号。如果我最终需要这样做,我倾向于有一个显式next_state
变量,我将它用于除case
语句和 the之外的所有内容state := next_state;
(正好在时钟进程结束时)。它向代码审查者展示了您打算这样做!