有限状态机设计中的一个问题
//状态转换
always @(posedge clk or negedge rst)
begin
if (!rst)
current_state <= s1;
else
current_state <= next_state;
end
//next_state
always @(current_state or in)
begin
case (current_state)
s1:
if (…)
next_state = s3;
s2:
if (…)
next_state = s5;
…
default:
next_state <= s1;
endcase
end
//输出信号
always @(current_state or in)
begin
case (current_state)
s1:
if (…)
out = 1'b1;
s2:
if (…)
out = 1'b0;
…
default:
out = 1'b0;
endcase
end
但是在rst下降沿的时候想要给将out设为0.
在modelsim仿真的时候,如果把第一个always块改写成如下:
always @(posedge clk or negedge rst)
begin
if (!rst)
begin
current_state <= s1;
out <= 1'b0;
end
else
current_state <= next_state;
end
这样仿真结果是对的,但是这样就在两个always块里对out信号赋值,貌似是不可综合的。
那么,应该怎么做才能达到想要的时序效果?
看了你这个3段式状态机,我有疑问了。
因为之前也看过别人写的3段式状态机,和你这个很不一样哈。
我把你的优化一下如下吧,你看着合适就用,不合适就自己取舍吧。
/*
always @(posedge clk or negedge rst)
begin
if (!rst)
current_state <= s1;
else
current_state <= next_state;
end
*/
reg[3:0] flag_cnt;
wireflag_en;
always @(posedge clk or negedge rst)
begin
if (!rst)
flag_cnt <= 4'b0000;
else
flag_cnt <= flag_cnt + 1'b1;
assign flag_en = flag_cnt = 4'b1111 ? 1: 0;
always @(posedge clk or negedge rst)
begin
if (!rst)
current_state <= s1;
else if(flag_en)//这里做一个延迟处理,具体打几个时钟看你需要。
current_state <= next_state;
end
//next_state 这段代码是组合逻辑啊,我给你改正下,注意=,<=的用法哈
always @(*)
begin
case (current_state)
s1:
if (…)
next_state = s3;
s2:
if (…)
next_state = s5;
…
default:
next_state = s1;
endcase
end
/*
//输出信号
always @(current_state or in)
begin
case (current_state)
s1:
if (…)
out = 1'b1;
s2:
if (…)
out = 1'b0;
…
default:
out = 1'b0;
endcase
end
*/
//以下这段代码改动比较大,自己体会哈
always @(posedge clk or negedge rst)
begin
if (!rst)begin
current_state <= s1;
out <= 1'b0;
end
elsebegin
case (next_state)
s1:
if (…)
out <= 1'b1;
s2:
if (…)
out <= 1'b0;
…
default:
out <= 1'b0;
endcase
end
end
//你的代码感觉没用好next_state,3段式状态机 形似神不似。
都不對哈,這個問題很簡單。
LZ只要再加一個
reg reg_out.
always @(posedge clk or rstb)
if(!rstb) reg_out <= 0;
else reg_out <= out;
你好啊~看了你的回复我有一些疑问,如下:
reg[3:0] flag_cnt;
wireflag_en;
always @(posedge clk or negedge rst)
begin
if (!rst)
flag_cnt <= 4'b0000;
else
flag_cnt <= flag_cnt + 1'b1;
assign flag_en = flag_cnt = 4'b1111 ? 1: 0;
always @(posedge clk or negedge rst)
begin
if (!rst)
current_state <= s1;
else if(flag_en)//这里做一个延迟处理,具体打几个时钟看你需要。
current_state <= next_state;
end
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面这个状态转换的模块,为什么要做延迟处理?我觉得应该没有必要吧。
------------------------------------------------------------------------------------------------------------------------------
always @(*)
begin
case (current_state)
s1:
if (…)
next_state = s3;
s2:
if (…)
next_state = s5;
…
default:
next_state = s1;
endcase
end
------------------------------------------------------------------------------------------------------------------------------
原先这个next_state模块case的default语句的非阻塞赋值,是我笔误了,不好意思,很感谢你指出。但是我想问为什么把我的敏感列表always@(current_state or in)改成了always@(*)。按照我的理解always@(*)的意思是把所有输入作为敏感列表,但是我的状态机里current_state变化了应该也是要对next_state进行赋值的,还是说我的理解有问题?
------------------------------------------------------------------------------------------------------------------------------
always @(posedge clk or negedge rst)
begin
if (!rst)begin
current_state <= s1;
out <= 1'b0;
end
elsebegin
case (next_state)
s1:
if (…)
out <= 1'b1;
s2:
if (…)
out <= 1'b0;
…
default:
out <= 1'b0;
endcase
end
end
------------------------------------------------------------------------------------------------------------------------------
对于这个always块我有一个跟状态机不相关的疑问,是和非阻塞赋值有关的。麻烦你也帮我解答一下吧。
关于非阻塞赋值<=,有一个说法是在进行非阻塞赋值的时候,假设敏感列表为posedge clk,在一个时间步(time step)开始的时候估计<=右边的表达式并在这个time step结束的时候用<=右边的值更新左边的变量。
这个time step就是clk上升沿到来以后的一个时钟周期,所以在进行非阻塞赋值的时候,我们会看到赋值会延迟一个周期。但是为什么在rst下降沿将信号置零时,置零不会发生延迟?
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
不好意思,因为我实在是太菜鸟了,问题比较多,麻烦你了。
其实我也不是啥高手,只是前不久刚好看到了这种3段式状态机的写法,,个人比较认同这种风格,所以在这里推荐给你了哈。一起学习。
下面就个人理解,回答你的问题,有不认同的地方欢迎大家提出,我们共同进步。
1、延时处理,这个就注释来说我没说必须,可以理解为若有必要可以在这里做处理。
还有,你原来的代码后两个模块都是组合逻辑,所以肯定是没必要加的。
我写的第三个模块是时序的,而且用的是next_state,加点延时,防止在一个时钟周期的时候,状态和赋值同时跳变。(这个是个人理解,具体的大家有什么想发,也可以告诉我,在这里先谢谢了)
2、alway @(*),这个语句,,你的理解都没错;我的理解是,在组合逻辑里可以这样写,比你加信号进去
简洁哈,个人习惯罢了;当然如果是指定了信号的话,当然就不能这样写了。
3、这个问题简单,你百度哈,什么是异步复位同步复位就明白了。
关于我说的第三个问题,你好像误解我了。我百度了下同步复位和异步复位来确认我对于复位的理解没有偏差。
我这个问题是问非阻塞赋值。麻烦看一下以下两段代码和波形图。
1.
always @(posedge clk or negedge rst)
begin
if (!rst)
hint <= 1'b0;
else if ((current_state == 1'b1) &&
(bitstream == 2‘d60))
hint <= 1'b1;
else
hint <= hint;
end
波形图如下图1
可以看到红色矩形处的clk上升沿,已经满足了else if的条件,但是hint延迟了一个周期跳变为1
于是我写了以下简单的测试代码
2.
always @(posedge clk or negedge rst)
begin
if (!rst)
a <= 1'b0;
else
a <= 1'b1;
end
波形图如下图2
可以看到红色矩形clk的上升沿处,a的跳变没有延迟。
可以解释一下这是为什么吗?我百思不得其解。
谢谢了~
-
哦,这个问题也简单。
在这样的仿真波形中,你要明白时钟的边沿检测是在前沿。
就第一幅图而言,红框范围时钟边沿检测到的是0,而不是60。
同理,你按照这样的原则可以验证一下,在第二副图中,让rst的跳变处在时钟边沿上。结果也会同第一副图一样。我按照你说的试了一下 发现始终边沿上的复位也是没有问题的,如下图
不过觉得你说的采时钟沿前的信号很有道理,呵呵同步复位电路,异步复位电路,你还需在理解下。
现在的这个时序图和以前那个比较,是不一样的。
现在这个是异步复位状态,a值的改变不受时钟控制。
以前那图是异步复位解除状态,a值的改变受时钟控制。状态图怎么读呀?