您的代码很好,尽管我同意 Greg 的观点,即在组合过程中使用阻塞赋值更好。
在你的 cmets 上:
简单来说,调度器包含 5 个队列(SV 有 17 个),但是
您只对其中 2 个感兴趣:active event queue 和
nonblocking assignment update queue。在给定的仿真周期中,
模拟器处理活动事件队列,然后进行非阻塞更新
队列。通常,这将创建更多事件,并且模拟器循环
以预定的顺序围绕队列,直到没有更多事件发生
这个模拟时间。然后模拟器移动到下一个时间
事件被安排(例如在下一个时钟边沿)。
假设“同时”发生 4 件事:fsm_state 发生了变化,
是f(x) 的更改,您的两个NBA 任务都已执行。据,直到...为止
就模拟器而言,这4条语句是同一个执行的
模拟循环,但顺序未定义。 “一次”的定义是
相当复杂,但假设它们都是由于时钟沿而发生的,
语句之间没有排序依赖关系。模拟器通常是
单线程,所以它实际上会以不同的方式执行 4 个语句
真实次,但它知道所有 4 次预计会同时发生
模拟时间。
fsm_state 和 f(dff1) 上的更改为 update events,并添加到
调度程序的active event queue。
两个 NBA 的 RHS 立即评估,LHS 更新是
添加到nonblocking assignment update queue。
模拟器现在看到一个队列,上面有 4 个事件。它执行两个活动
事件优先,以未定义的顺序,所以 fsm_in 和 fsm_out 得到他们的新
价值观。如果没有更多活动事件,则执行这两个
非阻塞更新,以未定义的顺序,所以 dff1 和 fsm_state 现在得到
他们的新价值观。
在您的情况下,模拟周期尚未完成,因为更改
fsm_in 也是一个更新事件,这会触发评估/执行
对fsm_in 敏感的always 块。这是evaluation
event。 sim执行always块,立即读取新值
fsm_in,并将fsm_state的更新添加到NBA任务更新中
队列。如果没有活动事件,则执行分配,并且
fsm_state 获得了新的价值。
此过程一直持续到此模拟周期中不再有事件,并且
如果将来安排了某些事情,则模拟器会提前时间。
您可以从 Verilog LRM 的第 5 节中获得所有这些信息,但它不会
很有意义。所有的语言都是在标准化后期移植的
处理和使用(VHDL)术语在 LRM 的其他地方没有使用。它
也都以匹配 Verilog-XL 的行为的方式添加,并且
专门记录特定于 XL 的非确定性,所以不要指望
太多了。 NBA 直到 1992 年才被添加到语言中,我
思考。不要为 SV LRM 烦恼;还有更多的队列,并且
普通文本已更改,只是增加了另一层混乱。
Cliff Cummings 在他的一篇论文中有一个简化的描述(关于
非阻塞赋值),但请仔细阅读。我很确定
活动事件队列的描述不正确(用于 RHS 评估
NBA)。如果他是对的,那会引起各种各样的问题;他大概
从早期版本的 LRM 中获得描述。
最好的办法是查找有关 VHDL delta 周期的任何文本。这些
很容易理解,他们工作,并且一直在做,他们有
多年来潜入 Verilog。细节不同,但你不
需要知道比增量周期更多的知识。