这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » FPGA » 非index与index状态机写法

共2条 1/1 1 跳转至

非index与index状态机写法

菜鸟
2017-06-29 15:30:19     打赏
状态机的写法应该是用三段式写法,即第一部分说明初始状态,current_state<=next_state,第二部分是状态机的状态转化的描述,第三部分是每一步状态的组合逻辑的描述。这样写调理更加清晰,也更加利于综合器综合。而且,大家一致认同的是onehot编码是状态机编码的一种非常优秀的方式,虽然占的位数可能稍多一点,但是省去了状态变量的译码电路,因此总体上是比较划算的,而且采用onehot编码还可以比较有效地避免竞争冒险现象。现在讨论的焦点在于状态机状态变量的索引(index)和非索引写法。现在我就给出两个简单的程序,分别是用index写法和非index写法。
非index写法,这个大家都应该很熟悉了:
  1. module test2(clk,reset,ena,out1,out2,out3);
  2. input clk,reset,ena;
  3. output[3:0] out1,out2,out3;

  4. parameter s1=3'b001;
  5. parameter s2=3'b010;
  6. parameter s3=3'b100;

  7. reg[2:0] current_state,next_state;
  8. reg[3:0] out1,out2,out3;

  9. always@(posedge clk or negedge reset)
  10. begin
  11.         if(reset==0)
  12.                 begin
  13.                 current_state<=s1;
  14.                 end
  15.         else
  16.                 current_state<=next_state;
  17. end

  18. always@(current_state or ena)
  19. begin
  20.         next_state = current_state;//***************************sign1
  21.         case(current_state)
  22.                 s1:
  23.                         begin
  24.                                 if(ena==0)
  25.                                         next_state=s1;
  26.                                 else
  27.                                         next_state=s2;
  28.                         end
  29.                 s2:
  30.                         next_state=s3;
  31.                 s3:
  32.                         next_state=s1;
  33.         endcase
  34. end

  35. always@(posedge clk or negedge reset)
  36. begin
  37.         if(!reset)
  38.                 begin
  39.                         out1<=4'b0000;
  40.                         out2<=4'b0000;
  41.                         out3<=4'b0000;
  42.                 end
  43.         else if(next_state==s1)  //个人觉得此处可以用CURRENT_STATE来替代,似乎更符合逻辑,
  44.                 out1<=4'd5;
  45.         else if(next_state==s2)
  46.                 out2<=4'd6;
  47.         else if(next_state==s3)
  48.                 out3<=4'd2;
  49. end

  50. endmodule
复制代码
在程序当中sign1这一句,论坛上已经讨论过了,到底加不加,至少我现在做出来的结果是不管加不加都不影响最后的结果。我想可能它的作用类似于后面那个程序sign2处那句话的作用吧,因此说有了它才能够综合成状态机不是没有道理的。但是事实上,从我做的结果来看都无关紧要了。上面的程序是可以被Synplify和Quartus综合成状态机的,而且由于上面程序的状态非常的少,用Synplify综合的时候会自动的改变编码方式,将onehot编码改成binary编码。当状态比较多的时候,状态机编码会被综合成onehot编码。


现在我们重点来看看所谓的index编码写法:
  1. module test(clk,reset,ena,out1,out2,out3,state_out);
  2. input clk,reset,ena;
  3. output[3:0] out1,out2,out3;
  4. output[2:0] state_out;

  5. parameter s1=0;
  6. parameter s2=1;
  7. parameter s3=2;

  8. reg[2:0] current_state,next_state;
  9. reg[3:0] out1,out2,out3;

  10. always@(posedge clk or negedge reset)
  11. begin
  12.         if(reset==0)
  13.                 current_state<=3'b001;
  14.         else
  15.                 current_state<=next_state;
  16. end

  17. always@(current_state or ena)
  18. begin
  19.         next_state=3'b000;//synthesis parallel_case
  20.         case(1'b1)
  21.                 current_state[s1]:
  22.                         begin
  23.                                 if(ena==0)
  24.                                         next_state[s1]=1'b1;
  25.                                 else
  26.                                         next_state[s2]=1'b1;
  27.                         end
  28.                 current_state[s2]:
  29.                         next_state[s3]=1'b1;
  30.                 current_state[s3]:
  31.                         next_state[s1]=1'b1;
  32.                 default:
  33.                         _state[s1]=1'b1;
  34.         endcase
  35. end

  36. always@(posedge clk or negedge reset)
  37. begin
  38.         if(!reset)
  39.                 begin
  40.                         out1<=4'b0000;
  41.                         out2<=4'b0000;
  42.                         out3<=4'b0000;
  43.                 end
  44.         else if(next_state[s1]==1)
  45.                 out1<=4'd5;
  46.         else if(next_state[s2]==1)
  47.                 out2<=4'd6;
  48.         else if(next_state[s3]==1)
  49.                 out3<=4'd2;
  50. end

  51. assign state_out=current_state;

  52. endmodule
复制代码
    这种写法,小弟最开始是在《基于Verilog HDL的数字系统应用设计》(王钿, 卓兴旺编著,国防工业出版社,2006)上面看到的。然后又在论坛上面看到有人发帖,道出了这种写法的原始出处,来自于一个叫做cliff的外国佬的paper,据说这个人是经常跟mentor等作培训的人。下面重点讨论这种写法。
    有人说,传统的非index写法并没有体现出onehot的优势,onehot的优势在于状态每一次变化的时候都只有一位在变,但是实际上我们可以看到,在综合的时候很多时候即使你写成noehot编码,综合器也会跟你综合成binary码,而这种index编码是彻底的进行位操作,从而从根本上体现了onehot的优势。接下来,关键在于这种写法是否被综合成了状态机。
    根据我和几位论坛上朋友的实验结果在Synplify当中这种index码是被综合成了状态机的,而且在综合报告当中可以看到状态机报告:由于状态太少,编码方式被综合成binary码。然而这种写法在Quartus当中却没有综合成状态机!准确的说是没有在状态机报告当中体现出来。在Quartus当中仿真,选择functional模式,仿真波形毫无问题,非常正确,但是一旦选择成timing模式就出问题了。状态机状态current_state出现了下面一些非常规的编码:011,101。但是整个电路仿真照常运转,逻辑输出都没有出错,整个状态机非常正常的运转。但是一直让人不解的是,这个状态变量怎么会出现哪些莫名其妙的情况,我们认为分析这个程序的电路的时候,在case的前面有一句:next_state=3'b0,这句实际上是保证了每一次状态首先每一位都是清零的,然后再进行后面的某一位变成一的操作。为了更进一步的看整个状态,我把波形图符在后面,而且用了一句assignstate_out=current_state;将状态变量输出。论坛上有人提到过,状态变量是不可以直接作为输出的,但是我想这样做是没有问题的。本来从理论上讲,用assign连接的两个变量的值应该是一样的,但是我们看到波形图,这两个值并不一样!!!state_out的最后一位成功的变成了0,也即是把state_out看成状态机的状态变量的话,整个状态机是完全没有错的。然而为什么这两个值会不一样,我们可以看到最后综合过后的电路,我从Quartus里面抓了图放在后面,可以看到current_state[0]到state_out[0]中间加了一个反相器,这样就把那些莫名其妙的状态值规整成了合理的状态值。这一点我至今仍旧没有像得很明白。个人觉得,这里本来像是Quartus这个的一个bug,然后被发现了,写Quartus的人用了这种加反相器的办法来修正这个bug。
   回过头来,不管怎样,这种写法虽然在Quartus的报告里面没有将它综合成状态机,但是实际上我们可以看到他仍旧是用状态机的方法来实现的。综合一些网友的观点,不管电路最后是否综合成状态机,只要电路功能等各方面达到要求都是可以的。如果是在做FPGA的话,由于这种写法并不是Quartus推荐的写法,因此他的优越性没有得到体现,或许在做ASIC的时候他在提高频率上的好处才会得到充分的体现。现在可以肯定的是,这种写法本身并没有错,而且据说是synopsys所推崇的一种写法,但是Quartus却不认同。至于这种写法的好坏,我也不再这里做过多的评价了。
有几点我想补充一下:

1.上写的那个测试程序状态太少了,这个时候采用binary状态机译码逻辑不大,还更省寄存器,因此会更好一些,这也是综合器自动综合成binary的原因。

2.FPGA是触发器密集型的,一个LE由一个LUT+一个DFF(典型的)组成,用了一个LUT这个LE也就算用完了;而在大状态机条件下,binary编码会导致大的译码逻辑,进而使译码逻辑增大(因为一个状态需要多位表示),因此还不如用one-hot划算。对于ASIC则不同,它的基本单元是由与门、非门、或门、DFF等电路,一个DFF占的面积比与非门等大,因此,用binary编码在面积上会更划算。

3.index和非index的one-hot编码无非是希望让综合工具更好地识别并进行优化,对于一个较好的综合工具来说,这两者是等价的,综合出来的效果也是一样的,因此,这两者的区别主要是哪一种能让综合工具更好地识别,就我个人认识而言,index编码反应了one-hot的本质(非index编码在表面上看有多位参与了译码,这不是one-hot的本质),可以降低对综合器的依靠。就我测试过的情况来说,除quartus外,synplify、dc compile都能很好的识别非index 的编码,综合效果基本上一样的。quartus在状态较为复杂的情况下,似乎并不能很好的识别非index状态机,将所有状态编码都参与了状态译码,综合出来的效果比binary还要差。目前我见过的公司主要使用非index的编码,然后依靠工具对状态机进行识别和优化。

4.状态机在综合后就变成网表了,这时已经只有单元电路的概念,没有了状态机的概念。


高工
2020-12-27 11:37:47     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]