在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 4735|回复: 9

[求助] 有限状态机设计中的一个问题

[复制链接]
发表于 2013-1-24 21:39:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
是这样的,我写的三段式状态机,3个always块大致如下:
//状态转换
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信号赋值,貌似是不可综合的。
那么,应该怎么做才能达到想要的时序效果?
发表于 2013-1-25 11:15:09 | 显示全部楼层
看了你这个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;
wire  flag_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
    else  begin
      case (next_state)
      s1:
      if (…)
        out <= 1'b1;
      s2:
      if (…)
        out <= 1'b0;
        …

    default:
        out <= 1'b0;
    endcase
    end
end

//你的代码感觉没用好next_state,3段式状态机 形似神不似。
发表于 2013-1-25 12:38:34 | 显示全部楼层
都不對哈,這個問題很簡單。
LZ只要再加一個
reg reg_out.
always @(posedge clk or rstb)
    if(!rstb) reg_out <= 0;
    else reg_out <= out;
 楼主| 发表于 2013-1-25 13:57:50 | 显示全部楼层
回复 2# 刹那天堂
你好啊~看了你的回复我有一些疑问,如下:

reg[3:0] flag_cnt;
wire  flag_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
    else  begin
      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下降沿将信号置零时,置零不会发生延迟??
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
不好意思,因为我实在是太菜鸟了,问题比较多,麻烦你了。
发表于 2013-1-25 17:18:17 | 显示全部楼层
其实我也不是啥高手,只是前不久刚好看到了这种3段式状态机的写法,,个人比较认同这种风格,所以在这里推荐给你了哈。。。一起学习。
下面就个人理解,回答你的问题,有不认同的地方欢迎大家提出,我们共同进步。
1、延时处理,这个就注释来说我没说必须,可以理解为若有必要可以在这里做处理。
   还有,你原来的代码后两个模块都是组合逻辑,所以肯定是没必要加的。
   我写的第三个模块是时序的,而且用的是next_state,加点延时,防止在一个时钟周期的时候,状态和赋值同时跳变。(这个是个人理解,具体的大家有什么想发,也可以告诉我,在这里先谢谢了)

2、alway @(*),这个语句,,你的理解都没错;我的理解是,在组合逻辑里可以这样写,比你加信号进去
  简洁哈,个人习惯罢了;当然如果是指定了信号的话,当然就不能这样写了。

3、这个问题简单,你百度哈,什么是异步复位同步复位就明白了。
 楼主| 发表于 2013-1-25 22:17:02 | 显示全部楼层
本帖最后由 zerorenee 于 2013-1-25 22:25 编辑

回复 5# 刹那天堂

关于我说的第三个问题,你好像误解我了。我百度了下同步复位和异步复位来确认我对于复位的理解没有偏差。

我这个问题是问非阻塞赋值。麻烦看一下以下两段代码和波形图。
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的跳变没有延迟。


可以解释一下这是为什么吗?我百思不得其解。。。。
谢谢了~~~
1.png
2.png
发表于 2013-1-28 10:23:11 | 显示全部楼层
本帖最后由 刹那天堂 于 2013-1-28 10:28 编辑

哦,这个问题也简单。
在这样的仿真波形中,你要明白时钟的边沿检测是在前沿。

就第一幅图而言,红框范围时钟边沿检测到的是0,而不是60。

同理,你按照这样的原则可以验证一下,在第二副图中,让rst的跳变处在时钟边沿上。结果也会同第一副图一样。
 楼主| 发表于 2013-1-29 14:51:27 | 显示全部楼层
回复 7# 刹那天堂


   我按照你说的试了一下 发现始终边沿上的复位也是没有问题的,如下图
   不过觉得你说的采时钟沿前的信号很有道理,呵呵
4.png
发表于 2013-1-31 14:57:41 | 显示全部楼层
本帖最后由 刹那天堂 于 2013-2-1 09:15 编辑

回复 8# zerorenee


    同步复位电路,异步复位电路,你还需在理解下。

现在的这个时序图和以前那个比较,是不一样的。

现在这个是异步复位状态,a值的改变不受时钟控制。
以前那图是异步复位解除状态,a值的改变受时钟控制。
发表于 2015-7-31 15:17:09 | 显示全部楼层
状态图怎么读呀?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条

小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-9-21 15:34 , Processed in 0.048036 second(s), 11 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表