|
時(shí)序電路的狀態(tài)是一個(gè)狀態(tài)變量集合,這些狀態(tài)變量在任意時(shí)刻的值都包含了為確定電路的未來行為而必需考慮的所有歷史信息。
狀態(tài)機(jī)采用VerilogHDL語(yǔ)言編碼,建議分為三個(gè)always段完成。這是為什么呢?
設(shè)計(jì)FSM的方法和技巧多種多樣,但是總結(jié)起來有兩大類:第一種,將狀態(tài)轉(zhuǎn)移和狀態(tài)的操作和判斷等寫到一個(gè)模塊(process、block)中。另一種是將狀態(tài)轉(zhuǎn)移單獨(dú)寫成一個(gè)模塊,將狀態(tài)的操作和判斷等寫到另一個(gè)模塊中(在Verilog代碼中,相當(dāng)于使用兩個(gè)“always” block)。其中較好的方式是后者。其原因如下。
首先FSM和其他設(shè)計(jì)一樣,最好使用同步時(shí)序方式設(shè)計(jì),好處不再累述。而狀態(tài)機(jī)實(shí)現(xiàn)后,狀態(tài)轉(zhuǎn)移是用寄存器實(shí)現(xiàn)的,是同步時(shí)序部分。狀態(tài)的轉(zhuǎn)移條件的判斷是通過組合邏輯判斷實(shí)現(xiàn)的,之所以第二種比第一種編碼方式合理,就在于第二種編碼將同步時(shí)序和組合邏輯分別放到不同的程序塊(process,block)中實(shí)現(xiàn)。這樣做的好處不僅僅是便于閱讀、理解、維護(hù),更重要的是利于綜合器優(yōu)化代碼,利于用戶添加合適的時(shí)序約束條件,利于布局布線器實(shí)現(xiàn)設(shè)計(jì)。
三段式建模描述FSM的狀態(tài)機(jī)輸出時(shí),只需指定case敏感表為次態(tài)寄存器,然后直接在每個(gè)次態(tài)的case分支中描述該狀態(tài)的輸出即可,不用考慮狀態(tài)轉(zhuǎn)移條件。
三段式描述方法雖然代碼結(jié)構(gòu)復(fù)雜了一些,但是換來的優(yōu)勢(shì)是使FSM做到了同步寄存器輸出,消除了組合邏輯輸出的不穩(wěn)定與毛刺的隱患,而且更利于時(shí)序路徑分組,一般來說在FPGA/CPLD等可編程邏輯器件上的綜合與布局布線效果更佳。
示例如下:
//第一個(gè)進(jìn)程,同步時(shí)序always模塊,格式化描述次態(tài)寄存器遷移到現(xiàn)態(tài)寄存器
always @ (posedge clk or negedge rst_n) //異步復(fù)位
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state;//注意,使用的是非阻塞賦值
//第二個(gè)進(jìn)程,組合邏輯always模塊,描述狀態(tài)轉(zhuǎn)移條件判斷
always @ (current_state) //電平觸發(fā)
begin
next_state = x; //要初始化,使得系統(tǒng)復(fù)位后能進(jìn)入正確的狀態(tài)
case(current_state)
S1: if(...)
next_state = S2; //阻塞賦值
...
endcase
end
//第三個(gè)進(jìn)程,同步時(shí)序always模塊,格式化描述次態(tài)寄存器輸出
always @ (posedge clk or negedge rst_n)
...//初始化
case(next_state)
S1:
out1 <= 1'b1; //注意是非阻塞邏輯
S2:
out2 <= 1'b1;
default:... //default的作用是免除綜合工具綜合出鎖存器。
endcase
end
三段式并不是一定要寫為3個(gè)always塊,如果狀態(tài)機(jī)更復(fù)雜,就不止3段了。
//注:================================================================
1. 三段always模塊中,第一個(gè)和第三個(gè)always模塊是同步時(shí)序always模塊,用非阻塞賦值(“ <= ”);第二個(gè)always模塊是組合邏輯always模塊,用阻塞賦值(“ = ”)。
2. 第二部分為組合邏輯always模塊,為了抑制warning信息,對(duì)于always的敏感列表建議采用always@(*)的方式。
3. 第二部分,組合邏輯always模塊,里面判斷條件一定要包含所有情況!可以用else保證包含完全。
4. 第二部分,組合邏輯電平要維持超過一個(gè)clock,仿真時(shí)注意。
5. 需要注意:第二部分case中的條件應(yīng)該為當(dāng)前態(tài)(current_state),第三部分case中的條件應(yīng)該為次態(tài)(next_state)。
6. 編碼原則,binary和gray-code適用于觸發(fā)器資源較少,組合電路資源豐富的情況(CPLD),對(duì)于FPGA,適用one-hot code。這樣不但充分利用FPGA豐富的觸發(fā)器資源,還因?yàn)橹恍璞容^一個(gè)bit,速度快,組合電路簡(jiǎn)單。
7. 初始化狀態(tài)和默認(rèn)狀態(tài)。
一個(gè)完備的狀態(tài)機(jī)(健壯性強(qiáng))應(yīng)該具備初始化狀態(tài)和默認(rèn)狀態(tài)。當(dāng)芯片加電或者復(fù)位后,狀態(tài)機(jī)應(yīng)該能夠自動(dòng)將所有判斷條件復(fù)位,并進(jìn)入初始化狀態(tài)。需要注明的一點(diǎn)是,大多數(shù)FPGA有GSR(Global Set/Reset)信號(hào),當(dāng)FPGA加電后,GSR信號(hào)拉高,對(duì)所有的寄存器,RAM等單元復(fù)位/置位,這時(shí)配置于FPGA的邏輯并未生效,所以不能保證正確的進(jìn)入初始化狀態(tài)。所以使用GSR企圖進(jìn)入FPGA的初始化狀態(tài),常常會(huì)產(chǎn)生種種不必一定的麻煩。一般的方法是采用異步復(fù)位信號(hào),當(dāng)然也可以使用同步復(fù)位,但是要注意同步復(fù)位的邏輯設(shè)計(jì)。解決這個(gè)問題的另一種方法是將默認(rèn)的初始狀態(tài)的編碼設(shè)為全零,這樣GSR復(fù)位后,狀態(tài)機(jī)自動(dòng)進(jìn)入初始狀態(tài)。
令一方面狀態(tài)機(jī)也應(yīng)該有一個(gè)默認(rèn)(default)狀態(tài),當(dāng)轉(zhuǎn)移條件不滿足,或者狀態(tài)發(fā)生了突變時(shí),要能保證邏輯不會(huì)陷入“死循環(huán)”。這是對(duì)狀態(tài)機(jī)健壯性的一個(gè)重要要求,也就是常說的要具備“自恢復(fù)”功能。對(duì)應(yīng)于編碼就是對(duì)case,if-else語(yǔ)句要特別注意,要寫完備的條件判斷語(yǔ)句。VHDL中,當(dāng)使用CASE語(yǔ)句的時(shí)候,要使用“When Others”建立默認(rèn)狀態(tài)。使用“IF...THEN...ELSE”語(yǔ)句的時(shí)候,要用在“ELSE”指定默認(rèn)狀態(tài)。Verilog中,使用“case”語(yǔ)句的時(shí)候要用“default”建立默認(rèn)狀態(tài),使用“if...else”語(yǔ)句的注意事項(xiàng)相似。
8. 另外提一個(gè)技巧:大多數(shù)綜合器都支持Verilog編碼狀態(tài)機(jī)的完備狀態(tài)屬性--“full case”。這個(gè)屬性用于指定將狀態(tài)機(jī)綜合成完備的狀態(tài),如Synplicity的綜合工具(Synplify/Synplify Pro,Amplify,etc)支持的命令格式如下:
case (current_state) // synthesis full_case
2’b00 : next_state <= 2’b01;
2’b01 : next_state <= 2’b11;
2’b11 : next_state <= 2’b00;
//這兩段代碼等效
case (current_state)
2’b00 : next_state <= 2’b01;
2’b01 : next_state <= 2’b11;
2’b11 : next_state <= 2’b00;
default : next_state <= 2bx;
9. Synplicity還有一個(gè)關(guān)于狀態(tài)機(jī)的綜合屬性,叫“synthesis parallel_case”,其功能是檢查所有的狀態(tài)是“并行的”(parallel),也就是說在同一時(shí)間只有一個(gè)狀態(tài)能夠成立。
10. 狀態(tài)機(jī)的定義可以用parameter定義,但是不推薦使用`define宏定義的方式,因?yàn)閌define宏定義在編譯時(shí)自動(dòng)替換整個(gè)設(shè)計(jì)中所定義的宏,而parameter僅僅定義模塊內(nèi)部的參數(shù),定義的參數(shù)不會(huì)與模塊外的其他狀態(tài)機(jī)混淆。
11. 對(duì)于狀態(tài)比較多的狀態(tài)機(jī),可以將所有狀態(tài)分為幾個(gè)大狀態(tài),然后再使用小狀態(tài),可以減少狀態(tài)譯碼的時(shí)間。
12. 在代碼中添加綜合器的綜合約束屬性或者在圖形界面下設(shè)置綜合約束屬性可以比較方便的改變狀態(tài)的編碼。
如VHDL的示例:
Synplicity:
attribute syn_encoding : string;
attribute syn_encoding of <signal_name> : type is "value ";
-- The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.
Exemplar:
-- Declare TYPE_ENCODING_STYLE. attribute
-- Not needed if the exemplar_1164 package is used
type encoding_style. is (BINARY, ONEHOT, GRAY, RANDOM, AUTO);
attribute TYPE_ENCODING_STYLE. encoding_style;
...
attribute TYPE_ENCODING_STYLE. of <typename> : type is ONEHOT;
Verilog示例:
Synplicity:
Reg[2:0] state; /* synthesis syn_encoding = "value" */;
// The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.
Exemplar:
Parameter /* exemplar enum <type_name> */ s0 = 0, s1 = 1, s2 = 2, s3 = 3, S4 = 4;
Reg [2:0] /* exemplar enum <type_name> */ present_state, next_state ;
13. 小技巧:仔細(xì)檢查綜合器的綜合報(bào)告,目前大多數(shù)的綜合器對(duì)所綜合出的latch都會(huì)報(bào)“warning”,通過綜合報(bào)告可以較為方便地找出無意中生成的latch
|
評(píng)分
-
查看全部評(píng)分
|