多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > 互聯(lián)網(wǎng) > 數(shù)字集成電路設(shè)計-12-狀態(tài)機的四種寫法

數(shù)字集成電路設(shè)計-12-狀態(tài)機的四種寫法

來源:程序員人生   發(fā)布時間:2014-09-29 23:35:29 閱讀次數(shù):3610次

引言

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

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


1,模塊功能

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


2,一段式

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


/* * 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,兩段式

狀態(tài)機的另外一種寫法是‘兩段式’的。兩段式的寫法,整個狀態(tài)機由兩個always塊組成,第一個塊只負(fù)責(zé)狀態(tài)轉(zhuǎn)移,第二個塊負(fù)責(zé)轉(zhuǎn)移條件和對應(yīng)狀態(tài)的輸出。其中第一個塊是時序邏輯,第二個塊是組合邏輯。脈動計數(shù)器狀態(tài)機的兩段式寫法又是怎樣的呢?


/* * 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,三段式

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


/* * 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,四段式

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


/* * 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,驗證

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

執(zhí)行:


simvision wave/wave.trn

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




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


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 午夜免费视频观看在线播放 | 日韩成人精品日本亚洲 | 欧美区亚洲区 | 真人性做爰aa毛片免费视频观看 | 国产主播福利在线 | 欧美日韩中文一区二区三区 | 妇欲欢公爽公妇高h欲 | 毛片女人毛片一级毛片毛片 | 国产资源中文字幕 | 狼人天堂网 | 黄网站大全 | 美国免费高清一级毛片 | 中文乱码一二三四有限公司 | 亚洲欧美久久婷婷爱综合一区天堂 | 色拍自拍亚洲综合在线 | 男女污视频在线观看 | 久久天天躁夜夜躁狠狠85台湾 | 免费观看黄色的网站 | 一本一道久久综合狠狠老 | 精品中文字幕一区二区三区四区 | 在线播放人成午夜免费视频 | 狼人天堂网 | 亚洲综合第一欧美日韩中文 | 国语对白清晰好大好白在线 | 最近的中文字幕视频大全高清 | 久久艹综合 | 亚洲经典一区二区三区 | 一级做α爱过程免费视频 | 亚洲精品影院 | 亚洲国产高清一区二区三区 | 一级做a免费视频观看网站 一级做a爰片久久毛片 | 小说区 综合区 都市激情 | 免费观看男女羞羞的视频网站 | 高清视频在线观看+免费 | 国产精品久久久久久久久久久威 | 国产永久免费高清在线观看视频 | 亚洲黄网址 | 久久在线视频播放 | 亚洲一区二区三区欧美 | 综合 欧美 小说 另类 图 | 动漫羞羞网站 |