目錄
狀態(tài)機(jī)
1、Mealy 狀態(tài)機(jī)
2、Moore 狀態(tài)機(jī)
3、三段式狀態(tài)機(jī)
狀態(tài)機(jī)
? ? ? ?Verilog 是硬件描述語(yǔ)言,硬件電路是并行執(zhí)行的,當(dāng)需要按照流程或者步驟來(lái)完成某個(gè)功能時(shí),代碼中通常會(huì)使用很多個(gè) if 嵌套語(yǔ)句來(lái)實(shí)現(xiàn),這樣就增加了代碼的復(fù)雜度,以及降低了代碼的可讀性,這個(gè)時(shí)候就可以使用狀態(tài)機(jī)來(lái)編寫代碼。狀態(tài)機(jī)相當(dāng)于一個(gè)控制器,它將一項(xiàng)功能的完成分解為若干步,每一步對(duì)應(yīng)于二進(jìn)制的一個(gè)狀態(tài),通過(guò)預(yù)先設(shè)計(jì)的順序在各狀態(tài)之間進(jìn)行轉(zhuǎn)換,狀態(tài)轉(zhuǎn)換的過(guò)程就是實(shí)現(xiàn)邏輯功能的過(guò)程。
? ? ? ?狀態(tài)機(jī),全稱是有限狀態(tài)機(jī)(Finite State Machine,縮寫為 FSM),是一種在有限個(gè)狀態(tài)之間按一定規(guī)律轉(zhuǎn)換的時(shí)序電路,可以認(rèn)為是組合邏輯和時(shí)序邏輯的一種組合。狀態(tài)機(jī)通過(guò)控制各個(gè)狀態(tài)的跳轉(zhuǎn)來(lái)控制流程,使得整個(gè)代碼看上去更加清晰易懂,在控制復(fù)雜流程的時(shí)候,狀態(tài)機(jī)優(yōu)勢(shì)明顯,因此基本上都會(huì)用到狀態(tài)機(jī),如 SDRAM 控制器等。在本手冊(cè)提供的例程中,會(huì)有多個(gè)用到狀態(tài)機(jī)設(shè)計(jì)的例子,希望大家能夠慢慢體會(huì)和理解,并且能夠熟練掌握。
? ? ? ?根據(jù)狀態(tài)機(jī)的輸出是否與輸入條件相關(guān),可將狀態(tài)機(jī)分為兩大類,即摩爾(Moore)型狀態(tài)機(jī)和米勒(Mealy) 型狀態(tài)機(jī)。
- ? Mealy 狀態(tài)機(jī):組合邏輯的輸出不僅取決于當(dāng)前狀態(tài),還取決于輸入狀態(tài)。
- ? Moore 狀態(tài)機(jī):組合邏輯的輸出只取決于當(dāng)前狀態(tài)。
1、Mealy 狀態(tài)機(jī)
? ? ? ?米勒狀態(tài)機(jī)的模型如下圖所示,模型中第一個(gè)方框是指產(chǎn)生下一狀態(tài)的組合邏輯 F,F 是當(dāng)前狀態(tài)和輸入信號(hào)的函數(shù),狀態(tài)是否改變、如何改變,取決于組合邏輯 F 的輸出;第二框圖是指狀態(tài)寄存器,其由一組觸發(fā)器組成,用來(lái)記憶狀態(tài)機(jī)當(dāng)前所處的狀態(tài),狀態(tài)的改變只發(fā)生在時(shí)鐘的跳邊沿;第三個(gè)框圖是指產(chǎn)生輸出的組合邏輯 G,狀態(tài)機(jī)的輸出是由輸出組合邏輯 G 提供的,G 也是當(dāng)前狀態(tài)和輸入信號(hào)的函數(shù)。
2、Moore 狀態(tài)機(jī)
? ? ? ?摩爾狀態(tài)機(jī)的模型如下圖所示,對(duì)比米勒狀態(tài)機(jī)的模型可以發(fā)現(xiàn),其區(qū)別在于米勒狀態(tài)機(jī)的輸出由當(dāng)前狀態(tài)和輸入條件決定的,而摩爾狀態(tài)機(jī)的輸出只取決于當(dāng)前狀態(tài)。
3、三段式狀態(tài)機(jī)
? ? ? 根據(jù)狀態(tài)機(jī)的實(shí)際寫法,狀態(tài)機(jī)還可以分為一段式、二段式和三段式狀態(tài)機(jī)。
? ? ? 一段式:整個(gè)狀態(tài)機(jī)寫到一個(gè) always 模塊里面,在該模塊中既描述狀態(tài)轉(zhuǎn)移,又描述狀態(tài)的輸入和輸出。不推薦采用這種狀態(tài)機(jī),因?yàn)閺拇a風(fēng)格方面來(lái)講,一般都會(huì)要求把組合邏輯和時(shí)序邏輯分開(kāi);從代碼維護(hù)和升級(jí)來(lái)說(shuō),組合邏輯和時(shí)序邏輯混合在一起不利于代碼維護(hù)和修改,也不利于約束。
? ? ? ? 二段式:用兩個(gè) always 模塊來(lái)描述狀態(tài)機(jī),其中一個(gè) always 模塊采用同步時(shí)序描述狀態(tài)轉(zhuǎn)移;另一個(gè)模塊采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件,描述狀態(tài)轉(zhuǎn)移規(guī)律以及輸出。不同于一段式狀態(tài)機(jī)的是,它需要定義兩個(gè)狀態(tài),現(xiàn)態(tài)和次態(tài),然后通過(guò)現(xiàn)態(tài)和次態(tài)的轉(zhuǎn)換來(lái)實(shí)現(xiàn)時(shí)序邏輯。
? ? ? ? 三段式:在兩個(gè) always 模塊描述方法基礎(chǔ)上,使用三個(gè) always 模塊,一個(gè) always 模塊采用同步時(shí)序描述狀態(tài)轉(zhuǎn)移,一個(gè) always 采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件,描述狀態(tài)轉(zhuǎn)移規(guī)律,另一個(gè) always 模塊描述狀態(tài)輸出(可以用組合電路輸出,也可以時(shí)序電路輸出)。
? ? ? ? 實(shí)際應(yīng)用中三段式狀態(tài)機(jī)使用最多,因?yàn)槿问綘顟B(tài)機(jī)將組合邏輯和時(shí)序分開(kāi),有利于綜合器分析優(yōu)化以及程序的維護(hù);并且三段式狀態(tài)機(jī)將狀態(tài)轉(zhuǎn)移與狀態(tài)輸出分開(kāi),使代碼看上去更加清晰易懂,提高了代碼的可讀性,推薦大家使用三段式狀態(tài)機(jī),本文也著重講解三段式。
? ? ? ?三段式狀態(tài)機(jī)的基本格式是:
- ? ? ? 第一個(gè) always 語(yǔ)句實(shí)現(xiàn)同步狀態(tài)跳轉(zhuǎn);
- ? ? ? 第二個(gè) always 語(yǔ)句采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件;
- ? ? ? 第三個(gè) always 語(yǔ)句描述狀態(tài)輸出(可以用組合電路輸出,也可以時(shí)序電路輸出)。
? ? ? ? 在開(kāi)始編寫狀態(tài)機(jī)代碼之前,一般先畫出狀態(tài)跳轉(zhuǎn)圖,這樣在編寫代碼時(shí)思路會(huì)比較清晰,下面以一個(gè) 7 分頻為例(對(duì)于分頻等較簡(jiǎn)單的功能,可以不使用狀態(tài)機(jī),這里只是演示狀態(tài)機(jī)編寫的方法),狀態(tài)跳轉(zhuǎn)圖如下圖所示:
狀態(tài)跳轉(zhuǎn)圖畫完之后,接下來(lái)通過(guò) parameter 來(lái)定義各個(gè)不同狀態(tài)的參數(shù),如下代碼所示:
parameter S0 = 7'b0000001; //獨(dú)熱碼定義方式
parameter S1 = 7'b0000010;
parameter S2 = 7'b0000100;
parameter S3 = 7'b0001000;
parameter S4 = 7'b0010000;
parameter S5 = 7'b0100000;
parameter S6 = 7'b1000000;
這里是使用獨(dú)熱碼的方式來(lái)定義狀態(tài)機(jī),每個(gè)狀態(tài)只有一位為 1,當(dāng)然也可以直接定義成十進(jìn)制的 0,1,2……7。
? ? ? ?因?yàn)槲覀兌x成獨(dú)熱碼的方式,每一個(gè)狀態(tài)的位寬為 7 位,接下來(lái)還需要定義兩個(gè) 7 位的寄存器,一 個(gè)用來(lái)表示當(dāng)前狀態(tài),另一個(gè)用來(lái)表示下一個(gè)狀態(tài),如下所示:
reg [6:0] curr_st ; //當(dāng)前狀態(tài)
reg [6:0] next_st ; //下一個(gè)狀態(tài)
? ? ? ?接下來(lái)就可以使用三個(gè) always 語(yǔ)句來(lái)開(kāi)始編寫狀態(tài)機(jī)的代碼,第一個(gè) always 采用同步時(shí)序描述狀態(tài)轉(zhuǎn)移,第二個(gè) always 采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件,第三個(gè) always 是描述狀態(tài)輸出,一個(gè)完整的三段式狀態(tài)機(jī)的例子如下代碼所示:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/06/01 14:27:15
// Design Name:
// Module Name: divider7_fsm
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//三段式狀態(tài)機(jī)的基本格式是:
//第一個(gè) always 語(yǔ)句實(shí)現(xiàn)同步狀態(tài)跳轉(zhuǎn);
//第二個(gè) always 語(yǔ)句采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件;
//第三個(gè) always 語(yǔ)句描述狀態(tài)輸出(可以用組合電路輸出,也可以時(shí)序電路輸出)。
//在開(kāi)始編寫狀態(tài)機(jī)代碼之前,一般先畫出狀態(tài)跳轉(zhuǎn)圖,這樣在編寫代碼時(shí)思路會(huì)比較清晰.
//以一個(gè) 7 分頻為例
module divider7_fsm(
//系統(tǒng)時(shí)鐘與復(fù)位
input sys_clk,
input sys_rst_n,
//輸出時(shí)鐘
output reg clk_divide_7
);
//在編寫狀態(tài)機(jī)代碼時(shí)首先要定義狀態(tài)變量(代碼中的參數(shù) S0~S6)與狀態(tài)寄存器(curr_st、next_st)
//parameter define
parameter S0 = 7'b0000001; //獨(dú)熱碼定義方式
parameter S1 = 7'b0000010;
parameter S2 = 7'b0000100;
parameter S3 = 7'b0001000;
parameter S4 = 7'b0010000;
parameter S5 = 7'b0100000;
parameter S6 = 7'b1000000;
//reg define
reg [6:0] curr_st; //當(dāng)前狀態(tài)
reg [6:0] next_st; //下一個(gè)狀態(tài)
//*********************************************************
//** main code
//**********************************************************
//狀態(tài)機(jī)的第一段采用同步時(shí)序描述狀態(tài)轉(zhuǎn)移
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
curr_st <= S0;
else
curr_st <= next_st;
end
//狀態(tài)機(jī)的第二段采用邏輯組合判斷狀態(tài)轉(zhuǎn)移條件
always @(*) begin
case (curr_st)
S0:next_st = S1;
S1:next_st = S2;
S2:next_st = S3;
S3:next_st = S4;
S4:next_st = S5;
S5:next_st = S6;
S6:next_st = S0;
default:next_st = S0;
endcase
end
//狀態(tài)機(jī)的第三段描述狀態(tài)輸出(這里采用時(shí)序電路輸出)
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
clk_divide_7 <= 1'b0;
else if ((curr_st == S0) | (curr_st == S1) | (curr_st == S2) | (curr_st == S3))
clk_divide_7 <= 1'b0;
else if ((curr_st == S4) | (curr_st == S5) | (curr_st == S6))
clk_divide_7 <= 1'b1;
else
;
end
endmodule
//采用這種描述方法雖然代碼結(jié)構(gòu)復(fù)雜了一些,
//但是這樣做的好處是可以有效地濾去組合邏輯輸出的毛刺,
//同時(shí)也可以更好的進(jìn)行時(shí)序計(jì)算與約束,另外對(duì)于總線形式的輸出信號(hào)來(lái)說(shuō),
//容易使總線數(shù)據(jù)對(duì)齊,減小總線數(shù)據(jù)間的偏移,從而降低接收端數(shù)據(jù)采樣出錯(cuò)的頻率。
? ? ? ? 在編寫狀態(tài)機(jī)代碼時(shí)首先要定義狀態(tài)變量(代碼中的參數(shù) S0~S6)與狀態(tài)寄存器(curr_st、next_st),如代碼中第 10 行至第 21 行所示;接下來(lái)使用三個(gè) always 語(yǔ)句來(lái)實(shí)現(xiàn)三段狀態(tài)機(jī),第一個(gè) always 語(yǔ)句實(shí)現(xiàn)同步狀態(tài)跳轉(zhuǎn)(如代碼的第 27 至第 33 行所示),在復(fù)位的時(shí)候,當(dāng)前狀態(tài)處在 S0 狀態(tài),否則將下一個(gè)狀態(tài)賦值給當(dāng)前狀態(tài);第二個(gè) always 采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件(如代碼的第 35 行至第 47 行代碼所示),這里每一個(gè)狀態(tài)只保持一個(gè)時(shí)鐘周期,也就是直接跳轉(zhuǎn)到下一個(gè)狀態(tài),在實(shí)際應(yīng)用中,一般根據(jù)輸入的條件來(lái)判斷是否跳轉(zhuǎn)到其它狀態(tài)或者停留在當(dāng)前轉(zhuǎn)態(tài),最后在 case 語(yǔ)句后面增加一個(gè) default 語(yǔ)句,來(lái)防止?fàn)顟B(tài)機(jī)處在異常的狀態(tài);第三個(gè) always 輸出分頻后的時(shí)鐘(如代碼的第 49 至第 59 行代碼所示),狀態(tài)機(jī)的第三段可以使用組合邏輯電路輸出,也可以使用時(shí)序邏輯電路輸出,一般推薦使用時(shí)序電路輸出,因?yàn)闋顟B(tài)機(jī)的設(shè)計(jì)和其它設(shè)計(jì)一樣,最好使用同步時(shí)序方式設(shè)計(jì),以提高設(shè)計(jì)的穩(wěn)定性,消除毛刺。
? ? ? ?從代碼中可以看出,輸出的分頻時(shí)鐘 clk_divide_7 只與當(dāng)前狀態(tài)(curr_st)有關(guān),而與輸入狀態(tài)無(wú)關(guān),所以屬于摩爾型狀態(tài)機(jī)。狀態(tài)機(jī)的第一段對(duì)應(yīng)摩爾狀態(tài)機(jī)模型的狀態(tài)寄存器,用來(lái)記憶狀態(tài)機(jī)當(dāng)前所處的狀態(tài);狀態(tài)機(jī)的第二段對(duì)應(yīng)摩爾狀態(tài)機(jī)模型產(chǎn)生下一狀態(tài)的組合邏輯 F;狀態(tài)機(jī)的第三段對(duì)應(yīng)摩爾狀態(tài)機(jī)產(chǎn)生輸出的組合邏輯 G,因?yàn)椴捎脮r(shí)序電路輸出有很大的優(yōu)勢(shì),所以這里第三段狀態(tài)機(jī)是由時(shí)序電路輸出的。
? ? ? ?狀態(tài)機(jī)采用時(shí)序邏輯輸出的狀態(tài)機(jī)模型如下圖所示:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-489597.html
? ? ? ?采用這種描述方法雖然代碼結(jié)構(gòu)復(fù)雜了一些,但是這樣做的好處是可以有效地濾去組合邏輯輸出的毛刺,同時(shí)也可以更好的進(jìn)行時(shí)序計(jì)算與約束,另外對(duì)于總線形式的輸出信號(hào)來(lái)說(shuō),容易使總線數(shù)據(jù)對(duì)齊,減小總線數(shù)據(jù)間的偏移,從而降低接收端數(shù)據(jù)采樣出錯(cuò)的頻率。 文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-489597.html
到了這里,關(guān)于Verilog 高級(jí)知識(shí)點(diǎn)---狀態(tài)機(jī)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!