VerilogHDL基本語法綜述_第1頁
VerilogHDL基本語法綜述_第2頁
VerilogHDL基本語法綜述_第3頁
VerilogHDL基本語法綜述_第4頁
VerilogHDL基本語法綜述_第5頁
已閱讀5頁,還剩128頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

VerilogHDL基本語法

語匯代碼的編寫標準常量、變量及數據類型關鍵字和標示符

運算符

語句綜合代碼的編寫標準

規定了文本布局、命名和注釋的約定,以提高源代碼的可讀性和可維護性。每個VerilogHDL源文件中只準編寫一個頂層模塊,也不能把一個頂層模塊分成幾部分寫在幾個源文件中。源文件名字應與文件內容有關,最好與頂層模塊同名!源文件名字的第一個字符必須是字母或下劃線,不能是數字或$符號!每行只寫一個聲明語句或說明。源代碼用層層縮進的格式來寫。語匯代碼的編寫標準2定義變量名的大小寫應自始至終保持一致(如變量名第一個字母均大寫)。變量名應該有意義,而且含有一定的有關信息。局部變量名(如循環變量)應簡單扼要。通過注釋對源代碼做必要的說明,尤其對接口(如模塊參數、端口、任務、函數變量)做必要的注釋很重要。語匯代碼的編寫標準3常量盡可能多地使用參數定義和宏定義,而不要在語句中直接使用字母、數字和字符串。

參數定義(用一個標識符來代表一個常量)的格式:

parameter參數名1=表達式,參數名2=表達式,……;

宏定義(用一個簡單的宏名來代替一個復雜的表達式)的格式:’define標志符(即宏名)字符串(即宏內容)語匯代碼的編寫標準4常量整型數:5表達方式說明舉例+/-<位寬>’<進制><數字>完整的表達方式8’b11000101或8’hc5<進制><數字>缺省位寬,則位寬由機器系統決定,至少32位hc5<數字>缺省進制為十進制,位寬默認為32位197注:這里位寬指對應二進制數的寬度。常量x表示不定值,z表示高阻值;“?”是z的另一種表示符號,建議在case語句中使用?表示高阻態z為提高可讀性,在較長的數字之間可用下劃線_隔開!但不可以用在<進制>和<數字>之間。當常量未指明位寬時,默認為32位。617 //位寬,基數符號不寫會采用default值(32bit十進制)8’d32 //8-bit十進制值為32

8’h1A8’o378’b0001_110032’bx //”x”表unknown4’b0??? //”?”表示高阻常量7常量實數十進制計數法,科學計數法

7.21.8e-4 //1.8*10-49.5E6字符串與字符變量字符串為兩個雙引號“

”之間的字符,不許跨行“Thisisastring!”;//共17個字符8常量參數(符號常量)

參數是一個常量,經常用于定義時延和變量的寬度。

parameterbyte_size=8;//定義一個常數參數 parameter,byte_msb=byte_size-1;//用數表達式賦值 parameteraverage_delay=(r+f)/2;//用常數表達式賦值9變量變量即在程序運行過程中其值可以改變的量

VerilogHDL中共有19種數據類型;其中3個最基本的數據類型為:網絡型(netstype)寄存器型(registertype)數組型(memorytype)10變量

線網類型:netstype表示Verilog結構化元件間的物理連線。它的值由驅動元件的值決定;如果沒有驅動元件連接到線網,線網的缺省值為z。

寄存器類型:registertype表示一個抽象的數據存儲單元,它只能在always語句和initial語句中被賦值,并且它的值從一個賦值到另一個賦值被保存下來。寄存器類型的變量具有x的缺省值。11wire型變量它是最常用的nets型變量,常用來表示以assign語句賦值的組合邏輯信號。模塊中的輸入/輸出信號類型缺省為wire型。可用做任何方程式的輸入,或“assign”語句和實例元件的輸出。變量12wire

數據名1,數據名2,……,數據名n;wire[n-1:0]

數據名1,數據名2,……,數據名m;或wire[n:1]

數據名1,數據名2,……,數據名m;每條總線位寬為n共有m條總線wire型向量(總線)格式變量13變量14register類型:

在程序塊中作變量用,對信號賦值需要用該數據類型,賦值時用關鍵字initial或always開始。常用register變量reg:是最常見的數據類型,常代表觸發器.integer:

32位帶符號整數型變量,可以作為普通寄存器使用,典型應用為高層次行為建模。time類型:無符號時間變量。real和realtime類型:實數寄存器(或實數時間寄存器)變量register型變量與nets型變量的根本區別是:register型變量需要被明確地賦值,并且在被重新賦值前一直保持原值。register型變量必須通過過程賦值語句賦值!不能通過assign語句賦值!在過程塊內被賦值的每個信號必須定義成register型!15reg型變量定義——在過程塊中被賦值的信號,往往代表觸發器,但不一定就是觸發器(也可以是組合邏輯信號)!reg

數據名1,數據名2,……,數據名n;格式變量16reg[n-1:0]

數據名1,數據名2,……,數據名m;或reg[n:1]

數據名1,數據名2,……,數據名m;每個向量位寬為n共有m個reg型向量[例]reg[4:1]regc,regd;//regc,regd為4位寬的reg型向量reg型向量(總線)變量17

用reg型變量生成組合邏輯舉例:

modulerw1(a,b,out1,out2);

inputa,b;

outputout1,out2;

regout1;

wireout2;

assignout2=a;

always@(b)

out1<=~b;

endmoduleaout2BUFFbINVout1過程賦值語句連續賦值語句電平觸發Verilog中reg與wire的區別reg型變量既可生成觸發器,也可生成組合邏輯;wire型變量只能生成組合邏輯。變量18用reg型變量生成觸發器舉例:

modulerw2(clk,d,out1,out2);

inputclk,d;

outputout1,out2;

regout1;

wireout2;

assignout2=d&~out1;

always@(posedgeclk)

begin

out1<=d;

end

endmodule

過程賦值語句連續賦值語句dout2AND2i1clkout1DQDFF上沿觸發變量19變量Memory類型

VerilogHDL通過對reg型變量建立數組來對存儲器建模,可以描述RAM型存儲器,ROM存儲器和reg文件。數組中的每一個單元通過一個數組索引進行尋址。在Verilog語言中沒有多維數組存在。memory型數據是通過擴展reg型數據的地址范圍來生成的。20變量格式:reg[n-1:0]存儲器名[m-1:0];reg[n-1:0]定義了存儲器中每一個存儲單元的大小,即該存儲單元是一個n位的寄存器。存儲器名后的[m-1:0]或[m:1]則定義了該存儲器中有多少個這樣的寄存器。最后用分號結束定義語句。21變量例:reg[7:0]mema[255:0];這個例子定義了一個名為mema的存儲器,該存儲器有256個8位的存儲器。該存儲器的地址范圍是0到255。注意:對存儲器進行地址索引的表達式必須是常數表達式。22變量Verilog的變量的四種邏輯狀態:

0:邏輯零、邏輯非、低電平

1:邏輯1、邏輯真、高電平

x或X:不定態

z或Z:高阻態23關鍵字關鍵字——事先定義好的確認符,用來組織語言結構;或者用于定義VerilogHDL提供的門元件(如and,not,or,buf)。用小寫字母定義!

——如always,assign,begin,case,casex,else,end,for,function,if,input,output,repeat,table,time,while,wire24用戶程序中的變量、節點等名稱不能與關鍵字同名!關鍵詞25edgeelseendendcaseendfunctionendprimitiveendmoduleendspecifyendtableendtaskeventforforceforeverforkfunctionhighz0highz1ififnoneinitialinoutinputintegerjoinlargemacromodulemediummodulenandnegedgenornotnotif0notif1nmosoroutputparameterpmosposedgeprimitivepulldownpulluppull0pull1andalwaysassignbeginbufbufif0bufif1casecasexcasezcmosdeassigndefaultdefparamdisable關鍵詞26tri0tri1vectoredwaitwandweak0weak1whilewireworxnorxorrcmosrealrealtimeregreleaserepeatrnmosrpmosrtranrtranif0rtranif1scalaredsmallspecifyspecparamstrengthstrong0strong1supply0supply1tabletasktrantranif0tranif1timetritriandtriortrireg特殊字符$:以$開頭的標識符代表系統命令$time:返回目前的仿真時間$display:顯示出信號的值$stop:停止仿真#時延控制 not#3not1(sel_,sel);//instancedelay #5a=0;b=0;cin=1; //proceduralstatementdelay27標示符28

任何用VerilogHDL語言描述的“東西”都通過其名字來識別,這個名字被稱為標識符。

如源文件名、模塊名、端口名、變量名、常量名、實例名等。

標識符可由字母、數字、下劃線和$符號構成;但第一個字符必須是字母或下劃線,不能是數字或$符號!

在VerilogHDL中變量名是區分大小寫的!標識符不能與關鍵字同名!標示符

標識符必須是由a-z,A-Z,0-9,_,$這些字符組成,最長只能到1024個字符

開頭必須由a-z,A-Z或下劃線_開頭

可以在標識符所取的非法名稱前加上反斜杠“\”,并在名稱結尾加上空白鍵,這樣就可以用任何可印出的ASCII字符來當作標識符的名稱了;而反斜杠和空白鍵不會被視為標識符的一部分29標示符30合法的名字:A_99_ZReset_54MHz_Clock$Module

不合法的名字:123a$datamodule7seg.v運算符31進行整數除法運算時,結果值略去小數部分,只取整數部分!

%稱為求模(或求余)運算符,要求%兩側均為整型數據;求模運算結果值的符號位取第一個操作數的符號位!

[例]-11%3結果為-2進行算術運算時,若某操作數為不定值x,則整個結果也為x。 運算符32運算符

位運算符:按位進行運算,結果的位數不變

兩個不同長度的操作數進行位運算時,將自動按右端對齊,位數少的操作數會在高位用0補齊

[例]若A=5’b11001,B=3’b101,則A&B=(5’b11001)&(5’b00101) =5’b0000133運算符

關系運算結果為1位的邏輯值1或0或x。關系運算時,若關系為真,則返回值為1;若聲明的關系為假,則返回值為0;若某操作數為不定值x,則返回值為x。

等式運算符運算結果為1位的邏輯值1或0或x。等于運算符(==)和全等運算符(===)的區別:使用等于運算符時,兩個操作數必須逐位相等,結果才為1;若某些位為x或z,則結果為x。使用全等運算符時,若兩個操作數的相應位完全一致(如同是1,或同是0,或同是x,或同是z),則結果為1;否則為0。34==01xz01xz10xx01xxxxxxxxxx===01xz01xz1000010000100001“==”的真值表“===”的真值表等于運算的結果可能為1或0或x全等于運算的結果只有1或0運算符35左移會擴充位數!將操作數右移或左移n位,相當于將操作數除以或乘以2n。右移位數不變,但右移的數據會丟失!運算符

移位運算符:將操作數右移或左移n位,同時用n個0填補移出的空位。

[例]4’b1001>>3=4’b0001; 4’b1001>>4=4’b0000 4’b1001<<1=5’b10010;

4’b1001<<2=6’b100100;

1<<6=32’b100000036運算符條件運算符<條件>?<條件為真表達式>:<條件為假表達式> EX:tri_data=en?data_out:32’bz;//三態37類別運算符優先級邏輯、位運算符!~高低算術運算符*/%+-移位運算符<<>>關系運算符<<=>>=等式運算符==!====!==縮減、位運算符&~&^^~|~|邏輯運算符&&||條件運算符?:運算符的優先級為提高程序的可讀性,建議使用括號來控制運算的優先級![例](a>b)&&(b>c)

(a==b)||(x==y)

(!a)||(a>b)運算符38語句39賦值語句連續賦值語句過程賦值語句塊語句begin_end語句fork_join語句條件語句if_else語句case語句循環語句forever語句while語句repeat語句for語句結構說明語句initial語句always語句task語句function語句編譯預處理語句‘define語句‘timescale語句‘include語句語句40賦值語句分為兩類:連續賦值語句——assign語句,用于對wire型變量賦值,是描述組合邏輯最常用的方法之一

[例]assignc=a&b;//a、b、c均為wire型變量過程賦值語句——用于對reg型變量賦值,有兩種方式:

非阻塞(non-blocking)賦值方式:

賦值符號為<=,如b<=a;阻塞(blocking)賦值方式:

賦值符號為=,如b=a;

非阻塞賦值方式

always@(posedgeclk)

begin

b<=a;

c<=b;

endclkDFFcDQDQabDFF非阻塞賦值在塊結束時才完成賦值操作!注:c的值比b的值落后一個時鐘周期!語句41阻塞賦值方式

always@(posedgeclk)

begin

b=a;

c=b;

end阻塞賦值在該語句結束時就完成賦值操作!clkDFFcDQab注:在一個塊語句中,如果有多條阻塞賦值語句,在前面的賦值語句沒有完成之前,后面的語句就不能被執行,就像被阻塞了一樣,因此稱為阻塞賦值方式。這里c的值與b的值一樣

!語句42非阻塞(non-blocking)賦值方式(b<=a):b的值被賦成新值a的操作,并不是立刻完成的,而是在塊結束時才完成;塊內的多條賦值語句在塊結束時同時賦值;硬件有對應的電路。阻塞(blocking)賦值方式(b=a):b的值立刻被賦成新值a;完成該賦值語句后才能執行下一句的操作;硬件沒有對應的電路,因而綜合結果未知。建議在初學時只使用一種方式,不要混用!建議在可綜合風格的模塊中使用非阻塞賦值!語句43

塊語句用來將兩條或多條語句組合在一起,使其在格式上更像一條語句,以增加程序的可讀性。

塊語句有兩種:begin_end語句——標識順序執行的語句fork_join語句——標識并行執行的語句語句44順序塊塊內的語句是順序執行的;每條語句的延遲時間是相對于前一條語句的仿真時間而言的;直到最后一條語句執行完,程序流程控制才跳出該順序塊。語句45begin

語句1;語句2;

語句n;endbegin:塊名塊內聲明語句;語句1;語句2;

語句n;end注:塊內聲明語句可以是參數聲明、reg型變量聲明、integer型變量聲明、real型變量聲明語句。或順序塊的格式語句46[例]begin

b=a;

c=b;//c的值為a的值

end[例]begin

b=a;

#10

c=b;//在兩條賦值語句間延遲10個時間單位

end注:這里標識符“#”表示延遲;在模塊調用中“#”表示參數的傳遞語句47

[例]用順序塊和延遲控制組合產生一個時序波形。

parameterd=50;

reg[7:0]r;

begin //由一系列延遲產生的波形

#dr=’

h35;

#dr=’

hE2;

#dr=’

h00;

#dr=’

hF7;

#d–>end_wave;

//觸發事件end_wave

end注:每條語句的延遲時間d是相對于前一條語句的仿真時間而言的!語句48用fork_join標識的塊語句并行塊塊內的語句是同時執行的;塊內每條語句的延遲時間是相對于程序流程控制進入到塊內時的仿真時間而言的;延遲時間用于給賦值語句提供時序;當按時間排序在最后的語句執行完或一個disable語句執行時,程序流程控制跳出該并行塊。49fork

語句1;語句2;

語句n;joinfork:塊名塊內聲明語句;語句1;語句2;

語句n;join或注:塊內聲明語句可以是參數聲明、reg型變量聲明、integer型變量聲明、real型變量聲明語句、time型變量聲明語句和事件(event)說明語句。并行塊的格式語句50[例4]用并行塊和延遲控制組合產生一個時序波形。

reg[7:0]r;

fork

//由一系列延遲產生的波形

#50r=’

h35;

#100r=’

hE2;

#150r=’

h00;

#200r=’

hF7;

#250–>end_wave;

//觸發事件end_wave

join波形同例3注:在fork_join塊內,各條語句不必按順序給出!但為增加可讀性,最好按被執行的順序書寫!語句51語句if-else條件語句case語句for循環語句52if(條件表達式) 塊語句1 elseif(條件表達式2)塊語句2 …… elseif(條件表達式n)塊語句nelse

塊語句n+1case(敏感表達式)

值1:塊語句1

值2:塊語句2 ……

值n:塊語句n default:塊語句n+1endcasefor(表達式1;表達式2;表達式3)塊語句若if與else的數目不一樣,注意用“begin_end”語句來確定if與else的配對關系!if(表達式1)

if(表達式2)語句1;

else

語句2;else

if(表達式3)語句3;

else

語句4;if(表達式1)

begin

if(表達式2)語句1;

endelse

語句2;當if與else的數目不一樣時,最好用“begin_end”語句將單獨的if語句括起來:if語句的嵌套:語句53語句case語句與if-else語句區別if-else語句適于對不同的條件,執行不同的語句;對于每個判定只有兩個分支。case語句適于對同一個控制信號取不同的值時,輸出取不同的值!它是多分支語句。當控制信號只有一個時,最好采用case語句,比較簡潔!54是case語句的兩種變體語句casecasezcasex的區別在case語句中,分支表達式每一位的值都是確定的(或者為0,或者為1);在casez語句中,若分支表達式某些位的值為高阻值z,則不考慮對這些位的比較;在casex語句中,若分支表達式某些位的值為z或不定值x,則不考慮對這些位的比較。在分支表達式中,可用“?”來標識x或z55modulemux_z(out,a,b,c,d,select);outputout;inputa,b,c,d;input[3:0]select;regout;//必須聲明

always@(select[3:0]oraorborcord)begin

casez(select)4’b???1:out=a;

4’b??1?:out=b;

4’b?1??:out=c;

4’b1???:out=d;

endcaseendendmodule[例]用casez描述的數據選擇器這里“?”表示高阻態語句56使用條件語句注意事項

應注意列出所有條件分支,否則當條件不滿足時,編譯器會生成一個鎖存器保持原值!

這一點可用于設計時序電路,如計數器:條件滿足時加1,否則保持原值不變。

而在組合電路設計中,應避免生成隱含鎖存器!有效的方法是在if語句最后寫上else項;在case語句最后寫上default項。語句57如何正確使用if語句?生成了不想要的鎖存器:不會生成鎖存器:always@(alord)beginif(al)q<=d;

enddDFFD

Qalq[例]設計一個數據選擇器always@(alord)beginif(al)q<=d;

elseq<=0;

end0dalqmultiplexer當al為0時,q保持原值!當al為0時,q等于0!語句58always@(sel[1:0]oraorb)case(sel[1:0])2’b00:q<=a;

2’b11:q<=b;

endcase生成了不想要的鎖存器:[例]設計一個數據選擇器always@(sel[1:0]oraorb)case(sel[1:0])2’b00:q<=a;

2’b11:q<=b;

default:q<=’b0;

endcase不會生成鎖存器:如何正確使用case語句?當sel為00或11以外的值時,q保持原值!避免生成鎖存器的原則:如果用到if語句,最好寫上else項;如果用到case語句,最好寫上default項。語句59循環語句for語句——通過3個步驟來決定語句的循環執行:(1)給控制循環次數的變量賦初值。(2)判定循環執行條件,若為假則跳出循環;若為真,則執行指定的語句后,轉到第(3)步。(3)修改循環變量的值,返回第(2)步。repeat語句——連續執行一條語句n次while語句——執行一條語句,直到循環執行條件不滿足;若一開始條件即不滿足,則該語句一次也不能被執行!forever語句——無限連續地執行語句,可用disable語句中斷!語句60for語句for

(表達式1;表達式2;表達式3)語句for(循環變量賦初值;循環執行條件;循環變量增值)執行語句8條語句相當于采用while語句建立的循環結構:begin

循環變量賦初值;

while(循環執行條件)begin<執行語句>

循環變量增值;

endendfor語句比while語句簡潔!語句61repeat語句

連續執行一條或多條語句n次。repeat

(循環次數表達式)語句repeat

(循環次數表達式)

begin……

end執行語句為多條語句或格語句62[例]兩個8位二進制數乘法注:不如采用for語句簡單!語句631.while語句

有條件地執行一條或多條語句。首先判斷循環執行條件表達式是否為真。若為真,則執行后面的語句或語句塊;然后再回頭判斷循環執行條件表達式是否為真,若為真,再執行一次后面的語句;如此不斷,直到條件表達式不為真。while

(循環執行條件表達式)語句while

(循環執行條件表達式)

begin

……

end或語句while64modulecount1s_while(count,rega,clk); output[3:0]count; input[7:0]rega;inputclk;reg[3:0]count;always@(posedgeclk) begin:count1reg[7:0]tempreg;//用作循環執行條件表達式

count=0;//count初值為0tempreg=rega;//tempreg初值為rega

while(tempreg)

//若tempreg非0,則執行以下語句

beginif(tempreg[0])count=count+1;

//只要tempreg最低位為1,則count加1

tempreg=tempreg>>1;

//右移1位

endendendmodule[例]對一個8位二進制數中值為1的位進行計數。改變循環執行條件表達式的值如何用for語句改寫此程序呢?語句65無條件連續執行forever后面的語句或語句塊。forever

語句forever

begin……

end或常用在測試模塊中產生周期性的波形,作為仿真激勵信號。常用disable語句跳出循環!注:不同于always語句,不能獨立寫在程序中,一般用在initial語句塊中!initialbegin:Clocking clk=0;#10forever#10clk=!clk;endinitialbegin:Stimulus ……

disableClocking;//停止時鐘

end語句

forever語句66initial說明語句

——只執行一次always說明語句——不斷重復執行,直到仿真

結束task說明語句——可在程序模塊中的一處或

多處調用function說明語句——可在程序模塊中的一處

或多處調用語句結構說明語句67always塊語句包含一個或一個以上的聲明語句(如:過程賦值語句、任務調用、條件語句和循環語句等),在仿真運行的全過程中,在定時控制下被反復執行。語句結構說明語句在always塊中被賦值的只能是register型變量(如reg,integer,real,time)。每個always塊在仿真一開始便開始執行,當執行完塊中最后一個語句,繼續從always塊的開頭執行。68always

<時序控制><語句>注1:如果always塊中包含一個以上的語句,則這些語句必須放在begin_end或fork_join塊中!always@(posedgeclkornegedgeclear)

begin

if(!clear)qout=0;//異步清零

elseqout=1;

end

語句6970[例]生成一個0延遲的無限循環跳變過程——形成仿真死鎖

alwaysareg=~areg;[例]在測試文件中,用于生成一個無限延續的信號波形——時鐘信號注2:always語句必須與一定的時序控制結合在一起才有用!如果沒有時序控制,則易形成仿真死鎖!‘definehalf_period50modulehalf_clk_top;regreset,clk;//輸入信號

wireclk_out;//輸出信號

always#half_periodclk=~clk;……endmodule 語句70always@(<敏感信號表達式>)

begin//過程賦值語句

//if語句

//case語句

//while,repeat,for循環

//task,function調用

end一般為輸入敏感信號表達式又稱事件表達式或敏感表,當其值改變時,則執行一遍塊內語句;在敏感信號表達式中應列出影響塊內取值的所有信號!

敏感信號可以為單個信號,也可為多個信號,中間需用關鍵字or連接!敏感信號不要為x或z,否則會阻擋進程!always塊語句一個變量不能在多個always塊中被賦值!語句71always的時間控制可以為沿觸發,也可為電平觸發。關鍵字posedge表示上升沿;negedge表示下降沿。always@(posedgeclockorposedgereset)begin……endalways@(aorborc)begin……end由兩個沿觸發的always塊由多個電平觸發的always塊語句7273always塊語句是用于綜合過程的最有用的語句之一,但又常常是不可綜合的。為得到最好的綜合結果,always塊程序應嚴格按以下模板來編寫:模板1always@(Inputs)//所有輸入信號必須列出,用or隔開

begin

……//組合邏輯關系

end

模板2always@(Inputs)//所有輸入信號必須列出,用or隔開

if(Enable)

begin

……//鎖存動作

end

語句73模板3always@(posedgeClock)//Clockonly

begin

……//同步動作

end

模板4always@(posedgeClockornegedgeReset)//ClockandResetonly

begin

if(!Reset)//測試異步復位電平是否有效

……//異步動作

else……//同步動作

end//可產生觸發器和組合邏輯語句74當always塊有多個敏感信號時,一定要采用if-elseif語句,而不能采用并列的if語句!否則易造成一個寄存器有多個時鐘驅動,將出現編譯錯誤。always@posedgemin_clkornegedgereset)

beginif(reset)min<=0;

elseif(min=8’h59)//當reset無效且min=8’h59時

beginmin<=0;h_clk<=1;end

end

通常采用異步清零!只有在時鐘周期很小或清零信號為電平信號時采用同步清零。千萬別寫成if哦!語句75initial

begin

語句1;語句2;

……

語句n;

end格式

[例]利用initial語句生成激勵波形。

initialbegininputs=’b000000;#10inputs=’b011001;#10inputs=’b011011;#10inputs=’b011000;#10inputs=’b001000;end在仿真的初始狀態對各變量進行初始化;在測試文件中生成激勵波形作為電路的仿真信號。語句initial語句76……parametersize=16;reg[3:0]addr;regreg1;reg[7:0]memory[0:15];initialbeginreg1=0;for(addr=0;addr<size;addr=addr+1);memory[addr]=0;end……[例]對各變量進行初始化。語句77除module以外,Verilog還提供了任務(task)和函數(function)可重復調用定義和調用都包含在module內部語句78 task和function語句分別用來由用戶定義任務和函數。

任務和函數往往是大的程序模塊中在不同地點多次用到的相同的程序段。

利用任務和函數可將一個很大的程序模塊分解為許多較小的任務和函數,便于理解和調試。

輸入、輸出和總線信號的值可以傳入、傳出任務和函數。語句task和function語句79task任務名; //無需定義端口名列表

端口與類型說明; //調用時按順序和類型列出 局部變量說明; 塊語句endtask當希望能夠對一些信號進行一些運算并輸出多個結果(即有多個輸出變量)時,宜采用任務結構。常常利用任務來幫助實現結構化的模塊設計,將批量的操作以任務的形式獨立出來,使設計簡單明了。

語句<任務名>(端口1,端口2,……);80…..always@(posedgesys_clk)beginif(read_request==1)beginread_mem(IR,PC); //Eventandfunctioncalls endendtaskread_mem;output[15:0]data_in;input[15:0]addr;always@(posedgeread_grant)begin ADDRESS=addr; #15data_in=data;endendtask…….語句注1:任務的定義與調用必須在一個module模塊內!注2:任務被調用時,需列出端口名列表,

且必須與任務定義中的I/O變量一一對應!注3:一個任務可以調用其他任務和函數。81[例]通過任務調用完成4個4位二進制輸入數據的冒泡排序。

任務的定義任務的調用82function函數的目的是通過返回一個用于某表達式的值,來響應輸入信號。適于對不同變量采取同一運算的操作。函數在模塊內部定義,通常在本模塊中調用,也能根據按模塊層次分級命名的函數名從其他模塊調用。而任務只能在同一模塊內定義與調用!語句83語句Function

function<位寬>函數名;

輸入端口與類型說明;

局部變量說明;

塊語句

endfiction注意:1.函數不能調用任務,任務可調用任何其他函數和任務

2.函數只有輸入變量且至少一個

3.函數定義的塊語句不許出現定時控制

4.函數通過函數名返回一個值缺省則返回1位reg型數據<函數名>(<表達式><表達式>)與函數定義中的輸入變量對應!84always@(posedgesys_clk)begin…..IR=swap_bits(IR);…..endfunction[15:0]swap_bits;input[15:0]in_vec;reg[15:0]temp_reg;integeri;beginfor(I=15;I>=0;I=I-1)temp_reg[15-i]=in_vec[i];swap_bits=temp_reg;endendfunctioin語句85語句

注1:函數的調用是通過將函數作為調用函數的表達式中的操作數來實現的!

注2:函數在綜合時被理解成具有獨立運算功能的電路,每調用一次函數,相當于改變此電路的輸入,以得到相應的計算結果。86函數的使用規則函數的定義不能包含任何時間控制語句——用延遲#、事件控制@或等待wait標識的語句。函數不能啟動(即調用)任務!定義函數時至少要有一個輸入參量!且不能有任何輸出或輸入/輸出雙向變量。在函數的定義中必須有一條賦值語句,給函數中的一個內部寄存器賦以函數的結果值,該內部寄存器與函數同名。語句87[例]利用函數對一個8位二進制數中為0的位進行計數。只有輸入變量內部寄存器對應函數的輸入變量語句88任務(task)函數(function)目的或用途可計算多個結果值通過返回一個值,來響應輸入信號輸入與輸出可為各種類型(包括inout型)至少有一個輸入變量,但不能有任何output或inout型變量被調用只可在過程賦值語句中調用,不能在連續賦值語句中調用可作為表達式中的一個操作數來調用,在過程賦值和連續賦值語句中均可調用調用其他任務和函數任務可調用其他任務和函數函數可調用其他函數,但不可調用其他任務返回值不向表達式返回值向調用它的表達式返回一個值任務與函數的區別語句89語句

“編譯預處理”是VerilogHDL編譯系統的一個組成部分。編譯預處理語句以西文符號“‵”開頭——注意,不是單引號“’”!

在編譯時,編譯系統先對編譯預處理語句進行預處理,然后將處理結果和源程序一起進行編譯。90‵define語句

宏定義語句——用一個指定的標志符(即宏名)來代表一個字符串(即宏內容)。宏定義的作用:以一個簡單的名字代替一個長的字符串或復雜表達式;以一個有含義的名字代替沒有含義的數字和符號。‵define

標志符(即宏名)字符串(即宏內容)[例]‵defineINina+inb+inc+ind宏展開——在編譯預處理時將宏名替換為字符串的過程。語句91關于宏定義的說明宏名可以用大寫字母,也可用小寫字母表示;但建議用大寫字母,以與變量名相區別。‵define語句可以寫在模塊定義的外面或里面。宏名的有效范圍為定義命令之后到源文件結束。在引用已定義的宏名時,必須在其前面加上符號“‵”!使用宏名代替一個字符串,可簡化書寫,便于記憶,易于修改。語句92關于宏定義的說明預處理時只是將程序中的宏名替換為字符串,不管含義是否正確。只有在編譯宏展開后的源程序時才報錯。宏名和宏內容必須在同一行中進行聲明!宏定義不是VerilogHDL語句,不必在行末加分號!如果加了分號,會連分號一起置換!語句93[例]moduletest;rega,b,c,d,e,out;‵defineexpressiona+b+c+d;assignout=‵expression+e;……經過宏展開后,assign語句為:

assignout=a+b+c+d;+e;//出現語法錯誤!錯誤!語句94[例]moduletest;rega,b,c;wireout;‵defineaaa+b

‵defineccc+‵aa//引用已定義的宏名‵aa來定義宏ccassignout=‵cc;……經過宏展開后,assign語句為:

assignout=c+a+b;語句在進行宏定義時,可引用已定義的宏名,實現層層置換。95文件包含語句——一個源文件可將另一個源文件的全部內容包含進來。‵include

“文件名”預處理后‵include

“file2.v”Afile1.vBfile2.vABfile1.v將file2.v中全部內容復制插入到‵include“file2.v”命令出現的地方格式語句‵include語句96使用‵include語句的好處

避免程序設計人員的重復勞動!不必將源代碼復制到自己的另一源文件中,使源文件顯得簡潔。(1)可以將一些常用的宏定義命令或任務(task)組成一個文件,然后用‵include語句將該文件包含到自己的另一源文件中,相當于將工業上的標準元件拿來使用。(2)當某幾個源文件經常需要被其他源文件調用時,則在其他源文件中用‵include語句將所需源文件包含進來。

語句97[例]用‵include語句設計16位加法器adder模塊位拼接改變被引用模塊adder中的參數size為my_size98一個‵include語句只能指定一個被包含的文件;若要包含n個文件,需用n個‵include語句。‵include語句可出現在源程序的任何地方。被包含的文件若與包含文件不在同一子目錄下,必須指明其路徑!‵include“aaa.v”

“bbb.v”

//非法!‵include“parts/count.v”

//合法!‵include“aaa.v”

‵include“bbb.v”

//合法!語句99可將多個‵include語句寫在一行;在該行中,只可出現空格和注釋行。文件包含允許嵌套。‵include“aaa.v”

‵include“bbb.v”

//合法!‵include

“file2.v”………………file1.v‵include

“file3.v”………………file2.v(不包含‵include命令)………………file3.v語句100時間尺度語句——用于定義跟在該命令后模塊的時間單位和時間精度。‵timescale<時間單位>/<時間精度>時間單位——用于定義模塊中仿真時間和延遲時間的基準單位;時間精度——用來聲明該模塊的仿真時間和延遲時間的精確程度。在同一程序設計里,可以包含采用不同時間單位的模塊。此時用最小的時間精度值決定仿真的時間單位。格式語句‵timescale語句101‵timescale1ps/1ns//非法!‵timescale1ns/1ps//合法!時間精度至少要和時間單位一樣精確,時間精度值不能大于時間單位值!在‵timescale語句中,用來說明時間單位和時間精度參量值的數字必須是整數。其有效數字為1、10、100;單位為秒(s)、毫秒(ms)、微秒(us)、納秒(ns)、皮秒(ps)、毫皮秒(fs)。語句102[例]‵timescale語句應用舉例。‵timescale10ns/1ns//時間單位為10ns,時間精度為1ns……regsel;

initialbegin#10sel=0;//在10ns10時刻,sel變量被賦值為0#10sel=1;//在10ns20時刻,sel變量被賦值為1end……語句103語句的順序執行:(1)在

“always”模塊內,邏輯按書寫的順序執行。(2)順序語句——“always”模塊內的語句。(3)在“always”模塊內,若隨意顛倒賦值語句的書寫順序,可能導致不同的結果!(見[例3.11.1]、[例3.11.2])。(4)注意阻塞賦值語句當本語句結束時即完成賦值操作!語句104105[例]順序執行模塊1。moduleserial1(q,a,clk);outputq,a;inputclk;regq,a;always@(posedgeclk)begin

q=~q;//阻塞賦值語句

a=~q;endendmodule[例]順序執行模塊2。moduleserial2(q,a,clk);outputq,a;inputclk;regq,a;always@(posedgeclk)begin

a=~q;

q=~q;endendmodule對前一時刻的q值取反對當前時刻的q值取反對前一時刻的q值取反對前一時刻的q值取反a和q的波形反相!a和q的波形完全相同!語句105語句的并行執行:(1)“always”模塊、“assign”語句、實例元件都是同時(即并行)執行的!(2)它們在程序中的先后順序對結果并沒有影響。(3)將兩條賦值語句分別放在兩個“always”模塊中,盡管兩個“always”模塊順序相反,但仿真波形完全相同。語句106[例]并行執行模塊1。moduleparall1(q,a,clk);outputq,a;inputclk;regq,a;always@(posedgeclk)begin

q=~q;

endalways@(posedgeclk)begin

a=~q;

endendmodule[例]并行執行模塊2。moduleparall2(q,a,clk);outputq,a;inputclk;regq,a;always@(posedgeclk)begin

a=~q;endalways@(posedgeclk)begin

q=~q;

endendmodule語句107(1)把設計分割成較小的功能塊,每塊用行為風格設計。除設計中對速度響應要求比較臨界的部分外,都應避免門級描述。(2)建立一個好的時鐘策略(如單時鐘、多相位時鐘,經過門產生的時鐘、多時鐘域等)。保證源代碼中時鐘和復位信號是干凈的(即不是由組合邏輯或沒有考慮到的門產生的)。綜合代碼的編寫標準綜合:將用HDL語言或圖形方式描述的電路設計轉換為實際門級電路(如觸發器、邏輯門等),得到一個網表文件,用于進行適配(在實際器件中進行布局和布線)。108(3)建立一個好的測試策略,使所有觸發器都是可復位的,使測試能通過外部管腳進行,又沒有冗余的功能。(4)所有源代碼都必須遵守并符合在always塊語句的4種可綜合標準模板之一。(5)描述組合和鎖存邏輯的always塊,必須在always塊開頭的控制事件列表中列出所有的輸入信號。綜合代碼的編寫標準109(6)描述組合邏輯的always塊,一定不能有不完全賦值,即所有輸出變量必須被各輸入值的組合值賦值,不能有例外。(7)描述組合和鎖存邏輯的always塊一定不能包含反饋,即在always塊中已被定義為輸出的寄存器變量絕對不能再在該always塊中讀進來作為輸入信號。綜合代碼的編寫標準110(8)時鐘沿觸發的always塊必須是單時鐘的,且任何異步控制輸入(通常是復位或置位信號)必須在控制事件列表中列出。例:always@(posedgeclkornegedgesetornegedgereset)(9)避免生成不想要的鎖存器。在無時鐘的always塊中,若有的輸出變量被賦了某個信號變量值,而該信號變量并未在該always塊的電平敏感控制事件中列出,則會在綜合中生成不想要的鎖存器。綜合代碼的編寫標準111(10)避免生成不想要的觸發器。在時鐘沿觸發的always塊中,如果用非阻塞賦值語句對reg型變量賦值;或者當reg型變量經過多次循環其值仍保持不變,則會在綜合中生成觸發器。用reg型變量生成觸發器舉例:

modulerw2(clk,d,out1);

inputclk,d;

outputout1;

regout1;

always@(posedgeclk)//沿觸發

out1<=d;

endmodule

非阻塞賦值語句dclkout1DQDFF綜合代碼的編寫標準112若不想生成觸發器,而是希望用reg型變量生成組合邏輯,則應使用電平觸發:

modulerw2(clk,d,out1);

inputclk,d;

outputout1;

regout1;

always@(d)//電平觸發

out1<=d;endmodule

dout1BUFF綜合代碼的編寫標準113(11)所有內部狀態寄存器必須是可復位的,這是為了使RTL級和門級描述能夠被復位成同一個已知的狀態,以便進行門級邏輯驗證。(12)對存在無效狀態的有限狀態機和其他時序電路(如4位十進制計數器有6個無效狀態),必須明確描述所有的2的N次冪種狀態下的行為(包括無效狀態),才能綜合出安全可靠的狀態機。綜合代碼的編寫標準114(13)一般地,在賦值語句中不能使用延遲,否則是不可綜合的。(14)不要使用integer型和time型寄存器,否則將分別綜合成32位和64位的總線。(15)仔細檢查代碼中使用動態指針(如用指針或地址變量檢索的位選擇或存儲單元)、循環聲明或算術運算部分,因為這類代碼在綜合后會生成大量的門,且難以優化。綜合代碼的編寫標準115Verilog不同抽象級別

一個復雜電路的完整VerilogHDL模型由若干個VerilogHDL模塊構成,每個模塊由若干的子模塊構成——可分別用不同抽象級別的VerilogHDL描述。116Verilog不同抽象級別在同一個VerilogHDL模塊中可有多種級別的描述。系統級(systemlevel):用高級語言結構(如case語句)實現的設計模塊外部性能的模型;算法級(algorithmiclevel):用高級語言結構實現的設計算法模型(寫出邏輯表達式);RTL級(registertransferlevel):描述數據在寄存器之間流動和如何處理這些數據的模型;門級(gatelevel):描述邏輯門(如與門、非門、或門、與非門、三態門等)以及邏輯門之間連接的模型;開關級(switchlevel):描述器件中三極管和儲存節點及其之間連接的模型。117Verilog不同抽象級別電路描述行為級描述:側重對模塊行為功能的抽象描述結構級描述:側重對模塊內部結構實現的具體描述行為級模塊描述由多個并行運行的過程塊組成過程塊由過程語句(initial與always)和塊語句(串行塊begin-end與并行塊fork-join)組成塊語句由過程賦值語句和高級程序語句構成過程賦值語句:阻塞與非阻塞式賦值高級程序語句:if-else、case、while、wait……包括系統級,算法級,RTL級1181.邏輯功能描述——算法級注:首先必須根據邏輯功能寫出邏輯表達式![例]用邏輯表達式實現4選1數據選擇器modulemux4_1(out,in1,in2,in3,in4,cntrl1,cntrl2);outputout;inputin

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論