我想知道下面代码的行为。总共有两个块,一个是组合来计算next_state
信号,另一个是顺序,它将执行一些逻辑并确定是否关闭系统。它通过将shutdown_now
信号设置为高,然后调用state <= next_state
来完成此操作。
我的问题是,如果条件成立,shutdown_now
信号在state <= next_state
行之前以阻塞方式设置(在时钟周期n期间),则时钟周期n + 1期间的状态是SHUTDOWN
或RUNNING
?换句话说,自shutdown_now = 1'b1
信号以来,两个状态机上的state
行阻止是否通过next_state
确定依赖于它?
enum {IDLE, RUNNING, SHUTDOWN} state, next_state;
logic shutdown_now;
// State machine (combinational)
always_comb begin
case (state)
IDLE: next_state <= RUNNING;
RUNNING: next_state <= shutdown_now ? SHUTDOWN : RUNNING;
SHUTDOWN: next_state <= SHUTDOWN;
default: next_state <= SHUTDOWN;
endcase
end
// Sequential Behavior
always_ff @ (posedge clk) begin
// Some code here
if (/*some condition*/) begin
shutdown_now = 1'b0;
end else begin
shutdown_now = 1'b1;
end
state <= next_state;
end
答案 0 :(得分:1)
首先,您没有关注属性编码。 always_comb
应仅使用阻止(=
)分配,永不阻止(<=
)。 always_ff
是相反的,只有非阻塞(<=
)分配,永不阻止(=
)。
使用代码,state
将RUNNING
。这是因为next_state
的分配是非阻塞的,因此next_state
直到调度程序的后期才会更新。
假设,如果next_state
和shutdown_now
都是阻止分配,那么模拟器将具有竞争条件。在评估next_state
之前或之后,可以评估和更新state
。这就是为什么在同一个总块中混合阻塞和非阻塞不是一个好主意。
如果编码正确,即next_state = ...
和shutdown_now <= ...
,则状态也会转到RUNNING
。这是因为shutdown_now
更新在所有计划的评估完成后发生。因此next_state
在评估1'b1
之后才会看到state
。
答案 1 :(得分:0)
迈尔斯,你真的只有一台状态机,这是你的always_comb块中的代码。 always_ff只创建一个寄存器来保存你的状态。
现在编写代码的方式,您将按以下顺序执行关闭:
不确定是否需要在always_ff块中使用关闭逻辑。如果将该代码移动到always_comb块,则可以使其余代码保持不变,并且状态机将在周期n + 1中移至SHUTDOWN状态。
答案 2 :(得分:0)
以下是我希望代码执行的方式:
您有两个寄存器:“shutdown_now”寄存器和“状态”寄存器。
在clk的posedge上,这两个寄存器的状态都是原子更新的。即:当对shutdown_now进行阻塞分配时,当state_next更新时,当前进程不会中断。相反,为了always_ff过程的目的,state_next是在posedge clk模拟“tick”开始时保存的任何值。
所以:
在第一个posedge时钟滴答:shutdown_now将从0切换到1.
一旦“posedge clk”进程完成,“always_comb”块将注意到它有工作要做,并将更新state_next(即来自2个寄存器的新状态的组合解码)。
在第二个posedge时钟滴答:状态被更新的state_next锁存。
因此,关闭系统需要2个周期,而不是1个。