当我们在verilog中编写有限状态机时,有两种方法来编写有限状态机,首先是使用3 always块(1用于下一状态组合逻辑+1用于前置状态->下一状态顺序逻辑+1用于输出逻辑),第二种方法是对所有3个操作只使用一个always块,但我的输出波形都是different..why,是这样的吗?
例如,我以两种方式编写了简单的fsm代码,我的输出被移位了20个时间单元
第一种方法:
//using one alwys block
module moore_20_1(x_in,y_out,clk,reset);
input wire clk,reset,x_in;
output reg y_out;
reg [1:0] state;
parameter start=2'b00,s0=2'b01,s1=2'b10,s2=2'b11;
always @ (posedge clk)//next state logic + ps->ns logic + output logic
begin
if(reset==1'b1) begin
state<=start;
y_out<=0;
end
else begin
case(state)
start: begin if(x_in) state<=s0;
else state<=s0;
y_out<=0;
end
s0: begin if(x_in) state<=s1;
else state<=s0;
y_out<=0;
end
s1: begin if(x_in) state<=s2;
else state<=s1 ;
y_out<=0;
end
s2: begin if(x_in) state<=s0;
else state<=s2;
y_out<=1;
end
endcase
end
end
endmodule第二种方式
//moore machine using 3 always block(ps->ns+output logic+next-sate logic)
module moore_5_20_2(x_in,y_out,clk,reset);
input wire clk,reset,x_in;
output reg y_out;
reg [1:0] state;
reg [1:0] next_state;
parameter start=2'b00,s0=2'b01,s1=2'b10,s2=2'b11;
//ps->ns logic
always@ (posedge(clk))
if(reset==1'b1)
next_state<= #1 start;
else
next_state<= #1 state;
//next-stae logic
always @(next_state,x_in)
case(next_state)
start: begin if(x_in) state<=s0;
else state=s0;
end
s0: begin if(x_in) state<=s1;
else state=s0;
end
s1: begin if(x_in) state<=s2;
else state=s1 ;
end
s2: begin if(x_in) state<=s0;
else state=s2;
end
endcase
//OUTPUT LOGIc
always@(next_state)
if (reset==1'b1) y_out<= 0;
else begin
case(next_state)
start:y_out<= 0;
s0: y_out<= 0;
s1: y_out<=0;
s2: y_out<=#1 1;
endcase
end
endmodule为什么输出被移位了20个时间单位?
发布于 2014-07-31 08:10:48
我将对您如何测试这两种方法做一些假设,即在您的测试台中有类似以下内容:
initial begin
clk = 0;
forever #10 clk = ~clk;
end我也假设第二种方式是20 (或者可能是19?)基于我认为的错误,比第一种方法提前了几个时间单位。
基本上,第一种方法是在寄存器中缓冲输出y_out,而第二种方法是组合设置y_out。
由于这是一台Moore机器(这两个实现都是),因此输出仅依赖于当前状态。在第一种方式中,在时钟边沿上,y_out被设置为基于“当前”状态的值(即,在时钟边沿之前的时刻状态是什么)。虽然状态也可能在时钟边沿发生变化,但在确定此时钟周期的y_out的下一个值之前,不会发生这种情况。这意味着在单个时钟周期中,y_out将根据前一个周期中的状态进行设置,并一直保持到下一个时钟边沿。
在第二种方式中,y_out是组合设置的,而不是在时钟边沿设置的。在这种情况下,下一个状态逻辑将确定state,并且当时钟沿出现时,next_state将变为state (由于某种原因,在1个时间单位之后...)。因此,现在确定输出y_out的组合块将被唤醒,并将y_out设置为该状态的任意值。因此,y_out将接受当前状态的输出,即此时钟周期的状态,而不是第一种方式中的前一个时钟周期的状态。
例如,假设我们处于s1状态,并且断言了x_in。因此,在第二种方式中,state已经在s2为过渡做好了准备。时钟边沿出现了。
在第一种方式中,always块被唤醒。reset没有在case语句中如此断言。我们在s1中,x_in被断言,因此state将变为s2,y_out被设置为0。直到下一个时钟边沿。因此,在下一个时钟沿之前,我们看起来就像是在s2中,y_out为0,此时y_out将变为1。
在第二种方式中,状态寄存器块总是在1个时间单位后唤醒,并且next_state变为s2。一旦next_state变为s2,y_out的输出逻辑块将被唤醒,现在next_state为s2,因此y_out现在将变为1(或在1个时间单位后再次变为1?)。因此,看起来我们在s2中,y_out是1(大致),大约领先20个时间单位。
注意:这其中涉及的许多混淆(部分如Tim提到的)并不是特别好的风格。我更喜欢第二种方式,但是你实现它的方式有点不太理想。这里是一个建议的重写,以供将来参考(尽管我也采取了一些简化自由):
module nice_moore_machine(
input wire clock, reset, x_in,
output reg y_out);
reg [1:0] state, next_state;
parameter start = 2'b00, s0 = 2'b01, s1 = 2'b10, s2 = 2'b11;
/* State register (synchronous reset) */
always @(posedge clk) begin
if (reset) begin
state <= start;
end
else begin
state <= next_state;
end
end
/* Next state logic */
always @(*) begin
case (state)
start: begin
next_state = s0;
end
s0: begin
next_state = (x_in) ? s1 : s0;
end
s1: begin
next_state = (x_in) ? s2 : s1;
end
s2: begin
next_state = (x_in) ? s0 : s2;
end
endcase
end
/* Output logic */
always @(*) begin
y_out = (state == s2); /* Note that y_out could be a net and use an assign in this case */
end
endmodule希望这能帮助你更好地理解!
https://stackoverflow.com/questions/24894120
复制相似问题