第6節(jié) 功能描述-時(shí)序邏輯
6.1 always 語(yǔ)句
時(shí)序邏輯的代碼一般有兩種: 同步復(fù)位的時(shí)序邏輯和異步復(fù)位的時(shí)序邏輯。在同步復(fù)位的時(shí)序邏輯中復(fù)位不是立即有效,而在時(shí)鐘上升沿時(shí)復(fù)位才有效。 其代碼結(jié)構(gòu)如下:
在異步復(fù)位的時(shí)序邏輯中復(fù)位立即有效,與時(shí)鐘無(wú)關(guān)。 其代碼結(jié)構(gòu)如下:
針對(duì)時(shí)序邏輯的 verilog 設(shè)計(jì)提出以下建議:
為了教學(xué)的方便代碼統(tǒng)一采用異步時(shí)鐘邏輯,建議同學(xué)們都采用此結(jié)構(gòu),這樣設(shè)計(jì)時(shí)只需考慮是用時(shí)序邏輯還是組合邏輯結(jié)構(gòu)來(lái)進(jìn)行代碼編寫即可。在 實(shí)際工作中請(qǐng)遵從公司的相應(yīng)規(guī)范進(jìn)行代碼設(shè)計(jì)(自行考慮是使用那種時(shí)序邏輯結(jié)構(gòu)以及組合邏輯電路) 。
沒(méi)有復(fù)位信號(hào)的時(shí)序邏輯代碼設(shè)計(jì)是不規(guī)范的,建議不要這樣使用。
6.2 D 觸發(fā)器
數(shù)字電路中介紹了多種觸發(fā)器,如 JK 觸發(fā)器、 D 觸發(fā)器、 RS 觸發(fā)器、 T 觸發(fā)器等。在 FPGA中使用的是最簡(jiǎn)單的觸發(fā)器——D 觸發(fā)器。
6.2.1 D 觸發(fā)器結(jié)構(gòu)
圖 1.3- 37 是 D 觸發(fā)器的結(jié)構(gòu)圖,可以將其視為一個(gè)芯片, 該芯片擁有 4 個(gè)管腳,其中 3 個(gè)是輸入管腳:時(shí)鐘 clk、復(fù)位 rst_n、信號(hào) d; 1 個(gè)是輸出管腳: q。
該芯片的功能如下:當(dāng)給管腳 rst_n 給低電平(復(fù)位有效), 即賦值為 0 時(shí),輸出管腳 q 處于低電平狀態(tài)。如果管腳 rst_n 為高電平, 則觀察管腳 clk 的狀態(tài), 當(dāng) clk 信號(hào)由 0 變 1 即處于上升沿的時(shí)候,將此時(shí) d 的值賦給 q。若 d 是低電平,則 q 也是低電平;若 d 是高電平,則 q 也是高電平。
6.2.2 D 觸發(fā)器波形
圖 1.3- 38 為 D 觸發(fā)器的功能波形圖, 該波形圖反映了 D 觸發(fā)器各個(gè)信號(hào)的變化情況,從左到右表示時(shí)間的走勢(shì)。 從圖中可以看到時(shí)鐘信號(hào)有規(guī)律地進(jìn)行高低變化(初始的波形狀態(tài)是設(shè)想的并不代表實(shí)際波形,在后續(xù)的時(shí)鐘信號(hào)和復(fù)位信號(hào)給出后,波形才按照指令進(jìn)行變換)。
按照從左向右的順序觀察波形圖可以發(fā)現(xiàn):
開始狀態(tài)下, rst_n 等于 1, d 等于 0, q 等于 1。
隨后 rst_n 由 1 變 0,此時(shí)輸出信號(hào) q 立即變成 0。對(duì)應(yīng)的功能是:當(dāng)給管腳 rst_n 低電平,也就是賦值為 0 時(shí),輸出管腳 q 處于低電平狀態(tài)。
在 rst_n 為 0 期間,即使在有時(shí)鐘或信號(hào) d 發(fā)生變化的情況下 q 仍然保持為低電平。
在 rst_n 由 0 變成 1 撤消復(fù)位后, q 沒(méi)有立刻發(fā)生變化。
在第 4 個(gè)時(shí)鐘上升沿時(shí),此時(shí) rst_n 等于 1,而 d 等于 1, 因此 q 變成了 1。
第 5 個(gè)時(shí)鐘上升沿,仍然是同樣情況, rst_n=1, d=1, 因此 q=1。
在第 6 個(gè)時(shí)鐘上升沿, rst_n=1, d=0, 因此 q=0。
第 7~10 個(gè)時(shí)鐘沿也是按同樣方式判斷。對(duì)應(yīng)的功能是:如果管腳 rst_n 為高電平, 則觀察管腳 clk,在 clk 由 0 變 1 即上升沿的時(shí)候,將現(xiàn)在 d 的值賦給 q。若 d 是低電平, q 也是低電平;若 d 是高電平, q 也是高電平。
6.2.3 D 觸發(fā)器代碼
首先, 觀察如下這段時(shí)序邏輯的代碼:
從語(yǔ)法上分析該段代碼的功能為:該段代碼總是在“時(shí)鐘 clk 上升沿或者復(fù)位 rst_n 下降沿”的
時(shí)候執(zhí)行一次。具體執(zhí)行方式如下:
如果復(fù)位 rst_n=0,則 q 的值為 0;
如果復(fù)位 rst_n=1,則將 d 的值賦給 q(注意,前提條件是時(shí)鐘上升沿的時(shí)候)。
上例的功能與本案例的功能是相同的:當(dāng)給管腳 rst_n 給低電平,也就是賦值為 0 時(shí),輸出管腳q 就處于低電平狀態(tài)。如果管腳 rst_n 為高電平則觀察管腳 clk,在 clk 由 0 變 1 即上升沿的時(shí)候,將現(xiàn)在 d 的值賦給 q, d 是低電平, q 也是低電平, d 是高電平, q 也是高電平。
因此可以看出這段代碼的功能與 D 觸發(fā)器的功能是一樣的,即該代碼其實(shí)就是在描述一個(gè) D 觸發(fā)器, 也就是 D 觸發(fā)器的代碼。
前文中已經(jīng)講過(guò)在 FPGA 設(shè)計(jì)中可以用原理圖的形式來(lái)設(shè)計(jì),也可以用硬件描述語(yǔ)言來(lái)設(shè)計(jì)。
當(dāng)用原理圖來(lái)設(shè)計(jì)時(shí)幾個(gè) D 觸發(fā)器還可以忍受,但如果出現(xiàn)幾千幾萬(wàn)個(gè) D 觸發(fā)器則必定是頭暈眼花,而用硬件描述語(yǔ)言 Verilog 則不存在這一問(wèn)題。
6.2.4 怎么看 FPGA 波形
下面來(lái)討論如下圖所示的波形, 先觀察在第 4 個(gè)時(shí)鐘上升沿的時(shí)刻, 思考一下此時(shí)看到的信號(hào) q的值是多少?是 0 還是 1? 或者觀察到的是 q 的上升沿?
首先明確一點(diǎn): Verilog 代碼對(duì)應(yīng)的是硬件,因此應(yīng)該從硬件的角度來(lái)分析這個(gè)問(wèn)題。再來(lái)理清一下代碼的因果關(guān)系:先有時(shí)鐘上升沿, 此為因, 然后再將 d 的值賦給 q,這才是結(jié)果。這個(gè)因果是有先后關(guān)系的,對(duì)于硬件來(lái)說(shuō)這個(gè)“先后”無(wú)論是多么地迅速,也一定會(huì)占用一定時(shí)間,所以 q 的變化會(huì)稍后于 clk 的上升沿。例如下圖就是硬件的實(shí)際變化情況。
圖 1.3- 40 中就很容易看出,第 4 個(gè)時(shí)鐘上升沿時(shí)刻對(duì)應(yīng)的 q 值為 0,也就是變化前的值。上面的波形雖然更將近于實(shí)際,但這樣畫圖使這一過(guò)程非常復(fù)雜, 且非必要操作。 因此建議只需掌握這種看波形規(guī)則,即 時(shí)鐘上升沿看信號(hào),是看到變化之前的值 (由于時(shí)鐘變換需要時(shí)間,具有時(shí)延性)。
所以第 4 個(gè)時(shí)鐘上升沿時(shí),看到 q 值為 0;在第 6 個(gè)時(shí)鐘上升沿時(shí),看到 q 值為 1;在第 7 個(gè)時(shí)鐘上升沿時(shí),看到 q 值為 0;在第 8 個(gè)時(shí)鐘上升沿時(shí),看到 q 值為 1;在第 10 個(gè)時(shí)鐘上升沿時(shí),看到 q 值為 0。注意一下,復(fù)位信號(hào)是在系統(tǒng)開始時(shí)刻或者出現(xiàn)異常時(shí)才使用,一般上電后就不會(huì)再次進(jìn)行復(fù)位, 也可以認(rèn)為復(fù)位是一種特殊情況。
下面考慮正常使用的情況:無(wú)論是從功能上還是波形上,都可以看到信號(hào) q 只在時(shí)鐘上升沿才
變化, 而絕對(duì)不會(huì)在中間發(fā)生變化。在一般的數(shù)字系統(tǒng)中大部分信號(hào)之間的傳遞都是在同一個(gè)時(shí)鐘下進(jìn)行的,即大部分都是同步電路(即在輸入信號(hào)的變化跟隨時(shí)鐘信號(hào)的上升沿進(jìn)行相應(yīng)的變化)。跨時(shí)鐘的電路占比非常小,屬于特殊的異步電路。
下面具體分析每個(gè)時(shí)鐘下 q 信號(hào)的情況:
在 rst_n 由 1 變 0 時(shí), q 立刻變成 0。
在第 2 個(gè)時(shí)鐘上升沿,看到 rst_n 為 0。按代碼功能, q 仍然為 0。
在第 3 個(gè)時(shí)鐘上升沿,看到 rst_n 為 0。按代碼功能, q 仍然為 0。
在第 4 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 1, q 值為 0。按代碼功能, q 變成 1。
在第 5 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 1, q 值為 1。按代碼功能, q 變成 1。
在第 6 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 0, q 值為 1。按代碼功能, q 變成 0。
在第 7 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 1, q 值為 0。按代碼功能, q 變成 1。
在第 8 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 0, q 值為 1。按代碼功能, q 變成 0。
在第 9 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 0, q 值為 0。按代碼功能, q 變成 0。
在第 10 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, d 值為 1, q 值為 0。按代碼功能, q 變成 1。
6.3 時(shí)鐘
時(shí)鐘信號(hào)是每隔固定時(shí)間上下變化的信號(hào)。本次上升沿和上一次上升沿之間占用的時(shí)間就是時(shí)鐘周期, 其倒數(shù)為時(shí)鐘頻率。高電平占整個(gè)時(shí)鐘周期的時(shí)間, 被稱為占空比。
FPGA 中時(shí)鐘的占空比一般是 50%,即高電平時(shí)間和低電平時(shí)間一樣。其實(shí)占空比在 FPGA 內(nèi)部沒(méi)有太大的意義,因?yàn)?FPGA 使用的是時(shí)鐘上升沿來(lái)觸發(fā), 設(shè)計(jì)師們更加關(guān)心的是時(shí)鐘頻率。
如果時(shí)鐘的上升沿每秒出現(xiàn)一次,說(shuō)明時(shí)鐘的時(shí)鐘周期為 1 秒,時(shí)鐘頻率為 1Hz。如果時(shí)鐘的
上升沿每 1 毫秒出現(xiàn)一次,說(shuō)明時(shí)鐘的時(shí)鐘周期為 1 毫秒,時(shí)鐘頻率為 1000Hz,或?qū)懗?1kHz。
現(xiàn)在普通 FPGA 器件所支持的時(shí)鐘頻率范圍一般不超過(guò) 150M,高端器件一般不超過(guò) 700M( 注意,該值為經(jīng)驗(yàn)值,實(shí)際時(shí)鐘的頻率與其具體器件和設(shè)計(jì)電路有關(guān)) , 所對(duì)應(yīng)的時(shí)鐘周期在納秒級(jí)范圍。 因此在本教材中所有案例的時(shí)鐘頻率一般選定范圍是幾十至一百 M 左右。
下面列出本教材常用到的時(shí)鐘頻率以及所對(duì)應(yīng)的時(shí)鐘周期,方便進(jìn)行換算(1s = 1000000000ns)。
時(shí)鐘是 FPGA 中最重要的信號(hào),其他所有信號(hào)在時(shí)鐘的上升沿統(tǒng)一變化,這就像軍隊(duì)里的令旗,所有軍隊(duì)在看到令旗到來(lái)的時(shí)刻執(zhí)行已經(jīng)設(shè)定好的命令。
時(shí)鐘這塊令旗影響著整體電路的穩(wěn)定。首先,時(shí)鐘要非常穩(wěn)定地進(jìn)行跳動(dòng)。就如軍隊(duì)令旗, 如果時(shí)快時(shí)慢就會(huì)讓人無(wú)所適從,容易出錯(cuò)。而如果令旗非常穩(wěn)定,每個(gè)人都知道令旗的指揮周期, 就可以判斷令旗到來(lái)前是否可以完成任務(wù), 如果無(wú)法完成則進(jìn)行改正(修改代碼), 從而避免系統(tǒng)出錯(cuò)。
其次,一個(gè)高效的軍隊(duì)中令旗越少越好, 如果不同部隊(duì)對(duì)標(biāo)不同的令旗,那么部隊(duì)協(xié)作就容易出現(xiàn)問(wèn)題,整個(gè)軍隊(duì)無(wú)法高效的完成工作,容易出現(xiàn)錯(cuò)誤。同樣的道理, FPGA 系統(tǒng)的時(shí)鐘必定是越少越好,最好只存在一個(gè)時(shí)鐘。
以上就是要求不要把信號(hào)放在時(shí)序邏輯敏感列表的原因。
FPGA時(shí)鐘信號(hào)總結(jié),保證電路實(shí)際工作中的性能和穩(wěn)定性:
時(shí)鐘信號(hào)越少越好;
時(shí)鐘信號(hào)不能隨意變換;
實(shí)際應(yīng)用中不要將產(chǎn)生的輸出信號(hào)作為時(shí)鐘信號(hào);
6.4 時(shí)序邏輯代碼和硬件
先來(lái)分析一下下面這段代碼:
仍然從語(yǔ)法上分析該段代碼的功能。該段代碼總是在“時(shí)鐘 clk 上升沿或者復(fù)位 rst_n 下降沿”
的時(shí)候執(zhí)行一次。 具體執(zhí)行方法如下:
如果復(fù)位 rst_n=0,則 q 的值為 0;
如果復(fù)位 rst_n=1,則將(a+d)的結(jié)果賦給 q(注意,前提條件是時(shí)鐘上升沿的時(shí)候)。
假設(shè)用信號(hào) c 表示 a+d 的結(jié)果,則第 2 點(diǎn)可改為:如果復(fù)位 rst_n=1,則將 c 的值賦給 q(注意,前提條件是時(shí)鐘上升沿的時(shí)刻)。很明顯這是一個(gè) D 觸發(fā)器,輸入信號(hào)為 d,輸出為 q,時(shí)鐘為 clk,復(fù)位為 rst_n,其電路示意圖如下圖所示:
可知 c 是 a+d 的結(jié)果, 因此其自然是通過(guò)一個(gè)加法器實(shí)現(xiàn),畫出上面代碼所對(duì)應(yīng)的電路結(jié)構(gòu)圖,可以看出在 D 觸發(fā)器的基礎(chǔ)上增加了一個(gè)加法器。
很容易分析出上面電路的功能:信號(hào) a 和信號(hào) b 相加得到 c, c 連到 D 觸發(fā)器的輸入端。當(dāng) clk出現(xiàn)上升沿時(shí),將 c 的值傳給 q。這與代碼功能是一致的。
下面是代碼和硬件所對(duì)應(yīng)的波形圖。
先看信號(hào) c 的波形: c 的產(chǎn)生只有與 a 和 d 有關(guān),與 rst_n 和 clk 無(wú)關(guān)。 c 是 a+d 的結(jié)果,按照二進(jìn)制加法: 0+0=0, 0+1=1, 1+1=0 可以畫出 c 的波形。
在第 1 個(gè)時(shí)鐘期間, a=0, d=0,所以 c=0+0=0;
在第 2 個(gè)時(shí)鐘期間, a=1, d=0,所以 c=1+0=1;
在第 3 個(gè)時(shí)鐘期間, a=1, d=1,所以 c=1+1=0;
在第 4 個(gè)時(shí)鐘期間, a=0, d=1,所以 c=0+1=1;
在第 5 到第 6 個(gè)時(shí)鐘期間, a=0, d=0,所以 c=0+0=0;
在第 7 個(gè)時(shí)鐘期間, a=1, d=1,所以 c=1+1=0;
在第 8 個(gè)時(shí)鐘期間, a=0, d=1,所以 c=0+1=1;
在第 9 個(gè)時(shí)鐘期間, a=0, d=0,所以 c=0+0=0;
在第 10 個(gè)時(shí)鐘期間, a=0, d=1,所以 c=0+1=1。
再看信號(hào) q 的波形:q 是 D 觸發(fā)器的輸出, 其只在 rst_n 的下降沿或者 clk 的上升沿才變化,其他時(shí)刻不變化, 即 a、 d、 c 發(fā)生變化時(shí), q 不會(huì)立刻發(fā)生改變。
下面具體分析每個(gè)時(shí)鐘下 q 信號(hào)的情況:
在 rst_n 由 1 變 0 時(shí), q 立刻變成 0。
在第 2 個(gè)時(shí)鐘上升沿,看到 rst_n 為 0。按代碼功能, q 仍然為 0。
在第 3 個(gè)時(shí)鐘上升沿,看到 rst_n 為 0。按代碼功能, q 仍然為 0。
在第 4 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 0, q 值為 0。按代碼功能, q 變成 0;
在第 5 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 1, q 值為 0。按代碼功能, q 變成 1;
在第 6 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 0, q 值為 1。按代碼功能, q 變成 0;
在第 7 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 0, q 值為 0。按代碼功能, q 變成 0;
在第 8 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 0, q 值為 0。按代碼功能, q 變成 0;
在第 9 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 1, q 值為 0。按代碼功能, q 變成 1;
在第 10 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 0, q 值為 1。按代碼功能, q 變成 0;
在第 11 個(gè)時(shí)鐘上升沿,看到 rst_n 為 1, c 值為 1, q 值為 0。按代碼功能, q 變成 1。
在討論時(shí)序邏輯的加法器時(shí)對(duì)加法器的輸出 c 和 D 觸發(fā)器的輸出 q 分開進(jìn)行討論,就像兩塊獨(dú)立的電路。 同樣的道理, 在設(shè)計(jì) Verilog 代碼時(shí)也可以將其分開來(lái)進(jìn)行編寫。
先將下面的硬件電路用 Verilog 描述出來(lái):
該電路對(duì)應(yīng)的電路可以寫成:
也可以寫成:
上面的兩段代碼,都是描述同一加法器硬件電路。接著用 Verilog 對(duì)觸發(fā)器進(jìn)行描述。
其代碼的寫法如下:
最后可以看到, 兩段代碼都有信號(hào) c,說(shuō)明這兩段代碼是相連的, 利用硬件連接起來(lái)可以變成如下圖所示的電路。
由此可見,下面兩段代碼所對(duì)應(yīng)的硬件電路是一模一樣的。
那么這兩種代碼哪一種比較好呢?答案是這兩段代碼并無(wú)區(qū)別, 因?yàn)閮烧叩挠布窍嗤摹S纱艘部梢缘弥u(píng)估 verilog 代碼好壞的最基本標(biāo)準(zhǔn), 即不是看代碼行數(shù)而是看硬件。
利用D觸發(fā)器結(jié)合組合邏輯電路和基于D觸發(fā)器的代碼拓展總結(jié):
從性能上來(lái)說(shuō):兩者所表述的功能是一樣的;
從代碼的可讀性上,前者更加直觀,能夠通過(guò)仿真工具將加法器具現(xiàn),但如果代碼量比較多可以使用后者,減少代碼的冗余;
6.5 阻塞賦值和非阻塞賦值
在 always 語(yǔ)句塊中, Verilog 語(yǔ)言支持兩種類型的賦值:阻塞賦值和非阻塞賦值。阻塞賦值使用“=”語(yǔ)句;非阻塞賦值使用“ <=”語(yǔ)句。
阻塞賦值:在一個(gè)“ begin…end”的多行賦值語(yǔ)句,先執(zhí)行當(dāng)前行的賦值語(yǔ)句,再執(zhí)行下一行的賦值語(yǔ)句。
非阻塞賦值:在一個(gè)“ begin…end”的多行賦值語(yǔ)句,在同一時(shí)間內(nèi)同時(shí)賦值。
上面兩個(gè)例子中, 1 到 4 行部分是阻塞賦值,程序會(huì)先執(zhí)行第 2 行,得到結(jié)果后再執(zhí)行第 3 行。6 至 9 行這一段是非阻塞賦值,第 7 行和第 8 行的賦值語(yǔ)句是同時(shí)執(zhí)行的。
具體分析一下這兩段代碼這件的區(qū)別:假設(shè)當(dāng)前 c 的值為 0, d 的值為 0, a 的新值為 1。阻塞賦值的執(zhí)行過(guò)程和結(jié)果為:程序先執(zhí)行第 2 行,此時(shí) c 的值將更新為 1,然后再執(zhí)行 3 行,此時(shí) c+a 也就是相當(dāng)于 1+1=2, 即 d 的值為 2。
非阻塞賦值的執(zhí)行過(guò)程和結(jié)果為:程序同時(shí)執(zhí)行第 7 行和 8 行。需要特別注意是,在執(zhí)行第 8行的時(shí)候,第 7 行還并未執(zhí)行, 這也就意味著 c 的值還沒(méi)有發(fā)生變化,即此時(shí) c 的值為 0。同時(shí)執(zhí)行的結(jié)果是, c 的值為 1, d 的值為 1。
根據(jù)VerilogHDL硬件描述語(yǔ)言規(guī)范要求,組合邏輯中應(yīng)使用阻塞賦值“=”,時(shí)序邏輯中應(yīng)使用非阻塞賦值“ <=”。可以將這個(gè)規(guī)則牢牢記住, 按照這一規(guī)則進(jìn)行設(shè)計(jì)絕對(duì)不會(huì)發(fā)生錯(cuò)誤。制定這個(gè)規(guī)范的原因并不是考慮語(yǔ) 法需要,而是為了正確的進(jìn)行硬件描述。
原文鏈接:https://blog.csdn.net/Royalic/article/details/121196434
-
代碼
+關(guān)注
關(guān)注
30文章
4791瀏覽量
68694 -
時(shí)序邏輯
+關(guān)注
關(guān)注
0文章
39瀏覽量
9168 -
異步復(fù)位
+關(guān)注
關(guān)注
0文章
47瀏覽量
13323
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論