我参加了一个关于嵌入式系统设计的课程和我的一个同学,他们接受了另一个课程,声称另一门课程的讲师不会让他们实现这样的状态机:
architecture behavioral of sm is
type state_t is (s1, s2, s3);
signal state : state_t;
begin
oneproc: process(Rst, Clk)
begin
if (Rst = '1') then
-- Reset
elsif (rising_edge(Clk)) then
case state is
when s1 =>
if (input = '1') then
state <= s2;
else
state <= s1;
end if;
...
...
...
end case;
end if;
end process;
end architecture;
但他们不得不这样做:
architecture behavioral of sm is
type state_t is (s1, s2, s3);
signal state, next_state : state_t;
begin
syncproc: process(Rst, Clk)
begin
if (Rst = '1') then
--Reset
elsif (rising_edge(Clk)) then
state <= next_state;
end if;
end process;
combproc: process(state)
begin
case state is
when s1 =>
if (input = '1') then
next_state <= s2;
else
next_state <= s1;
end if;
...
...
...
end case;
end process;
end architecture;
对于我来说,非常缺乏经验,第一种方法看起来更加简单,因为所有内容都是时钟的,并且引入锁存器的风险较小(没有?)。
我的同学不能告诉我为什么他的讲师不会让他们使用其他方式来实现它,所以我试图找到每个人的利弊。 他们中的任何人都喜欢工业吗?为什么我要避免一个或另一个?
答案 0 :(得分:6)
单一流程形式更简单,更短。仅这一点就减少了它包含错误的可能性。
然而,它也消除了困扰对方组合过程的“不完全敏感性列表”问题应该使其成为明显的赢家,无论其他任何考虑因素。
然而,有很多文本和教程建议相反,没有正确地证明这个建议或(至少在一个案例中我找不到atm)在单一流程形式中引入一个愚蠢的错误并拒绝整个想法这个错误的理由。
单进程表单不能正常运行的仅事物(AFAIK)是非时钟输出。这些都是(IMO)糟糕的做法,因为它们可以在最好的时间进行比赛,并且可以通过单独的组合过程来处理仅用于输出如果你真的不得不这样做。
我猜这背后有一些实际的原因;可能是20世纪90年代中期的综合工具,无法可靠地处理单一流程形式,并使其成为讲师从中学习的原始文档。就像那些爆炸的非标准std_logic_arith
库一样。因此神话已经延续了......
如果他们看到可以通过现代综合工具的东西,那些相同的讲师可能会很合适:整数,枚举,记录类型,循环,函数和程序更新信号(Xilinx ISE现在很好用这些。一些版本的Synplicity有功能问题,但接受与Out参数相同的程序。)
另一条评论:我更喜欢if Rst = '1' then
而不是if (Rst = '1') then
。它看起来不像线路噪音(或C)。
答案 1 :(得分:4)
我同意Brian的观点。一个进程状态机的唯一问题是你不能有非时钟输出,如果输入到输出需要0延迟,这就是一个问题。否则,一个过程模型有助于最小化错误,因为它明确地将输出与状态联系起来。
我在学校教过两种过程模型,但发现一种过程模型是工业界普遍接受的。我相信在学校使用这两个过程模型的原因是,它让学生了解组合逻辑相对于寄存器的位置如何根据代码的编写方式(IMO在开始时非常重要)以及它意味着什么而变化为他们的设计。但是,如果只是强制您使用两个过程模型而没有解释,则无法实现此目的。
答案 2 :(得分:2)
第一种方法看起来更加简单,因为所有内容都是时钟控制的,并且引入锁存器的风险较小(没有?)。
是的,所有的第一种方法都是 no 引入锁存器的机会。它可能会引入触发器,但这很好。
第二种方法可以引入真正的异步锁存器,即使在最好的情况下,我使用的后端FPGA工具也不能很好地处理它们,并且在某些架构中根本不支持,因此必须构建在门或查找表之外。
此外,如果在第二个过程中您的灵敏度列表错误,您的模拟可能与您的综合结果不同!这是因为合成器(出于我放弃尝试理解的原因)将敏感度列表视为填充了您读取的所有信号(完全忽略了过程中的VHDL语言规范),而模拟器将完全按照您的要求进行操作说。
答案 3 :(得分:1)
唉。我个人讨厌双进程状态机的事情。他可能是一个老家伙,这是20年前最可靠的方式。工具了解你的方式,我个人更喜欢这种方法。
答案 4 :(得分:0)
你的同学是绝对正确的。这里的问题是你的问题不完整。你的同事代码比你的更好的原因是人们通常在同一个过程中定义输出值和下一个状态值,如下所示(这与你自己的代码相同,只是添加了输出值) ,这导致“坏”代码):
elsif (rising_edge(clk)) then
case state is
when s1 =>
--define outputs:
outp1 <= ...;
outp2 <= ...;
...
--define next state:
if (input = '1') then
state <= s2;
else
state <= s1;
end if;
when s2 =>
...
...
end case;
end if;
回想一下,在FSM中,输出由组合逻辑部分产生,因此它是无记忆的。但是,在上面的代码中,输出值被注册,这不是FSM必须产生的。实际上,注册输出是对FSM的逐个案例决定(输出可以注册,例如,用于去除毛刺,这是一个特殊的,计划的决定,而不是强制情况,如上面的代码所示) 。