今天給大俠帶來(lái)的是一周掌握FPGA Verilog HDL 語(yǔ)法,今天開(kāi)啟第五天。
上一篇提到了case語(yǔ)句、循環(huán)語(yǔ)句(forever、repeat、while、for)、結(jié)構(gòu)說(shuō)明語(yǔ)句(initial、always、task、 function)等,此篇我們繼續(xù)來(lái)看編譯預(yù)處理,結(jié)合實(shí)例理解理論語(yǔ)法,會(huì)讓你理解運(yùn)用的更加透徹。下面咱們廢話就不多說(shuō)了,一起來(lái)看看吧。
編譯預(yù)處理
Verilog HDL語(yǔ)言和C語(yǔ)言一樣也提供了編譯預(yù)處理的功能。“編譯預(yù)處理”是Verilog HDL編譯系統(tǒng)的一個(gè)組成部分。Verilog HDL語(yǔ)言允許在程序中使用幾種特殊的命令(它們不是一般的語(yǔ)句)。Verilog HDL編譯系統(tǒng)通常先對(duì)這些特殊的命令進(jìn)行“預(yù)處理”,然后將預(yù)處理的結(jié)果和源程序一起在進(jìn)行通常的編譯處理。
在Verilog HDL語(yǔ)言中,為了和一般的語(yǔ)句相區(qū)別,這些預(yù)處理命令以符號(hào)“ `”開(kāi)頭(注意這個(gè)符號(hào)是不同于單引號(hào)“ '”的)。這些預(yù)處理命令的有效作用范圍為定義命令之后到本文件結(jié)束或到其它命令定義替代該命令之處。Verilog HDL提供了以下預(yù)編譯命令:
`accelerate,`autoexpand_vectornets,`celldefine,`default_nettype,`define,`else,`endcelldefine,`endif,`endprotect,`endprotected,`expand_vectornets,`ifdef,`include,`noaccelerate,`noexpand_vectornets , `noremove_gatenames , `noremove_netnames ,`nounconnected_drive , `protect , `protecte , `remove_gatenames , `remove_netnames ,`reset,`timescale,`unconnected_drive
在這里只對(duì)常用的`define、`include、`timescale進(jìn)行介紹,其余的請(qǐng)自行查閱資料。
宏定義 `define
用一個(gè)指定的標(biāo)識(shí)符(即名字)來(lái)代表一個(gè)字符串,它的一般形式為:
`define 標(biāo)識(shí)符(宏名) 字符串(宏內(nèi)容)
如:`define signal string
它的作用是指定用標(biāo)識(shí)符signal來(lái)代替string這個(gè)字符串,在編譯預(yù)處理時(shí),把程序中在該命令以后所有的signal都替換成string。這種方法使用戶能以一個(gè)簡(jiǎn)單的名字代替一個(gè)長(zhǎng)的字符串,也可以用一個(gè)有含義的名字來(lái)代替沒(méi)有含義的數(shù)字和符號(hào),因此把這個(gè)標(biāo)識(shí)符(名字)稱為“宏名”,在編譯預(yù)處理時(shí)將宏名替換成字符串的過(guò)程稱為“宏展開(kāi)”。`define是宏定義命令。
例1:
`define WORDSIZE 8 module reg[1:`WORDSIZE] data;//這相當(dāng)于定義 reg[1:8] data; ……
關(guān)于宏定義的八點(diǎn)說(shuō)明:
1) 宏名可以用大寫(xiě)字母表示,也可以用小寫(xiě)字母表示。建議使用大寫(xiě)字母,以與變量名相區(qū)別。
2) `define命令可以出現(xiàn)在模塊定義里面,也可以出現(xiàn)在模塊定義外面。宏名的有效范圍為定義命令之后到原文件結(jié)束。通常,`define命令寫(xiě)在模塊定義的外面,作為程序的一部分,在此程序內(nèi)有效。
3) 在引用已定義的宏名時(shí),必須在宏名的前面加上符號(hào)“`”,表示該名字是一個(gè)經(jīng)過(guò)宏定義的名字。
4) 使用宏名代替一個(gè)字符串,可以減少程序中重復(fù)書(shū)寫(xiě)某些字符串的工作量。而且記住一個(gè)宏名要比記住一個(gè)無(wú)規(guī)律的字符串容易,這樣在讀程序時(shí)能立即知道它的含義,當(dāng)需要改變某一個(gè)變量時(shí),可以只改變 `define命令行,一改全改。如例1中,先定義WORDSIZE代表常量8,這時(shí)寄存器data是一個(gè)8位的寄存器。如果需要改變寄存器的大小,只需把該命令行改為:`define WORDSIZE 16。這樣寄存器data則變?yōu)橐粋€(gè)16位的寄存器。由此可見(jiàn)使用宏定義,可以提高程序的可移植性和可讀性。
5) 宏定義是用宏名代替一個(gè)字符串,也就是作簡(jiǎn)單的置換,不作語(yǔ)法檢查。預(yù)處理時(shí)照樣代入,不管含義是否正確。只有在編譯已被宏展開(kāi)后的源程序時(shí)才報(bào)錯(cuò)。
6) 宏定義不是Verilog HDL語(yǔ)句,不必在行末加分號(hào)。如果加了分號(hào)會(huì)連分號(hào)一起進(jìn)行置換。如:
例2:
moduletest; reg a, b, c, d, e,out; `defineexpression a+b+c+d; assignout=`expression+e; ... endmodule
經(jīng)過(guò)宏展開(kāi)以后,該語(yǔ)句為:
assign out = a+b+c+d;+e;
顯然出現(xiàn)語(yǔ)法錯(cuò)誤。
7) 在進(jìn)行宏定義時(shí),可以引用已定義的宏名,可以層層置換。如:
例3:
moduletest; reg a, b, c; wireout; `defineaa a+b `definecc c+`aa assignout=`cc; endmodule
這樣經(jīng)過(guò)宏展開(kāi)以后,assign語(yǔ)句為:
assign out = c + a + b;
8) 宏名和宏內(nèi)容必須在同一行中進(jìn)行聲明。如果在宏內(nèi)容中包含有注釋行,注釋行不會(huì)作為被置換的內(nèi)容。如:
例4:
module `define typ_nand nand #5//define a nand with typical delay `typ_nandg121(q21,n10,n11); ……… endmodule
經(jīng)過(guò)宏展開(kāi)以后,該語(yǔ)句為:
nand #5 g121(q21,n10,n11);
宏內(nèi)容可以是空格,在這種情況下,宏內(nèi)容被定義為空的。當(dāng)引用這個(gè)宏名時(shí),不會(huì)有內(nèi)容被置換。
注意:組成宏內(nèi)容的字符串不能夠被以下的語(yǔ)句記號(hào)分隔開(kāi)的。
注釋行
數(shù)字
字符串
確認(rèn)符
關(guān)鍵詞
雙目和三目字符運(yùn)算符
如下面的宏定義聲明和引用是非法的。`define first_half "start of string$display(`first_half end of string");
注意在使用宏定義時(shí)要注意以下情況:
1) 對(duì)于某些 EDA軟件,在編寫(xiě)源程序時(shí),如使用和預(yù)處理命令名相同的宏名會(huì)發(fā)生沖突,因此建議不要使用和預(yù)處理命令名相同的宏名。
2) 宏名可以是普通的標(biāo)識(shí)符(變量名)。例如signal_name 和 'signal_name的意義是不同的。但是這樣容易引起混淆,建議不要這樣使用。
“文件包含”處理`include
所謂“文件包含”處理是一個(gè)源文件可以將另外一個(gè)源文件的全部?jī)?nèi)容包含進(jìn)來(lái),即將另外的文件包含到本文件之中。Verilog HDL語(yǔ)言提供了`include命令用來(lái)實(shí)現(xiàn)“文件包含”的操作。其一般形式為:如下圖1
上圖表示“文件包含”的含意。(a)為文件File1.v,它有一個(gè)`include "File2.v"命令,然后還有其它的內(nèi)容(以A表示)。(b)為另一個(gè)文件File2.v,文件的內(nèi)容以B表示。在編譯預(yù)處理時(shí),要對(duì)`include命令進(jìn)行“文件包含”預(yù)處理:將File2.v的全部?jī)?nèi)容復(fù)制插入到 `include "File2.v"命令出現(xiàn)的地方,即File2.v 被包含到File1.v中,得到(c)所示的結(jié)果。在接著往下進(jìn)行的編譯中,將“包含”以后的File1.v作為一個(gè)源文件單位進(jìn)行編譯。
“文件包含”命令是很有用的,它可以節(jié)省程序設(shè)計(jì)人員的重復(fù)勞動(dòng)??梢詫⒁恍┏S玫暮甓x命令或任務(wù)(task)組成一個(gè)文件,然后用`include命令將這些宏定義包含到自己所寫(xiě)的源文件中,相當(dāng)于工業(yè)上的標(biāo)準(zhǔn)元件拿來(lái)使用。另外在編寫(xiě)Verilog HDL源文件時(shí),一個(gè)源文件可能經(jīng)常要用到另外幾個(gè)源文件中的模塊,遇到這種情況即可用`include命令將所需模塊的源文件包含進(jìn)來(lái)。
例1:(1)文件aaa.v
moduleaaa(a,b,out); input a, b; outputout; wireout; assignout= a^b; endmodule(2)文件bbb.v
`include"aaa.v" modulebbb(c,d,e,out); input c,d,e; outputout; wire out_a; wireout; aaaaaa( .a(c), .b(d), .out(out_a) ); assignout=e&out_a; endmodule
在上面的例子中,文件bbb.v用到了文件aaa.v中的模塊aaa的實(shí)例器件,通過(guò)“文件包含”處理來(lái)調(diào)用。模塊aaa實(shí)際上是作為模塊bbb的子模塊來(lái)被調(diào)用的。在經(jīng)過(guò)編譯預(yù)處理后,文件bbb.v實(shí)際相當(dāng)于下面的程序文件bbb.v:
moduleaaa(a,b,out); input a, b; outputout; wireout; assignout= a ^ b; endmodule
modulebbb(c, d, e,out); input c, d, e; outputout; wire out_a; wireout; aaaaaa( .a(c), .b(d), .out(out_a) ); assignout= e & out_a; endmodule
關(guān)于“文件包含”處理的四點(diǎn)說(shuō)明:
1) 一個(gè)`include命令只能指定一個(gè)被包含的文件,如果要包含n個(gè)文件,要用n個(gè)`include命令。注意下面的寫(xiě)法是非法的`include"aaa.v""bbb.v"
2) `include命令可以出現(xiàn)在Verilog HDL源程序的任何地方,被包含文件名可以是相對(duì)路徑名,也可以是絕對(duì)路徑名。例如:'include"parts/count.v"
3) 可以將多個(gè)`include命令寫(xiě)在一行,在`include命令行,只可以出空格和注釋行。例如下面的寫(xiě)法是合法的。 'include "fileB" 'include "fileC" //including fileB and fileC
4) 如果文件1包含文件2,而文件2要用到文件3的內(nèi)容,則可以在文件1用兩個(gè)`include命令分別包含文件2和文件3,而且文件3應(yīng)出現(xiàn)在文件2之前。例如在下面的例子中,即在file1.v中定義:
`include"file3.v" `include"file2.v" moduletest(a,b,out); input[1:`size2] a, b; output[1:`size2]out; wire[1:`size2]out; assignout= a+b; endmodule
file2.v的內(nèi)容為:
`define size2 `size1+1 . . .
file3.v的內(nèi)容為:
`define size1 4 . . .
這樣,file1.v和file2.v都可以用到file3.v的內(nèi)容。在file2.v中不必再用 `include "file3.v"了。
5) 在一個(gè)被包含文件中又可以包含另一個(gè)被包含文件,即文件包含是可以嵌套的。例如上面的問(wèn)題也可以這樣處理,見(jiàn)下圖2、圖3。
它的作用和下圖,圖3的作用是相同的。
時(shí)間尺度 `timescale
`timescale命令用來(lái)說(shuō)明跟在該命令后的模塊的時(shí)間單位和時(shí)間精度。使用`timescale命令可以在同一個(gè)設(shè)計(jì)里包含采用了不同的時(shí)間單位的模塊。例如,一個(gè)設(shè)計(jì)中包含了兩個(gè)模塊,其中一個(gè)模塊的時(shí)間延遲單位為ns,另一個(gè)模塊的時(shí)間延遲單位為ps。EDA工具仍然可以對(duì)這個(gè)設(shè)計(jì)進(jìn)行仿真測(cè)試。
`timescale 命令的格式如下:
`timescale<時(shí)間單位>/<時(shí)間精度>
在這條命令中,時(shí)間單位參量是用來(lái)定義模塊中仿真時(shí)間和延遲時(shí)間的基準(zhǔn)單位的。時(shí)間精度參量是用來(lái)聲明該模塊的仿真時(shí)間的精確程度的,該參量被用來(lái)對(duì)延遲時(shí)間值進(jìn)行取整操作(仿真前),因此該參量又可以被稱為取整精度。如果在同一個(gè)程序設(shè)計(jì)里,存在多個(gè)`timescale命令,則用最小的時(shí)間精度值來(lái)決定仿真的時(shí)間單位。另外時(shí)間精度至少要和時(shí)間單位一樣精確,時(shí)間精度值不能大于時(shí)間單位值。
在`timescale命令中,用于說(shuō)明時(shí)間單位和時(shí)間精度參量值的數(shù)字必須是整數(shù),其有效數(shù)字為1、10、100,單位為秒(s)、毫秒(ms)、微秒(us)、納秒(ns)、皮秒(ps)、毫皮秒(fs)。這幾種單位的意義說(shuō)明見(jiàn)下表。
下面舉例說(shuō)明`timescale命令的用法。
[例1]: `timescale 1ns/1ps
在這個(gè)命令之后,模塊中所有的時(shí)間值都表示是1ns的整數(shù)倍。這是因?yàn)樵赻timescale命令中,定義了時(shí)間單位是1ns。模塊中的延遲時(shí)間可表達(dá)為帶三位小數(shù)的實(shí)型數(shù),因?yàn)?`timescale命令定義時(shí)間精度為1ps.
[例2]:`timescale 10us/100ns
在這個(gè)例子中,`timescale命令定義后,模塊中時(shí)間值均為10us的整數(shù)倍。因?yàn)閌timesacle 命令定義的時(shí)間單位是10us。延遲時(shí)間的最小分辨度為十分之一微秒(100ns),即延遲時(shí)間可表達(dá)為帶一位小數(shù)的實(shí)型數(shù)。
例3:
`timescale10ns/1ns moduletest; regset; parameterd=1.55; initial begin #dset=0; #dset=1; end endmodule
在這個(gè)例子中,`timescale命令定義了模塊test的時(shí)間單位為10ns、時(shí)間精度為1ns。因此在模塊test中,所有的時(shí)間值應(yīng)為10ns的整數(shù)倍,且以1ns為時(shí)間精度。這樣經(jīng)過(guò)取整操作,存在參數(shù)d中的延遲時(shí)間實(shí)際是16ns(即1.6×10ns),這意味著在仿真時(shí)刻為16ns時(shí)寄存器set被賦值0,在仿真時(shí)刻為32ns時(shí)寄存器set被賦值1。仿真時(shí)刻值是按照以下的步驟來(lái)計(jì)算的。
1) 根據(jù)時(shí)間精度,參數(shù)d值被從1.55取整為1.6。
2) 因?yàn)闀r(shí)間單位是10ns,時(shí)間精度是1ns,所以延遲時(shí)間#d作為 時(shí)間單位的整數(shù)倍為16ns。
3) EDA工具預(yù)定在仿真時(shí)刻為16ns的時(shí)候給寄存器set賦值0 (即語(yǔ)句 #d set=0;執(zhí)行時(shí)刻),在仿真時(shí)刻為32ns的時(shí)候給 寄存器set賦值1(即語(yǔ)句 #d set=1;執(zhí)行時(shí)刻),
注意:如果在同一個(gè)設(shè)計(jì)里,多個(gè)模塊中用到的時(shí)間單位不同,需要用到以下的時(shí)間結(jié)構(gòu)。
1) 用`timescale命令來(lái)聲明本模塊中所用到的時(shí)間單位和時(shí)間精度。
2) 用系統(tǒng)任務(wù)$printtimescale來(lái)輸出顯示一個(gè)模塊的時(shí)間單位和時(shí)間精度。
3) 用系統(tǒng)函數(shù)$time和$realtime及%t格式聲明來(lái)輸出顯示EDA工具記錄的時(shí)間信息。
條件編譯命令`ifdef、`else、`endif
一般情況下,Verilog HDL源程序中所有的行都將參加編譯。但是有時(shí)希望對(duì)其中的一部分內(nèi)容只有在滿足條件才進(jìn)行編譯,也就是對(duì)一部分內(nèi)容指定編譯的條件,這就是“條件編譯”。有時(shí),希望當(dāng)滿足條件時(shí)對(duì)一組語(yǔ)句進(jìn)行編譯,而當(dāng)條件不滿足時(shí)則編譯另一部分。
條件編譯命令有以下幾種形式:
1)
`ifdef 宏名 (標(biāo)識(shí)符) 程序段1
`else
程序段2
`endif
它的作用是當(dāng)宏名已經(jīng)被定義過(guò)(用`define命令定義),則對(duì)程序段1進(jìn)行編譯,程序段2將被忽略;否則編譯程序段2,程序段1被忽略。其中`else部分可以沒(méi)有,即: 2)
`ifdef 宏名 (標(biāo)識(shí)符)
程序段1
`endif
這里的 “宏名” 是一個(gè)Verilog HDL的標(biāo)識(shí)符,“程序段”可以是Verilog HDL語(yǔ)句組,也可以是命令行。這些命令可以出現(xiàn)在源程序的任何地方。
注意:被忽略掉不進(jìn)行編譯的程序段部分也要符合Verilog HDL程序的語(yǔ)法規(guī)則。
通常在Verilog HDL程序中用到`ifdef、`else、`endif編譯命令的情況有以下幾種:
? 選擇一個(gè)模塊的不同代表部分。
? 選擇不同的時(shí)序或結(jié)構(gòu)信息。
? 對(duì)不同的EDA工具,選擇不同的激勵(lì)。
總結(jié)
Verilog HDL的語(yǔ)法與C語(yǔ)言的語(yǔ)法有許多類似的地方,但也有許多不同的地方。我們學(xué)習(xí)Verilog HDL語(yǔ)法要善于找到不同點(diǎn),著重理解如:阻塞〔Blocking〕和非阻塞〔Non-Blocking〕賦值的不同;順序塊和并行塊的不同;塊與塊之間的并行執(zhí)行的概念;task和function的概念。Verilog HDL還有許多系統(tǒng)函數(shù)和任務(wù)也是C語(yǔ)言中沒(méi)有的如:$monitor、$readmemb、$stop等等,而這些系統(tǒng)任務(wù)在調(diào)試模塊的設(shè)計(jì)中是非常有用的,我們只有通過(guò)閱讀大量的Verilog調(diào)試模塊實(shí)例,經(jīng)過(guò)長(zhǎng)期的實(shí)踐,經(jīng)常查閱理論知識(shí)才能逐步掌握。
Day 5 就到這里,到這里,經(jīng)過(guò)五天的Verilog HDL基礎(chǔ)語(yǔ)法的學(xué)習(xí),基本語(yǔ)法差不多都在這里了,從Day 6 繼續(xù)開(kāi)始,最后兩天將推出思考題(附參考答案),大俠可以自行思考,檢測(cè)一下自己這一周的語(yǔ)法學(xué)習(xí)效果,大俠保重,告辭。
-
FPGA
+關(guān)注
關(guān)注
1642文章
21918瀏覽量
611981 -
Verilog
+關(guān)注
關(guān)注
28文章
1364瀏覽量
111463 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7628瀏覽量
139695 -
HDL語(yǔ)言
+關(guān)注
關(guān)注
0文章
48瀏覽量
9065
原文標(biāo)題:一周掌握FPGA Verilog HDL語(yǔ)法 day 5
文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
深入理解FPGA Verilog HDL語(yǔ)法(一)
深入理解FPGA Verilog HDL語(yǔ)法(二)
[下載]cpld\fpga\verilog hdl視頻教程
FPGA-Verilog HDL語(yǔ)法參考
FPGA雙沿發(fā)送之Verilog HDL實(shí)現(xiàn) 精選資料推薦
FPGA雙沿采樣之Verilog HDL實(shí)現(xiàn) 精選資料分享
Verilog_HDL的基本語(yǔ)法詳解(夏宇聞版)

評(píng)論