从别人那学习的,要转载还是什么嘛?
https://blog.youkuaiyun.com/CLL_caicai/article/details/104427711
这是学习来源的网址,这应该就不会侵权了,要是侵权了就联系我,我就改一下
接下来步入正题
学习三段式状态机的过程中,我把状态转移条件写错了,仿真中出现了问题,所以这里纪记录以下
对本设计说明:
输入:clk、rst_n
输出:seq
功能:三段式状态机控制输出1011序列
首先是正确的结果:
从图中可以发现,当c_state是3时,下一个clk就输出序列中的第一个数字“1”,之后就按照“011”的顺序输出;这也就对应着状态0的时候输出1,状态1的时候输出0,状态2输出1,状态3输出1。这个也就解释了代码中“=”和“<=”的使用情况。
对应代码展开再看一下:
(1)状态转移部分:使用非阻塞赋值,当n_state发生变化是,下一个clk后c_state才变化,和仿真图中是对应的上的
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
c_state <= s0;
else
c_state <= n_state;
end
突发奇想,我把这个改成阻塞赋值试一下,报错了
Error (suppressible): (vsim-3601) Iteration limit 10000000 reached at time 10 ns.
翻译了一下:
错误(可禁止):(vsim-3601) 在 10 ns 时达到迭代限制 10000000。
查了一下问题,也有关于这个的帖子:
有关这个问题描述的链接
里边写的是: 代码中存在逻辑回环,即将一个组合逻辑单元赋值产生的敏感变量与另一个组合逻辑相关,同时作为另一个组合逻辑单元的敏感变量。
奥!是因为下边的转台转移条件也是组合逻辑模块,它的敏感变量是c_state,而c_state是这个模块产生的敏感变量
行,那就放弃这个想法了
(2)状态转移条件:这里是组合逻辑,阻塞赋值,也就是当c_state变化时,n_state立刻变化,同时的,感觉这里还是挺巧妙的,c_state变成n_state的状态,然后n_state变成下一个状态,写代码的真厉害!
always @(c_state or rst_n)//这里没有posedge negedge,也不是clk
begin
if(!rst_n)
begin
n_state = s0;
end
else
begin
case(c_state)
s0:n_state = s1;//注意这里用的是=,这是为什么
s1:n_state = s2;
s2:n_state = s3;
s3:n_state = s0;
default:n_state = s0;
endcase
end
end
从代码的注释中就可以看出我当时犯了两个错误,
①case中使用的<=;
②always@()中写的是clk和rst_n两个信号,所以我觉得以后写组合逻辑还是直接写@(*)好了,这样就可以避免习惯写成时序逻辑的形式
------还是再记录一下错误代码对应的仿真结果:把c_state写成clk
//状态转移条件
always @(clk or rst_n)//这里没有posedge negedge,也不是clk
begin
if(!rst_n)
begin
n_state = s0;
end
else
begin
case(c_state)
s0:n_state = s1;//注意这里用的是=,这是为什么
s1:n_state = s2;
s2:n_state = s3;
s3:n_state = s0;
default:n_state = s0;
endcase
end
end
看一下仿真结果,先只看n_state,其第一次变化是在rst_n由低变高时,这时clk时上升沿的状态(那如果rst_n没处于clk的上升沿,n_state还会变吗???);第二次以及后边每一次都是在clk下降沿的时候,clk下降沿之前c_state发生一次变化,和这个变化不同步,和clk的下降沿同步,所以是随着always@()内的敏感信号发生变化的
针对上边的问题,我把rst_n的上升沿和clk的上升沿时刻时间差开了,得到结果如下:n_state在rst_n的上升沿处发生改变,所以是敏感信号之间or的关系
总结一下:
- 组合逻辑的"always@()“和”="要注意
- 仿真结果中,组合逻辑的输出信号是随敏感信号同时变化的,阻塞赋值的体现
- 组合逻辑中,只有always@()中的敏感信号变化时才会变化,即使下边代码中写的信号和敏感信号不一样,也时随着敏感信号发生变化
(3)输出部分
case中是根据n_state输出结果,这样就能做到在状态0时输出1,状态1时输出0,后续等等
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
seq <= 1'b0;
end
else
begin
case(n_state)
s0:seq <= 1'b1;
s1:seq <= 1'b0;
s2:seq <= 1'b1;
s3:seq <= 1'b1;
default:seq <= 1'b0;
endcase
end
end