看到网上有些人写的数字设计中关于三段式的文章
觉得其中有误解的成分,特别是对于编译/综合的误解,有必要解释一下再加上好久没写什么文章,版面又冷清,似乎有点不称职了. 我们假设有这么一个状态机:
有一个输入S是用来改变状态机的状态的,每当上沿时就改变一下状态机的状态
另外有两个输入A,B,有一个输出C
还有一个时钟clk以及一个复位nrst
初始的时候(复位后)状态为0
输出值为两个输入值的与
状态为1时
输出值为两个输入的或
状态为2时
输出值为两个输入的异或
状态为3时
输出值为两个输入的异或非 本帖最后由 cjaizss 于 2011-06-08 13:55 编辑
我们现在用一段式来写这个状态机,我这里用verilog编写,VHDL类似,我就不写了.
为了简单,在这里,我不过滤毛刺.
module mytest1(clk,nrst,S,A,B,C);
input clk,nrst,S,A,B;
output C;
reg stat;
reg S2;
reg C;
always@(negedge nrst or posedge clk)
if(!nrst)
S2<=0;
else
S2<=S;
always@(negedge nrst or posedge clk)
if(!nrst) begin
stat <= 0;
C<=0;
end
else
case(stat)
0:
C<=A&B;
if(S&!S2)
stat<=1;
1:
C<=A|B;
if(S&!S2)
stat<=2;
2:
C<=A^B;
if(S&!S2)
stat<=3;
3:
C<=A==B;
if(S&!S2)
stat<=0;
default:
stat<=0;
endcase
endmodule
上面就是一段式的写法,状态转换和状态机的输出写在一个进程里,下面我们再看看三段式的写法 本帖最后由 cjaizss 于 2011-06-08 14:08 编辑
module mytest2(clk,nrst,S,A,B,C);
input clk,nrst,S,A,B;
output C;
reg nx_stat,stat;
reg S2;
reg C;
always@(negedge nrst or posedge clk)
if(!nrst)
S2<=0;
else
S2<=S;
always@(negedge nrst or posedge clk)
if(!nrst)
stat <= 0;
else
stat <= nx_stat;
always@(S2,S,stat)
case(stat)
0:if(S&!S2)nx_stat<=1;elsenx_stat<=stat;
1:if(S&!S2)nx_stat<=2;elsenx_stat<=stat;
2:if(S&!S2)nx_stat<=3;elsenx_stat<=stat;
3:if(S&!S2)nx_stat<=0;elsenx_stat<=stat;
endcase
always@(negedge nrst or posedge clk)
if(!nrst) begin
C<=0;
end
else
case(nx_stat)
0:
C<=A&B;
1:
C<=A|B;
2:
C<=A^B;
3:
C<=A==B;
endcase
endmodule
cjaizss 发表于 2011-06-08 13:40 http://bbs.chinaunix.net/images/common/back.gif
顾名思义,三段式就表示,描述一个状态机分三段,三个进程。
上面verilog代码中,除了第一个之外,其他三个就是了。
看上去,代码中要维护两个状态值,stat和nx_stat,stat表示状态机当前状态,nx_stat表示下一刻状态
第一个进程,每到时钟上沿,nx_stat就要赋给stat.
第二个进程,根据当时的状态、输入值为nx_stat赋值。
第三个进程,产生输出。 第一个进程比较容易理解,第三个进程也很容易理解.
关键在于第二个进程
网上有很多的说法,比如有的说,这样的三段式写法性能上会好,但会使用更多的触发器,这是一种误解,因为它并不会导致使用更多的触发器.
这就涉及到编译(并非综合)是如何进行的,第二个进程的敏感表中有太多的值,那么把它综合成一个时序电路显然是不显示的,于是编译器会往组合电路的方向去想.
但如果要正确编译为组合逻辑,首先,必须所有的输入都在敏感表中,这是最基本的要求.
其次,任何情况下都必须有输出,else后面悬挂的部分不写的话,逻辑是有问题的,原因就在于这是组合电路,不是时序电路.
always@(S2,S,stat)
case(stat)
0:if(S&!S2)nx_stat<=1;elsenx_stat<=stat;
1:if(S&!S2)nx_stat<=2;elsenx_stat<=stat;
2:if(S&!S2)nx_stat<=3;elsenx_stat<=stat;
3:if(S&!S2)nx_stat<=0;elsenx_stat<=stat;
endcase
网上有人说,这一段的逻辑应该用=,而不应该用<=
一个是阻塞赋值,一个是非阻塞.
这又是一个误解,无所谓的.
我发这个帖子的关键之处,是要说明为什么写三段式,这里误解就更多了.
和一段式一样,三段式只是一种RTL的写法,两种本质并无区别.
但是,三段式的写法逻辑和组合分开,这样做至少人看着会舒服很多,编译器也会舒服.
人看着舒服,修改起来就方便一些.
页:
[1]