作者:NingHeChuan(寧河川)
前言:狀態機大法好,狀態機幾乎可以實現一切時序邏輯電路。
有限狀態機(Finite State Machine, FSM),根據狀態機的輸出是否與輸入有關,可分為Moore型狀態機和Mealy型狀態機。Moore型狀態機輸出僅僅與現態有關和Mealy型狀態機不僅與現態有關,也與輸入有關,所以會受到輸入的干擾,可能會產生毛刺(Glith)的現象,所以我們通常使用的是Moore型狀態機。
狀態機的編碼,二進制編碼(Binary),格雷碼編碼(Gray-code),獨熱碼(One-hot)。不同的編碼方式是防止在狀態轉移中發生突變,使得狀態轉移更為穩定,系統更加可靠,但是通常情況下我們直接采用的是二進制進行編碼,除非系統對穩定性和狀態編碼有特殊要求。
狀態機的描述,一段式、二段式、三段式。
一段式狀態機,將組合邏輯和時序邏輯混合在一起,這樣的寫法對于邏輯簡單的狀態機來說還是可以使用的,但是對于復雜的邏輯就不推薦了,如果狀態復雜也會容易出錯,而且一個always塊中信號太多也不利于維護和修改。
//狀態參數聲明
parameter S0 = 4‘b0000,
S1 = 4’b0001,
s2 = 4‘b0010;
//FSM one segment
reg [3:0] state;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
state 《= S0;
else begin
case(state)
S0:
S1:
S2:
。
。
。
default:
endcase
end
end
兩段式狀態機也是一種常用的寫法,它把組合邏輯和時序邏輯區分出來,第一段負責狀態的轉移,第二段是組合邏輯賦值,但是這種寫法的缺點是,組合邏輯較容易產生毛刺等常見問題,關于組合邏輯較容易產生毛刺原因,下文會提到。
//狀態參數聲明
parameter S0 = 4’b0000,
S1 = 4‘b0001,
s2 = 4’b0010;
//FSM two segment
reg [3:0] pre_state;
reg [3:0] next_state;
//--------------------------------------
//FSM one
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
pre_state 《= S0;
else
pre_state 《= next_state;
end
//FSM two
always @(*)begin
case(pre_state)
S0:
S1:
S2:
。
。
。
default:;
endcase
end
三段式狀態機就可以較好的解決一段二段的不足,我也是比較推薦的寫法,第一段采用時序邏輯負責狀態轉移,第二段組合邏輯負責數據賦值,第三段時序邏輯負責輸出,代碼層次清晰,容易維護,時序邏輯的輸出解決了兩段式寫法中組合邏輯的毛刺問題。但是資源消耗會多一些,此外,三段式從輸入到輸出會比一段式和二段式延遲一個時鐘周期。在書寫狀態機的時候,一定要事先設計好狀態轉移圖,將所有的狀態都考慮到,避免狀態進入死循環,或者跳到偏離態。
//狀態參數聲明
parameter S0 = 4‘b0000,
S1 = 4’b0001,
s2 = 4‘b0010;
//FSM three segment
//--------------------------------------
//FSM one
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
pre_state 《= S0;
else
pre_state 《= next_state;
end
//FSM two
always @(*)begin
case(pre_state)
S0:
S1:
S2:
。
。
。
default:;
endcase
end
//FSM three
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
dout 《= ’b0;
else begin
case(pre_state)
S0:
S1:
S2:
。
。
。
default:;
endcase
end
end
如下圖,我通過一個實例來說明一下狀態機的使用。下面是一個序列檢測狀態轉移圖,檢測是的使1101這個序列,我們給這個序列的檢測序列是11101 1101這一串數據。在這個序列檢測器中,我們允許使用重復位。也就是說,前一個“1101”最后一位的1可以作為后一個“1101”序列的起始位。如果不允許重復為位,只需要將S4到S2的轉移替換成S4到S1即可。
首先,從輸出狀態S0開始檢測,當S0檢測到1時跳到S1,否則跳回S0,S1檢測到1狀態跳到S2,否則跳回S0,S2檢測到0狀態跳到S3,否則還停留在S2狀態,因為這里我們的檢測序列允許重復位,所以S1檢測到的1與S2檢測到的1保留,不舍棄作為一下組1101的前兩位,所以只需要繼續檢測下一位數據即可。S3、S4的狀態一次類推。這里舉著個例子是為了說明狀態機的狀態跳轉,在我們實際的設計中這種情況也是會遇到的。
在使用狀態機來描述時序電路的時候,首先應該做的是畫出狀態轉移圖,然后根據狀態跳轉來描述代碼,最后便會事半功倍。這段序列檢測的代碼我也貼出來。當然這只是序列檢測的一個應用了,我前面也說了狀態機機會可以實現一切的時序電路。如果你遇到實在不好解決的設計,那么這個時候,你就可以考慮一下使用狀態機了。
module state(
input mclk,
input rst_n,
input din,
output reg dout;
);
parameter s0 = 3‘b000,
s1 = 3’b001,
s2 = 3‘b010,
s3 = 3’b011,
s4 = 3‘b100;//狀態
//此為三段式狀態機,還有一段式狀態機,二段式狀態機
reg [2:0] present_state, next_state;
//用摩爾狀態機設計1011序列檢測器
//狀態寄存器
always @(posedge mclk or negedge rst_n)
begin
if(!rst_n)
present_state 《= s0;
else
present_state 《= next_state;
end
//狀態轉換模塊
always @(*)
begin
case(present_state)
s0: if(din==1)
next_state = s1;
else
next_state = s0;
s1: if(din==0)
next_state = s2;
else
next_state = s1;
s2: if(din==1)
next_state = s3;
else
next_state = s0;
s3: if(din==1)
next_state = s4;
else
next_state = s2;
s4: if(din==0)
next_state = s2;
else
next_state = s1;
default: next_state = s0;
endcase
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
dout 《= 1’b0;
else if(present_state ==s4)
dout 《= 1‘b1;
else
dout 《= 1’b0;
end
63 endmodule
在狀態機的設計中,一段式狀態機用時序邏輯,二段式狀態機第一段用時序邏輯,第二段用組合邏輯,三段式狀態機第一段用時序邏輯,第二段用組合邏輯,第三段用時序邏輯。我在設計的時候,嘗試把第二段寫成時序邏輯,最終結果并沒有影響,時序邏輯隨時鐘變化,組合邏輯是直接賦值,所以在第三段狀態機進行輸出時,輸出結果肯定是穩定的,但是這樣會限制fmax。如果用時序邏輯的主頻率過高的話,可能不如第二段組合邏輯賦值來的穩定,這里就還需要考慮到時序分析了,暫且不談。這里還需要提的是使用三段式狀態機相較于一段二段式,會延遲一個時鐘周期輸出,就是因為第三段使用了時序邏輯的緣故。
既然談狀態機的時候,說到了組合邏輯會產生毛刺的現象,那么這里就順便整理一下,為什么組合邏輯會產生毛刺,組合邏輯的冒險與競爭分析。
競爭(Competition)在組合邏輯電路中,某個輸入變量通過兩條或兩條以上的途徑傳到輸出端,由于每條途徑延遲時間不同,到達輸出門的時間就有先有后,這種現象稱為競爭。把不會產生錯誤輸出的競爭的現象稱為非臨界競爭。把產生暫時性的或永久性錯誤輸出的競爭現象稱為臨界競爭。
冒險(risk)信號在器件內部通過連線和邏輯單元時,都有一定的延時。延時的大小與連線的長短和邏輯單元的數目有關,同時還受器件的制造工藝、工作電壓、溫度等條件的影響。信號的高低電平轉換也需要一定的過渡時間。由于存在這兩方面因素,多路信號的電平值發生變化時,在信號變化的瞬間,組合邏輯的輸出有先后順序,并不是同時變化,往往會出現一些不正確的尖峰信號,這些尖峰信號稱為“毛刺”。如果一個組合邏輯電路中有“毛刺”出現,就說明該電路存在冒險
競爭冒險(Competition risk)產生原因:由于延遲時間的存在,當一個輸入信號經過多條路徑傳送后又重新會合到某個門上,由于不同路徑上門的級數不同,或者門電路延遲時間的差異,導致到達會合點的時間有先有后,從而產生瞬間的錯誤輸出。
首先看下面這個電路,使用了兩個邏輯門,一個非門和一個與門,本來在理想情況下F的輸出應該是一直穩定的0輸出,但是實際上每個門電路從輸入到輸出是一定會有時間延遲的,這個時間通常叫做電路的開關延遲。而且制作工藝、門的種類甚至制造時微小的工藝偏差,都會引起這個開關延遲時間的變化。
實際上如果算上非門的延遲的話,那么F最后就會產生毛刺。信號由于經由不同路徑傳輸達到某一匯合點的時間有先有后的現象,就稱之為競爭,由于競爭現象所引起的電路輸出發生瞬間錯誤的現象,就稱之為冒險,所以在設計中我們要注意避免這個現象,最簡單的避免方法是盡量使用時序邏輯同步輸出。
這篇狀態機和組合邏輯的冒險競爭就聊到這里,下次我們接著說時序邏輯的冒險競爭。
評論
查看更多