日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > 數字集成電路設計-12-狀態機的四種寫法

數字集成電路設計-12-狀態機的四種寫法

來源:程序員人生   發布時間:2014-09-29 23:35:29 閱讀次數:3615次

引言

在實際的數字電路設計中,狀態機是最常用的邏輯,而且往往是全部邏輯的核心部分,所以狀態機的質量,會在比較大的程度上影響整個電路的質量。

本小節我們通過一個簡單的例子(三進制脈動計數器)來說明一下狀態機的4中寫法。


1,模塊功能

由于我們的目的在于說明狀態機的寫作方式,所以其邏輯越簡單有利于理解。就是一個簡單的脈動計數器,每個三個使能信號輸出一個標示信號。


2,一段式

狀態機的寫法,一般有四種,即一段式,兩段式,三段式,四段式。對于一段式的寫法,整個狀態機的狀態轉移、轉移條件、對應狀態的輸出都寫在一個always塊里,故稱‘一段式’。那么,脈動計數器狀態機的一段式寫法該怎么寫呢?如下所示:


/* * file : fsm1.v * author: Rill * date : 2014-05-11 */ module Mfsm1 ( clk, rst, enable, done ); input wire clk; input wire rst; input wire enable; output reg done; parameter s_idle = 4'd0; parameter s_1 = 4'd1; parameter s_2 = 4'd2; parameter s_3 = 4'd3; reg [3:0] state; always @(posedge clk) begin if(rst) begin done <=1'b0; state <= s_idle; end else begin case(state) s_idle: begin if(enable) state <= s_1; done <= 1'b0; end s_1: begin if(enable) state <= s_2; done <= 1'b0; end s_2: begin if(enable) begin state <= s_3; done <= 1'b1; end else begin done <= 1'b0; end end s_3: begin state <= s_idle; done <= 1'b0; end default: begin state <= s_idle; done <= 1'b0; end endcase end end endmodule


3,兩段式

狀態機的另外一種寫法是‘兩段式’的。兩段式的寫法,整個狀態機由兩個always塊組成,第一個塊只負責狀態轉移,第二個塊負責轉移條件和對應狀態的輸出。其中第一個塊是時序邏輯,第二個塊是組合邏輯。脈動計數器狀態機的兩段式寫法又是怎樣的呢?


/* * file : fsm2.v * author: Rill * date : 2014-05-11 */ module Mfsm2 ( clk, rst, enable, done ); input wire clk; input wire rst; input wire enable; output reg done; parameter s_idle = 4'd0; parameter s_1 = 4'd1; parameter s_2 = 4'd2; parameter s_3 = 4'd3; reg [3:0] current_state; reg [3:0] next_state; always @(posedge clk) begin if(rst) begin current_state <= s_idle; end else begin current_state <= next_state; end end always @(*) begin case(current_state) s_idle: begin if(enable) next_state = s_1; done = 1'b0; end s_1: begin if(enable) next_state = s_2; done = 1'b0; end s_2: begin if(enable) next_state = s_3; done = 1'b0; end s_3: begin next_state = s_idle; done = 1'b1; end default: begin next_state = s_idle; done = 1'b0; end endcase end endmodule



4,三段式

從上面可以看出,兩段式的寫法是從一段式發展而來的,將一段式的寫法中將狀態轉移部分提取出來,作為一個獨立的always塊,就變成了兩段式。按照這個思路繼續推進,如果將兩段式的第二個塊中的轉移條件提取出來,也作為一個獨立的塊,就變成了‘三段式’,三段式的寫法中,狀態轉移塊是時序邏輯,轉移條件塊是組合邏輯,對應狀態的輸出是時序邏輯。那么,脈動計數器狀態機的三段式寫法是怎樣的呢?


/* * file : fsm3.v * author: Rill * date : 2014-05-11 */ module Mfsm3 ( clk, rst, enable, done ); input wire clk; input wire rst; input wire enable; output reg done; parameter s_idle = 4'd0; parameter s_1 = 4'd1; parameter s_2 = 4'd2; parameter s_3 = 4'd3; reg [3:0] current_state; reg [3:0] next_state; always @(posedge clk) begin if(rst) begin current_state <= s_idle; end else begin current_state <= next_state; end end always @(*) begin case(current_state) s_idle: begin if(enable) next_state = s_1; end s_1: begin if(enable) next_state = s_2; end s_2: begin if(enable) next_state = s_3; end s_3: begin next_state = s_idle; end default: begin next_state = s_idle; end endcase end always @(posedge clk) begin if(rst) begin done <= 1'b0; end else begin case(next_state) s_idle: begin done <= 1'b0; end s_1: begin done <= 1'b0; end s_2: begin done <= 1'b0; end s_3: begin done <= 1'b1; end default: begin done <= 1'b0; end endcase end end endmodule



5,四段式

上面的三種狀態機的寫法是我們經常提到的,也是經典的三種。這三種寫法在邏輯上是完全等價的,也就是是說,無論采用哪種寫法,模塊的功能都是一樣的,但前兩種一般只出現在教科書中,在實際的項目中是很少見到的。原因在于生成網表的綜合器,由于目前的綜合器還不夠智能,其優化算法對三種寫法的敏感度不同,造成最終生成的電路有所區別,有時候區別較大,尤其是對于復雜的狀態機。無數血與淚的實踐證明,使用前面兩種寫法生成的電路在時序、性能、功耗和面積等方面的表現都不如三段式的寫法,所以即使三段式的寫法會讓你多敲幾次鍵盤,在實際的電路設計中盡量采用三段式的寫法來描述狀態機,多敲的那幾次鍵盤換來的電路質量的提高是完全值得的。
俗話說,“沒有最好,只有更好”。三段式的寫法是不是最好的呢?我認為不見得如此。上面說到,如果采用三段式的寫法,代碼會變長,如果是大的狀態機,結果會更明顯。那么,有沒有一種寫法,既能產生優質的電路,又能少敲幾次鍵盤呢?答案是肯定的。
仔細觀察上面三種寫法,你會發現,無論是哪種寫法,都會使用case語句,case語句不僅占用的代碼行數最多,而且綜合器對case語句還有不同的解析(full case和parallel case),如果我們將三段式的寫法中的case語句換成assign語句,并將狀態轉移塊進一步將當前狀態和下一個狀態拆分開,就變成了“四段式”,四段式的寫法由狀態識別,狀態轉移,轉移條件和對應狀態的輸出四部分組成。那么,脈動計數器狀態機四段式的寫法又是如何實現的呢?


/* * file : fsm4.v * author: Rill * date : 2014-05-11 */ module Mfsm4 ( clk, rst, enable, done ); input wire clk; input wire rst; input wire enable; output done; parameter s_idle = 4'd0; parameter s_1 = 4'd1; parameter s_2 = 4'd2; parameter s_3 = 4'd3; reg [3:0] current_state; wire c_idle = (current_state == s_idle); wire c_1 = (current_state == s_1); wire c_2 = (current_state == s_2); wire c_3 = (current_state == s_3); wire n_idle = c_3; wire n_1 = c_idle & enable; wire n_2 = c_1 & enable; wire n_3 = c_2 & enable; wire [3:0] next_state = {4{n_idle}} & s_idle | {4{n_1}} & s_1 | {4{n_2}} & s_2 | {4{n_3}} & s_3; always @(posedge clk) begin if(rst) current_state <= s_idle; else if(n_idle | n_1 | n_2 | n_3) current_state = next_state; end assign done = c_3; endmodule



6,驗證

通過對比,我們很容易就會發現,采用四段式寫法寫出來的狀態機,代碼數量會減少很多,不僅如此,由于使用的語句類型減少了(只有賦值語句),生成電路的質量也會有所改善。那是否在進行電路設計的時候采用四段式的寫法就沒有缺點了呢?還有句俗話叫“金無足赤,人無完人”,由于四段式的寫法將狀態機拆分的過于零散,以至于綜合器都識別不出來它是一個狀態機了,所以在做覆蓋率(coverage)分析的時候,分析工具只會按一般的邏輯進行分析,各個狀態之間的轉換概率就分析不出來了。
既然狀態機有這么多種寫法,在實際工作中采用哪一種呢?我認為三段式和四段式都是可以接受的(我個人習慣四段式的寫法)。如果將來有一天綜合器對四種寫法綜合出來的電路都差不多,那讀者就可以根據自己的喜好來任意選擇了。 
上面提到,無論采用哪種寫法,模塊實現的功能都是完全相同的,倒底是不是呢?我們需要寫一個簡單的測試激勵(testbench)來驗證一下。


/* * file : tb.v * author: Rill * date : 2014-05-11 */ module tb; reg clk; reg rst; reg enable; wire done1; wire done2; wire done3; wire done4; Mfsm1 fsm1 ( .clk(clk), .rst (rst), .enable(enable), .done(done1) ); Mfsm2 fsm2 ( .clk(clk), .rst (rst), .enable(enable), .done(done2) ); Mfsm3 fsm3 ( .clk(clk), .rst (rst), .enable(enable), .done(done3) ); Mfsm4 fsm4 ( .clk(clk), .rst (rst), .enable(enable), .done(done4) ); always #1 clk = ~clk; integer loop; initial begin clk = 0; rst = 0; enable = 0; loop = 0; repeat (10) @(posedge clk); rst = 1; repeat (4) @(posedge clk); rst = 0; repeat (100) @(posedge clk); for(loop=1;loop<10;loop=loop+1) begin enable = 1; @(posedge clk); enable = 0; @(posedge clk); end repeat (100) @(posedge clk); $stop; end endmodule


7,modelsim下的波形




8,ncsim的波形

上面是用windows下的modelsim得到的仿真波形,如果我們用ncsim(IUS),并且在Linux下,我們最好寫一個簡單的腳本來進行仿真,提高工作效率。


#! /bin/bash # # fsm.sh # usage: ./fsm.sh c/w/r # Rill create 2014-09-03 # TOP_MODULE=tb tcl_file=run.tcl if [ $# != 1 ];then echo "args must be c/w/r" exit 0 fi if [ $1 == "c" ]; then echo "compile lib..." ncvlog -f ./vflist -sv -update -LINEDEBUG; ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE} exit 0 fi if [ -e ${tcl_file} ];then rm ${tcl_file} -f fi touch ${tcl_file} if [ $1 == "w" ];then echo "open wave..." echo "database -open waves -into waves.shm -default;" >> ${tcl_file} echo "probe -shm -variable -all -depth all;" >> ${tcl_file} echo "run" >> ${tcl_file} echo "exit" >> ${tcl_file} fi if [ $1 == "w" -o $1 == "r" ];then echo "sim start..." ncsim ${TOP_MODULE} -input ${tcl_file} fi echo "$(date) sim done!"

運行腳本: 


./fsm.sh c ./fsm.sh w

執行:


simvision wave/wave.trn

即可得到仿真波形,如下所示:




從中可以看出,ncsim和modelsim得到的仿真波形有所不同。


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 福利av在线| 精品视频在线一区 | 亚洲a人 | 欧美 日韩 综合 | 日韩成人综合网 | 免费av黄色片 | 欧美日韩在线影院 | 日本成人黄色片 | 亚洲区视频在线 | 中文字幕一区二区三区在线视频 | 久久996热在线播放 日韩精品第一区 | 亚洲一区二区黄色 | 国产日产久久高清欧美一区 | 久久99网 | 九九综合九九 | 91看片淫黄大片 | 久久精品视频网站 | 九一精品| 91精品国产综合久久久久久丝袜 | 青草青草久 | 久综合| 99久草| av大片网站| 91精品国产日韩91久久久久久 | 久热久热 | 国产精品久久久久久久久免费相片 | 91欧美一区二区三区综合在线 | 国产理论 | 日韩在线二区 | 亚洲欧美在线一区 | 91av官网 | 青草精品 | 欧美专区在线播放 | 噜噜社 | 国产精品久久久久久久久久久久久 | 一区二区三区 在线 | 中文字幕精品一区久久久久 | 国产伦精品一区二区三区 | 黄视频网站在线观看 | 日韩福利 | 熟女少妇a性色生活片毛片 国产伊人精品 |