《Xilinx FPGACPLD設計初級教程》課件第3章_第1頁
《Xilinx FPGACPLD設計初級教程》課件第3章_第2頁
《Xilinx FPGACPLD設計初級教程》課件第3章_第3頁
《Xilinx FPGACPLD設計初級教程》課件第3章_第4頁
《Xilinx FPGACPLD設計初級教程》課件第3章_第5頁
已閱讀5頁,還剩151頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第3章VerilogHDL語言基礎知識3.1VerilogHDL簡介

3.2VerilogHDL模塊的基本結構

3.3VerilogHDL語言規(guī)范3.4VerilogHDL語言中的常量和變量3.5VerilogHDL語言中的運算符3.6VerilogHDL語言中的塊語句和賦值語句3.7過程語句3.8條件語句3.9循環(huán)語句3.10task和function說明語句3.11系統任務和函數3.12編譯預處理

習題3

3.1VerilogHDL簡介

3.1.1硬件描述語言HDL

硬件描述語言(HardwareDescriptionLanguage,HDL)是一種用文本形式描述數字電路和設計數字邏輯系統的語言。數字邏輯電路設計者可利用這種語言來描述硬件電路的思想,然后利用電子設計自動化(ElectronicDesignAutomation,EDA)工具進行仿真,再自動綜合到門級電路,用ASIC或FPGA實現其功能。目前,這種稱之為高層次設計(HighLevelDesign)的方法已被廣泛采用。硬件描述語言的發(fā)展至今已有20多年的歷史,并成功應用于設計的各個階段(仿真、驗證、綜合等)。到20世紀80年代,已出現了上百種硬件描述語言,它們對設計自動化起到了極大的促進和推動作用。但是,這些語言一般各自面向特定的設計領域與層次,而且眾多的語言使用戶無所適從,因此急需一種面向設計的多領域、多層次且得到普遍認同的標準硬件描述語言。進入20世紀80年代后期,硬件描述語言向著標準化的方向發(fā)展。最終,VHDL和VerilogHDL語言適應了這種趨勢的要求,先后成為IEEE標準。3.1.2VerilogHDL的歷史

VerilogHDL是在1983年,由GDA(GatewayDesignAutomation)公司的PhilMoorby為模擬器產品開發(fā)而首創(chuàng)的硬件建模語言。PhilMoorby后來成為Verilog-XL的主要設計者和Cadence公司的第一個合伙人。在1984~1985年,Moorby設計出了第一個關于Verilog-XL的仿真器,1986年,他提出了用于快速門級仿真的XL算法,這是他在VerilogHDL的發(fā)展史上做出的又一巨大貢獻。隨著Verilog-XL算法的成功,VerilogHDL語言得到了迅速發(fā)展。1989年,Cadence公司收購了GDA公司,VerilogHDL語言成為Cadence公司的私有財產。1990年,Cadence公司決定公開VerilogHDL語言,于是成立了OVI(OpenVerilogInternational)組織來負責VerilogHDL語言的發(fā)展。基于VerilogHDL的優(yōu)越性,IEEE于1995年制定了VerilogHDL的IEEE標準,稱為IEEEStandard1364-1995。3.1.3VerilogHDL語言與C語言的比較

VerilogHDL作為一種高級的硬件描述編程語言,具有類似于C語言的風格。其中的許多語句(如if語句、case語句等)和C語言中的對應語句十分相似。表3.1中列舉了兩種語言中一些相同或相似的關鍵字,表3.2中對比了這兩種語言的運算符。由此可看出,如果讀者已經掌握C語言編程的基礎,那么學習VerilogHDL并不困難,我們只要對VerilogHDL某些語句的特殊方面著重理解,并加強上機練習就能很好地掌握它,就能利用它的強大功能來設計復雜的數字邏輯電路。表3.1C語言與VerilogHDL語言相對應的關鍵字比較表3.2C語言與VerilogHDL語言相對應的運算符比較值得注意的是,VerilogHDL語言與C語言的最大不同在于,C程序是順序執(zhí)行語句,VerilogHDL程序是并行執(zhí)行語句,即用C語言寫出的代碼是一行接一行依次執(zhí)行的,而用VerilogHDL語言寫出的代碼是在同一時間同時運行的。 3.2VerilogHDL模塊的基本結構

VerilogHDL程序的基本設計單元是“模塊”(module)。一個模塊又由幾個部分組成。為了清晰地說明模塊的構成,下面舉例說明如何用VerilogHDL語言描述一個簡單的與門邏輯單元結構。其與門邏輯單元如圖3.1所示。圖3.1與門邏輯單元上述程序中,第一行定義了模塊的端口,聲明了模塊的輸入/輸出口;第二行利用input關鍵字定義a、b為輸入端口;第三行利用output關鍵字定義c為輸出端口;第四行定義了端口的數據類型;第五行則描述了模塊實現的功能,描述完成后用endmodule關鍵字完成這個模塊的設計。上述程序的第五行也可寫成“andA1(c,a,b)”,其中,A1為與門邏輯單元定義的名字。在VerilogHDL語言中一些基本的邏輯門和開關級結構模型都內置在其中,在程序設計中可直接使用。這種描述電路的方式叫做門級結構描述,此方式將在第4章中詳細介紹。通過上面的例子可以看出,VerilogHDL的模塊設計是通過module和endmodule聲明語句實現的。每個VerilogHDL程序包括4個主要部分:模塊聲明、I/O說明、信號類型說明和邏輯功能描述。

1.模塊聲明

模塊的端口聲明了模塊的輸入/輸出口。其格式如下:

module 模塊名(口1,口2,口3,口4,…);

模塊結束的關鍵字為:endmodule。

2.?I/O說明

對模塊的輸入/輸出端口說明有如下三種格式:

(1)輸入口:

input端口名1,端口名2,…,端口名N; //(共有N個輸入口)

(2)輸出口:

output端口名1,端口名2,…,端口名N; //(共有N個輸出口)

(3)輸入/輸出口:

inout端口名1,端口名2,…,端口名N; //(共有N個輸入/輸出口)

I/O說明也可以寫在端口聲明語句中。其格式如下:

modulemodule_name(inputport1,inputport2,…,outputport1,outputport2,…,inoutport1,inoutport2,...);

3.信號類型說明

VerilogHDL語言提供了各種信號類型,它們代表數字電路中的各種物理連接和物理實體。在模塊中所有用到的信號都必須進行數據類型的定義。如果類型沒有定義,則綜合器將其默認為wire型數據類型。

下面為定義信號數據類型的幾個例子。

wireA,B,C;

//定義信號A、B、C的數據類型為wire連線型

reg[3:0]counter; //定義信號counter的數據類型為4位reg型

4.邏輯功能描述

邏輯功能描述是模塊中最重要的部分。對電路的邏輯描述有多種方法,除了下面工程中常用的三種方法外,還可以調用用戶自定義函數(function)和任務(task)等來描述邏輯電路。

1)用“assign”聲明語句

例如:

assignf=(~a&c);

“assign”語句一般給wire型數據信號賦值。這種方法的句法很簡單,只需寫一個“assign”,后面再加一個邏輯方程式即可。

2)用元件例化

例如:

nandnand2_inst(c,a,b);

上述語句表示在設計中用到一個同與非門(nand)一樣的名為nand2_inst的與門,其輸入端為a、b,輸出端為c。要求每個實例元件的名字必須是唯一的,以避免與其他調用與非門(nand)的實例混淆。采用元件例化的方法就如同在C語言下調用庫函數一樣。用VerilogHDL語言進行數字電路設計時有兩種元件例化的方式:一種是例化VerilogHDL語言中本身內置的基本邏輯門和開關級結構模型;另一種是通過支持VerilogHDL語言的數字電路設計軟件例化自帶的擴充系列元件庫。比如,在本書第6章提到的DCM(數字時鐘管理器)就是ISE中自帶的元件庫,而在其他公司的設計軟件中將不會有此DCM元件庫。用“always”塊既可用于描述組合邏輯,又可描述時序邏輯。上面的例子用“always”塊生成了一個2選1的多路選擇器,這是一種行為描述方式?!癮lways”塊可用很多種語法來表達邏輯,例如上例中就用了if...else語句來表達邏輯關系。不管設計者用哪種語法表達邏輯關系,最終綜合工具會把源代碼自動綜合成相對應的器件邏輯構造方式。例如,對于CPLD器件,綜合工具將生成相對應的門級結構來表示組合或時序的邏輯電路;對于FPGA器件,綜合工具將生成相對應的LUT(查表)法來表示組合或時序的邏輯電路。上面三個例子分別采用“assign”語句、元件例化和“always”塊來描述邏輯功能。這三個例子描述的邏輯功能是同時執(zhí)行的。也就是說,如果把這三項寫到一個Verilog模塊文件中,則它們的次序不會影響邏輯實現的功能。這就是前面提到的VerilogHDL語言與C語言的不同。此外,VerilogHDL程序是并行執(zhí)行語句,C程序是順序執(zhí)行語句。然而,在“always”模塊內,邏輯是按照指定的順序執(zhí)行的,這對于初學者來說很不容易理解。難道這個說法是錯誤的嗎?其實VerilogHDL語言定義了一個串行塊(begin-end)語法,在begin-end串行塊中的語句是按照串行方式順序執(zhí)行的,定義這個串行塊語法很重要,因為大多數邏輯都存在因果關系。但請注意,兩個或更多的“always”模塊也是同時執(zhí)行的,但是模塊內部的語句是順序執(zhí)行的。這個VerilogHDL語法現象很重要,初學者需要重點理解。

3.3VerilogHDL語言規(guī)范

VerilogHDL語言和其他語言一樣,也有自己的語言規(guī)范。下面介紹一些基本的語言規(guī)范。

1.空白符

在VerilogHDL程序代碼中,空白符包括空格、tab、換行和換頁。使用空白符是為了使程序閱讀起來更方便,在綜合時空白符被忽略。

2.注釋

注釋是為了使閱讀者更容易理解程序,在綜合時也將被忽略。在VerilogHDL程序代碼中有兩種注釋方式。

(1)單行注釋:以“//”開始到本行結束,不允許續(xù)行,如上例中的“//”注釋。

(2)多行注釋:以“/*”開始,到“*/”結束。

3.標志符

VerilogHDL中的標志符可以是字母、數字以及符號“$”和“_”(下劃線)的任意組合,但標志符的第一個字符必須以字母或者下劃線開頭。另外,標志符還可以用“\”開頭,以空白符結尾,但反斜線和空白符在綜合時將被忽略。標志符是區(qū)分大小寫的。以下是幾個合法標志符的舉例。

_nand2_inst//以下劃線開頭的標志符

counter//以字母開頭的標志符

\full_add1//“\”將被忽略,等同于full_add1標志符

COUNTER//COUNTER與counter是不同的標志符

以下是幾個非法標志符的舉例。

50counter//非法,標志符不允許以數字開頭

cnt# //非法,標志符中不允許包含字符#

4.關鍵字

VerilogHDL語言中的關鍵字是區(qū)分大小寫的。例如,把關鍵字“always”寫成“ALWAYS”是錯誤的,這樣“ALWAYS”就變成了標志符。

3.4VerilogHDL語言中的常量和變量

3.4.1常量

在程序運行過程中,其值不能被改變的量稱為常量。VerilogHDL中的常量主要包括3種類型:整數型、實數型和字符串型。下劃線符號“_”可以隨意用在整數或實數中,它在綜合時將被忽略,其作用是提高易讀性。但要注意的是,下劃線符號在常量中不能作為首字符來用。

VerilogHDL有下列4種基本的值。

(1)?0:低電平、邏輯0或“假”。

(2)?1:高電平、邏輯1或“真”。

(3)?x或X:未知的邏輯狀態(tài)。

(4)?z或Z:高阻態(tài)。這4種值的含義都內置于語言中。例如一個為0的值,綜合工具會根據語句的環(huán)境自動判斷出是表示邏輯還是條件。另外,VerilogHDL語言中并不是只有值1表示條件為真,除0以外所有確定的數值都表示條件為真。在門的輸入或一個表達式中為“z”的值通常理解成“x”。此外,x值和z值都是不區(qū)分大小寫的。也就是說,值Ox3z與值OX3Z是相同的。VerilogHDL中的常量是由以上四類基本值組成的。

1.整數型

在VerilogHDL中,定義整數型常量的方式如下:

+/-<位寬>'<進制><數字>“+/-”定義整數的正負。整數為正數時,“+”可忽略不寫;整數為負數時,“-”應寫在數字定義表達式的最前面。注意:負號不可以放在位寬和進制之間,也不可以放在進制和具體的數之間。

位寬為整數對應的二進制寬度,它的單位為bit。

進制用來定義整數的類型,它有以下4種表示形式:

(1)二進制整數(b或B);

(2)十進制整數(d、D或缺省);

(3)十六進制整數(h或H);

(4)八進制整數(o或O)。

數字是基于進制的數字序列。另外,十六進制中的a~f是不區(qū)分大小寫的。以下是一些合法的整數表達式的舉例:

8'b10101111 //位寬為8位的二進制數

8'hF2 //位寬為8位的十六進制數

6'o71 //位寬為6位的八進制數

4'd8 //位寬為4位的十進制數

以下是一些非法的整數表達式的舉例:

4'd-9 //非法,負號應該放在最左邊,即?-4'd9

(5+3)'b11001011 //非法,位寬不能為表達式在定義整數表達式時還應注意以下幾點:

(1)當數字不說明位寬時,數字的位寬采用缺省位寬(這由具體的機器系統決定,但至少為32位)。如果一個整數的位寬沒有定義,則其寬度為相應值中定義的位數。

例如:

hf2 //至少32位十六進制數

'b101 //3位二進制數

'o566 //3位八進制數

(2)在默認位寬與進制情況下,整數就代表十進制的數。

例如:

76 //表示十進制數76

-35 //表示十進制數-35

(3)?x(或z)在二進制中代表1位x(或z),在八進制中代表3位x(或z),在十六進制中代表4位x(或z)。

例如:

6'bxxx010 //等同于6'ox2

8'b1001zzzz //等同于8'h9z

(4)如果定義的位寬比實際的位數長,則通常在數字左邊填0補位。對于數字左邊一位是x或z的情況,就要用相對應的x或z來補位。

例如:

8'b11 //等同于8'b00000011

8'bx01z //等同于8'bxxxxx01z

如果定義的位寬比實際的位數小,那么最左邊多余的位將被忽略。

例如:

4'b1101_1100 //等同于4'b1100

(5)?“?”是高阻態(tài)z的另一種表達符號,二者是等價的。另外,在使用case表達式時建議使用這種寫法,以提高程序的可讀性。

例如:

12'dz //位寬為12位的十進制數,其值為高阻值

12'd? //等同于12'dz

(6)下劃線可以用來分隔數字,以提高程序可讀性。但不可以用在位寬和進制處,只能用在具體的數字之間。

例如:

16'b1010_1011_1111_1010 //合法格式

8'b_0011_1010 //非法格式

(7)在定義整數型常量的方式中,位寬和“'”之間以及進制和數值之間允許出現空格,但在“'”和進制之間以及數值之中是不允許出現空格的。

例如:

8'b1011_1010 //合法格式

8'b1011_1011 //非法格式

2.實數型

實數型數據可用以下兩種形式定義:

(1)十進制計數法,規(guī)定此方法的小數點兩側必須有數字,如5.0、6.728、-0.1、6。

(2)科學計數法,如35_1.2e2(其值為35120.0)、2.6E-3(其值為0.0026)。

VerilogHDL語言中的實數型數據可轉化為整數型數據,其轉化方法采用數學中的四舍五入法則。

3.字符串型

字符串是雙引號內的字符序列。字符串不能分成多行書寫。另外,字符串中一個字母為8位ASCII值,存儲一串字符串的位空間大小需用字符串中的個數乘以8來計算。字符串中的空格也算一個字符。例如:

"VerilogHDL" //定義字符串

...

reg[11*8:1]Message; //申請存儲空間

Message="VerilogHDL"

字符串中的特殊字符需用“\”來說明,如

\n //換行符

\t //Tab鍵

\\ //字符“\”本身

\" //雙引號"

\206 //八進制數206對應的ASCII值3.4.2符號常量

在VerilogHDL語言中,可用parameter來定義常量,即用parameter定義一個標識符來代表一個常量,此常量稱為符號常量。采用標識符代表一個常量可提高程序的可讀性和可維護性。parameter型數據是一種常量型數據,其說明格式如下:

parameter 參數名1?=?表達式,參數名2?=?表達式,…,參數名n?=?表達式:例如:

parameterdatawidth=8;//定義參數datawidth為常量8

parametere=25,f=29; //定義兩個常數參數

parameterr=5.7; //聲明r為一個實型參數

parameterbyte_size=8,byte_msb=byte_size-1; //用常數表達式賦值

利用parameter型數據可方便地在層次模塊間改變參數。下面用一個例子進行示范。引用acreage實例時,d1、d2的width將采用不同的值2和5,且d1的height為5,即用#(2,5)向d1中傳遞width=2,height=5,用#(5)向d2中傳遞width=5,height仍為1。

3.4.3變量

變量是指在程序運行過程中可以任意改變的量。VerilogHDL語言中變量有以下兩種定義類型。

(1)線網類型(net):表示VerilogHDL結構化元件間的物理連線,它的值由驅動元件的值決定,例如連續(xù)賦值或門的輸出。線網的缺省值為z(高阻態(tài))。

(2)寄存器類型(register):表示一個抽象的數據存儲單元,它只能在always語句和initial語句中被賦值。寄存器的缺省值為x(未知狀態(tài))。

net數據類型包括wire、tri、wor、trior、wand、triand、trieg、tri0、tri1、supply0和supply1。register數據類型包括reg、integer、real和time。線網類型中的wire類型和寄存器類型中的reg類型是在工程中經常用到的兩種類型,其他的幾乎不用。因此下面我們將詳細介紹這兩種類型。

1.?wire型變量

wire型數據常用來表示用assign關鍵字指定的組合邏輯信號。VerilogHDL程序模塊中輸入/輸出信號類型缺省時自動定義為wire型。wire型信號可以用作任何方程式的輸入,也可以用作“assign”語句或實例元件的輸出。

wire型變量的定義格式如下:

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

wire是wire型數據的確認符,[n-1:0]代表該數據的位寬,數據名用來定義變量的名字。如果一次定義多個數據,則數據名之間用逗號隔開。聲明語句的最后要用分號表示語句結束。例如:

wirea; //定義了一個1位的名為a的wire型數據變量

wire[7:0]b; //定義了一個8位的名為b的wire型數據變量

wire[8:1]c; //定義了一個8位的名為c的wire型數據變量

wire[9:2]d; //定義了一個8位的名為d的wire型數據變量

2.?reg型變量

reg型數據常用在“always”和“initial”過程塊中,reg型數據的缺省初始值是不定值。reg型數據可以賦正值,也可以賦負值。但當一個reg型數據是一個表達式中的操作數時,它的值被當作無符號值,即正值。例如,當一個四位的寄存器用作表達式中的操作數時,如果開始寄存器被賦以值-1,則在表達式中進行運算時,其值被認為是+15。

reg型變量的定義格式與wire類似,如下所示:

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

reg是reg型數據的確認標識符,[n-1:0]代表該數據的位寬,數據名用來定義變量的名字。如果一次定義多個數據,則數據名之間用逗號隔開。聲明語句的最后要用分號表示語句結束。

例如:

rega; //定義了一個1位的名為a的reg型數據變量

reg[3:0]b; //定義了一個4位的名為b的reg型數據變量

reg[4:1]c,d; //定義了兩個4位的名為c、d的reg型數據變量在VerilogHDL語言中,用reg類型變量可構成寄存器和存儲器,其中,存儲器也被稱為數組。它們的定義格式如下:

reg[n-1:0]數據名1,數據名2,…; //定義寄存器

reg[n-1:0]數據名1[i-1:0],數據名2[j-1:0],…; //定義存儲器例如:

regmybit; //定義一個名為mybit的1位寄存器

reg[7:0]mybyte; //定義一個名為mybyte的8位寄存器

regmyarray[3:0]; //定義四個名為myarray的1位存儲器

reg[7:0]memory[11:0]; //定義一個名為memory的行為12位、列為8位的數組雖然寄存器和存儲器的定義格式很相似,但它們的讀/寫操作也有不同之處。一個由n個1位寄存器構成的存儲器組是不同于一個n位寄存器的。例如:

reg[n-1:0]rega; //一個n位寄存器

regmema[n-1:0]; //一個由n個1位寄存器構成的存儲器組

一個n位寄存器可以在一條賦值語句中進行賦值,而一個完整的存儲器則不行。

例如:

rega=?0; //合法賦值語句

mema=?0; //非法賦值語句如果想對memory中的存儲單元進行讀/寫操作,則必須指定該單元在存儲器中的地址。例如,下面的寫法是正確的。

mema[3]=0; //給memory中的第3個存儲單元賦值為0

注意:如果要對變量重新賦值,那么此變量就只能出現在一個過程語句中。 3.5VerilogHDL語言中的運算符

VerilogHDL語言的運算符范圍很廣,按其功能大致可分為以下幾類:

(1)算術運算符(+、-、*、/、%);

(2)位運算符(~、&、|、^、^~、~^);

(3)邏輯運算符(&&、||、!);

(4)關系運算符(>、<、>=、<=);

(5)等式運算符(==、!=、===、!==);

(6)移位運算符(<<、>>);

(7)條件運算符(?:);

(8)拼接運算符({?});

(9)縮減運算符(&、~&、|、~|、^、~^、^~)。

上述運算符在使用時同C語言的運算符一樣,也有優(yōu)先級別。表3.3是對各種運算符的優(yōu)先級的說明。不過建議在書寫程序時用括號(?)來控制運算符的優(yōu)先級,這樣可增加程序的可讀性,避免出錯。表3.3運算符的優(yōu)先級別在VerilogHDL語言中運算符所帶的操作數是不同的,按其所帶操作數的個數運算符可分為以下三種:

(1)單目運算符:可以帶一個操作數,操作數放在運算符的右邊。

(2)雙目運算符:可以帶兩個操作數,操作數放在運算符的兩邊。

(3)三目運算符:可以帶三個操作,這三個操作數用三目運算符分隔開。例如:

clk=~clk; //“~”是一個單目取反運算符,clk是操作數

c=a|b; //“|”是一個雙目按位或運算符,a和b是操作數

r=s?a:b; //“?:”是一個三目條件運算符,s、a和b是操作數

下面按功能分類對運算符的使用進行介紹。3.5.1算術運算符

在VerilogHDL語言中,常用的算術運算符包括以下5種:

(1)?+:加法運算符;

(2)?-:減法運算符;

(3)?*:乘法運算符;

(4)?/:?除法運算符;

(5)?%:求模運算符,或稱為求余運算符,如7%3的值為1。

注意:在進行算術運算操作時,如果某一個操作數有不確定的值x,則整個結果也為不定值x。3.5.2位運算符

VerilogHDL語言中位運算符包括:

(1)?~:按位取反;

(2)?&:按位與;

(3)?|:按位或;

(4)?^:按位異或;

(5)?^~?或?~^:按位同或(異或非)。

下面對各運算符分別進行介紹。

1.按位取反運算符

按位取反是一個單目運算符,用來對一個操作數進行按位取反運算,其運算規(guī)則如表3.4所示。表3.4按位取反的真值表

2.按位與運算符

按位與運算就是將兩個操作數的相應位進行與運算,其運算規(guī)則如表3.5所示。表3.5按位與的真值表

3.按位或運算符

按位或運算就是將兩個操作數的相應位進行或運算,其運算規(guī)則如表3.6所示。表3.6按位或的真值表

4.按位異或運算符

按位異或運算就是將兩個操作數的相應位進行異或運算,其運算規(guī)則如表3.7所示。表3.7按位異或的真值表

5.按位同或運算符

按位同或運算就是將兩個操作數的相應位先進行異或運算再進行非運算,其運算規(guī)則如表3.8所示。表3.8按位同或的真值表注意:兩個長度不同的數據進行位運算時,系統會自動使兩者遵守右端對齊原則。位數少的操作數會在相應的高位用0填滿,以使兩個操作數按位進行操作。

例如,A=5'b10101,B=2'b11,則有:

~A=5'b01010;

A&B=5'b00001;

A|B=5'b10111;

A^B=5'b10110;

A^~B=5'b01001。3.5.3邏輯運算符

VerilogHDL語言中邏輯運算符包括:

(1)?&&:邏輯與;

(2)?||:邏輯或;

(3)?!:邏輯非;

“&&”和“||”是雙目運算符,“!”是單目運算符。表3.9為邏輯運算符的真值表。表中的“真”表示操作數位中有邏輯1出現,即位中的邏輯不全為0;“假”則表示操作數位中的邏輯全為0。表3.9邏輯運算符的真值表例如:若A=1,B=0,C=4'b1001,D=4'b0000,則有:

!A=0;!B=1;A&&B=0;A||B=1;

!C=0;!D=1;C&&D=0;C||D=1;3.5.4關系運算符

VerilogHDL語言中關系運算符包括:

(1)?<:小于;

(2)?>:大于;

(3)?<=:小于或等于;

(4)?>=:大于或等于。

注:“<=”操作符可作為賦值符號,這將在3.6節(jié)中詳細講解。

關系運算符是雙目運算符。在進行關系運算時,如果兩個操作數比較的結果是假,則返回值是0;如果比較的結果是真,則返回值是1;如果某個操作數的值不定,則關系是模糊的,返回值是不確定值。3.5.5等式運算符

VerilogHDL語言中等式運算符包括:

(1)?==:等于;

(2)?!=:不等于;

(3)?===:全等;

(4)?!==:不全等。這四種運算符都是雙目運算符,其結果由兩個操作數的值決定。但“==”和“!=”運算符會比“===”和“!==”運算符多出一個比較結果——不定值(x)。這是因為操作數中某些位可能是不定值x和高阻值z。用“==”和“!=”運算符進行比較時,結果可能為不定值x;“===”和“!==”運算符則不同,它們在對操作數進行比較時對某些位的不定值x和高阻值z也進行比較,兩個操作數必須完全一致,其比較結果只有1或0。“===”和“!==”運算符常用于case表達式的判別,所以又稱為“case等式運算符”。這四個等式運算符的優(yōu)先級別是相同的。表3.10列出了“==”和“===”運算符的真值表?!?=”和“!==”運算符的真值表類似,讀者可自行推導出來。表3.10相等運算符(==)和全等運算符(===)的真值表下面舉例說明“==”和“===”的區(qū)別。例如:

if(A==1'bx)beginend;(當A等于x時,這個語句不執(zhí)行)

if(A===1'bx)beginend;(當A等于x時,這個語句執(zhí)行)3.5.6移位運算符

在VerilogHDL中有以下兩種移位運算符:

(1)?>>:右移;

(2)?<<:左移。

其使用方法如下:

a>>n或a<<n

a代表要進行移位的操作數,n代表要移幾位。這兩種移位運算都用0來填補移出的空位。例如:

start=1; //start在初始時刻的值設為0001

result=(start<<2); //移位后,start的值為0100,然后賦給result從上面的例子中可以看出,start在移過兩位以后,用0來填補空出的位。

進行移位運算時應注意移位前后變量的位數,例如:

4'b1001<<1=5'b10010;

4'b1001<<2=6'b100100;

1<<6=32'b1000000;

4'b1001>>1=4'b0100;

4'b1001>>4=4'b0000;3.5.7條件運算符

VerilogHDL中的條件運算符為?:。

該條件運算符的定義與C語言中的定義一樣。方式如下:

信號=條件?真條件返回的表達式:假條件返回的表達式;

例如:

out=(a>=b)?a:b;

這是一個比較器語句,返回兩者(a和b)中較大的數。3.5.8位拼接運算符

VerilogHDL語言中的拼接運算符為{}。

該運算符可以把兩個或多個信號的某些位拼接起來。其使用方法如下:

{信號1的某幾位,信號2的某幾位,...,...,信號n的某幾位}

即把某些信號的某些位詳細地列出來,中間用逗號分開,最后用大括號括起來表示一個整體信號。

例如:

{a,b[6:5],c,3'b101} //等同于{a,b[6],b[5],c,1'b1,1'b0,1'b1}

{b,{3{a,b}}} //等同于{b,a,b,a,b,a,b}3.5.9縮減運算符

VerilogHDL中的縮減運算符如下:

(1)?&:與;

(2)?~&:與非;

(3)?|:或;

(4)?~|:或非;

(5)?^:異或;

(6)?~^或^~:同或??s減運算符是單目運算符,放在操作數前面。縮減運算是對單個操作數進行邏輯遞推運算,最后的運算結果是一位二進制數??s減運算的具體運算過程為:第一步將操作數的第一位與第二位進行邏輯運算,第二步將運算結果與第三位進行邏輯運算,依次類推,直至最后一位。

例如:

reg[3:0]A;

regC;

C=&A; //等同于C=((A[0]&A[1])&A[2])&A[3]

3.6VerilogHDL語言中的塊語句和賦值語句

3.6.1塊語句

在VerilogHDL程序中,塊語句是用塊標志符begin-end或fork-join來界定的一組語句,這類似于C語言中的“{?}”,通常用來將兩條或多條語句組合在一起。3.6.2賦值語句

在VerilogHDL語言中,信號有以下兩種賦值方式:

(1)?=:阻塞賦值;

(2)?<=:非阻塞賦值。

阻塞賦值和非阻塞賦值的區(qū)別是:阻塞賦值在阻塞語句結束時就立即完成賦值操作;非阻塞賦值是在整個過程塊結束時才完成賦值操作。在上例的“always”塊中采用阻塞賦值方式,定義了兩個reg型信號b和c,clk信號的上升沿到來時,a先賦值給b,然后b賦值給c(即等于a)。需要注意的是,上述兩個步驟是在同一個clk周期內執(zhí)行的,并且?guī)缀鯖]有延遲。阻塞賦值描述的電路如圖3.2所示。圖3.2阻塞賦值描述的電路如果把上例“always”塊中的阻塞賦值方式改為非阻塞賦值方式(即b<=a,c<=b),則在clk信號的上升沿到來時,a賦值給b和b賦值給c是同時進行的,即在同一個clk周期內b取a的值,同時c取b的值,但c并沒有把b更新后的值取出來,而取的是原來的b值,這樣一來,c值將總比b值延遲一個clk周期。非阻塞賦值描述的電路如圖3.3所示。圖3.3非阻塞賦值描述的電路阻塞語句和非阻塞語句是兩個非常重要的概念,在應用中應加以區(qū)別。通常,阻塞賦值用于描述組合邏輯電路,而非阻塞賦值則用于描述時序邏輯電路。

3.7過程語句

VerilogHDL語言中的一般過程模塊都從屬于以下兩種結構的說明語句。

(1)?initial說明語句;

(2)?always說明語句。

initial和always說明語句在仿真的一開始同時執(zhí)行。initial語句只執(zhí)行一次,相反,always語句則不斷地重復執(zhí)行,直到仿真過程結束。在一個模塊中,使用initial和always語句的次數是不受限制的。3.7.2always語句

always過程語句使用的模板如下:

always@(<敏感信號表達式>)

begin

//過程賦值

//if-else、case、casex、casez選擇語句

//for、while等循環(huán)塊

//task、function調用

end

always過程語句通常帶有觸發(fā)條件,觸發(fā)條件被寫在敏感信號列表中,只有當觸發(fā)條件滿足條件或發(fā)生變化時,其后的“begin-end”塊語句才能被執(zhí)行。

敏感信號可以分為兩種類型:邊沿敏感型、電平敏感型。

1.邊沿敏感型

例如:

always@(posedgeclockornegedgereset)//由兩個邊沿觸發(fā)always塊

begin

end

posedge和negedge是VerilogHDL提供的兩個關鍵字。上述敏感信號中posedgeclock表示時鐘信號clock的上升沿作為觸發(fā)條件,而negedge

reset則表示reset信號的下降沿作為觸發(fā)條件。 3.8條件語句

3.8.1if-else語句

if語句類似C語言中的if-else語句。其使用方法有以下三種:

(1)?if(表達式) 語句;

(2)?if(表達式) 語句1;

?else 語句2;

(3)?if(表達式1) 語句1;

elseif(表達式2) 語句2;

?elseif(表達式3) 語句3;

?…

elseif(表達式m) 語句m;

?else 語句n;在使用if-else語句時,應注意以下幾點:

(1)上述三種形式中,“表達式”一般為邏輯表達式或關系表達式,也可以是1位的變量。系統對表達式的值進行判斷,若為0、x、z,則按“假”處理;若為1,則按“真”處理,執(zhí)行指定的語句。

(2)在if和else后面可以包含多個操作語句,多操作語句時用begin和end這兩個關鍵詞將幾個語句包含起來成為一個復合塊語句。例如:

(3)“表達式”中允許一定形式的簡寫方式。

例如:

if(a)//等同于if(a==1)

if(!b)//等同于if(b!=1)

(4)?if語句可以嵌套使用。在if語句中包含一個或多個if語句稱為if語句的嵌套使用。一般形式如下:當敏感表達式的值為1時,執(zhí)行語句1;當值為2時,執(zhí)行語句2;依次類推。如果敏感表達式的值與上面列出的值都不符,則執(zhí)行default后面的語句。如果前面已列出了敏感表達式所有可能的取值,則default語句可以省略。

例如:

//此程序為本書實驗五中的一小段程序,它的作用是依次快速點亮EZBoard開發(fā)

//板上的四位數碼管。因人眼存在惰性現象,故誤認為四位數碼管同時處于點亮狀態(tài)

always@(posedgems2_clkornegedgesys_rst)begin在case語句中,敏感表達式與1~n間的比較是一種全等比較,必須保證兩者對應位的值全等。casez與casex語句是case語句的兩種擴展類型。在casez語句中,如果分支表達式某些位的值為高阻z,那么對這些位的值就不予比較,即此位的值相等,因此只需比較其他的位。在casex語句中,如果比較的雙方有一方的某些位的值是x或z,那么該位的值就都不予比較。case、casez和casex的比較關系如表3.11所示。表3.11case、casez和casex語句的真值表此外,可用符號“?”來表示0、1、z、x這四種值。 3.9循環(huán)語句

在VerilogHDL中提供如下四種類型的循環(huán)語句。

(1)?forever語句;

(2)?repeat語句;

(3)?while語句;

(4)?for語句。

一般綜合器只支持for循環(huán)語句,不過建議盡量少用for循環(huán)語句,因為for循環(huán)語句占用的邏輯資源大。循環(huán)語句一般用于仿真語言中。下面對各種循環(huán)語句進行詳細介紹。3.9.1forever語句

forever語句的使用格式如下:

forever 語句;

forever begin

多條語句

end

forever循環(huán)語句常用于產生周期性的波形,用來作為仿真測試信號。它與always語句的不同之處在于不能獨立寫在程序中,而必須寫在initial塊中。3.9.2repeat語句

repeat語句的使用格式如下:

repeat(循環(huán)次數表達式)語句;

repeat(循環(huán)次數表達式)???begin

多條語句

end3.9.3while語句

while語句的使用格式如下:

while(循環(huán)次數條件表達式)語句

while(循環(huán)次數條件表達式)begin

多條語句

end

下面舉一個while語句的例子,該例用while循環(huán)語句實現了一個32位整數的循環(huán)顯示。3.9.4for語句

for循環(huán)語句的一般形式如下:

for(表達式1;表達式2;表達式3)語句

for語句的執(zhí)行過程如下:

(1)先求解表達式1。

(2)求解表達式2,若其值為真(非0),則執(zhí)行for語句中指定的內嵌語句,然后執(zhí)行下面的第3步;若為假(0),則結束循環(huán),轉到第(5)步。

(3)若表達式為真,則在執(zhí)行指定的語句后,求解表達式3。

(4)轉回上面的步驟(2)繼續(xù)執(zhí)行。

(5)執(zhí)行for語句下面的語句。

3.10task和function說明語句

3.10.1task說明語句

task說明語句的格式如下:

task<任務名>;

<端口及數據類型聲明語句>

<語句1>

<語句2>

<語句n>

endtask

任務的調用格式如下:

<任務名>(端口1,端口2,...,端口n);3.10.2function說明語句

定義function函數的目的是返回一個用于表達式的值。其定義格式如下:

function<返回值的類型或范圍>(函數名);

<端口說明語句>

<變量類型說明語句>

<語句1>

<語句2>

<語句n>

endfunction

<返回值的類型或范圍>這一項是可選項,如缺省則返回值為一位寄存器類型數據。函數的定義把函數返回值所賦值寄存器的名稱初始化為與函數同名的內部變量。例如:

function[7:0]getbyte;

input[15:0]address;

begin

getbyte=address[7:0];//從地址字中提取低字節(jié)

end

endfunction

函數的調用格式如下:

<函數名>(<表達式>,<表達式>*)其中,函數名作為確認符。下面的例子通過對兩次調用函數getbyte的結果值進行位拼接運算來生成一個字。

word=control?{getbyte(msbyte),getbyte(lsbyte)}:0;

與任務相比較,函數的使用有較多的約束。下面給出的是函數的使用規(guī)則。

(1)函數的定義不能包含有任何時間控制語句,即任何用#、@或wait來標識的語句。

(2)函數不能啟動任務。

(3)定義函數時至少要有一個輸入參量。

(4)在函數的定義中必須有一條賦值語句給函數中的一個內部變量賦以函數的結果值,該內部變量具有和函數名相同的名字。

3.11系統任務和函數

VerilogHDL的系統任務和系統函數主要用于仿真。在數字電路設計中,仿真是一個重要的環(huán)節(jié),它可以檢查電路邏輯設計的準確性。一個復雜的邏輯電路被VerilogHDL語言描述后,綜合器綜合出來的只是一個個模塊的組合。如果中間的哪個模塊描述錯誤,則此時不借助仿真器來查看內部信號,要查出錯誤是相當困難的。

仿真可分為前仿真和后仿真。在設計輸入階段進行的仿真不考慮信號的時延等因素,稱為功能仿真,即前仿真;后仿真又稱時序仿真,它是指在選擇了具體器件并完成了布局布線后進行的含電路實際關系的仿真。

VerilogHDL語言中有以下系統函數和任務:

$bitstoreal、$rtoi、$display、$setup、$finish、$skew、$hold、$setuphold、$itor、$strobe、$period、$time、$printtimescale、$timefoemat、$realtime、$width、$realtobits、$write、$recovery。

在VerilogHDL語言中,每個系統函數和任務前面都用一個標識符?$?來加以確認。這些系統函數和任務提供了非常強大的功能。下面對一些常用的系統函數和任務逐一進行介紹。3.11.1系統任務$display和$write

$display和$write的格式如下:

$display("格式控制符",輸出變量列表);

$display("字符串");

$write("格式控制符",輸出變量列表);

$write("字符串");

$display和?$write是兩個系統任務,兩者的功能都類似于C語言中的printf函數,都用于顯示結果信息。其區(qū)別是$display在執(zhí)行完整個函數后能自動進行換行,而?$write不能。如果想在一行里輸出多個信息,則可以使用?$write。在?$display和?$write中,定義信號的輸出格式控制符如表3.12所示。表3.12格?式?控?制?符有時輸出的信號需要用空格隔開,如用“\t”字符,表示一個Tab鍵。這種字符在VerilogHDL語言中叫做轉義字符。表3.13中列舉了幾種常用的轉義字符。表3.13轉義字符如果輸出列表中表達式的值包含有不確定的值或高阻值,則其輸出結果遵循以下規(guī)則:

(1)在輸出格式為十進制的情況下:

①如果表達式值的所有位均為不定值,則輸出結果為小寫的x。

②如果表達式值的所有位均為高阻值,則輸出結果為小寫的z。

③如果表達式值的部分位為不定值,則輸出結果為大寫的X。

④如果表達式值的部分位為高阻值,則輸出結果為大寫的Z。

(2)在輸出格式為十六進制和八進制的情況下:

①每4位二進制數為一組,代表一位十六進制數;每3位二進制數為一組,代表1位八進制數。

如果表達式值相對應的某進制數的所有位均為不定值,則該位進制數的輸出結果為小寫的x。

如果表達式值相對應的某進制數的所有位均為高阻值,則該位進制數的輸出結果為小寫的z。

如果表達式值相對應的某進制數的部分位為不定值,則該位進制數的輸出結果為大寫的X。

如果表達式值相對應的某進制數的部分位為高阻值,則該位進制數的輸出結果為大寫的Z。對于二進制輸出格式,表達式值的每一位的輸出結果為0、1、x、z。例如:

$display("%d",1'bx);

輸出結果為:x。

$display("%h",14'bx0_1010);

輸出結果為:xxXa。

$display("%h

%o",12'b001x_xx10_1x01,12'b001_xxx_101_x01);

輸出結果為:XXX1x5X。

注意:因為?$write在輸出時不換行,所以要注意它的使用??梢栽?$write中加入換行符\n,以確保明確地輸出顯示格式。3.11.2系統任務?$monitor

$monitor的格式如下:

$monitor(“格式控制符”,輸出變量名列表);

$monitor與$display和$write類似,都是輸出控制類的系統任務。但任務$monitor提供了監(jiān)控輸出變量的功能,每當輸出變量發(fā)生變化時,任務$monitor都將再執(zhí)行一遍。

例如:

$monitor($time,,"a=%bb=%h",a,b);

每次a或b信號的值發(fā)生變化都會激活上面的語句,并顯示當前仿真時間、二進制格式的a信號值和十六進制格式的b信號值。3.11.3系統函數?$time和?$realtime

$time和$realtime都是屬于返回仿真時間的系統函數。調用這兩個時間系統函數可以得到當前時刻距離仿真開始時刻的時間量值。$time函數與$realtime函數唯一不同之處是:$time函數以64位整數值的形式返回模擬時間,而$realtime函數以實數型數據返回模擬時間。

下面通過實例可看出$time和$realtime函數的具體區(qū)別,例如:上面的例子用仿真器,其輸出結果如下:

0 ts=x

2 ts=0

4 ts=1

$time顯示時刻受時間尺度比例的影響。在上面的例子中,時間尺度是10ns,因為$time輸出的時刻總是時間尺度的倍數,所以在18ns和36ns時刻分別輸出的結果為1.8和3.6。但因為$time的輸出數值為整數形式,所以1.8和3.6四舍五入后就變成了2和4。如果將上例中的$time改為$realtime,則仿真后輸出值變?yōu)?/p>

0 ts=x

1.8 ts=0

3.6 ts=13.11.4系統任務?$stop和?$finish

$stop和$finish的格式如下:

$stop;

$stop(n);

$finish;

$finish(n);系統任務?$stop和?$finish用于對仿真過程進行控制,分別表示中斷仿真和結束仿真。$?stop和?$finish后面可以帶參數n,n可以是0、1、2等值。如果不帶參數,則默認的參數值為1。下面給出了對于不同的參數值,系統輸出的特征信息。

(1)不輸出任何信息;

(2)輸出當前仿真時刻和位置;

(3)輸出當前仿真時刻、位置和在仿真過程中所用memory及CPU時間的統計。3.11.5系統任務?$readmemb和?$readmemh

在VerilogHDL程序中有兩個系統任務$readmemb和$readmemh,用來從文件中讀取數據到存儲器中。這兩個系統任務可以在仿真的任何時刻被執(zhí)行使用,其使用格式如下:

$readmemb("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);

$readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);在這兩個系統任務中,被讀取的數據文件的內容只能包含空白位置(空格、換行、制表格(tab))、注釋行(//形式的和/*...*/形式的都允許)、二進制或十六進制的數字。數字中不能包含位寬說明和格式說明。對于?$readmemb系統任務,每個數字必須是二進制數字;對于$readmemh系統任務,每個數字必須是十六進制數字。數字中不定值x或X、高阻值z或Z和下劃線的使用方法及代表的意義與一般VerilogHDL程序中的用法及意義是一樣的。另外,數字必須用空白位置或注釋行來分隔開。定義系統任務?$readmemb和?$readmemh時,起始地址和結束地址均可缺省。如果缺省起始地址,則表示從存儲器的首地址開始存儲;如果缺省結束地址,則表示一直存儲到存儲器的結束地址。3.11.6系統函數?$random

$random是一個產生隨機數的函數。每次調用此函數將返回一個32位(bit)的隨機數,該隨機數是一個帶符號的整型數。

其調用格式如下:

$random;

$random%n;當$random函數后面定義了一個n(n需大于0)值時,產生的隨機數就有了一定的范圍,其范圍是(-n+1)~(n-1)。

例如:

reg[23:0]data;

data=$random%80;//data的值是在-79~79之間的隨機數

3.12編?譯?預?處?理

VerilogHDL語言和C語言一樣也提供了編譯預處理的功能?!熬幾g預處理”是VerilogHDL編譯系統的一個組成部分。VerilogHDL語言允許在程序中使用幾種特殊的命令。Verilo

溫馨提示

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

評論

0/150

提交評論