第一篇:學(xué)習(xí)verilog后的總結(jié)
關(guān)于這個學(xué)期學(xué)習(xí)verilog hdl語言后的小結(jié)
在完成本次verilog大作業(yè)的過程中,我不僅學(xué)到了很多只靠看書本學(xué)不到的知識,而且體會到了團隊協(xié)作的力量,在團隊成員的合作下,經(jīng)歷了不少困難,終于完成了verilog的大作業(yè),雖然過程并不是和想象中的一樣,而且作業(yè)也與老師要求的有點差距,但是從中學(xué)習(xí)到了許多關(guān)于verilog的使用與仿真的基礎(chǔ)知識,也對課上學(xué)到的語句有了更深的理解,并將其應(yīng)用到了實際工程中,使自己的運用能力得到了很好的鍛煉,對基本操作已經(jīng)較熟練的掌握,對其中一些細(xì)節(jié)問題,如仿真時間的選取等也有了自己的理解。實踐出真知,通過在軟件上反復(fù)改程序、跑程序我也學(xué)會了很多只看書本發(fā)現(xiàn)不了的問題,鍛煉了自己的解決問題能力。這對于今后的學(xué)習(xí)是有很大的幫助的。以下做一下簡要總結(jié):
這次的大作業(yè)是通過我們小組四個同學(xué)共同努力下完成的,其中有很多收獲也有很多感受。這次的大作業(yè)給了我們一次很好的鍛煉機會,通過這次大作業(yè),我開始熟悉用verilog設(shè)計的最基本的方法和流程,課堂上學(xué)到的東西只有自己通過應(yīng)用才能加深自己的理解,課堂上學(xué)到的并不是全部,要想真正的學(xué)好這門課,只有在實踐中運用才能真正的體會到這門課的精髓,這次的大作業(yè)很好的驗證了。
有一個外因也是給了我們的幫助,那就是網(wǎng)絡(luò)的強大,在這個信息的時代,互聯(lián)網(wǎng)的作用顯而易見,如果能夠充分得利用網(wǎng)絡(luò)上海量的信息,掌握一定的檢索技巧,就可以獲得很多有價值的東西,比如參考別人的算法和程序段,觀看關(guān)于Quartus II軟件的使用教程視頻。這比起關(guān)起門來自己鉆研要強上不少。對于如何使用verilog hdl寫出可綜合的代碼真的是一件不容易的事情,而真正的可以寫出可綜合的代碼確實還需要經(jīng)過很長時間的鍛煉。而對Quartus II的使用,感覺也只會得不多,還有很多功能諸如時序分析,邏輯分析,引腳分配等都不會使用。
在完成這次大作業(yè)的過程中充分感受到自己知識的不足以及學(xué)以致用的重要性,有很多不懂的地方,要通過不斷的學(xué)習(xí)來提高自己,這正驗證了學(xué)海無涯這句古話。這次的大作業(yè)是一次很好的實踐。通過大家一起設(shè)計,大家都很有收獲,不僅完成了作業(yè),而且學(xué)到了知識,關(guān)鍵的是自己的自學(xué)能力有所提高,所以希望以后還有更多實踐的機會,這對于我們的提高大有好處。
最后,我還得感謝我的隊友們,這次作業(yè)的完成是我們共同努力的結(jié)果,我真正感受到了團隊的力量,也體會到了老師為什么一定要求必須絕對完成的良苦用心。
11光電A1 朱
2014.01.01
第二篇:verilog學(xué)習(xí)日志
1.解決xilinx的仿真庫的編輯問題
2.模塊的做法和調(diào)用方法,帶參數(shù)模塊的應(yīng)用:兩種方法modelname #(value)madelcase();
二、用defparam 改變參數(shù)。
3.Begin ……end之間是串行執(zhí)行的語句。在實際的電路中各條語句并不是完全串行的。4.Fork……join之間是并行執(zhí)行的語句,但是不可綜合;
5.表征過程模塊的四種工程模塊:initial模塊,always模塊,task模塊,function模塊;一個程序中可以有多個initial模塊和always模塊,但是initial模塊只執(zhí)行一次,不可綜合,而always模塊是不斷重復(fù)執(zhí)行的,可以綜合。6.數(shù)據(jù)類型兩大類:線網(wǎng)類型和寄存器類型
7.線網(wǎng)類型:結(jié)構(gòu)化原件之間的物理連接,默認(rèn)值高阻z;寄存器表示數(shù)據(jù)的存儲單元,默認(rèn)值為x;寄存器類型數(shù)據(jù)保持最后一次賦值,而線型數(shù)據(jù)需要持續(xù)的驅(qū)動; 8.線網(wǎng)數(shù)據(jù)場用來以關(guān)鍵字assign指定組合邏輯信號。模塊中輸入輸出默認(rèn)為wire類型,可綜合的線網(wǎng)類型有wire,tri,supply0,supply1;線網(wǎng)類型的變量賦值只能通過assign來完成,不能用于always語句。
9.寄存器類型的數(shù)據(jù)沒有強弱之分,且所有的寄存器類型變量都必須明確給出類型說明(無默認(rèn)狀態(tài))。10.If語句指定了一個有限編碼邏輯,case結(jié)果是并行的,沒有優(yōu)先級,if……else占用面積小但速度較慢,case語句占用面積大,但速度較快。11.如果if……else語句塊為單句則直接寫就可以,如果不只一句則要用begin……end括起來。12.循環(huán)語句for,while,repeat可以綜合,forever不可綜合。13.對于reg型數(shù)據(jù)不能用assign賦值。
14.拼接數(shù)據(jù)時最好將數(shù)據(jù)的進制形式都寫詳細(xì),否則仿真出錯,不知為何?例如:parameter a = 8;b = {{a{1’b0}},c};
15.module mult_8b_for(16.a,b,q 17.);18.parameter bsize = 8;19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.input [bsize1:0] b_t;reg [bsize1)begin
if(b_t[0])
begin
q = q + a_t;//一定要使用阻塞賦值
end else 36.37.38.39.40.begin
q = q;//一定要使用阻塞賦值
end
a_t = a_t <<1;//一定要使用阻塞賦值 b_t = b_t >>1;//一定要使用阻塞賦值
41.42.end end
43.Endmodule
44.Always語句中使用非阻塞賦值“<=”時,只有在always結(jié)束后才會把右端的賦值給左邊的寄存器,如果采用非阻塞賦值,則會造成循環(huán)語句只執(zhí)行一次。雖然模塊整體是時序邏輯,但是循環(huán)部分卻是組合邏輯。
45.Task和function是綜合的,不過綜合出來都是組合電路。46.在第一行Task語句中不能列出端口名稱。
47.Task中可以調(diào)用其他的任務(wù)或函數(shù),也可以調(diào)用自身;
48.任務(wù)定義的結(jié)構(gòu)體內(nèi)部能出現(xiàn)always或initial過程塊(可能是因為其只能綜合成組合電路的緣故吧)。但是可以在always或initial中調(diào)用。調(diào)用時要與聲明的端口順序相同。且只能在過程塊中調(diào)用。
49.任務(wù)的輸出端口必須和寄存器類型的數(shù)據(jù)變量對應(yīng)。50.Function不允許有輸出端口的聲明,函數(shù)定義在函數(shù)內(nèi)部會隱式的定義一個寄存器變量,該寄存器變量和函數(shù)同名并且位寬也一致。函數(shù)內(nèi)部不能調(diào)用任務(wù)。
51.觸摸板如何禁止:下載一個UltraNav驅(qū)動按上,到控制面板鼠標(biāo)里面就可以禁止觸摸板了。Win7下可以直接去禁止,不用安裝驅(qū)動程序。
52.保證敏感信號列表的完備性。不要在組合邏輯中引入環(huán)路。
53.同步時序電路的準(zhǔn)則:
1、單時鐘策略,單時鐘沿策略。
2、避免使用門控時鐘。
3、不要再子模塊內(nèi)部使用計數(shù)器分頻產(chǎn)生所需時鐘。推薦的方式是有一個專門的子模塊來管理系統(tǒng)時鐘。
54.同步電路在目前數(shù)字電路系統(tǒng)中占絕對優(yōu)勢,和異步電路相比有下列優(yōu)勢:對溫度、電壓、生產(chǎn)過程等外部參數(shù)的適應(yīng)性強;可以消除毛刺和內(nèi)部的歪斜的數(shù)據(jù),能將設(shè)計頻率提高的吉赫茲。但是需要更多的資源,而且其時鐘翻轉(zhuǎn)頻率高,功耗也比較大。55.關(guān)鍵路徑:最大的可能時鐘頻率是由電路中最慢的邏輯路徑?jīng)Q定的。一種消除這種限制的方法是將復(fù)雜的運算分開成為數(shù)個簡單的運算,這種技術(shù)稱為pipelining。56.要輸就輸給追求,要嫁就嫁給幸福。
57.第九章的二級流水線仿真時結(jié)果中顯示不對,不知道為何,可能是testbench寫的不好,有時間一定要搞明白。58.提高工作速度的兩種方式:并行方式和流水線方式。核心思想是面積換速度。59.‘timescale 1ns / 1ps 代表時延單位為1ns,時延精度為1ps。
60.亞穩(wěn)態(tài):多時鐘設(shè)計中,必然存在亞穩(wěn)態(tài),當(dāng)觸發(fā)器的建立時間和保持時間沒有達到要求是,觸發(fā)器就會處于邏輯1和邏輯0之間的第3中狀態(tài)。及亞穩(wěn)態(tài)。
61.狀態(tài)機不僅僅是一種電路,而且是一種設(shè)計思想,他可以說是一個廣義時序電路,狀態(tài)機是數(shù)字設(shè)計的“大腦”。
62.狀態(tài)機開發(fā)流程:首先要抽象出事物的狀態(tài),再次明確狀態(tài)和輸入輸出之間的關(guān)系,讓后得到系統(tǒng)的狀態(tài)轉(zhuǎn)移圖,并用verilog實現(xiàn)。
63.Moore狀態(tài)機輸出僅僅依賴于當(dāng)前狀態(tài),與輸入無關(guān),下一個狀態(tài)與輸入和當(dāng)前狀態(tài)有關(guān),64.Mealy狀態(tài)機的輸出與輸入和當(dāng)前狀態(tài)有關(guān),65.狀態(tài)機的容錯處理:對剩余狀態(tài)進行處理。方法:轉(zhuǎn)入空閑狀態(tài)、轉(zhuǎn)入特定狀態(tài)、轉(zhuǎn)入預(yù)定義的專門處理錯誤的狀態(tài),如報警。66.狀態(tài)機設(shè)計原則:單獨用一個verilog模塊來描述一個有限狀態(tài)機。使用代表狀態(tài)名的參數(shù)parameter來給狀態(tài)賦值,而不是用宏定義。在組合always塊中使用阻塞賦值,在時序always塊中使用非阻塞賦值,67.利用三段式設(shè)計狀態(tài)機。第一段處理當(dāng)前狀態(tài)的賦值。第二段處理下一個狀態(tài)的賦值。第三段處理輸出的賦值。
68.Case后面沒有begin 結(jié)尾處加endcase;
69.利用stateCAD做狀態(tài)機,注意填寫條件是沒有標(biāo)點符號,而在寫輸出時有標(biāo)點;ise軟件在10版本以后就沒有自帶的CAD軟件了,下了一個單獨運行的一樣可以用。70.同步整形電路:同步電路具備最穩(wěn)定的工作狀態(tài)和工作能力因此經(jīng)常需要將外部輸入的異步信號進行同步處理(與系統(tǒng)時鐘同步)和整形(經(jīng)輸入信號由不規(guī)則的波形提取為具有一個時鐘周期長的脈沖信號)。313頁。71.Assign只能用來給wire和output賦值,不能用來給reg類型賦值;
72.Xst:528-Multi-source in Unit
75.綜合synthesize:查看綜合報告、查看RTL級原理圖、檢查語法。實現(xiàn):implement,翻譯、映射、布局布線,實現(xiàn)之前要進行約束條件的編輯。76.
第三篇:verilog作業(yè)題
1、以結(jié)構(gòu)描述方式實現(xiàn)下列邏輯:
F=AB+ACD(CD的非)
2、以連續(xù)賦值語句設(shè)計8位總線驅(qū)動器。
3、以always語句設(shè)計8位總線驅(qū)動器。
4、以always語句設(shè)計8位雙向總線驅(qū)動器。
1、設(shè)計一個具有低電平使能端和高電平使能端的2-4譯碼器。
2、設(shè)計一個JK觸發(fā)器。
3、設(shè)計一個24分頻期,要求輸出信號占空比為1:1。
4、一個掛在總線上的16位寄存器。
5、設(shè)計一個8位線編碼器,輸入為D7 - D0,D7優(yōu)先級最高,D0最低。當(dāng)Di為高電平輸入時,F(xiàn)=1,OUT為其編碼,否則F=0。
1、以結(jié)構(gòu)描述方式實現(xiàn)下列邏輯:
Y=ABC(BC的非)+DE+ CFG(CFG的非)
2、試設(shè)計一個具有使能端ncs的2-4譯碼器。
3、試設(shè)計一個4位加減運算器,輸入為A、B、CIN、M,輸出為OUT和COUT。當(dāng)M=0時執(zhí)行加法運算,M=1時,執(zhí)行減法運算。
4、試設(shè)計一個14分頻器,要求占空比1:1。
5、試設(shè)計一個具有三態(tài)輸出緩沖的8位數(shù)據(jù)寄存器。
6、試設(shè)計一個具有清0和置數(shù)功能的8位二進制加1計數(shù)器。
7、設(shè)計一個16位移位寄存器。
8、設(shè)計一個16位雙向移位寄存器,當(dāng)d=0時右移, d=1時左移。
1設(shè)中斷請求有效電平為高電平,中斷請求輸入線INTR0—INTR15中INTR15優(yōu)先權(quán)最高。試設(shè)計一個中斷優(yōu)先權(quán)編碼器。當(dāng)有中斷請求時,INT=1,同時輸出中斷請求輸入線的編碼V;否則INT=0,V的輸出任意。
2試設(shè)計一個具有同步清0和同步置數(shù)功能的8位二進制加1計數(shù)器。
3試設(shè)計一個“11010100”序列檢測器.4設(shè)計一個8位雙向移位寄存器。其I/O端口和控制端口包括d(移位方向控制,當(dāng)d=0時右移, d=1時左移)、數(shù)據(jù)串行輸入din、數(shù)據(jù)并行輸入data(8位)、dout數(shù)據(jù)串行輸出、數(shù)據(jù)并行輸出q(8位)、同步時鐘clk、并行置數(shù)load等。
5設(shè)計每周期8個采樣點的鋸齒波信號發(fā)生器。
6設(shè)計每周期8個采樣點的正弦波信號發(fā)生器。
第四篇:學(xué)verilog小結(jié)
學(xué)習(xí)verilog一段時間 小結(jié) 學(xué)習(xí)verilog, verilog, verilog小結(jié)
一:基本
Verilog中的變量有線網(wǎng)類型和寄存器類型。線網(wǎng)型變量綜合成wire,而寄存器可能綜合成WIRE,鎖存器和觸發(fā)器。
二:verilog語句結(jié)構(gòu)到門級的映射
1、連續(xù)性賦值:assign 連續(xù)性賦值語句邏輯結(jié)構(gòu)上就是將等式右邊的驅(qū)動左邊的結(jié)點。因些連續(xù)性賦值的目標(biāo)結(jié)點總是綜合成由組合邏輯驅(qū)動的結(jié)點。Assign語句中的延時綜合時都將忽視。
2、過程性賦值:
過程性賦值只出現(xiàn)在always語句中。
阻塞賦值和非阻塞賦值就該賦值本身是沒有區(qū)別的,只是對后面的語句有不同的影響。
建議設(shè)計組合邏輯電路時用阻塞賦值,設(shè)計時序電路時用非阻塞賦值。
過程性賦值的賦值對象有可能綜合成wire,latch,和flip-flop,取決于具體狀況。如,時鐘控制下的非阻塞賦值綜合成flip-flop。
過程性賦值語句中的任何延時在綜合時都將忽略。
建議同一個變量單一地使用阻塞或者非阻塞賦值。
3、邏輯操作符:
邏輯操作符對應(yīng)于硬件中已有的邏輯門
4、算術(shù)操作符:
Verilog中將reg視為無符號數(shù),而integer視為有符號數(shù)。因此,進行有符號操作時使用
integer,使用無符號操作時使用reg。
5、進位:
通常會將進行運算操作的結(jié)果比原操作數(shù)擴展一位,用來存放進位或者借位。如:
Wire [3:0] A,B;
Wire [4:0] C;Assign C=A+B;C的最高位用來存放進位。
6、關(guān)系運算符: 關(guān)系運算符:<,>,<=,>= 和算術(shù)操作符一樣,可以進行有符號和無符號運算,取決于數(shù)據(jù)類型是reg,net還是
integer。
7、相等運算符:==,!= 注意:===和!==是不可綜合的。
可以進行有符號或無符號操作,取決于數(shù)據(jù)類型
8、移位運算符:
左移,右移,右邊操作數(shù)可以是常數(shù)或者是變量,二者綜合出來的結(jié)果不同。
9、部分選擇: 部分選擇索引必須是常量。
10、BIT選擇:
BIT選擇中的索引可以用變量,這樣將綜合成多路(復(fù)用)器。
11、敏感表:
Always過程中,所有被讀取的數(shù)據(jù),即等號右邊的變量都要應(yīng)放在敏感表中,不然,綜合時不能正確地映射到所用的門。
12、IF:
如果變量沒有在IF語句的每個分支中進行賦值,將會產(chǎn)生latch。如果IF語句中產(chǎn)生了latch,則IF的條件中最好不要用到算術(shù)操作。Case語句類似。Case的條款可以是變量。
如果一個變量在同一個IF條件分支中先贖值然后讀取,則不會產(chǎn)生latch。如果先讀取,后贖值,則會產(chǎn)生latch。
13、循環(huán):
只有for-loop語句是可以綜合的。
14、設(shè)計時序電路時,建議變量在always語句中賦值,而在該always語句外使用,使綜合時能準(zhǔn)確地匹配。建議不要使用局部變量。
15、不能在多個always塊中對同一個變量贖值
16、函數(shù)
函數(shù)代表一個組合邏輯,所有內(nèi)部定義的變量都是臨時的,這些變量綜合后為wire。
17、任務(wù):
任務(wù)可能是組合邏輯或者時序邏輯,取決于何種情況下調(diào)用任務(wù)。
18、Z:
Z會綜合成一個三態(tài)門,必須在條件語句中賦值
19、參數(shù)化設(shè)計:
優(yōu)點:參數(shù)可重載,不需要多次定義模塊
四:模塊優(yōu)化
1、資源共享:
當(dāng)進程涉及到共用ALU時,要考慮資源分配問題。可以共享的操作符主要有:關(guān)系操作符、加減乘除操作符。通常乘和加不共用ALU,乘除通常在其內(nèi)部共用。
2、共用表達式: 如:C=A+B;D=G+(A+B);兩者雖然有共用的A+B,但是有些綜合工具不能識別.可以將第二句改為:D=G+C;這樣
只需兩個加法器.
3、轉(zhuǎn)移代碼:
如循環(huán)語句中沒有發(fā)生變化的語句移出循環(huán).
4、避免latch:
兩種方法:
1、在每一個IF分支中對變量賦值。
2、在每一個IF語句中都對變量賦初值。
5:模塊:
綜合生成的存儲器如ROM或RAM不是一種好方法。最好用庫自帶的存儲器模塊。
五、驗證: 1、敏感表:
在always語句中,如果敏感表不含時鐘,最好將所有的被讀取的信號都放在敏感表中。
2、異步復(fù)位:
建議不要在異步時對變量讀取,即異步復(fù)位時,對信號贖以常數(shù)值。
第五篇:Verilog HDL 的入門學(xué)習(xí)
先記下來:
1、不使用初始化語句;
2、不使用延時語句;
3、不使用循環(huán)次數(shù)不確定的語句,如:forever,while等;
4、盡量采用同步方式設(shè)計電路;
5、盡量采用行為語句完成設(shè)計;
6、always過程塊描述組合邏輯,應(yīng)在敏感信號表中列出所有的輸入信號;
7、所有的內(nèi)部寄存器都應(yīng)該可以被復(fù)位;
8、用戶自定義原件(UDP元件)是不能被綜合的。一:基本
Verilog中的變量有線網(wǎng)類型和寄存器類型。線網(wǎng)型變量綜合成wire,而寄存器可能綜合成WIRE,鎖存器和觸發(fā)器,還有可能被優(yōu)化掉。二:verilog語句結(jié)構(gòu)到門級的映射
1、連續(xù)性賦值:assign 連續(xù)性賦值語句邏輯結(jié)構(gòu)上就是將等式右邊的驅(qū)動左邊的結(jié)點。因此連續(xù)性賦值的目標(biāo)結(jié)點總是綜合成由組合邏輯驅(qū)動的結(jié)點。Assign語句中的延時綜合時都將忽視。
2、過程性賦值:
過程性賦值只出現(xiàn)在always語句中。
阻塞賦值和非阻塞賦值就該賦值本身是沒有區(qū)別的,只是對后面的語句有不同的影響。
建議設(shè)計組合邏輯電路時用阻塞賦值,設(shè)計時序電路時用非阻塞賦值。過程性賦值的賦值對象有可能綜合成wire, latch,和flip-flop,取決于具體狀況。如,時鐘控制下的非阻塞賦值綜合成flip-flop。過程性賦值語句中的任何延時在綜合時都將忽略。建議同一個變量單一地使用阻塞或者非阻塞賦值。
3、邏輯操作符:
邏輯操作符對應(yīng)于硬件中已有的邏輯門,一些操作符不能被綜合:===、!==。
4、算術(shù)操作符:
Verilog中將reg視為無符號數(shù),而integer視為有符號數(shù)。因此,進行有符號操作時使用integer,使用無符號操作時使用reg。
5、進位:
通常會將進行運算操作的結(jié)果比原操作數(shù)擴展一位,用來存放進位或者借位。如: Wire [3:0] A,B;Wire [4:0] C;Assign C=A+B;C的最高位用來存放進位。
6、關(guān)系運算符: 關(guān)系運算符:<,>,<=,>= 和算術(shù)操作符一樣,可以進行有符號和無符號運算,取決于數(shù)據(jù)類型是reg,net還是integer。
7、相等運算符:==,!= 注意:===和!==是不可綜合的。
可以進行有符號或無符號操作,取決于數(shù)據(jù)類型
8、移位運算符:
左移,右移,右邊操作數(shù)可以是常數(shù)或者是變量,二者綜合出來的結(jié)果不同。
9、部分選擇:
部分選擇索引必須是常量。
10、BIT選擇:
BIT選擇中的索引可以用變量,這樣將綜合成多路(復(fù)用)器。
11、敏感表:Always過程中,所有被讀取的數(shù)據(jù),即等號右邊的變量都要應(yīng)放在敏感表中,不然,綜合時不能正確地映射到所用的門。
12、IF:
如果變量沒有在IF語句的每個分支中進行賦值,將會產(chǎn)生latch。如果IF語句中產(chǎn)生了latch,則IF的條件中最好不要用到算術(shù)操作。Case語句類似。Case的條款可以是變量。
如果一個變量在同一個IF條件分支中先贖值然后讀取,則不會產(chǎn)生latch。如果先讀取,后贖值,則會產(chǎn)生latch。
13、循環(huán):
只有for-loop語句是可以綜合的。
14、設(shè)計時序電路時,建議變量在always語句中賦值,而在該always語句外使用,使綜合時能準(zhǔn)確地匹配。建議不要使用局部變量。
15、不能在多個always塊中對同一個變量贖值
16、函數(shù)
函數(shù)代表一個組合邏輯,所有內(nèi)部定義的變量都是臨時的,這些變量綜合后為wire。
17、任務(wù):
任務(wù)可能是組合邏輯或者時序邏輯,取決于何種情況下調(diào)用任務(wù)。
18、Z:
Z會綜合成一個三態(tài)門,必須在條件語句中賦值
19、參數(shù)化設(shè)計:
優(yōu)點:參數(shù)可重載,不需要多次定義模塊 四:模塊優(yōu)化
1、資源共享:
當(dāng)進程涉及到共用ALU時,要考慮資源分配問題。可以共享的操作符主要有:關(guān)系操作符、加減乘除操作符。通常乘和加不共用ALU,乘除通常在其內(nèi)部共用。
2、共用表達式: 如:C=A+B;
D=G+(A+B);兩者雖然有共用的A+B,但是有些綜合工具不能識別.可以將第二句改為:D=G+C;這樣只需兩個加法器.
3、轉(zhuǎn)移代碼:
如循環(huán)語句中沒有發(fā)生變化的語句移出循環(huán).
4、避免latch:
兩種方法:
1、在每一個IF分支中對變量賦值。
2、在每一個IF語句中都對變量賦初值。5:模塊:
綜合生成的存儲器如ROM或RAM不是一種好方法,只是成堆的寄存器,很費資源。最好用庫自帶的存儲器模塊。
五、驗證: 1、敏感表:
在always語句中,如果敏感表不含時鐘,最好將所有的被讀取的信號都放在敏感表中。2、異步復(fù)位:
建議不要在異步時對變量讀取,即異步復(fù)位時,對信號賦以常數(shù)值。
Averilog的流行,有兩方面的原因;B verilog與VHDL相比的優(yōu)點 C典型的verilog模塊 D verilog語法要點
A)verilog的流行,有兩方面的原因: 1它是cadence的模擬器verilog-XL的基礎(chǔ),cadence的廣泛流行使得verilog在90年代深入人心;2它在硅谷獲得廣泛使用;B)verilog與VHDL相比的優(yōu)點二者的關(guān)系仿佛C與FORTRAN,具體而言: 1 verilog的代碼效率更高: 比較明顯的對比: VHDL在描述一個實體時采用entity/architecture模式, verilog在描述一個實體時只需用一個“module/edumodule”語句塊.此外verilog的高效性還在很多地方體現(xiàn)出來;2 verilog支持二進制的加減運算: VHDL在進行二進制的加減運算時使用conv_***函數(shù)或者進行其他的定義,總之必須通知編譯器;verilog直接用形如“c=a+b”的表示二進制的加減運算;3綜合時可控制性好: VHDL對信號不加區(qū)分地定義為“signal”, 而verilog區(qū)分為register類型的和wire類型的;但是也有人支持VHDL,認(rèn)為verilog和VHDL的關(guān)系仿佛C和C++.C)典型的verilog模塊 討論以下典型電路的verilog描述: *與非門;*加法器;//即全加器 * D觸發(fā)器;*計數(shù)器;//**分頻的counter * latch;*時序機;*RAM;//用synopsys的 *模塊引用;*預(yù)編譯;*與非門的verilog描述如下: //verilog使用和C語言相同的注釋方法
module nd02(a1,a2,zn);//一個verilog模塊總是以module開始,以endmodule 結(jié)束,nd02是模塊名,a1,a2,zn是模塊的3個輸入輸出信號
input a1,a2;//告訴編譯器a1,a2對此模塊而言是輸入,并且數(shù)據(jù)類型是“bit” output zn;//告訴編譯器zn對此模塊而言是輸出,數(shù)據(jù)類型也是“bit” nand(zn,a1,a2);//我理解nand是運算符,我們不必深究verilog中的正式術(shù)語是什 么了吧,總之這種形式表示zn=~(a1 && a2);你一定已經(jīng)想到類似的運算符還有“not”,“and”,“or”,“nor”,“xor”了吧;除了“not”,括號里的信號數(shù)可以任意,例如or(z,f,g,h)表示z=f || g || h,并且延時是3個單位時間,#x表示延時x個單位時間;endmodule
*加法器的verilog描述如下: module ad03d1(A,B,CI,S,CO);input [2:0] A,B;//表示A,B是輸入信號,并且是3位矢量,上界是2,下界是0 input CI;output [2:0] S;output CO;assign {CO,S}=A+B+CI;//一對“{”和“}”表示鏈接,即將CO和S合并成4位矢量 endmodule
*帶異步清零端的D觸發(fā)器的verilog描述如下: module dfctnb(d,cp,cdn,q,qn);input d,cp,cdn;output q,qn;reg q,qn;//關(guān)鍵字“reg”表示q和qn是“register”類型的信號;verilog中有兩種類型的信號:“register”類型和“wire”類型.你可以簡單地把register類型的信號想象為某個D觸發(fā)器的輸出,而wire類型的的信號是組合邏輯的輸出.二者的最大區(qū)別在于:你可以對register類型的信號進行定時賦值(用wait語句在特定時刻的賦值,詳見下面always語句),而對于wire類型的信號則不可.always wait(cdn==0)//表示每當(dāng)cdn=0時,將要對D觸發(fā)器清零,“always”和“wait”嵌套,“wait”和“@”是verilog的兩個關(guān)鍵字,表示一旦有某事發(fā)生;則執(zhí)行下面的語句塊,“always”有點象C語言中的“if...then...”,“wait”和“@”的區(qū)別:請參考本模塊.wait表示本語句塊的進程停止,直到“cdn=0”的條件出現(xiàn)才繼續(xù);我理解在verilog中,每個最外層語句塊都是一個***的進程;“@”(請看下個always語句)也表示本語句塊的進程停止,直到后面定義“posedge cp”(即出現(xiàn)cp的上升沿)的事件出現(xiàn)才繼續(xù);也許wait和@可以合二為一吧,但至少到目前verilog中wait表示“條件”,@表示“事件”;具體運用中,wait總是用于類似“wait(xxx=1)”之類的場合,@總是用于類似“@(xxx)”或“@(posedge/negedge xxx)”之類的場合整句話的意思是“每當(dāng)cdn等于0時,則作以下事情” begin //begin...end結(jié)構(gòu)的用法類似于pascal語言
q=0;
qn=1;
wait(cdn==1);end always @(posedge cp)//“@(posedge cp)”中有兩個關(guān)鍵字:“@(x)”表示“每當(dāng)事件x發(fā)
生”,“posedge x”表示“x的上升沿,”negedge x“表示”x的下降沿“,整句話的意思是”每當(dāng)cp的上升沿,則作以下事情“
if(cdn)//如果cdn=1(意味著清零端無效)
begin
q=d;
qn=~q;//”~“表示反相
end endmodule *計數(shù)器的verilog描述如下: module count(in,set,cp,out);//此計數(shù)器,在cp的上升沿將輸入賦給輸出,在cp的上升沿使輸出加一 input [15:0] in;input set,cp;output [15:0] out;reg [15:0] out;always @(posedge set)out = in;always @(posedge cp)out = out+1;//verilog容許一個信號同時出現(xiàn)在等號兩端,只要它是reg類型的 endmodule
*latch的描述如下: always @(clk or d)
if(clk)q = d;
*時序機的verilog描述如下: always @(posedge CLK)//D是下一個狀態(tài),Q是當(dāng)前狀態(tài),e1,e2是輸入,a,b是輸出 Q=D;always @(Q or othercase)begin //當(dāng)Q變化或輸入e1,e2變化時D要相應(yīng)變化 D = Q;//note1 a = 0;b = 0;......case(Q)q1:begin q1 action;if(e1)D=d1;if(e2)D=d2;else D=d3;a = 1;//note 2 end q2:begin b = 1;......end default:begin a = 0;b = 0;......end end---annotations---note 1: This is a custom expression,after reset,D should be equal to Q;note 2: In this state machine,a is only equal to 1 at state q1,in other state,a is equal to 0;* RAM的verilog描述如下: module ram(din,ain,dout,aout,rd,wr);//這是一個雙口RAM,分別有:輸入端:輸入地址ain;輸入數(shù)據(jù)din;上升沿有效的寫信號wr;/輸出端:輸出地址aout;輸出數(shù)據(jù)dout;高電平有效的讀信號rd;inout [7:0] din;input [7:0] ain,aout;input rd,wr;output [7:0] dout;reg [7:0] memory [0:255];//請注意這是存儲陣列的描述方法,描述了一個共有2 56個字的存儲陣列,每個字是8位
assign dout = rd ? memory[aout] : 8'bz;//”assign“關(guān)鍵字表示并行賦值語句的 開始”?“運算符的作用和在C語言中一樣”8'bz“是一個常量,表示一個字節(jié)的高阻態(tài),其中8表示長度是8bit,”'“是固定分割符,”b“表示后面的數(shù)據(jù)是以比特形式給出的,”z“表示高阻;舉例:4'ha表示長4bit的數(shù)”1010“。類似的還可舉出5'b10111,6'o33等等
always @(posedge wr)memory[ain] = din;endmodule *模塊引用
假設(shè)在前面(可以是別的模塊)定義了module ram(din,ain,dout,aout,rd,wr),則引用此
模塊時只需寫 ram myram(din_in_map,ain_in_map,dout_in_map,aout_in_map,rd_in_map,wr_in_map);//其中”ram“是所引用的module名,”myram“是你起的instance名,”din_in_map“等等是圖中的節(jié)點名,和器件(module)中的”din...“進行”虛實結(jié)合“;*預(yù)編譯
類似C語言,只需寫
`include ”
“,反上撇號”`“是verilog的預(yù)編譯符,類似C中的”#“.D)verilog語法要點 *基本原則
設(shè)計時應(yīng)該把你的系統(tǒng)劃分為計數(shù)器,觸發(fā)器,時序機,組合邏輯等等可綜合的單元,對此不同的IC公司和EDA開發(fā)商可能根據(jù)自己的見解和經(jīng)驗提出不同的要求,并且對verilog程序的細(xì)節(jié)進行自己的規(guī)定,但有一點是對的:即寫硬件描述語言不象寫C語言那樣符合語法就行.單單符合verilog語法的程序可能被拒絕綜合,甚至被拒絕模擬;*最外層可以寫什么? 這里所說的最外層是指module語句后的第一層,在這一層可以寫這些可執(zhí)行語句: assign和nand等定義組合邏輯的語句, always語句, 模塊引用語句, 一些以”$“開頭的系統(tǒng)定義語句.特別注意不可以寫if語句.if語句只能放在always內(nèi)部.不推薦寫wait語句,因為不能綜合.*不可以在多個always語句中對一個信號賦值.1.強烈建議用同步設(shè)計 2.在設(shè)計時總是記住時序問題
3.在一個設(shè)計開始就要考慮到地電平或高電平復(fù)位、同步或異步復(fù)位、上升沿或下降沿觸發(fā)等問題,在所有模塊中都要遵守它
4.在不同的情況下用if和case,最好少用if的多層嵌套(1層或2層比較合適,當(dāng)在3層以上時,最好修改寫法,因為這樣不僅可以reduce area,而且可以獲得好的timing)
5.在鎖存一個信號或總線時要小心,對于整個design,盡量避免使用latch,因為在DFT時很難test。
6.確信所有的信號被復(fù)位,在DFT時,所有的FlipFlop都是controllable,7.永遠(yuǎn)不要再寫入之前讀取任何內(nèi)部存儲器(如SRAM)
8.從一個時鐘到另一個不同的時鐘傳輸數(shù)據(jù)時用數(shù)據(jù)緩沖,他工作像一個雙時鐘FIFO(是異步的),可以用Async SRAM搭建Async FIFO。
9.在VHDL中二維數(shù)組可以使用,它是非常有用的。在VERILOG中他僅僅可以使用在測試模塊中,不能被綜合 10.遵守register-in register-out規(guī)則
11.像synopsys的DC的綜合工具是非常穩(wěn)定的,任何bugs都不會從綜合工具中產(chǎn)生 12.確保FPGA版本與ASIC的版本盡可能的相似,特別是SRAM類型,若版本一致是最理想的,但是在工作中FPGA版本一般用FPGA自帶的SRAM,ASIC版本一般用廠商提供的SRAM。13.在嵌入式存儲器中使用BIST 14.虛單元和一些修正電路是必需的
15.一些簡單的測試電路也是需要的,經(jīng)常在一個芯片中有許多測試模塊 16.除非低功耗不要用門控時鐘,強烈建議不要在design中使用gate clock 17.不要依靠腳本來保證設(shè)計。但是在腳本中的一些好的約束能夠起到更好的性能(例如前向加法器)
18.如果時間充裕,通過時鐘做一個多鎖存器來取代用MUX 19.不要用內(nèi)部tri-state, ASIC需要總線保持器來處理內(nèi)部tri-state,如IO cell。20.在top level中作pad insertion 21.選擇pad時要小心(如上拉能力,施密特觸發(fā)器,5伏耐壓等),選擇合適的IO cell 22.小心由時鐘偏差引起的問題 23.不要試著產(chǎn)生半周期信號
24.如果有很多函數(shù)要修正,請一個一個地作,修正一個函數(shù)檢查一個函數(shù) 25.在一個計算等式中排列每個信號的位數(shù)是一個好習(xí)慣,即使綜合工具能做 26.不要使用HDL提供的除法器
27.削減不必要的時鐘。它會在設(shè)計和布局中引起很多麻煩,大多數(shù)FPGA有1-4個專門的時鐘通道
良好代碼編寫風(fēng)格可以滿足信、達、雅的要求。在滿足功能和性能目標(biāo)的前提下,增強代碼的可讀性、可移植性,首要的工作是在項目開發(fā)之前為整個設(shè)計團隊建立一個命名約定和縮略語清單,以文檔的形式記錄下來,并要求每位設(shè)計人員在代碼編寫過程中都要嚴(yán)格遵守。良好代碼編寫風(fēng)格的通則概括如下:(1)對所有的信號名、變量名和端口名都用小寫,這樣做是為了和業(yè)界的習(xí)慣保持一致;對常量名和用戶定義的類型用大寫;(2)使用有意義的信號名、端口名、函數(shù)名和參數(shù)名;(3)信號名長度不要太長;(4)對于時鐘信號使用clk 作為信號名,如果設(shè)計中存在多個時鐘,使用clk 作為時鐘信號的前綴;
(5)對來自同一驅(qū)動源的信號在不同的子模塊中采用相同的名字,這要求在芯片總體設(shè)計時就定義好頂層子模塊間連線的名字,端口和連接端口的信號盡可能采用相同的名字;
(6)對于低電平有效的信號,應(yīng)該以一個下劃線跟一個小寫字母b 或n 表示。注意在同一個設(shè)計中要使用同一個小寫字母表示低電平有效;
(7)對于復(fù)位信號使用rst 作為信號名,如果復(fù)位信號是低電平有效,建議使用rst_n;
(8)當(dāng)描述多比特總線時,使用一致的定義順序,對于verilog 建議采用bus_signal[x:0]的表示;
(9)盡量遵循業(yè)界已經(jīng)習(xí)慣的一些約定。如*_r 表示寄存器輸出,*_a 表示異步信號,*_pn 表示多周期路徑第n 個周期使用的信號,*_nxt 表示鎖存前的信號,*_z 表示三態(tài)信號等;
(10)在源文件、批處理文件的開始應(yīng)該包含一個文件頭、文件頭一般包含的內(nèi)容如下例所示:文件名,作者,模塊的實現(xiàn)功能概述和關(guān)鍵特性描述,文件創(chuàng)建和修改的記錄,包括修改時間,修改的內(nèi)容等;
(11)使用適當(dāng)?shù)淖⑨寔斫忉屗械腶lways 進程、函數(shù)、端口定義、信號含義、變量含義或信號組、變量組的意義等。注釋應(yīng)該放在它所注釋的代碼附近,要求簡明扼要,只要足夠說明設(shè)計意圖即可,避免過于復(fù)雜;
(12)每一行語句獨立成行。盡管VHDL 和Verilog 都允許一行可以寫多個語句,當(dāng)時每個語句獨立成行可以增加可讀性和可維護性。同時保持每行小于或等于72 個字符,這樣做都是為了提高代碼得可讀性;
(13)建議采用縮進提高續(xù)行和嵌套語句得可讀性。縮進一般采用兩個空格,如西安交通大學(xué)SOC 設(shè)計中心2 如果空格太多則在深層嵌套時限制行長。同時縮進避免使用TAB 鍵,這樣可以避免不同機器TAB 鍵得設(shè)置不同限制代碼得可移植能力;
(14)在RTL 源碼的設(shè)計中任何元素包括端口、信號、變量、函數(shù)、任務(wù)、模塊等的命名都不能取Verilog 和VHDL 語言的關(guān)鍵字;
(15)在進行模塊的端口申明時,每行只申明一個端口,并建議采用以下順序: 輸入信號的clk、rst、enables other control signals、data and address signals。然后再申明輸出信號的clk、rst、enalbes other control signals、data signals;(16)在例化模塊時,使用名字相關(guān)的顯式映射而不要采用位置相關(guān)的映射,這樣可以提高代碼的可讀性和方便debug 連線錯誤;
(17)如果同一段代碼需要重復(fù)多次,盡可能使用函數(shù),如果有可能,可以將函數(shù)通用化,以使得它可以復(fù)用。注意,內(nèi)部函數(shù)的定義一般要添加注釋,這樣可以提高代碼的可讀性;
(18)盡可能使用循環(huán)語句和寄存器組來提高源代碼的可讀性,這樣可以有效地減少代碼行數(shù);
(19)對一些重要的always 語句塊定義一個有意義的標(biāo)號,這樣有助于調(diào)試。注意標(biāo)號名不要與信號名、變量名重復(fù);
(20)代碼編寫時的數(shù)據(jù)類型只使用IEEE 定義的標(biāo)準(zhǔn)類型,在VHDL 語言中,設(shè)計者可以定義新的類型和子類型,但是所有這些都必須基于IEEE 的標(biāo)準(zhǔn);(21)在設(shè)計中不要直接使用數(shù)字,作為例外,可以使用0 和1。建議采用參數(shù)定義代替直接的數(shù)字。同時,在定義常量時,如果一個常量依賴于另一個常量,建議在定義該常量時用表達式表示出這種關(guān)系;
(22)不要在源代碼中使用嵌入式的dc_shell 綜合命令。這是因為其他的綜合工具并不認(rèn)得這些隱含命令,從而導(dǎo)致錯誤的或較差的綜合結(jié)果。即使使用Design Compiler,當(dāng)綜合策略改變時,嵌入式的綜合命令也不如放到批處理綜合文件中易于維護。這個規(guī)則有一個例外的綜合命令,即編譯開關(guān)的打開和關(guān)閉可以嵌入到代碼中;
(23)在設(shè)計中避免實例化具體的門級電路。門級電路可讀性差,且難于理解和維護,如果使用特定工藝的門電路,設(shè)計將變得不可移植。如果必須實例化門電路,我們建議采用獨立于工藝庫的門電路,如SYNOPSYS 公司提供的GTECH 庫包含了高質(zhì)量的常用的門級電路;(24)避免冗長的邏輯和子表達式;
(25)避免采用內(nèi)部三態(tài)電路,建議用多路選擇電路代替內(nèi)部三態(tài)電路。
規(guī)則 #1: 建立時序邏輯模型時,采用非阻塞賦值語句。規(guī)則 #2: 建立latch模型時,采用非阻塞賦值語句。規(guī)則 #3: 在always塊中建立組合邏輯模型時,采用阻塞賦值語句。
規(guī)則 #4: 在一個always塊中同時有組合和時序邏輯時時,采用非阻塞賦值語句。規(guī)則 #5: 不要在一個always塊中同時采用阻塞和非阻塞賦值語句。規(guī)則 #6: 同一個變量不要在多個always塊中賦值。
規(guī)則 #7: 調(diào)用$strobe系統(tǒng)函數(shù)顯示用非阻塞賦值語句賦的值。規(guī)則 #8: 不要使用#0延時賦值。組合邏輯
1,敏感變量的描述完備性
Verilog中,用always塊設(shè)計組合邏輯電路時,在賦值表達式右端參與賦值的所有信號都必須在always @(敏感電平列表)中列出,always中if語句的判斷表達式必須在敏感電平列表中列出。如果在賦值表達式右端引用了敏感電平列表中沒有列出的信號,在綜合時將會為沒有列出的信號隱含地產(chǎn)生一個透明鎖存器。這是因為該信號的變化不會立刻引起所賦值的變化,而必須等到敏感電平列表中的某一個信號變化時,它的作用才表現(xiàn)出來,即相當(dāng)于存在一個透明鎖存器,把該信號的變化暫存起來,待敏感電平列表中的某一個
信號變化時再起作用,純組合邏輯電路不可能作到這一點。綜合器會發(fā)出警告。Example1: input a,b,c;reg e,d;always @(a or b or c)
begin
e=d&a&b;/*d沒有在敏感電平列表中,d變化時e不會立刻變化,直到a,b,c中某一個變化*/
d=e |c;
end Example2: input a,b,c;reg e,d;always @(a or b or c or d)
begin
e=d&a&b;/*d在敏感電平列表中,d變化時e立刻變化*/
d=e |c;
end 2,條件的描述完備性
如果if語句和case語句的條件描述不完備,也會造成不必要的鎖存器。Example1: if(a==1'b1)q=1'b1;//如果a==1'b0,q=? q將保持原值不變,生成鎖存器!Example2: if(a==1'b1)q=1'b1;else
q=1'b0;//q有明確的值。不會生成鎖存器!Example3: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;//如果a==2'b10或a==2'b11,q=? q將保持原值不變,鎖存器!
endcase Example4: reg[1:0] a,q;....case(a)
2'b00 : q=2'b00;
2'b01 : q=2'b11;
default: q=2'b00;//q有明確的值。不會生成鎖存器!
endcase Verilog中端口的描述
1,端口的位寬最好定義在I/O說明中,不要放在數(shù)據(jù)類型定義中; Example1: module test(addr,read,write,datain,dataout)input[7:0] datain;input[15:0] addr;input
read,write;output[7:0] dataout;//要這樣定義端口的位寬!wire addr,read,write,datain;reg dataout;Example2: module test(addr,read,write,datain,dataout)input datain,addr,read,write;output dataout;wire[15:0] addr;wire[7:0] datain;wire
read,write;reg[7:0] dataout;//不要這樣定義端口的位寬!2,端口的I/O與數(shù)據(jù)類型的關(guān)系:
端口的I/O 端口的數(shù)據(jù)類型
module內(nèi)部 module外部
input
wire
wire或reg
output
wire或reg
wire
inout
wire
wire 3,assign語句的左端變量必須是wire;直接用”=“給變量賦值時左端變量必須是reg!Example: assign a=b;//a必須被定義為wire!******** begin a=b;//a必須被定義為reg!end VHDL中STD_LOGIC_VECTOR和INTEGER的區(qū)別
例如A是INTEGER型,范圍從0到255;B是STD_LOGIC_VECTOR,定義為8位。A累加到255時,再加1就一直保持255不變,不會自動反轉(zhuǎn)到0,除非令其為0;而B累加到255時,再加1就會自動反轉(zhuǎn)到0。所以在使用時要特別注意!
以觸發(fā)器為例說明描述的規(guī)范性 1,無置位/清零的時序邏輯
always @(posedge CLK)
begin
Q<=D;
end 2,有異步置位/清零的時序邏輯
異步置位/清零是與時鐘無關(guān)的,當(dāng)異步置位/清零信號到來時,觸發(fā)器的輸出立即 被置為1或0,不需要等到時鐘沿到來才置位/清零。所以,必須要把置位/清零信號 列入always塊的事件控制表達式。
always @(posedge CLK or negedge RESET)
begin
if(!RESET)
Q=0;
else
Q<=D;
end 3,有同步置位/清零的時序邏輯
同步置位/清零是指只有在時鐘的有效跳變時刻置位/清零,才能使觸發(fā)器的輸出分
別轉(zhuǎn)換為1或0。所以,不要把置位/清零信號列入always塊的事件控制表達式。但是
必須在always塊中首先檢查置位/清零信號的電平。
always @(posedge CLK)
begin
if(!RESET)
Q=0;
else
Q<=D;
end 結(jié)構(gòu)規(guī)范性
在整個芯片設(shè)計項目中,行為設(shè)計和結(jié)構(gòu)設(shè)計的編碼是最重要的一個步驟。它對邏輯綜合和布線結(jié)果、時序測定、校驗?zāi)芰Αy試能力甚至產(chǎn)品支持都有重要的影響。考慮到仿真器和真實的邏輯電路之間的差異,為了有效的 進行仿真測試:
1,避免使用內(nèi)部生成的時鐘
內(nèi)部生成的時鐘稱為門生時鐘(gated clock)。如果外部輸入時鐘和門生時鐘同時驅(qū)動,則不可避免的兩者的步調(diào)不一致,造成邏輯混亂。而且,門生時鐘將會增加測試的難度
和時間。
2,絕對避免使用內(nèi)部生成的異步置位/清零信號
內(nèi)部生成的置位/清零信號會引起測試問題。使某些輸出信號被置位或清零,無法正常
測試。3,避免使用鎖存器
鎖存器可能引起測試問題。對于測試向量自動生成(ATPG),為了使掃描進行,鎖存器需要置為透明模式(transparent mode),反過來,測試鎖存器需要構(gòu)造特定的向量,這可非同一般。4,時序過程要有明確的復(fù)位值
使觸發(fā)器帶有復(fù)位端,在制造測試、ATPG以及模擬初始化時,可以對整個電路進行
快速復(fù)位。5,避免模塊內(nèi)的三態(tài)/雙向
內(nèi)部三態(tài)信號在制造測試和邏輯綜合過程中難于處理.近日讀 J.Bhasker 的
例外情況:變量的賦值和引用都僅出現(xiàn)在一條always語句中,則該變量被視為中
間變量而不是觸發(fā)器。
4.對于無時鐘事情的always語句(即組合邏輯建模),其時間表應(yīng)包括該alwa語
句引用的所有變量,否則會出現(xiàn)RTL與Netlist的不一致
芯片外部引腳很多都使用inout類型的,為的是節(jié)省管腿。一般信號線用做總線等雙向數(shù)據(jù)傳輸?shù)臅r候就要用到INOUT類型了。就是一個端口同時做輸入和輸出。inout在具體實現(xiàn)上一般用三態(tài)門來實現(xiàn)。三態(tài)門的第三個狀態(tài)就是高阻'Z'。當(dāng)inout端口不輸出時,將三態(tài)門置高阻。這樣信號就不會因為兩端同時輸出而出錯了,更詳細(xì)的內(nèi)容可以搜索一下三態(tài)門tri-state的資料.1 使用inout類型數(shù)據(jù),可以用如下寫法: inout data_inout;input data_in;reg data_reg;//data_inout的映象寄存器 reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三態(tài)門
//對于data_reg,可以通過組合邏輯或者時序邏輯根據(jù)data_in對其賦值.通過控制link_data的高低電平,從而設(shè)置data_inout是輸出數(shù)據(jù)還是處于高阻態(tài),如果處于高阻態(tài),則此時當(dāng)作輸入端口使用.link_data可以通過相關(guān)電路來控制.2 編寫測試模塊時,對于inout類型的端口,需要定義成wire類型變量,而其它輸入端口都定義成reg類型,這兩者是有區(qū)別的.當(dāng)上面例子中的data_inout用作輸入時,需要賦值給data_inout,其余情況可以斷開.此時可以用assign語句實現(xiàn):assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t是reg類型變量,在測試模塊中賦值.另外,可以設(shè)置一個輸出端口觀察data_inout用作輸出的情況: Wire data_out;Assign data_out_t=(!link)?data_inout:1’bz;else,in RTL inout use in top module(PAD)dont use inout(tri)in sub module 也就是說,在內(nèi)部模塊最好不要出現(xiàn)inout,如果確實需要,那么用兩個port實現(xiàn),到頂層的時候再用三態(tài)實現(xiàn)。理由是:在非頂層模塊用雙向口的話,該雙向口必然有它的上層跟它相連。既然是雙向口,則上層至少有一個輸入口和一個輸出口聯(lián)到該雙向口上,則發(fā)生兩個內(nèi)部輸出單元連接到一起的情況出現(xiàn),這樣在綜合時往往會出錯。
對雙向口,我們可以將其理解為2個分量:一個輸入分量,一個輸出分量。另外還需要一個控制信號控制輸出分量何時輸出。此時,我們就可以很容易地對雙向端口建模。例子: CODE: module dual_port(....inout_pin,....);inout inout_pin;wire inout_pin;wire input_of_inout;wire output_of_inout;wire out_en;assign input_of_inout = inout_pin;assign inout_pin = out_en ? output_of_inout : 高阻;endmodule 可見,此時input_of_inout和output_of_inout就可以當(dāng)作普通信號使用了。在仿真的時候,需要注意雙向口的處理。如果是直接與另外一個模塊的雙向口連接,那么只要保證一個模塊在輸出的時候,另外一個模塊沒有輸出(處于高阻態(tài))就可以了。如果是在ModelSim中作為單獨的模塊仿真,那么在模塊輸出的時候,不能使用force命令將其設(shè)為高阻態(tài),而是使用release命令將總線釋放掉
很多初學(xué)者在寫testbench進行仿真和驗證的時候,被inout雙向口難住了。仿真器老是提示錯誤不能進行。下面是我個人對inout端口寫testbench仿真的一些總結(jié),并舉例進行說明。在這里先要說明一下inout口在testbench中要定義為wire型變量。
先假設(shè)有一源代碼為: module xx(data_inout ,........);inout data_inout;........................assign data_inout=(!link)?datareg:1'bz;endmodule 方法一:使用相反控制信號inout口,等于兩個模塊之間用inout雙向口互連。這種方法要注意assign 語句只能放在initial和always塊內(nèi)。module test();wire data_inout;reg data_reg;reg link;initial begin..........end assign data_inout=link?data_reg:1'bz;endmodule 方法二:使用force和release語句,但這種方法不能準(zhǔn)確反映雙向端口的信號變化,但這種方法可以反在塊內(nèi)。module test();wire data_inout;reg data_reg;reg link;#xx;//延時
force data_inout=1'bx;
//強制作為輸入端口...............#xx;release data_inout;//釋放輸入端口 endmodule 很多讀者反映仿真雙向端口的時候遇到困難,這里介紹一下雙向端口的仿真方法。一個典型的雙向端口如圖1所示。
其中inner_port與芯片內(nèi)部其他邏輯相連,outer_port為芯片外部管腳,out_en用于控制雙向端口的方向,out_en為1時,端口為輸出方向,out_en為0時,端口為輸入方向。
用Verilog語言描述如下:
module bidirection_io(inner_port,out_en,outer_port);input out_en;inout[7:0] inner_port;inout[7:0] outer_port;assign outer_port=(out_en==1)?inner_port:8'hzz;assign inner_port=(out_en==0)?outer_port:8'hzz;endmodule
用VHDL語言描述雙向端口如下: library ieee;use IEEE.STD_LOGIC_1164.ALL;entity bidirection_io is port(inner_port : inout std_logic_vector(7 downto 0);out_en : in std_logic;outer_port : inout std_logic_vector(7 downto 0));end bidirection_io;architecture behavioral of bidirection_io is begin outer_port<=inner_port when out_en='1' else(OTHERS=>'Z');inner_port<=outer_port when out_en='0' else(OTHERS=>'Z');end behavioral;
仿真時需要驗證雙向端口能正確輸出數(shù)據(jù),以及正確讀入數(shù)據(jù),因此需要驅(qū)動out_en端口,當(dāng)out_en端口為1時,testbench驅(qū)動inner_port端口,然后檢查outer_port端口輸出的數(shù)據(jù)是否正確;當(dāng)out_en端口為0時,testbench驅(qū)動outer_port端口,然后檢查inner_port端口讀入的數(shù)據(jù)是否正確。由于inner_port和outer_port端口都是雙向端口(在VHDL和Verilog語言中都用inout定義),因此驅(qū)動方法與單向端口有所不同。
驗證該雙向端口的testbench結(jié)構(gòu)如圖2所示。
這是一個self-checking testbench,可以自動檢查仿真結(jié)果是否正確,并在Modelsim控制臺上打印出提示信息。圖中Monitor完成信號采樣、結(jié)果自動比較的功能。
testbench的工作過程為
1)out_en=1時,雙向端口處于輸出狀態(tài),testbench給inner_port_tb_reg信號賦值,然后讀取outer_port_tb_wire的值,如果兩者一致,雙向端口工作正常。2)out_en=0時,雙向端口處于輸如狀態(tài),testbench給outer_port_tb_reg信號賦值,然后讀取inner_port_tb_wire的值,如果兩者一致,雙向端口工作正常。用Verilog代碼編寫的testbench如下,其中使用了自動結(jié)果比較,隨機化激勵產(chǎn)生等技術(shù)。
`timescale 1ns/10ps module tb();reg[7:0] inner_port_tb_reg;wire[7:0] inner_port_tb_wire;reg[7:0] outer_port_tb_reg;wire[7:0] outer_port_tb_wire;reg out_en_tb;integer i;initial begin out_en_tb=0;inner_port_tb_reg=0;outer_port_tb_reg=0;i=0;repeat(20)begin #50 i=$random;out_en_tb=i[0];//randomize out_en_tb inner_port_tb_reg=$random;//randomize data outer_port_tb_reg=$random;end end
//**** drive the ports connecting to bidirction_io assign inner_port_tb_wire=(out_en_tb==1)?inner_port_tb_reg:8'hzz;assign outer_port_tb_wire=(out_en_tb==0)?outer_port_tb_reg:8'hzz;
//instatiate the bidirction_io module bidirection_io bidirection_io_inst(.inner_port(inner_port_tb_wire),.out_en(out_en_tb),.outer_port(outer_port_tb_wire));
//***** monitor ****** always@(out_en_tb,inner_port_tb_wire,outer_port_tb_wire)begin #1;if(outer_port_tb_wire===inner_port_tb_wire)begin $display(”n **** time=%t ****“,$time);$display(”O(jiān)K!out_en=%d“,out_en_tb);$display(”O(jiān)K!outer_port_tb_wire=%d,inner_port_tb_wire=%d“, outer_port_tb_wire,inner_port_tb_wire);end else begin $display(”n **** time=%t ****“,$time);$display(”ERROR!out_en=%d“,out_en_tb);$display(”ERROR!outer_port_tb_wire!= inner_port_tb_wire“);$display(”ERROR!outer_port_tb_wire=%d, inner_port_tb_wire=%d“, outer_port_tb_wire,inner_port_tb_wire);end end endmodule 今天重新回顧了一下阻塞賦值和非阻塞賦值的概念,感覺又有所收獲。
一、特點:
阻塞賦值:
1、RHS的表達式計算和LHS的賦值更新,這兩個動作之間不能插入其他動作,即所謂計算完畢,立即更新。
2、所謂阻塞就是指在一個“begin...end”塊中的多個阻塞賦值語句內(nèi),只有上一句完全執(zhí)行完畢后,才會執(zhí)行下一語句,否則阻塞程序的執(zhí)行。
非阻塞賦值:RHS的表達式計算和LHS的賦值更新分兩個節(jié)拍執(zhí)行,首先,應(yīng)該是RHS的表達式計算,得到新值后并不立即賦值,而是放在事件隊列中等待,直到當(dāng)前仿真時刻的后期才執(zhí)行(原因下文會提到)。
二、Verilog的分層事件隊列:
在Verilog中,事件隊列可以劃分為5個不同的區(qū)域,不同的事件根據(jù)規(guī)定放在不同的區(qū)域內(nèi),按照優(yōu)先級的高低決定執(zhí)行的先后順序,下表就列出了部分Verilog分層事件隊列。其中,活躍事件的優(yōu)先級最高(最先執(zhí)行),而監(jiān)控事件的優(yōu)先級最低,而且在活躍事件中的各事件的執(zhí)行順序是隨機的(注:為方便起見,在一般的仿真器中,對同一區(qū)域的不同事件是按照調(diào)度的先后關(guān)系執(zhí)行的)。當(dāng)前仿真 時間事件
活躍事件
阻塞賦值,非阻塞賦值的RHS計算…… 非活躍事件
顯式0延時的阻塞賦值…… 非阻塞賦值更新事件
由非阻塞語句產(chǎn)生的一個非阻塞賦值更新事件,并被調(diào)入當(dāng)前仿真時刻。監(jiān)控事件
$monitor和$strobe等系統(tǒng)任務(wù) 將來仿真
時間事件
被調(diào)度到將來仿真時間的事件
三、結(jié)論:
由上表就可以知道,阻塞賦值屬于活躍事件,會立刻執(zhí)行,這就是阻塞賦值“計算完畢,立刻更新”的原因。此外,由于在分層事件隊列中,只有將活躍事件中排在前面的事件調(diào)出,并執(zhí)行完畢后,才能夠執(zhí)行下面的事件,這就可以解釋阻塞賦值的第二個特點。
同樣是由上表知,非阻塞賦值的RHS計算屬于活躍事件,而非阻塞賦值更新事件排在非活躍事件之后,因此只有仿真隊列中所有的活躍事件和非活躍事件都執(zhí)行完畢后,才輪到非阻塞賦值更新事件,這就是非阻塞賦值必須分兩拍完成的原因。
以上就是我今天的讀書筆記,寫得倉促,如有不對,敬請指出。一.強調(diào)Verilog代碼編寫風(fēng)格的必要性。
強調(diào)Verilog代碼編寫規(guī)范,經(jīng)常是一個不太受歡迎的話題,但卻是非常有必要的。
每個代碼編寫者都有自己的編寫習(xí)慣,而且都喜歡按照自己的習(xí)慣去編寫代碼。與自己編寫風(fēng)格相近的代碼,閱讀起來容易接受和理解。相反和自己編寫風(fēng)格差別較大的代碼,閱讀和接受起來就困難一些。
曾有編程大師總結(jié)說,一個優(yōu)秀的程序員,能維護的代碼長度大約在1萬行數(shù)量級。代碼的整潔程度,很大程度上影響著代碼的維護難度。
遵循代碼編寫規(guī)范書寫的代碼,很容易閱讀、理解、維護、修改、跟蹤調(diào)試、整理文檔。相反代碼編寫風(fēng)格隨意的代碼,通常晦澀、凌亂,會給開發(fā)者本人的調(diào)試、修改工作帶來困難,也會給合作者帶來很大麻煩。
(實際上英文Coding Style有另一層涵義,更偏重的是,某一個電路,用那一種形式的語言描述,才能將電路描述得更準(zhǔn)確,綜合以后產(chǎn)生的電路更合理。本文更偏重的是,編寫Verilog代碼時的書寫習(xí)慣。)
二.強調(diào)編寫規(guī)范的宗旨。縮小篇幅 提高整潔度
便于跟蹤、分析、調(diào)試 增強可讀性,幫助閱讀者理解 便于整理文檔 便于交流合作
三.變量及信號命名規(guī)范。1.系統(tǒng)級信號的命名。
系統(tǒng)級信號指復(fù)位信號,置位信號,時鐘信號等需要輸送到各個模塊的全局信號;系統(tǒng)信號以字符串Sys開頭。
2.低電平有效的信號后一律加下劃線和字母n。如:SysRst_n;FifoFull_n; 3.經(jīng)過鎖存器鎖存后的信號,后加下劃線和字母r,與鎖存前的信號區(qū)別。如CpuRamRd信號,經(jīng)鎖存后應(yīng)命名為CpuRamRd_r。
低電平有效的信號經(jīng)過鎖存器鎖存后,其命名應(yīng)在_n后加r。如CpuRamRd_n信號,經(jīng)鎖存后應(yīng)命名為CpuRamRd_nr 多級鎖存的信號,可多加r以標(biāo)明。如CpuRamRd信號,經(jīng)兩級觸發(fā)器鎖存后,應(yīng)命名為CpuRamRd_rr。4.模塊的命名。
在系統(tǒng)設(shè)計階段應(yīng)該為每個模塊進行命名。命名的方法是,將模塊英文名稱的各個單詞首字母組合起來,形成3到5個字符的縮寫。若模塊的英文名只有一個單詞,可取該單詞的前3個字母。各模塊的命名以3個字母為宜。例如: Arithmatic Logical Unit模塊,命名為ALU。Data Memory Interface模塊,命名為DMI。Decoder模塊,命名為DEC。5.模塊之間的接口信號的命名。
所有變量命名分為兩個部分,第一部分表明數(shù)據(jù)方向,其中數(shù)據(jù)發(fā)出方在前,數(shù)據(jù)接收方在后,第二部分為數(shù)據(jù)名稱。兩部分之間用下劃線隔離開。
第一部分全部大寫,第二部分所有具有明確意義的英文名全部拼寫或縮寫的第一個字母大寫,其余部分小寫。
舉例:CPUMMU_WrReq,下劃線左邊是第一部分,代表數(shù)據(jù)方向是從CPU模塊發(fā)向存儲器管理單元模塊(MMU)。下劃線右邊Wr為Write的縮寫,Req是Request的縮寫。兩個縮寫的第一個字母都大寫,便于理解。整個變量連起來的意思就是CPU發(fā)送給MMU的寫請求信號。模塊上下層次間信號的命名也遵循本規(guī)定。
若某個信號從一個模塊傳遞到多個模塊,其命名應(yīng)視信號的主要路徑而定。6.模塊內(nèi)部信號:
模塊內(nèi)部的信號由幾個單詞連接而成,縮寫要求能基本表明本單詞的含義; 單詞除常用的縮寫方法外(如:Clock->Clk, Write->Wr, Read->Rd等),一律取該單詞的前幾個字母(如:Frequency->Freq, Variable->Var 等); 每個縮寫單詞的第一個字母大寫;
若遇兩個大寫字母相鄰,中間添加一個下劃線(如DivN_Cntr); 舉例:SdramWrEn_n;FlashAddrLatchEn;四.編碼格式規(guī)范。
1.分節(jié)書寫,各節(jié)之間加1到多行空格。如每個always,initial語句都是一節(jié)。每節(jié)基本上完成一個特定的功能,即用于描述某幾個信號的產(chǎn)生。在每節(jié)之前有幾行注釋對該節(jié)代碼加以描述,至少列出本節(jié)中描述的信號的含義。
2.行首不要使用空格來對齊,而是用Tab鍵,Tab鍵的寬度設(shè)為4個字符寬度。行尾不要有多余的空格。3.注釋。
使用//進行的注釋行以分號結(jié)束;
使用/* */進行的注釋,/*和*/各占用一行,并且頂頭; 例:
// Edge detector used to synchronize the input signal; 4.空格的使用:
不同變量,以及變量與符號、變量與括號之間都應(yīng)當(dāng)保留一個空格。Verilog關(guān)鍵字與其它任何字符串之間都應(yīng)當(dāng)保留一個空格。如: Always @(……)
使用大括號和小括號時,前括號的后邊和后括號的前邊應(yīng)當(dāng)留有一個空格。邏輯運算符、算術(shù)運算符、比較運算符等運算符的兩側(cè)各留一個空格,與變量分隔開來;單操作數(shù)運算符例外,直接位于操作數(shù)前,不使用空格。
使用//進行的注釋,在//后應(yīng)當(dāng)有一個空格;注釋行的末尾不要有多余的空格。例:
assign SramAddrBus = { AddrBus[31:24], AddrBus[7:0] };assign DivCntr[3:0] = DivCntr[3:0] + 4’b0001;assign Result = ~Operand;5.同一個層次的所有語句左端對齊;Initial、always等語句塊的begin關(guān)鍵詞跟在本行的末尾,相應(yīng)的end關(guān)鍵詞與Initial、always對齊;這樣做的好處是避免因begin獨占一行而造成行數(shù)太多; 例:
always @(posedge SysClk or negedge SysRst)begin if(!SysRst)DataOut <= 4'b0000;else if(LdEn)begin DataOut <= DataIn;End else DataOut <= DataOut + 4'b0001;end 6.不同層次之間的語句使用Tab鍵進行縮進,每加深一層縮進一個Tab; 8.在endmodule,endtask,endcase等標(biāo)記一個代碼塊結(jié)束的關(guān)鍵詞后面要加上一行注釋說明這個代碼塊的名稱;
9.在task名稱前加tsk以示標(biāo)記。在function的名稱前加func以示標(biāo)記。例如: task tskResetSystem; ……
endtask //of tskResetSystem 五.小結(jié):
以上列出的代碼編寫規(guī)范無法覆蓋代碼編寫的方方面面,還有很多細(xì)節(jié)問題,需要在實際編寫過程中加以考慮。并且有些規(guī)定也不是絕對的,需要靈活處理。并不是律條,但是在一個項目組內(nèi)部、一個項目的進程中,應(yīng)該有一套類似的代碼編寫規(guī)范來作為約束。總的方向是,努力寫整潔、可讀性好的代碼 二.reg型
在“always”塊內(nèi)被賦值的每一個信號都必須定義成reg型。reg型數(shù)據(jù)的缺省初始值是不定值。
reg型只表示被定義的信號將用在“always”塊內(nèi),理解這一點很重要。并不是說reg型信號一定是寄存器或觸發(fā)器的輸出。雖然reg型信號常常是寄存器或觸發(fā)器的輸出,但并不一定總是這樣。三.memory型
memory型數(shù)據(jù)是通過擴展reg型數(shù)據(jù)的地址范圍來生成的。其格式如下: reg [n-1:0] 存儲器名[m-1:0]; 或
reg [n-1:0] 存儲器名[m:1];
在這里,reg[n-1:0]定義了存儲器中每一個存儲單元的大小,即該存儲單元是一個n位的寄存器。存儲器名后的[m-1:0]或[m:1]則定義了該存儲器中有多少個這樣的寄存器。
reg [7:0] mema[255:0];這個例子定義了一個名為mema的存儲器,該存儲器有256個8位的存儲器。該存儲器的地址范圍是0到255。注意:對存儲器進行地址索引的表達式必須是常數(shù)表達式。
盡管memory型數(shù)據(jù)和reg型數(shù)據(jù)的定義格式很相似,但要注意其不同之處。如一個由n個1位寄存器構(gòu)成的存儲器組是不同于一個n位的寄存器的。見下例: reg [n-1:0] rega;//一個n位的寄存器
reg mema [n-1:0];//一個由n個1位寄存器構(gòu)成的存儲器組
一個n位的寄存器可以在一條賦值語句里進行賦值,而一個完整的存儲器則不行。見下例:
rega =0;
//合法賦值語句 mema =0;
//非法賦值語句
如果想對memory中的存儲單元進行讀寫操作,必須指定該單元在存儲器中的地址。下面的寫法是正確的。mema[3]=0;
//給memory中的第3個存儲單元賦值為0。3.3.1.基本的算術(shù)運算符
在Verilog HDL語言中,算術(shù)運算符又稱為二進制運算符,共有下面幾種: 1)+(加法運算符,或正值運算符,如 rega+regb,+3)2)
-(減法運算符,或負(fù)值運算符,如 rega-3,-3)3)×(乘法運算符,如rega*3)4)/(除法運算符,如5/3)5)%(模運算符,或稱為求余運算符,要求%兩側(cè)均為整型數(shù)據(jù)。如7%3的值為1)注意:
在進行算術(shù)運算操作時,如果某一個操作數(shù)有不確定的值x,則整個結(jié)果也為不定值x。1)~
//取反 2)&
//按位與 3)|
//按位或 4)^
//按位異或 5)^~
//按位同或(異或非)在Verilog HDL語言中存在三種邏輯運算符: 1)&&邏輯與 2)|| 邏輯或 3)!邏輯非
關(guān)系運算符共有以下四種: a < b
a小于b a > b
a大于b a <= b a小于或等于b a >= b a大于或等于b 3.3.5.等式運算符 3.3.6.移位運算符
3.3.7.位拼接運算符(Concatation)3.3.10.關(guān)鍵詞 在Verilog HDL中,所有的關(guān)鍵詞是事先定義好的確認(rèn)符,用來組織語言結(jié)構(gòu)。關(guān)鍵詞是用小寫字母定義的,因此在編寫原程序時要注意關(guān)鍵詞的書寫,以避免出錯。下面是Verilog HDL中使用的關(guān)鍵詞(請參閱附錄:Verilog語言參考手冊): always,and,assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive, endspecify, endtable,endtask,event,for,force,forever,fork,function,highz0,highz1, if,initial, inout, input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,notifl, or, output, parameter, pmos, posedge, primitive, pull0, pull1, pullup, pulldown, rcmos, reg, releses, repeat, mmos, rpmos, rtran, rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0, strong1, supply0, supply1, table, task, time, tran, tranif0, tranif1, tri, tri0, tri1, triand, trior,trireg,vectored,wait,wand,weak0,weak1,while,wire,wor, xnor,xor(1).非阻塞(Non_Blocking)賦值方式(如 b <= a;)1)
塊結(jié)束后才完成賦值操作。2)b的值并不是立刻就改變的。
3)
這是一種比較常用的賦值方法。(特別在編寫可綜合模塊時)(2).阻塞(Blocking)賦值方式(如 b = a;)1)
賦值語句執(zhí)行完后,塊才結(jié)束。
2)b的值在賦值語句執(zhí)行完后立刻就改變的。3)
可能會產(chǎn)生意想不到的結(jié)果。一.順序塊
順序塊有以下特點:
1)
塊內(nèi)的語句是按順序執(zhí)行的,即只有上面一條語句執(zhí)行完后下面的語句才能執(zhí)行。
2)
每條語句的延遲時間是相對于前一條語句的仿真時間而言的。3)
直到最后一條語句執(zhí)行完,程序流程控制才跳出該語句塊。
順序塊的格式如下: begin 語句1;語句2;......語句n;end 其中:
塊名即該塊的名字,一個標(biāo)識名。其作用后面再詳細(xì)介紹。
塊內(nèi)聲明語句可以是參數(shù)聲明語句、reg型變量聲明語句、integer型變量聲明語句、real型變量聲明語句。二.并行塊
并行塊有以下四個特點:
1)
塊內(nèi)語句是同時執(zhí)行的,即程序流程控制一進入到該并行塊,塊內(nèi)語句則開始同時并行地執(zhí)行。
2)
塊內(nèi)每條語句的延遲時間是相對于程序流程控制進入到塊內(nèi)時的仿真時間的。
3)
延遲時間是用來給賦值語句提供執(zhí)行時序的。
4)
當(dāng)按時間時序排序在最后的語句執(zhí)行完后或一個disable語句執(zhí)行時,程序流程控制跳出該程序塊。并行塊的格式如下: fork 語句1;語句2;.......語句n;join 其中:
塊名即標(biāo)識該塊的一個名字,相當(dāng)于一個標(biāo)識符。?
塊內(nèi)說明語句可以是參數(shù)說明語句、reg型變量聲明語句、integer型變量聲明語句、real型變量聲明語句、time型變量聲明語句、事件(event)說明語句。
在fork_join塊內(nèi),各條語句不必按順序給出,因此在并行塊里,各條語句在前還是在后是無關(guān)緊要的。見下例: 三.塊名
在VerilgHDL語言中,可以給每個塊取一個名字,只需將名字加在關(guān)鍵詞begin或fork后面即可。這樣做的原因有以下幾點。
1)
這樣可以在塊內(nèi)定義局部變量,即只在塊內(nèi)使用的變量。2)
這樣可以允許塊被其它語句調(diào)用,如被disable語句。
3)
在Verilog語言里,所有的變量都是靜態(tài)的,即所有的變量都只有一個唯一的存儲地址,因此進入或跳出塊并不影響存儲在變量內(nèi)的值。基于以上原因,塊名就提供了一個在任何仿真時刻確認(rèn)變量值的方法。casez語句用來處理不考慮高阻值z的比較過程,casex語句則將高阻值z和不定值都視為不必關(guān)心的情況。
如果用到if語句,最好寫上else項。如果用case語句,最好寫上default項。遵循上面兩條原則,就可以避免發(fā)生這種錯誤,使設(shè)計者更加明確設(shè)計目標(biāo),同時也增強了Verilog程序的可讀性。3.6.循環(huán)語句
在Verilog HDL中存在著四種類型的循環(huán)語句,用來控制執(zhí)行語句的執(zhí)行次數(shù)。1)forever
連續(xù)的執(zhí)行語句。2)repeat
連續(xù)執(zhí)行一條語句 n 次。
3)while
執(zhí)行一條語句直到某個條件不滿足。如果一開始條件即不滿足(為假),則語句一次也不能被執(zhí)行。
4)for通過以下三個步驟來決定語句的循環(huán)執(zhí)行。a)
先給控制循環(huán)次數(shù)的變量賦初值。
b)
判定控制循環(huán)的表達式的值,如為假則跳出循環(huán)語句,如為真則執(zhí)行指定的語句后,轉(zhuǎn)到第三步。c)#1:當(dāng)為時序邏輯建模,使用“非阻塞賦值”。#2:當(dāng)為鎖存器(latch)建模,使用“非阻塞賦值”。#3:當(dāng)用always塊為組合邏輯建模,使用“阻塞賦值”
#4:當(dāng)在同一個always塊里面既為組合邏輯又為時序邏輯建模,使用“非阻塞賦值”。
#5:不要在同一個always塊里面混合使用“阻塞賦值”和“非阻塞賦值”。#6:不要在兩個或兩個以上always塊里面對同一個變量進行賦值。#7:使用$strobe以顯示已被“非阻塞賦值”的值。#8:不要使用#0延遲的賦值。
#9:在VERILOG語法中,if...else if...else 語句是有優(yōu)先級的,一般說來第一個IF的優(yōu)先級最高,最后一個ELSE的優(yōu)先級最低。如果描述一個編碼器,在XILINX的XST綜合參數(shù)就有一個關(guān)于優(yōu)先級編碼器硬件原語句的選項Priority Encoder Extraction.而CASE語句是”平行“的結(jié)構(gòu),所有的CASE的條件和執(zhí)行都沒有“優(yōu)先級”。而建立優(yōu)先級結(jié)構(gòu)會消耗大量的組合邏輯,所以如果能夠使用CASE語句的地方,盡量使用CASE替換IF...ELSE結(jié)構(gòu)。
#10:XILINX的底層可編程硬件資源叫SLICE,由2個FF和2個LUT組成。FF觸發(fā)器 LUT查找表
ALTERA的底層可編程硬件資源叫LE, 由1個FF和1個LUT組成。#11:慎用鎖存器(latch),同步時序設(shè)計要盡量避免使用鎖存器,綜合出非目的性latch的主要原因在于不完全的條件判斷句。另外一種情況是設(shè)計中有組合邏輯的反饋環(huán)路(combinatorial feedback loops)。
#12:狀態(tài)機的一般設(shè)計原則,Biary, gray-code 編碼使用最少的觸發(fā)器,較多的組合邏輯。而one-hot編碼反之。所以CPLD多使用GRAY-CODE, 而FPGA多使用ONE-HOT編碼。另一方面,小型設(shè)計使用GRAY-CODE和BINARY編碼更有效,而大型狀態(tài)機使用ONE-HOT更有效。
#13:業(yè)界主流CPLD產(chǎn)品是lattice的LC4000系列和ALTERA的MAX3000系列。#14:復(fù)位使初始狀態(tài)可預(yù)測,防止出現(xiàn)禁用狀態(tài)。FPGA 和CPLD 的復(fù)位信號采用異步低電平有效信號,連接到其全局復(fù)位輸入端,使用專用路徑通道,復(fù)位信號必須連接到FPGA 和CPLD 的全局復(fù)位管腳。
#15:不要用時鐘或復(fù)位信號作數(shù)據(jù)或使能信號,也不能用數(shù)據(jù)信號作為時鐘或復(fù)位信號,否則HDL 綜合時會出現(xiàn)時序驗證問題。信號穿過時鐘的兩半個周期時,要在前后分別取樣;防止出現(xiàn)半穩(wěn)定狀態(tài)。
#16:fpga設(shè)計中不要使用門時鐘(don't use gated clock)。時鐘信號必須連接到全局時鐘管腳上。
#17:不要使用內(nèi)部三態(tài)信號,否則增加功耗。#18:只使用同步設(shè)計,不要使用延時單元。
#19:避免使用負(fù)延觸發(fā)的雙穩(wěn)態(tài)多諧振蕩器(flip flop)。
#20:不要使用信號和變量的默認(rèn)值(或初始值),用復(fù)位脈沖初始化 信號和變量。
#21:不要在代碼中使用buffer 類型的端口讀取輸出數(shù)據(jù);要使用out 類型,再增加另外變量或信號,以獲取輸出值。
這是因為buffer 類型的端口不能連接到其他類型的端口上,因此buffer 類型就會在整個設(shè)計的端口中傳播下去。
#22:對變量要先讀后寫;如果先寫后讀,就會產(chǎn)生長的組合邏輯和鎖存器(或寄存器)。這是因為變量值是立即獲取的。
#23:在組合邏輯進程中,其敏感向量標(biāo)中要包含所有要讀取得信號;這是為了防止出現(xiàn)不必要的鎖存器。
近期,在stephen Brown的一本書數(shù)字邏輯基礎(chǔ)與verilog設(shè)計一書中看到關(guān)于觸發(fā)器電路的時序分析。以前一直沒有搞明白這個問題,現(xiàn)在覺得豁然開朗。怕忘記了,特地摘抄與此與edacn網(wǎng)友分享。觸發(fā)器電路的時序分析:
圖7-84給出了一個使用D觸發(fā)器的簡單電路。我們想要計算該電路能正常工作的最大的時鐘頻率Fmax,并且想確定該電路的保持時間是否不夠長。在技術(shù)文獻中,這種類型的電路分析通常叫做時序分析。假設(shè)該觸發(fā)器的時序參數(shù)為:tsu=0.6ns,th=0.4ns,0.8ns<=tcQ<=1.0ns。給tcq參數(shù)規(guī)定一個范圍是因為延遲參數(shù)分布在一定范圍內(nèi),這樣處理是現(xiàn)成集成電路芯片常用的方法。為了計算最小的時鐘信號周期Tmin=1/Fmax,我們必須考慮在觸發(fā)器中從開始到結(jié)束的所有路徑。在這個簡單的電路中,只有一條這樣的路徑,這條路徑開始于數(shù)據(jù)被時鐘信號的正跳變沿加載進入觸發(fā)器,經(jīng)過tcQ的延遲后傳播到Q的輸出端,再傳播通過非門,同時必須滿足D輸入端的建立時間要求。因此: Tmin=tcQ+tNOT+tsu 由于我們關(guān)注的只是計算出最長的延遲時間,所以應(yīng)該用tcQ的最大值。為了計算出tNOT,我們將假設(shè)通過任何邏輯門的延遲都可以用1+0.1k進行計算,其中k是該門的輸入信號的個數(shù)。對非門而言,k=1,因此得到如下Tmin和Fmax的值:Tmin=1.0+1.1+0.6=2.7ns Fmax=1/2.7ns=370.37MHz 當(dāng)然,有必要檢查電路中的保持時間是否違反規(guī)定。在這種場合,我們必須核查從時鐘信號的正跳變沿到D輸入值改變的最短延遲。該延遲由tcQ+tNOT=0.8+1.1=1.9ns給定。因為1.9ns>0.4ns,所以保持時間夠長,沒有違反規(guī)定。再舉一個觸發(fā)器電路時序分析的例子,請考慮圖7-85所示的計數(shù)器電路。假設(shè)所用的觸發(fā)器的時序參數(shù)與圖7-84中用過的觸發(fā)器相同,請計算該電路能正常運行的最高頻率。再次假設(shè)通過邏輯門的傳播延遲可以用1+0.1k來計算。在這個電路中,存在著四個觸發(fā)器從開始到結(jié)束的許多路徑。最長的路徑從觸發(fā)器Q0起到觸發(fā)器Q3結(jié)束。在某個電路中最長的路徑成為關(guān)鍵路徑。關(guān)鍵路徑的延遲包括觸發(fā)器Q0的時鐘信號到Q的延遲、通過三個與門的傳播延遲和一個異或門的延遲。我們還必須考慮觸發(fā)器Q3的建立時間。因此,得到 Tmin=tcQ+3(tAND)+tXOR+tsu 用tcQ的最大值,得到 Tmin=1.0+3(1.2)+1.2+0.6=6.4ns Fmax=1/6.4ns=156.25MHz 該電路的最短路徑是從每個觸發(fā)器通過異或門反饋到該觸發(fā)器本身的輸入端。沿每個這樣路徑的最小延遲為tcQ+tXOR=0.8+1.2=2.0ns。因為2.0ns>th=0.4ns,因此保持時間足夠長,沒有違反規(guī)定。
在上面的分析中,假設(shè)時鐘信號同時到達所有四個觸發(fā)器。我們現(xiàn)在將重復(fù)這個分析,假設(shè)時鐘信號同時到達觸發(fā)器Q0,Q1,Q2,但到達觸發(fā)器Q3有一些延遲。始終到達不同的觸發(fā)器之間的時間差稱為時鐘偏差(clock skew),記作tskew,時鐘偏差可以由許多原因引起。
在圖7-85中,電路的關(guān)鍵路徑是從觸發(fā)器Q0起到觸發(fā)器Q3。然而,Q3的時鐘偏差使得這個延遲減少,因為時鐘偏差在數(shù)據(jù)被加載進該觸發(fā)器前提供了附加的時間。如果考慮增加1.5ns的時鐘偏差,則從觸發(fā)器Q0到觸發(fā)器Q3的路徑延遲由tcQ+3(tAND)+tXOR+tsu-tskew=6.4-1.5ns=4.9ns給定。該電路現(xiàn)在還存在一個不同的關(guān)鍵路徑,該路徑從觸發(fā)器Q0起到觸發(fā)器Q2結(jié)束。這條路徑的延遲為
Tmin=tcQ+2(tAND)+tXOR+tsu=1.0+2(1.2)+1.2+0.6ns=5.2ns Fmax=1/5.2ns=192.31MHz
在這種場合,時鐘偏差導(dǎo)致電路的最高時鐘頻率提高。但是,如果時鐘偏差是負(fù)的,即觸發(fā)器Q3的時鐘到達時間比其他觸發(fā)器更早一些,則會造成該電路的最高時鐘頻率Fmax降低。
因為數(shù)據(jù)加載到觸發(fā)器Q3被時鐘偏差延遲了,所以對所有起始于Q0,Q1,Q2而以Q3為結(jié)束點的路徑,都會產(chǎn)生使觸發(fā)器Q3的保持時間需要增加到th+tskew的影響。在該電路中,這種最短的路徑是從觸發(fā)器Q2到Q3的路徑,其延遲時間為TcQ+tAND+tXOR=0.8+1.2+1.2=3.2ns。因為3.2ns>th+tskew=1.9ns,所以保持時間足夠長,沒有違反規(guī)定。
如果對時鐘偏差值tskew>=3.2-th=2.8ns,重復(fù)以上保持時間的分析,則會出現(xiàn)保持時間不夠的情況。當(dāng)tskew>=2.8ns時,該電路將不可能在任何頻率下可靠地運行。由于時鐘偏差的存在會引起電路時序問題,所以好的電路設(shè)計方法必須保證時鐘信號到達所有觸發(fā)器的偏差盡可能小。
最后是我的總結(jié):確定最小周期是找關(guān)鍵路徑即最長路徑。確定Th是否違例是找最短路徑。最短路徑要大于Th。如果有Tskew的情況則要大于Th+Tskew(有skew的寄存器為最短路徑的終點的時候)
還有就是我對有Tskew的情況的時候為什么防止違例要最短路徑>Th+Tskew。因為Q0,Q1和Q2時鐘比Q3早,以他們?yōu)槠瘘c的路徑已經(jīng)開始走了一段時間后Q3的時鐘才到才開始打入數(shù)據(jù)。所以保持時間上要加上這段skew ISE 約束文件的基本操作 1.約束文件的概念
FPGA設(shè)計中的約束文件有3類:用戶設(shè)計文件(.UCF文件)、網(wǎng)表約束文件(.NCF文件)以及物理約束文件(.PCF文件),可以完成時序約束、管腳約束以及區(qū)域約束。3類約束文件的關(guān)系為:用戶在設(shè)計輸入階段編寫UCF文件,然后UCF文件和設(shè)計綜合后生成NCF文件,最后再經(jīng)過實現(xiàn)后生成PCF 文件。本節(jié)主要介紹UCF文件的使用方法。
UCF文件是ASC 2碼文件,描述了邏輯設(shè)計的約束,可以用文本編輯器和Xilinx約束文件編輯器進行編輯。NCF約束文件的語法和UCF文件相同,二者的區(qū)別在于: UCF文件由用戶輸入,NCF文件由綜合工具自動生成,當(dāng)二者發(fā)生沖突時,以UCF文件為準(zhǔn),這是因為UCF的優(yōu)先級最高。PCF文件可以分為兩個部分:一部分是映射產(chǎn)生的物理約束,另一部分是用戶輸入的約束,同樣用戶約束輸入的優(yōu)先級最高。一般情況下,用戶約束都應(yīng)在UCF文件中完成,不建議直接修改 NCF文件和PCF文件。2.創(chuàng)建約束文件
約束文件的后綴是.ucf,所以一般也被稱為UCF文件。創(chuàng)建約束文件有兩種方法,一種是通過新建方式,另一種則是利用過程管理器來完成。
第一種方法:新建一個源文件,在代碼類型中選取“Implementation Constrains File”,在“File Name”中輸入“one2two_ucf”。單擊“Next”按鍵進入模塊選擇對話框,選擇模塊“one2two”,然后單擊“Next”進入下一頁,再單擊“Finish”按鍵完成約束文件的創(chuàng)建。
第二種方法:在工程管理區(qū)中,將“Source for”設(shè)置為“Synthesis/Implementation”。“Constrains Editor”是一個專用的約束文件編輯器,雙擊過程管理區(qū)中“User Constrains”下的“Create Timing Constrains”就可以打開“Constrains Editor”,其界面如圖所示:
圖啟動Constrains Editor引腳約束編輯
在“Ports”選項卡中可以看到,所有的端口都已經(jīng)羅列出來了,如果要修改端口和FPGA管腳的對應(yīng)關(guān)系,只需要在每個端口的“Location”列中填入管腳的編號即可。例如在UCF文件中描述管腳分配的語法為: NET “端口名稱” LOC = 引腳編號;需要注意的是,UCF文件是大小敏感的,端口名稱必須和源代碼中的名字一致,且端口名字不能和關(guān)鍵字一樣。但是關(guān)鍵字NET是不區(qū)分大小寫的。3.編輯約束文件
在工程管理區(qū)中,將“Source for”設(shè)置為“Synthesis/Implementation”,然后雙擊過程管理區(qū)中“User Constrains”下的“Edit Constraints(Text)”就可以打開約束文件編輯器,如下圖所示,就會新建當(dāng)前工程的約束文件。圖用戶約束管理窗口 UCF文件的語法說明 1.語法
UCF文件的語法為:
{NET|INST|PIN} ”signal_name“ Attribute;其中,“signal_name”是指所約束對象的名字,包含了對象所在層次的描述;“Attribute”為約束的具體描述;語句必須以分號“;”結(jié)束。可以用“#”或“/* */”添加注釋。需要注意的是:UCF文件是大小寫敏感的,信號名必須和設(shè)計中保持大小寫一致,但約束的關(guān)鍵字可以是大寫、小寫甚至大小寫混合。例如: NET ”CLK“ LOC = P30;“CLK”就是所約束信號名,LOC = P30;是約束具體的含義,將CLK信號分配到FPGA的P30管腳上。
對于所有的約束文件,使用與約束關(guān)鍵字或設(shè)計環(huán)境保留字相同的信號名會產(chǎn)生錯誤信息,除非將其用” “括起來,因此在輸入約束文件時,最好用” “將所有的信號名括起來。2.通配符
在UCF文件中,通配符指的是“*”和“?”。“*”可以代表任何字符串以及空,“?”則代表一個字符。在編輯約束文件時,使用通配符可以快速選擇一組信號,當(dāng)然這些信號都要包含部分共有的字符串。例如: NET ”*CLK?“ FAST;將包含“CLK”字符并以一個字符結(jié)尾的所有信號,并提高了其速率。在位置約束中,可以在行號和列號中使用通配符。例如: INST ”/CLK_logic/*“ LOC = CLB_r*c7;把CLK_logic層次中所有的實例放在第7列的CLB中。3.定義設(shè)計層次
在UCF文件中,通過通配符*可以指定信號的設(shè)計層次。其語法規(guī)則為: * 遍歷所有層次
Level1/* 遍歷level1及以下層次中的模塊
Level1/*/ 遍歷level1種的模塊,但不遍歷更低層的模塊
例4-5 根據(jù)圖4-75所示的結(jié)構(gòu),使用通配符遍歷表4-3所要求的各個模塊。圖層次模塊示意圖 表要求遍歷的符號列表 管腳和區(qū)域約束語法
LOC約束是FPGA設(shè)計中最基本的布局約束和綜合約束,能夠定義基本設(shè)計單元在FPGA芯片中的位置,可實現(xiàn)絕對定位、范圍定位以及區(qū)域定位。此外,LOC還能將一組基本單元約束在特定區(qū)域之中。LOC語句既可以書寫在約束文件中,也可以直接添加到設(shè)計文件中。換句話說,ISE中的FPGA底層工具編輯器(FPGA Editor)、布局規(guī)劃器(Floorplanner)和引腳和區(qū)域約束編輯器的主要功能都可以通過LOC語句完成。?
LOC語句語法
INST ”instance_name “ LOC = location;
其中“l(fā)ocation”可以是FPGA芯片中任一或多個合法位置。如果為多個定位,需要用逗號“,”隔開,如下所示: LOC = location1,location2,...,locationx;目前,還不支持將多個邏輯置于同一位置以及將多個邏輯至于多個位置上。需要說明的是,多位置約束并不是將設(shè)計定位到所有的位置上,而是在布局布線過程中,布局器任意挑選其中的一個作為最終的布局位置。范圍定位的語法為:
INST “instance_name” LOC=location:location [SOFT];常用的LOC定位語句如表4-4所列。表常用的LOC定位語句 使用LOC完成端口定義時,其語法如下: NET ”Top_Module_PORT“ LOC = ”Chip_Port“;其中,“Top_Module_PORT”為用戶設(shè)計中頂層模塊的信號端口,“Chip_Port”為FPGA芯片的管腳名。
LOC語句中是存在優(yōu)先級的,當(dāng)同時指定LOC端口和其端口連線時,對其連線約束的優(yōu)先級是最高的。例如,在圖4-76中,LOC=11的優(yōu)先級高于LOC=38。圖 LOC優(yōu)先級示意圖 2.LOC屬性說明
LOC語句通過加載不同的屬性可以約束管腳位置、CLB、Slice、TBUF、塊RAM、硬核乘法器、全局時鐘、數(shù)字鎖相環(huán)(DLL)以及DCM模塊等資源,基本涵蓋了FPGA芯片中所有類型的資源。由此可見,LOC語句功能十分強大,表4-5列出了LOC的常用屬性。表 LOC語句常用屬性列表
Verilog HDL代碼描述對狀態(tài)機綜合的研究 2007-11-25 16:59 1 引言
Verilog HDL作為當(dāng)今國際主流的HDL語言,在芯片的前端設(shè)計中有著廣泛的應(yīng)用。它的語法豐富,成功地應(yīng)用于設(shè)計的各個階段:建模、仿真、驗證和綜合等。可綜合是指綜合工具能將Verilog HDL代碼轉(zhuǎn)換成標(biāo)準(zhǔn)的門級結(jié)構(gòu)網(wǎng)表,因此代碼的描述必須符合一定的規(guī)則。大部分?jǐn)?shù)字系統(tǒng)都可以分為控制單元和數(shù)據(jù)單元兩個部分,控制單元的主體是一個狀態(tài)機,它接收外部信號以及數(shù)據(jù)單元產(chǎn)生的狀態(tài)信息,產(chǎn)生控制信號,因而狀態(tài)機性能的好壞對系統(tǒng)性能有很大的影響。
有許多可綜合狀態(tài)機的Verilog代碼描述風(fēng)格,不同代碼描述風(fēng)格經(jīng)綜合后得到電路的物理實現(xiàn)在速度和面積上有很大差別。優(yōu)秀的代碼描述應(yīng)當(dāng)易于修改、易于編寫和理解,有助于仿真和調(diào)試,并能生成高效的綜合結(jié)果。2 有限狀態(tài)機
有限狀態(tài)機(Finite State Machine,FSM)在數(shù)字系統(tǒng)設(shè)計中應(yīng)用十分廣泛。根據(jù)狀態(tài)機的輸出是否與輸入有關(guān),可將狀態(tài)機分為兩大類:摩爾(Moore)型狀態(tài)機和米莉(Mealy)型狀態(tài)機。Moore型狀態(tài)機的輸出僅與現(xiàn)態(tài)有關(guān);Mealy型狀態(tài)機的輸出不僅與現(xiàn)態(tài)有關(guān),而且和輸入也有關(guān)。圖1是有限狀態(tài)機的一般結(jié)構(gòu)圖,它主要包括三個部分,其中組合邏輯部分包括狀態(tài)譯碼器和輸出譯碼器,狀態(tài)譯碼器確定狀態(tài)機的下一個狀態(tài),輸出譯碼器確定狀態(tài)機的輸出,狀態(tài)寄存器屬于時序邏輯部分,用來存儲狀態(tài)機的內(nèi)部狀態(tài)。圖1 狀態(tài)機的結(jié)構(gòu)框圖 2.1 好的狀態(tài)機標(biāo)準(zhǔn)
好的狀態(tài)機的標(biāo)準(zhǔn)很多,最重要的幾個方面如下:
第一,狀態(tài)機要安全,是指FSM不會進入死循環(huán),特別是不會進入非預(yù)知的狀態(tài),而且由于某些擾動進入非設(shè)計狀態(tài),也能很快的恢復(fù)到正常的狀態(tài)循環(huán)中來。這里面有兩層含義。其一要求該FSM的綜合實現(xiàn)結(jié)果無_毛刺等異常擾動,其二要求FSM要完備,即使受到異常擾動進入非設(shè)計狀態(tài),也能很快恢復(fù)到正常狀態(tài)。第二,狀態(tài)機的設(shè)計要滿足設(shè)計的面積和速度的要求。第三,狀態(tài)機的設(shè)計要清晰易懂、易維護。
需要說明的是,以上各項標(biāo)準(zhǔn),不是割裂的,它們有著直接緊密的內(nèi)在聯(lián)系。在芯片設(shè)計中,對綜合結(jié)果評判的兩個基本標(biāo)準(zhǔn)為:面積和速度。“面積”是指設(shè)計所占用的邏輯資源數(shù)量;“速度”指設(shè)計在芯片上穩(wěn)定運行所能夠達到的最高頻率。兩者是對立統(tǒng)一的矛盾體,要求一個設(shè)計同時具備設(shè)計面積最小,運行頻率最高,這是不現(xiàn)實的。科學(xué)的設(shè)計目標(biāo)應(yīng)該是:在滿足設(shè)計時序要求(包含對設(shè)計最高頻率的要求)的前提下,占用最小的芯片面積,或者在所規(guī)定的面積下,使設(shè)計的時序余量更大,頻率更高。另外,如果要求FSM安全,則很多時候需要使用“full case”的編碼方式,即將狀態(tài)轉(zhuǎn)移變量的所有向量組合情況都在FSM 中有相應(yīng)的處理,這經(jīng)常勢必意味著要多花更多的設(shè)計資源,有時也會影響FSM的頻率所以,上述的標(biāo)準(zhǔn)要綜合考慮,根據(jù)設(shè)計的要求進行權(quán)衡。2.2 狀態(tài)機描述方法
狀態(tài)機描述時關(guān)鍵是要描述清楚幾個狀態(tài)機的要素,即如何進行狀態(tài)轉(zhuǎn)移,每個狀態(tài)的輸出是什么,狀態(tài)轉(zhuǎn)移的條件等。具體描述時方法各種各樣,最常見的有三種描述方式:
第一,整個狀態(tài)機寫到一個always模塊里面,在該模塊中既描述狀態(tài)轉(zhuǎn)移,又描述狀態(tài)的輸入和輸出;第二,用兩個always模塊來描述狀態(tài)機,其中一個always模塊采用同步時序描述狀態(tài)轉(zhuǎn)移;另一個模塊采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件,描述狀態(tài)轉(zhuǎn)移規(guī)律以及輸出;第三,在兩個always模塊描述方法基礎(chǔ)上,使用三個always模塊,一個always模塊采用同步時序描述狀態(tài)轉(zhuǎn)移,一個采用組合邏輯判斷狀態(tài)轉(zhuǎn)移條件,描述狀態(tài)轉(zhuǎn)移規(guī)律,另一個always模塊描述狀態(tài)的輸出(可以用組合電路輸出,也可以時序電路輸出)。
一般而言,推薦的FSM 描述方法是后兩種。這是因為:FSM和其他設(shè)計一樣,最好使用同步時序方式設(shè)計,以提高設(shè)計的穩(wěn)定性,消除毛刺。狀態(tài)機實現(xiàn)后,一般來說,狀態(tài)轉(zhuǎn)移部分是同步時序電路而狀態(tài)的轉(zhuǎn)移條件的判斷是組合邏輯。
第二種描述方法同第一種描述方法相比,將同步時序和組合邏輯分別放到不同的always模塊中實現(xiàn),這樣做的好處不僅僅是便于閱讀、理解、維護,更重要的是利于綜合器優(yōu)化代碼,利于用戶添加合適的時序約束條件,利于布局布線器實現(xiàn)設(shè)計。在第二種方式的描述中,描述當(dāng)前狀態(tài)的輸出用組合邏輯實現(xiàn),組合邏輯很容易產(chǎn)生毛刺,而且不利于約束,不利于綜合器和布局布線器實現(xiàn)高性能的設(shè)計。第三種描述方式與第二種相比,關(guān)鍵在于根據(jù)狀態(tài)轉(zhuǎn)移規(guī)律,在上一狀態(tài)根據(jù)輸入條件判斷出當(dāng)前狀態(tài)的輸出,從而在不插入額外時鐘節(jié)拍的前提下,實現(xiàn)了寄存器輸出。
2.3 狀態(tài)機的編碼
二進制編碼(Binary)、格雷碼(Gray-code)編碼使用最少的觸發(fā)器,較多的組合邏輯,而獨熱碼(One-hot)編碼反之。獨熱碼編碼的最大優(yōu)勢在于狀態(tài)比較時僅僅需要比較一個位,從而一定程度上簡化了比較邏輯,減少了毛刺產(chǎn)生的概率。由于CPLD更多地提供組合邏輯資源,而FPGA更多地提供觸發(fā)器資源,所以CPLD多使用二進制編碼或格雷碼,而FPGA多使用獨熱碼編碼。另一方面,對于小型設(shè)計使用二進制和格雷碼編碼更有效,而大型狀態(tài)機使用獨熱碼更高效。3 實例說明
下面通過實例來說明Verilog HDL代碼描述對狀態(tài)機綜合結(jié)果的影響。
設(shè)計一個序列檢測器,用于檢測串行的二進制序列,每當(dāng)連續(xù)輸入三個或三個以上的1時,序列檢測器的輸出為1,其它情況下輸出為0。
假設(shè)初始的狀態(tài)為s0,輸入一個1的狀態(tài)記為s1,連續(xù)輸入二個1后的狀態(tài)記為s2,輸入三個或以上1的狀態(tài)記為s3,不論現(xiàn)態(tài)是何種狀態(tài)一旦輸入0的話,就返回到初始狀態(tài)。根據(jù)題意,可畫出狀態(tài)圖如圖2所示。圖2 狀態(tài)圖
根據(jù)狀態(tài)圖以及前面狀態(tài)機的介紹,可以采用一個always模塊來描述,狀態(tài)編碼采用二進制編碼,程序如下: module fsm(clk,ina,out);input clk,ina;output out;reg out;parameter s0 = 3'bOO,s1 =3'b01,s2 =3'b10,s3=3'b11;reg[0:1]state;always @(posedge clk)begin state<=s0;out =0;case(state)s0:begin state<=(ina)?s1:s0;out=0;end s1:begin state<=(ina)?s2:s0;out=0;end s2:begin state<=(ina)?s3:s0;out=0;end s3:begin state<=(ina)?s3:s0;out=1;end endcase end endmodule
采用Synplify Pro工具在Altera EPF10K10系列器件上進行綜合,其綜合的結(jié)果如圖3所示。
如果采用兩個always來描述,程序的模塊聲明、端口定義和信號類型部分不變,只是改動邏輯功能描述部分,改動部分的程序如下: alwys @(posedge dk)state fsm <=next_state;always @(state_fsm or ina)begin state<=s0;out =0;case(state_fsm)s0:begin next_state=(ina)?s1:s0;out=0;end s1:begin next state=(ina)?s2:s0;out=0: end s2:begin next_state=(ina)?s3:s0;out=0;end s3:begin next_state=(ina)?s3:s0;out=1;end endcase end endmodule
在相同的器件上其綜合的結(jié)果如圖4所示,比較圖3與圖4的綜合結(jié)果,可以看出。兩種綜合結(jié)果都是采用了兩個觸發(fā)器來存儲狀態(tài)。其不同的地方是輸出部分,采用一個always模塊的輸出結(jié)果是寄存器輸出。采用兩個always模塊描述的是組合邏輯直接輸出,這是因為代碼中的輸出賦值也放在了時鐘的上升沿(always @(posedge clk))。其綜合的結(jié)果是寄存器,因此它比直接組合邏輯輸出延遲一個時鐘周期。圖4
如果采用一位hot編碼,僅改動參數(shù)設(shè)置的兩行程序。采用一個always模塊描述,改動部分的程序如下:
parameter s0 = 3'b0001,s1 =3'b0010,s2 =3'b0100,s3=3'b1000;reg[0:3] state;圖5
綜合的結(jié)果如圖5所示。將圖5與圖3相比,可以看出:
圖5中狀態(tài)寄存器采用了4個觸發(fā)器來存儲狀態(tài),而圖3采用了兩個觸發(fā)器來存儲狀態(tài),這是由于它們的狀態(tài)編碼的不同而得到的不同的綜合結(jié)果,采用二進制編碼綜合得到的觸發(fā)器要比采用獨熱碼綜合得到的觸發(fā)器少。它們的共同之處都是采用了寄存器來輸出的。3 結(jié)束語
有多種可綜合狀態(tài)機的Verilog HDL代碼描述風(fēng)格。其綜合的結(jié)果是不同的。其中廣泛采用的是兩個或三個always模塊描述。組合邏輯輸出型狀態(tài)機不適合應(yīng)用在高速復(fù)雜系統(tǒng)設(shè)計中,在高速系統(tǒng)中應(yīng)當(dāng)采用寄存器輸出型狀態(tài)機。寄存器類型信號不會產(chǎn)生毛刺,并且輸出不含組合邏輯。會減少組合邏輯門延時。容易滿足高速系統(tǒng)設(shè)計要求。總之,狀態(tài)機的設(shè)計是數(shù)字系統(tǒng)設(shè)計中的關(guān)鍵部分,設(shè)計時做到心中有電路。充分考慮其綜合的結(jié)果,才能編寫出高質(zhì)量的綜合代碼。進而提高設(shè)計水平。
模塊劃分非常重要,除了關(guān)系到是否最大程度上發(fā)揮項目成員的協(xié)同設(shè)計能力,而且直接決定著設(shè)計的綜合、實現(xiàn)時間。下面是一些模塊劃分的原則。
a.對每個同步設(shè)計的子模塊的輸出使用寄存器(registering)。也即用寄存器分割同步時序模塊的原則。)@(F3 f+ D” j
使用寄存器的好處有:綜合工具在編譯綜合時會將所分割的子模塊中的組合電路和同步時序電路整體考慮。而且這種模塊結(jié)構(gòu)符合時序約束的習(xí)慣,便于使用時序約束熟悉進行約束。)q9 t/ |# a 7 p0 C b.將相關(guān)的邏輯或者可以復(fù)用的邏輯劃分在同一模塊內(nèi)。
這樣做的好處有,一方面將相關(guān)的邏輯和可以復(fù)用的邏輯劃分在同一模塊,可以最大程度的復(fù)用資源,減少設(shè)計消耗的面積。同時也更利于綜合工具優(yōu)化一個具體功能(操作)在時序上的關(guān)鍵路徑。其原因是,綜合工具只能同時考慮一部分邏輯,而所同時優(yōu)化的邏輯單元就是模塊,所以將相關(guān)功能劃分在同一模塊更有利于綜合器的優(yōu)化。;l/ w" k5 r9 G4 X4 x c.將不同優(yōu)化目標(biāo)的邏輯分開。
好的設(shè)計,在規(guī)劃階段,設(shè)計者就已經(jīng)思考了設(shè)計的大概規(guī)模和關(guān)鍵路徑,并對設(shè)計的優(yōu)化目標(biāo)有一個整體上的把握。對于時序緊張的部分,應(yīng)該獨立劃分為一個模塊,其優(yōu)化目標(biāo)為“speed”,這種劃分方法便于設(shè)計者進行時序約束,也便于綜合和實現(xiàn)工具進行優(yōu)化。比如時序優(yōu)化的利器Amplify,使用模塊進行區(qū)域優(yōu)化更方便一些。另一類矛盾集中在面積的設(shè)計,也應(yīng)該劃分成獨立的模塊,這類模塊的優(yōu)化目標(biāo)是“Area”,同樣將他們規(guī)劃到一起,更有利于區(qū)域布局與約束。這種根據(jù)優(yōu)化目標(biāo)進行優(yōu)化的方法的最大好處是,對于某個模塊綜合器僅僅需要考慮一種優(yōu)化目標(biāo)和策略,從而比較容易達到較好的優(yōu)化效果。相反的如果同時考慮兩種優(yōu)化目標(biāo),會使綜合器陷入互相制約的困境。
d.將松約束的邏輯歸到同一模塊。
有些邏輯的時序非常寬松,不需要較高的時序約束,可以將這類邏輯歸入同一模塊,如多周期路徑“multi-cycle”等。將這些模塊歸類,并指定松約束,則可以讓綜合器盡量的節(jié)省面積資源。
e.將RAM/ROM/FIFO等邏輯獨立劃分成模塊。
這樣做的好處是便于綜合器將這類資源類推為器件的硬件原語,同時仿真時消耗的內(nèi)存也會少些,便于提高仿真速度。(大多數(shù)仿真器對大面積的RAM都有獨特的內(nèi)存管理方式)0 o4 B!p5 Q-D)O)Y7 M/ ] f.合適的模塊規(guī)模。
規(guī)模大,利于“Resource Sharing”。但是對綜合器同時處理的邏輯量太大,不利于多模塊和增量編譯模式。關(guān)于約束,時序分析的問題匯總
很多人發(fā)貼,來信詢問關(guān)于約束、時序分析的問題,比如:如何設(shè)置setup,hold時間?如何使用全局時鐘和第二全局時鐘(長線資源)?如何進行分組約束?如何約束某部分組合邏輯?如何通過約束保證異步時鐘域之間的數(shù)據(jù)交換可靠?如何使用I/O邏輯單元內(nèi)部的寄存器資源?如何進行物理區(qū)域約束,完成物理綜合和物理實現(xiàn)?等等。。
為了解決大家的疑難,我們將逐一討論這些問題。今天先討論一下約束的作用?
有些人不知道何時該添加約束,何時不需要添加?有些人認(rèn)為低速設(shè)計不需要時序約束?關(guān)于這些問題,希望下面關(guān)于約束作用的論述能夠有所幫助!附加約束的基本作用有3:(1)提高設(shè)計的工作頻率
對很多數(shù)字電路設(shè)計來說,提高工作頻率非常重要,因為高工作頻率意味著高處理能力。通過附加約束可以控制邏輯的綜合、映射、布局和布線,以減小邏輯和布線延時,從而提高工作頻率。(2)獲得正確的時序分析報告
幾乎所有的FPGA設(shè)計平臺都包含靜態(tài)時序分析工具,利用這類工具可以獲得映射或布局布線后的時序分析報告,從而對設(shè)計的性能做出評估。靜態(tài)時序分析工具以約束作為判斷時序是否滿足設(shè)計要求的標(biāo)準(zhǔn),因此要求設(shè)計者正確輸入約束,以便靜態(tài)時序分析工具輸出正確的時序分析報告。(3)指定FPGA/CPLD引腳位置與電氣標(biāo)準(zhǔn)
FPGA/CPLD的可編程特性使電路板設(shè)計加工和FPGA/CPLD設(shè)計可以同時進行,而不必等FPGA/CPLD引腳位置完全確定,從而節(jié)省了系統(tǒng)開發(fā)時間。這樣,電路板加工完成后,設(shè)計者要根據(jù)電路板的走線對FPGA/CPLD加上引腳位置約束,使FPGA/CPLD與電路板正確連接。另外通過約束還可以指定IO引腳所支持的接口標(biāo)準(zhǔn)和其他電氣特性。為了滿足日新月異的通信發(fā)展,Xilinx新型FPGA/CPLD可以通過IO引腳約束設(shè)置支持諸如AGP、BLVDS、CTT、GTL、GTLP、HSTL、LDT、LVCMOS、LVDCI、LVDS、LVPECL、LVDSEXT、LVTTL、PCI、PCIX、SSTL、ULVDS等豐富的IO接口標(biāo)準(zhǔn)。
另外通過區(qū)域約束還能在FPGA上規(guī)劃各個模塊的實現(xiàn)區(qū)域,通過物理布局布線約束,完成模塊化設(shè)計等。貼2:時序約束的概念和基本策略!
時序約束主要包括周期約束(FFS到FFS,即觸發(fā)器到觸發(fā)器)和偏移約束(IPAD到FFS、FFS到OPAD)以及靜態(tài)路徑約束(IPAD到OPAD)等3種。通過附加