版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
7.1VerilogHDL語言總體結(jié)構(gòu)7.2端口聲明與數(shù)據(jù)類型聲明7.3數(shù)值的表示7.4連續(xù)賦值7.5模塊實例化7.6驗證設計7.7運算符(operator)7.8VerilogHDL行為級建模7.9任務和函數(shù)介紹7.10綜合設計:交通信號燈控制器7.11VerilogHDL語言的仿真工具習題
第7章VerilogHDL語言簡介
VerilogHDL語言是一種硬件描述語言,在20世紀80年代由GatewayDesignAutomation公司開發(fā),用于電路的模擬。1995年,VerilogHDL成為IEEE(InstituteofElectricalandElectronicsEngineers,電子電氣工程師協(xié)會)標準,即IEEE1364標準(Verilog-1995),2001年對該標準進行了修改(Verilog-2001)。Verilog-2001在Verilog-95上增加了一些新的特性,使VerilogHDL的表述更簡潔。目前大部分EDA工具都支持兩個標準。本書按Verilog-95標準對VerilogHDL進行簡要的介紹。
VerilogHDL語言可以在系統(tǒng)級、算法級、寄存器傳輸級RTL(RegisteredTransfer
Level)、門級和開關級(晶體管級)等多個抽象設計層次對數(shù)字電路或者系統(tǒng)進行建模。VerilogHDL本質(zhì)是一種復雜的描述數(shù)字系統(tǒng)的語言,句法上與C語
言相似,延用了C語言的多種操作符和結(jié)構(gòu),但是其語義上是基于并發(fā)硬件操作,完全不同于順序執(zhí)行的C語言。
VerilogHDL是一種仿真能力非常強大的語言,語言中包含了一部分可以用EDA工具進行邏輯綜合的子集。所謂的邏輯綜合就是指利用電子設計自動化EDA(ElectronicDesignAutomation)工具將VerilogHDL代碼轉(zhuǎn)換成電路。
VerilogHDL可以用于描述系統(tǒng)中的一個元件,也可以用于描述一個完整的系統(tǒng)。7.1VerilogHDL語言總體結(jié)構(gòu)
VerilogHDL語言描述主要由三個部分構(gòu)成:端口聲明(PortDeclaration)、信號數(shù)據(jù)類型聲明(DataTypeDeclaration)、電路模塊功能描述(CircuitFunctionality),圖7-1給出了一個基本VerilogHDL程序的組成結(jié)構(gòu)。
VerilogHDL程序以關鍵詞module開始,以關鍵字endmodule結(jié)束。module后面是一個模塊名標識符,它唯一
地標識一個模塊,模塊名后括號中的port_list是模塊的輸入和輸出列表。當portlist是空的時候,該模塊是一個仿真中模塊。圖7-1VerilogHDL的模塊組成結(jié)構(gòu)端口聲明(PortDeclarations):聲明一個端口的性質(zhì),如輸入(Input)、輸出(Output)還是雙向口(inout)以及端口的寬度([PORT_WIDTH1:0])。
信號數(shù)據(jù)類型聲明(DataTypeDeclarations):聲明module中用到的數(shù)據(jù)類型,如regport1,wireport2。
電路模塊功能描述(Circuitfunctionality):描述電路功能。與C語言一樣,在VerilogHDL語言中,除了關鍵字endmodule行外,每行以“;”號結(jié)束。VerilogHDL是大小寫敏感語言,語言中所有的關鍵字都是小寫,其注釋方式有兩種:一是單行注釋,注釋內(nèi)容在“//”之后,直至本行末;二是多行注釋,注釋內(nèi)容自“/*”開始,至“*/”結(jié)束。
【例7-1】
用Verilog語言描述兩輸入的異或門。
圖7-2(a)給出了一個異或門的Verilog描述,圖(b)給出了圖(a)的綜合結(jié)果。
圖7-3是VerilogHDL語言的基本元素組成圖,本章將按圖7-3對VerilogHDL語言的各個部分作簡單的介紹。圖7-2異或門的VerilogHDL描述圖7-3VerilogHDL語言的基本組成一個電路由多個不同的部件(模塊)構(gòu)成,這些部件之間并行地工作。一個部件可以是一個門,也可以是一個完成某些特殊功能的電路,如譯碼器、多路選擇器和計數(shù)器等,還可以是完成復雜任務的子系統(tǒng),如嵌入式微處理器等。Verilog語言中可以用三種方式來描述系統(tǒng)各個部件的功能:連續(xù)賦值(ContinuousAssignment)、過程模塊(ProceduralBlock)和模塊實例化(ModuleInstantiation)。此外,Verilog還可以用各種子程序如任務(task)、函數(shù)(function)或者系統(tǒng)任務(systemtask)來描述電路的行為或者仿真的行為。1.I/O端口聲明
I/O端口是一個模塊和其周圍環(huán)境進行通信的信號接口,模塊內(nèi)部的信號對于環(huán)境而言是不可見的。例如,圖7-4是一個兩輸入異或門的I/O端口。
VerilogHDL語言在模塊內(nèi)必須對輸入、輸出列表中的每個信號進行聲明,同時對輸入和輸出信號的數(shù)據(jù)類型進行聲明。7.2端口聲明與數(shù)據(jù)類型聲明圖7-4兩輸入XOR門的I/O端口基本語法是:
moduleidentifier(port_name1,port_name2,…port_nameN);
[mode][port_name1];//聲明端口類型
[mode][port_nameN];
[data_type][port_name1];//聲明端口數(shù)據(jù)類型
[data_type][port_nameN];
endmodule
mode類型有三種:input(輸入端口)、output(輸出端口)和inout(雙向端口)。這些都是關鍵字,不能用于信號名。(port_name1,…,port_nameN)是一個模塊的輸入和輸出端口名稱列表,這些名稱之間用“,”進行分離,輸入、輸出列表的最后一項沒
有“,”。[JP2][data_type][port_name1],…,[data_type][port_nameN]是對端口的數(shù)據(jù)類型進行聲明。
【例7-2】
兩輸入異或門的I/O端口聲明。
modulexor_2(in1,in2,out);
inputin1,in2;//聲明輸入信號
outputout;
//聲明輸出信號
wirein1,in2;
//聲明輸入端口的數(shù)據(jù)類型
wireout;
//聲明輸出端口的數(shù)據(jù)類型
endmodule
要特別注意的是:在模塊中不能再次定義模塊,即模塊不能嵌套。例如,下面的寫法是錯誤的。
moduleand_2(in1,in2,ou1);
moduledff(clk,rst,din,dout);//錯誤定義!
endmodule
endmodule
2.信號的數(shù)據(jù)類型聲明
在VerilogHDL中使用四值邏輯,它們分別是:
(1)“0”:表示邏輯0或者判定條件假。
(2)“1”:表示邏輯或者判定條件為真。
(3)“z”:高阻狀態(tài)。
(4)“x”:未知狀態(tài)。
“z”表示高阻態(tài),通常用于描述一個三態(tài)門;而“x”則是用于仿真或者建模,表示當前值不確定,當輸入沒有初始化或者輸出有沖突的時候,會出現(xiàn)“x”狀態(tài)。信號的取值是這四種邏輯值中的任意一種。信號數(shù)據(jù)類型的聲明說明在本模塊中使用的信號和參數(shù)的數(shù)據(jù)類型。
簡單的語法是:
[data_type][range][signal_name];
//聲明一個信號變量
或者
[data_type][range][signal_name1,signal_name2,…,
signal_nameN];
//同時聲明N個類型、范圍相同的信號變量
VerilogHDL有兩大類數(shù)據(jù)類型:線網(wǎng)類型組及寄存器類型組。
(1)線網(wǎng)類型組(netgroup)。
在VerilogHDL語言中,線網(wǎng)類型組用于描述硬件元件間的物理連線。線網(wǎng)類型的變量是連續(xù)賦值的輸出,也是不同部件之間的連接信號,它的值由驅(qū)動元件的值決定,如圖7-5所示。如果沒有驅(qū)動元件連接到線網(wǎng),線網(wǎng)的缺省值為“z”。在net類型中最常用的類型是wire類型。正如其名字所表示,它表示一個連接線。圖7-5線網(wǎng)類型組
wire數(shù)據(jù)類型表示比特信號。例如:
wirep1,p2;//聲明兩個1比特的信號
線網(wǎng)類型組(netgroup)中的其它數(shù)據(jù)類型包括:wand(線與)、supply0(電路地連接)、supply1(電源連接)等等,表示某類邏輯操作和功能,本書不涉及這些類型,有興趣的讀者可以參看本書后面列出的參考文獻。
(2)寄存器類型組(registergroup)。
寄存器組中的數(shù)據(jù)類型在行為模型中表示抽象存儲,是過程賦值的輸出。這個組中包括四種類型:reg、integer、real和time。大多數(shù)變量用reg類型,reg類型是可以綜合的。注意:綜合出來的電路既可以包含也可以不包含存儲元件。后三種數(shù)據(jù)類型只是用于建模和仿真。例如:
reg
d_flip;//聲明一個reg類型的信號變量
在VerilogHDL中可用[rang]表示一組信號。wire和reg類型的變量可以聲明成多位寬度的向量(vectors)。如果變量的寬度是一位,該變量即是標量(scalar)。我們可以用一維向量表示一組信號(總線)。例如:
wiresel;//標量信號
wire[7:0]data1,data2;//8比特數(shù)據(jù)
wire[31:0]addr;
//32比特地址
reg
[7:0]out;//8比特reg變量
信號的索引范圍可以是升序[low#:high#],也可以是降序[high#:low#],但是信號數(shù)據(jù)最左邊的那位就是二進制數(shù)的最高位??梢杂靡粋€二維向量表示一個存儲器,例如一個32*4的存儲器(表示一個存儲器有32個字,每個字有4位),用VerilogHDL可以表示成
reg
[3:0]data_mem
[31:0];
在VerilogHDL語言中允許使用一個向量中的一位或者多位,如:
Data1[1];//向量data1的第2位;
Data2[3:2];//向量data2中的第4比特和第3比特;
在Verilog語言中,整數(shù)常量可以表示成各種各樣的形式,一般的格式是:
[size]′[base][value]
其中,[base]說明數(shù)字的基數(shù),當一個數(shù)用十進制表示,可省略該項。該項有4種形式:
①borB:二進制;
②oorO:八進制;
③horH:十六進制;
④dorD:十進制。
7.3數(shù)值的表示
[value]:說明在對應的基數(shù)表示方式下對應的數(shù)。為了方便閱讀,一個數(shù)可以用“_”分割表示。如8′b1000_0011。
[size]:說明一個數(shù)值用幾位表示,這項是可選的。如果在一個數(shù)的表示中存在該項,那么這個數(shù)被認為是有位數(shù)表示的,否則是無位數(shù)表示的數(shù)。
[size]項顯式地表示了一個數(shù)值所用的位數(shù)。如果一個數(shù)所用位數(shù)小于size所規(guī)定的位數(shù),需要對該數(shù)擴展到size規(guī)定的位數(shù)。如果一個數(shù)值的最高位是x或z,那么在該數(shù)前用x或者z填充,擴展到規(guī)定的位數(shù);如果一個數(shù)有符號位,那么用符號位填充,擴展到規(guī)定的位數(shù);其它情況下,在該數(shù)前用0填充,擴展至規(guī)定的位數(shù)。如果一個數(shù)前省略了[size]項,那么它實際的表示依賴于計算機的結(jié)構(gòu),但是至少擴展到32位。
例如,表7-1所示為有位數(shù)表示的常數(shù),表7-2所示為無位數(shù)表示的常數(shù)。表7-1有位數(shù)表示的常數(shù)示例表7-2無位數(shù)表示的常數(shù)示例可以通過連續(xù)賦值描述組合電路的功能,基本語法是:assign[signalname]=[expression];
assign是VerilogHDL語言的關鍵詞;[signalname]的數(shù)據(jù)類型必須是wire類型;[expression]的數(shù)據(jù)類型沒有限制,它是由操作數(shù)和操作符變量構(gòu)成的表達式或者是函數(shù)。操作數(shù)類型可以是前面定義的任意數(shù)據(jù)類型。操作數(shù)可以是常數(shù)、整數(shù)、實數(shù),線網(wǎng)、寄存器、向量或者向量的一位或者多位。7.4連續(xù)賦值在連續(xù)賦值語句中,等式右邊表達式中的任何一個信號變量發(fā)生變化,表達式都要計算,例如:
wire[9:0]addr;
wire[31:0]bus;
wireout;
wire[7:0]result;
assignaddr=10′b0000_0010_11;
//表達式是常數(shù)
assigndata=bus^32′h0000_ffff;
//變量、常數(shù)和運算符構(gòu)成的表達式
assignout=in1|in2;
//變量、操作符和變量構(gòu)成的表達式
assignresult=mult(a,b);
//表達式是函數(shù)值模塊實例化是創(chuàng)建模塊的另外一個應用實例。通過模塊的實例化可以構(gòu)建更復雜的設計模塊或者系統(tǒng)。
實例化的一般語法形式:
[module_name][instance_name]
(.[port_name1]([signal_name1]),
.[port_name2]([signal_name2]),
.[port_nameN]([signal_nameN]));7.5模塊實例化
【例7-3】
一個兩位的比較器可以通過兩個一位比較器按照圖7-6所示的連接方式實現(xiàn)。
一位/兩位的比較器verilog的描述方式有如下兩種。
第1種:
moduleeq_1bit(i0,i1,eq);
inputi0,i1;
outputeq;
wirep0,p1,eq;
assignp0=~i0&~i1;
assignp1=i0&i1;
assigneq=p0|p1;
endmodule
圖7-6一個兩位比較器第2種:
moduleeq_2bit(a,b,a_eq_b);
input[1:0]a,b;
outputa_eq_b;
wiree0,e1,a_eq_b;
eq_1biteq_bit0_unit(.i0(a[0]),.i1(b[0]),.eq(e0));
//實例化模塊eq_1bit
eq_1biteq_bit1_unit(.i0(a[1]),.i1(b[1]),.eq(e1));
//實例化模塊eq_1bit
assigna_eq_b=e0&e1;
endmodule
在第2種描述方式中,句子
eq_1biteq_bit0_unit(.i0(a[0]),.i1(b[0]),.eq(e0))
表示實例化eq_1bit模塊,eq_bit0_unit是eq_1bit模塊的一個實例,(.i0(a[0]),.i1(b[0]),.eq(e0))表示實例eq_bit0_unit的輸入/輸出信號在本模塊中和其它模塊之間的信號連接關系。
在本例中,實例eq_bit0_unit是一個一位比較器,其輸
入端i0、i1在本模塊中連接到信號a[0]和b[0],其輸出端連接到e0上。注意“.”不可缺少。一個設計完成后,必須要確認設計是否滿足設計者所要求的功能。一種方法就是利用EDA軟件,在計算機上通過仿真確認所完成電路是否正確,我們稱之為電路驗證。
為了驗證一個電路是否正確,需要對所設計的電路提供輸入激勵,然后通過軟件觀察輸出是否正確。因此,除了設計模塊之外,還需要編寫激勵模塊,我們把這種模塊稱為testbench模塊。下面介紹如何編寫一個設計的testbench模塊。7.6驗證設計在testbench模塊中,實例化設計模塊,按照模塊的功能編寫模塊的輸入激勵,檢查和顯示輸出信息。以兩輸入的比較器為例,圖7-7給出了testbench模塊tb_eq_2bit和被仿真模塊eq_2bit之間的關系。從圖中可以看出,仿真模塊tb_eq_2bit本身沒有輸入和輸出,包含了模塊eq_2bit(設計模塊)的一個實例eq_2bit_inst。tb_eq_2bit內(nèi)產(chǎn)生eq_2bit_inst實例所需要的輸入激勵a、b,檢查和顯示其輸出信號a_eq_b。圖7-7測試模塊和設計模塊之間的關系
【例7-4】
編寫eq_2bit的測試模塊。
moduletb_eq_2bit;
//兩位比較器電路的testbench模塊名
reg[1:0]a,b;
//比較器輸入信號
wirea_eq_b;
//比較器輸出信號
initial
begin
//給出所有可能的輸入值
a=2′b00;b=2′b00;//初始時刻,給a,b賦值
#10a=2′b00;b=2′b01;//10個時間單位后,給a,b賦不同的值
#10a=2′b00;b=2′b10;//20個時間單位后,給a,b賦不同的值
#10a=2′b00;b=2′b11;//30個時間單位后,給a,b賦不同的值
#10a=2′b01;b=2′b00;//40個時間單位后,給a,b賦不同的值
#10a=2′b01;b=2′b01;//50個時間單位后,給a,b賦不同的值
#10a=2′b01;b=2′b10;//60個時間單位后,給a,b賦不同的值
#10a=2′b01;b=2′b11;//70個時間單位后,給a,b賦不同的值
#10a=2′b10;b=2′b00;//80個時間單位后,給a,b賦不同的值
#10a=2′b10;b=2′b01;//90個時間單位后,給a,b賦不同的值
#10a=2′b10;b=2′b10;//100個時間單位后,給a,b賦不同的值
#10a=2′b10;b=2′b11;//110個時間單位后,給a,b賦不同的值
#10a=2′b11;b=2′b00;//120個時間單位后,給a,b賦不同的值
#10a=2′b11;b=2′b01;//130個時間單位后,給a,b賦不同的值
#10a=2′b11;b=2′b10;//140個時間單位后,給a,b賦不同的值
#10a=2′b11;b=2′b11;//150個時間單元后,給a,b賦不同的值
end
eq_2biteq_2bit_inst(.a(a),.b(b),.a_eq_b(a_eq_b));
//兩位比較器實例化
endmodule在上面的例子中,initialbegin...end是一個過程塊,下節(jié)將詳細介紹。#10表示10個時間單位的延時。該過程塊給出了隨時間變化的輸入值,完整的仿真eq_2bit設計需要輸入a、b的全部組合,一共是16種,結(jié)果如圖7-8所示。圖7-8兩位比較器完整測試波形圖上面的例子介紹了如何建立一個驗證程序。驗證程序也是一個module,但是它沒有任何的輸入和輸出。在驗證程序中,需要實例化被驗證的設計;定義設計所需要的輸入和輸出;為輸入加載輸入激勵。在Verilog語言中包含了10類操作符、24種運算符。這些運算符對應著簡單的器件,比如加法器和比較器。表7-3說明了VerilogHDL中的運算符,表7-4給出了運算符的優(yōu)先級。7.7運算符(operator)表7-3VerilogHDL中的運算符表7-4運算符優(yōu)先級
1.算術(shù)運算符
在Verilog中,算術(shù)運算符共有六個:“+”、“-”、“*”、“/”、“%”和“**”,分別代表加、減、乘、除、
取模和指數(shù)運算?!?”和“-”也可以作為一元運算符,例如:-a。
在算術(shù)運算操作中,“+”和“-”運算符可以用EDA工具直接綜合成加法器和減法器。乘法是一個復雜的操作,對于乘法運算符“*”的綜合取決于綜合軟件以及目標器件的工藝。除法運算符“/”、求模運算符“%”和指數(shù)運算符“**”在通常情況下是不可綜合的。
2.移位運算符
移位運算符有四個:“<<”、“>>”、“<<<”、“>>>”,分別表示邏輯左移、邏輯右移、算術(shù)左移、算術(shù)右移。這組運算符是將一個向量向左或者向右移動給定的位數(shù),如果是邏輯移位,則用0填充在向量的高位(左移)或者低位(右移)。算術(shù)左移高位用低位填充,最低位用0來填充,符號位移出后,則丟棄,這樣,算術(shù)左移和邏輯左移的運算結(jié)果一樣。而算術(shù)右移低位用高位填充,把數(shù)的最高位看成符號位,用符號位填充高位,最低位移出后丟棄。例如:a=8′b0100_1111,b=8′b1100_1111,c=8′b10100011,有
x=a>>2;//x=0001_0011
y=b>>>2;
//y=1111_0011
z=c>>>3;
//z=1111_0100
算術(shù)右移將b的最高位看成符號位,用符號位填充;z=a<<2;
//z=0011_1100;
w=b<<<2;
//w=0011_1100
3.關系運算符
“>”、“<”、“>=”、“<=”是雙目比較運算,返回結(jié)果是布爾值,如果運算的結(jié)果是假的(false),則返回值是0;如果運算的結(jié)果是真的(true),則返回值是1。
“==”、“!=”、“===”、“!==”是等式運算符,返回值是真、假或x?!?==”和“!==”常在case語句中表示相等或者不等,操作數(shù)可以為“x”和“z”,這兩個運算符是不可綜合的,“==”和“!=”是可綜合的。相等關系運
算的描述見表7-5。表7-5相等關系運算
【例7-5】A=4′b0100,B=4′b0011;x=4′b1010,y=4′b1101;z=4′b1xxz,m=4′b1xxz,n=4′b1xxx。
(1)A==B,運算結(jié)果為0;
(2)x!=y,運算結(jié)果為1;
(3)z=x,運算結(jié)果是x;
(4)z===m,運算結(jié)果為1;
(5)m!==n,結(jié)果為邏輯1;
(6)z===n,結(jié)果為0。
4.位運算符、縮減運算符和邏輯運算符
位運算符、縮減運算符和邏輯運算符有幾分相似,都是與、或、異或、非的運算。這些運算都可以通過基本邏輯單元實現(xiàn)。
1)位運算符
位運算符包括四個:“&”(與運算),“|”(或運算),“^”(異或運算),“~”(取反運算)。除了“~”是單目運算符外,其它運算都需要兩個操作數(shù)。取反和異或的運算
可以組合使用,例如:“~^”和“^~”組合成異或非(同或)運算符,兩者是等價的。
這些運算符進行運算時按照一位一位運算的,所以稱它們?yōu)槲贿\算符。例如,有
wire[3:0]a,b,c;
語句
assignc=~(a|b);
等價于:
assignc[3]=~(a[3]|b[3]);
assignc[2]=~(a[2]|b[2]);
assignc[1]=~(a[1]|b[1]);
assignc[0]=~(a[0]|b[0]);
在VerilogHDL語言中的位運算中,對z和x進行相同的處理,表7-6~表7-10給出了位運算的真值表。表7-6“與”運算真值表表7-7“或”運算真值表表7-8“非”運算真值表表7-9“異或”運算真值表表7-10“同或”運算真值表
2)縮減運算符
縮減運算符有三個:“&”、“|”和“^”。它們與位運算符寫法相同,但是縮減運算符只有一個操作數(shù)??s減運算符的返回值是1位的二進制數(shù)。例如,有
wire[3:0]a;
wirey;
則語句:
assigny=|a;
等價于:
assigny=a[3]|a[2]|a[1]|a[0];
3)邏輯運算符
邏輯運算符有三個:“&&”(邏輯與)、“||“(邏輯或)和”!“(邏輯非)。邏輯運算符與位運算符不同。邏輯運算的特點是:
(1)邏輯運算的結(jié)果總是一位的,有三種取值,即1、0或者x。
(2)如果一個操作數(shù)不等于0,那么這個數(shù)等價邏輯1(真條件);如果操作數(shù)等于0,那么等價于邏輯0(假條件);如果一個操作數(shù)中包含x或者z,等價為x(不確定)。
(3)邏輯運算的操作數(shù)可以是變量或者是表達式。例如:
if((state==idle)||((state==op)&&(count>10)))
【例7-6】
表7-11給出了邏輯運算和位運算的一些例子。由于VerilogHDL中用0和1來代表假和真,所以位運算和邏輯運算在某些條件下可以交換使用。表7-11邏輯運算例子
5.拼接運算符和復制運算符
1)拼接運算符
用{}表示拼接運算,使用這個運算符可以把兩個或多個信號的某些位拼接形成一個向量,進行運算操作,多個信號變量用“,”隔開。
wirea1;
wire[3:0]a4;
wire[7:0]b8,c8,d8;
assignb8={a4,a4};
assignc8={a1,a1,a4,2′b00};
assignd8={b8[3:0],c8[3:0]};拼接運算的一個應用是進行信號變量移位或循環(huán)操作,舉例如下:
wire[7:0]a;
wire[7:0]rot,shl,sha;
assignrot={a[2:0],a[7:3]};
//a向右循環(huán)3位
assignshl={3′b000,a[8:3]};//a邏輯右移3位
assignsha={a[8],a[8],a[8],a[8:3]};
//a算術(shù)右移3位
2)復制運算符
用{N{}}表示對{}內(nèi)的數(shù)復制N次,形成新的向量。該操作可以用于化簡拼接的寫法。例如,
{4{2′b01}}
等價于
8′b01010101
又如,
assignsha={3{a[8]},a[8:3]};
//a算術(shù)右移3位
等價于:
assignsha={a[8],a[8],a[8],a[8:3]};
//a算術(shù)右移3位
6.條件運算符
條件運算符“?:”是三目運算符,其基本格式如下:[signal_name]=[boolean_exp]?[true_exp]:[false_exp];
其中,[boolean_exp]是指布爾表達式,返回值是真(1′b1)或假(1′b0)。如果[boolean_exp]為真,則[signal]為[true_exp]的值,否則為[false_exp]的值。例如,
wire[2:0]max;
assignmax=(a>b)?a:b;該運算用if-else語句表示如下:
if[boolean_exp]
[signal]=[true_exp];
else
[signal]=[false_exp];
條件運算符還可以嵌套,例如:
assignmax=(a>b)?((a>c)?a:c):
((b>c)?b:c);
在綜合時,條件運算符會被綜合成二選一選擇器。
7.表達式的位寬
VerilogHDL程序中的信號,連線和變量通常都具有不同的位寬,在存儲中,選擇的位數(shù)與位寬一致。例如,
wire[7:0]a,b;
assigna=8′b00000000;
assignb=0;上述代碼中,第一條assign語句是將8位的二進制數(shù)“00000000”賦給a,而第二條assign語句是指將整數(shù)0賦給b。在Verilog中整數(shù)是32位,即“0000_0000_0000_0000
_0000_0000_0000_0000”。由于b事先聲明為8位,故正確地從32位中截取8位的“00000000”。盡管這兩條assign語句的結(jié)果都是8位的“00000000”,但是我們必須清楚a和b分別是怎樣獲得的值。例如,
wire[7:0]a,b;
wire[7:0]sum8;
wire[8:0]sum9;
assignsum8=a+b;
assignsum9=a+b;
上述代碼中,第一條assign語句中所有的操作數(shù)都是8位,等號左邊的sum8也是8位的,而附加的進位位被丟棄了。在第二條assign語句中,由于sum9是9位的,所有“a”和“b”也被擴展成9位,而sum9[9]就是進位位的值。
我們同樣可以利用拼接運算符來完成上述運算:
assign{c_out,sum8}=a+b;
1.過程塊結(jié)構(gòu)
在VerilogHDL語言中有兩種結(jié)構(gòu)化過程語句always和initial,它們是行為建模中最基本的兩個語句,所有其它的行為語句可以出現(xiàn)在這兩個結(jié)構(gòu)化過程中。
always和initial語句不能嵌套。7.8VerilogHDL行為級建模
1)initial語句
initial語句只用于建立行為仿真,不能綜合。所有出現(xiàn)在initial中的語句構(gòu)成一個initial塊(initialblock),一個initial塊從時間0開始執(zhí)行,在仿真過程中每個語句只執(zhí)行一次。如果一個仿真程序中出現(xiàn)了多個initial塊,這些塊都是在0時刻開始執(zhí)行的,每個initial塊的執(zhí)行是相互獨立的?;镜恼Z法是:
initialbegin
statements_sequence;
end
【例7-7】initial模塊示例。
modulestimulus;//驗證模塊
regx,y,a,b,m;
initial
m=1′b0;//只有一個語句,可以省略begin/endinitialbegin
#5a=1′b1;
//多條語句,需要用begin/end
#25b=1′b0;
end
initialbegin
#10x=1′b0;
#25y=1′b1;
end
initial
#50$finish;
endmodule在上面的例子中有一個延時#delay,表示等待delay個時間單位。其執(zhí)行的結(jié)果如下:
timestatementexecuted
0m=1′b0;
5a=1′b1;
10x=1′b0;
30b=1′b0;
35y=1′b1;
50$finish;
2)always塊
always塊是Verilog語言中另外一種描述電路行為的語句,它是可綜合語句。
所有出現(xiàn)在always中的語句構(gòu)成一個always塊。always塊使用行為語句描述電路的功能。always的一般形式為
always@(event_list)begin
statements_sequence
end執(zhí)行always塊的條件是事件列表(event_list)中任何信號發(fā)生變化,即只要事件列表中的任何事件發(fā)生變化,就重復執(zhí)行語句序列。如果always塊的語句只有一條,可以省略begin/end。statement_sequence是指過程賦值語句序列。過程賦值語句和@(event_list)將在后續(xù)小節(jié)詳細介紹。例如,
regout1;
always@(in1orin2)
//in1或者in2發(fā)生變化,執(zhí)行out1=in1|in2語句
out1=in1|in2;
2.過程賦值語句
過程賦值語句的基本語法:
<delayorevent>lhs=<delayorevent>rhs;
<delayorevent>lhs<=<delayorevent>rhs;
上面兩個語句都是過程賦值語句,前者我們稱為阻塞賦值(=),而后者稱為非阻塞賦值。過程賦值語句的作用是用等式右邊的表達式(rhs)更新等式左邊的變量值(lhs)。等式左邊的變量值的類型有reg、integer、real和time。過程賦值與連續(xù)賦值的不同之處是:在連續(xù)賦值語句中,等式右邊表達式的值連續(xù)不斷地賦給等式的左邊,而在過程賦值語句中,一個變量存儲的值保持不變,直到過程賦值語句用不同的值更新該變量。
等式右邊的表達式可以是下面的幾種形式:
(1)reg、integer、real和time型變量,如a,b,c;
(2)變量的比特選擇,如addr[0];
(3)變量的部分選擇,如addr[31:16];
(4)上述類型的連接形式,如{4′h0,addr[15:0],a}。
1)阻塞賦值語句
用“=”進行賦值的語句是阻塞賦值語句。阻塞賦值可以按照它們在過程塊中的次序順序執(zhí)行,在它執(zhí)行結(jié)束之前,將阻止后續(xù)語句的執(zhí)行
【例7-8】
下面的表達式形式都是合法的:
rega,b,c;
reg
[15:0]data;
integercounter;
initial
begin
a=1′b0;b=1′b1;c=1′b1;
//在0時刻,將3′b011分別賦給a,b,c;counter=0;//在0時刻,counter賦初值0;
#10data[1]=a;//在第10個時間單位,將a賦給data[1];data[7:2]=6′b00_1011;
//將二進制數(shù)001011賦給data[7:2];#20counter=counter+1;//在第30個時間單位,將counter加1{a,b,c}=counter[2:0];
//在第30個時間單位,將counter的低三位分別賦給a,b,c
end
注意:如果等式右邊的數(shù)據(jù)寬度大于等式左邊變量的寬度,那么拋棄高位,而保留低位。如果等式右邊的數(shù)據(jù)寬度小于等式左邊變量的寬度,則高位用0填充。
2)非阻塞賦值語句
一條非阻塞賦值語句不阻止后續(xù)語句的執(zhí)行。
【例7-9】
阻塞與非阻塞賦值語句的執(zhí)行情況。如下兩段代碼分別為阻塞和非阻塞賦值語句。阻塞賦值:
regA,B;
initialbegin
A=#101′b1;
B=#51′b0;
A=#201′b0;
B=#151′b1;
end非阻塞賦值:
regA,B
initialbegin
A<=#101′b1;
B<=#51′b0;
A<=#201′b0;
B<=#151′b1;
end我們來考察阻塞語句與非阻塞語句的執(zhí)行情況,在本例中的時間單位是ns,如圖7-9所示,圖(a)是阻塞賦值結(jié)果,圖(b)是非阻塞賦值結(jié)果。初始,A、B值均為高阻態(tài)。對于非阻塞語句描述,10ns執(zhí)行語句A=1′b1;在該句執(zhí)行結(jié)束后的5s,即第15ns執(zhí)行B=1′b0;而此后的20ns,即到35ns前,A一直為1;35ns時執(zhí)行語句A=1′b1;在50ns的時候執(zhí)行B=1′b1??梢钥闯鲎枞Z句一定是本句執(zhí)行結(jié)束后,才允許運行其它語句的執(zhí)行。在一個過程塊中,它們是順序執(zhí)行的。圖7-9阻塞賦值和非阻塞賦值的輸出波形而對于非阻塞語句,它的執(zhí)行并不阻塞后續(xù)語句的執(zhí)行。因此,調(diào)度器在5ns時候執(zhí)行B=0;在10ns的時候執(zhí)行A=1;在15ns的時候執(zhí)行B=1,而在20ns的時候執(zhí)行A=0,如圖7-9(b)所示。
為了進一步看清楚阻塞語句與非阻塞語句的區(qū)別,我們再舉一個例子?!纠?-10】
阻塞語句與非阻塞語句的綜合。
阻塞賦值:
moduledff(clk,din,dout);
inputdin,clk;
outputdout;
rega,dout;
always@(posedge
clk)
begin
a=din;
dout=a;
end
endmodule
非阻塞賦值:
moduledff(clk,din,dout);
inputdin,clk;
outputdout;
rega,dout;
always@(posedge
clk)
begin
a<=din;
dout<=a;
end
endmodule
在阻塞賦值代碼中,由于a=din在瞬間完成后,執(zhí)行dout=a,然后在時鐘的上升沿到達的時候,更新等式左邊的值。因此,從仿真結(jié)果看,a和dout的值相同,其綜合的結(jié)果就是一個D觸發(fā)器。而非阻塞賦值代碼的綜合結(jié)果是一個兩位的移位寄存器,兩個等式右邊的表達式按照當前期的值計算出結(jié)果,然后保存在臨時變量中,在時鐘上升沿到達時,同時更新表達式的左邊。這樣,寄存器dout的結(jié)果是上一周
期a的結(jié)果,而a則是上一個周期din的結(jié)果。圖7-10給出了阻塞賦值與非阻塞賦值的綜合結(jié)果。圖7-10阻塞賦值和非阻塞賦值綜合結(jié)果
3.時序控制
時序控制用于說明過程語句執(zhí)行的仿真時間。有三種基本的時間控制語句:基于延時控制的時序控制、基于事件的時序控制和電平敏感的時序控制。
1)基于延時的時序控制
表達式中基于延時的時序控制說明了仿真器遇到語句和執(zhí)行語句之間的間隔。
在Verilog
語言中用“#delay”說明延時。在過程賦值語句中,主要的兩類延時控制是:
(1)正則延時(regulardelay):在過程表達式的左邊說明非零延時。如
#delaylhs=rhs;
等待delay時間后將rhs的值賦給lhs。
(2)內(nèi)定延時(intradelay):在賦值語句的右邊說明延時。
#delay1lhs=#delay2rhs;
仿真器執(zhí)行的過程如下:
●等待delay1;
●計算等式的右邊rhs;
●等待delay2后,將rhs的值賦給lhs。
【例7-11】
時間賦值語句舉例,其延時時序圖如圖7-11所示。
moduletest
parameterlatency=10,delta=2;
reg
[10:0]a,b;
regw1,w2;
integeri1,i2,delay3;
initialbegin
w1=1′b0;w2=1′b1;delay3=10;
圖7-11例7-25延時時序圖#delay3a=-23;
//使用標識符控制
#5i1=10;//在5時間單位后將10賦給整型變量i1
#latencyb=a+10′d15;
//用參數(shù)標識符(parameter_identifer)延時控制
i1=#(latency+delta)a&b+{w1,w2};//使用表達式控制
#10i2=#10i1-(b+a);
end
endmodule
我們將上述代碼做一定的修改,加深對延時語義的理解。timescale1ns/1ps
//{{Sectionbelowthiscommentisautomaticallymaintained
//andmaybeoverwritten
//{module{test1}}
moduletest;
parameterlatency=10,delta=2;
reg
[10:0]a,b;
reg
[10:0]c,d;
regw1,w2; integeri1,i2,i3,i4,delay3;
initialbegin
w1=1′b0;
w2=1′b1;
delay3=10;
#delay3a=-23;//使用標識符控制
#5i1=10;i3=10;i4=10;
//在5時間單位后將10賦給整型變量i1
#latencyb=a+10′d15;d=a+10′d15;
//用參數(shù)標識符(parameter_identifer)延時控制i1<=#(latency+delta)a&b+{w1,w2};//使用表達式控制
i3<=#(latency+delta)c&d+{w1,w2};//使用表達式控制
#10i2=#10i1-(b+a);
end
initial
begin
#10;
#5;
#latency;
#(latency+delta)i4<=c&d+{w1,w2};
end initial
begin
#10c=-23;
#5;
#(latency+1)c=21;
#(latency+delta+9)c=20;
end
endmodule
【例7-12】
在上述代碼中,i1、i3、i4在不同時刻的值分別是多少?說明i3<=#(latency+delta)c&d+{w1,w2};與#(latency+delta)i4<=c&d+{w1,w2};在賦值上的區(qū)別。
解
圖7-12所示時序圖能夠說明問題,由圖中可以看出,i3和i1是一樣的,i4和i3的區(qū)別在于:
i3<=#(latency+delta)c&d+{w1,w2};
而
#(latency+delta)i4<=c&d+{w1,w2};這兩種表達式產(chǎn)生了不同的結(jié)果,前者是先計算表達式的值,然后等待#(latency+delta)之后,將計算的結(jié)果賦予i3。而后者是等待#(latency+delta)之后,計算表達式的值并賦予i4。圖7-12延時時序圖
2)基于事件的時序控制
事件是指線網(wǎng)或者寄存器型的變量值的變化。事件可以用于觸發(fā)一個語句的執(zhí)行,也可以觸發(fā)一個塊語句的執(zhí)行。用@符號說明事件控制,用posedge和negedge關鍵詞說明一個信號的上升沿或下降沿的跳變。事件控制的一般形式如下:@(事件列表)事件列表可以為多種形式:
(1)單一事件或者是“posedge/negedge信號”:表示在信號的正沿/負沿發(fā)生時,觸發(fā)事件。例如,
@(clock)q1=d;
//無論何時信號clock發(fā)生了變化,執(zhí)行這個語句
@(negedgeclock)q2=d;//當clock下降沿時,執(zhí)行這個語句
q3=@(posedgeclock)d+1;
//計算d+1,當時鐘上升沿到來時,用d+1的值更新q3@(aorb)c=a^b;//a或者b發(fā)生變化時,用a^b更新c
(2)事件的組合:當有多個事件控制一個過程塊或者語句的時候,可以寫成“event1orevent2or…or
eventN”,也可以寫成“event1,event2,…,eventN”。例如,
always@(aorborc)begin
sum=a+b;
c=a&b;
end
always@(a,b,c)begin
sum=a+b;
c=a&b;
end當組合電路中的輸入變量過多時,敏感變量表中的變量容易遺落,造成仿真不正確。在VerilogHDL語言中,可以用@*或者@(*)代替@(event_list),@*或者@(*)包含always過程塊中所有等式右邊出現(xiàn)的變量,這種寫法不容易出錯。當寫組合電路時,推薦用@*或者@(*)表示事件控制。例如,
always@(*)begin
sum=a+b;
c=a&b;
end
(3)有名稱的事件:一個名稱事件用關鍵詞event說明,事件的觸發(fā)用->表示,觸發(fā)的事件可以用符號@來識別。這類事件并不保持任何數(shù)據(jù),僅僅用于仿真。限于篇幅關系,本書對這類事件不予介紹,有興趣讀者可讀參考相關文獻。
(4)用關鍵詞wait實現(xiàn)電平敏感的時序控制。
例如,
wait(count_able)#10count=count+1;
當count_able為高電平10s后,執(zhí)行count=count+1,如果count_able為1,那么每隔10個時間單位,count計數(shù)器加1直到count_able變成0。
注意:(3)和(4)語句都不可以綜合成電路。
4.條件語句
Verilog語言中包含了兩種條件語句:If條件語句和Case語句。
1)If條件語句
If是一種具有優(yōu)先級的條件分支結(jié)構(gòu)。它有三種格式:格式1:
If(<expression>)statement_sequence;
如果expression為真,則執(zhí)行語句序列(statement_sequence)。
格式2:
If(<expression>)statement_sequence1
elsestatement_sequence2
如果表達式成立,則執(zhí)行序列1;不成立,則執(zhí)行語句序列2。格式3:
If(<expression1>)
statement_sequence1
elseif(<expression2>)
statement_sequence2
elseif
else
statement_sequence_default
這是嵌套If條件語句格式,當expression1為真時,執(zhí)行statement_sequence1;不為真時,計算expression2是否為真。如果所有的表達式都不為真,則執(zhí)行statement_sequence_default。
【例7-13】
用If語句設計一個三選一的選擇器。
always@(*)begin
if(sela)q=a;
elseif(selb)q=b;
elseq=c;
end
【例7-14】
用If語句設計一個兩位的比較器。
modulecomparator(a,b,eq,gt,lt);
input[1:0]a,b;
outputgt,lt,eq;
reg
gt,lt,eq;
always@(*)
begin
gt=1′b0;//gt默認的值
eq=1′b0;
//eq默認的值
lt=1′b0;//lt默認的值
if(a>b)
gt=1′b1;
elseif(a==b)
eq=1′b1;
else
lt=1′b1;
end
endmodule
2)case語句
case語句的語法形式為
case(<expression>)
<condition1>:statement_sequence1
<condition2>:sequenceofstatement(s)
default:statement_sequence1
endcase
case語句是一種沒有優(yōu)先級的多路分支結(jié)構(gòu)。<expression>按照它們在case語句中的次序匹配不同的條件<conditon1>,<condition2>,…,<conditionN>,如果條件滿
足,則執(zhí)行的相應的語句序列;如果條件不滿足,則執(zhí)行default后面的語句序列。
case語句的行為類似于一個多路選擇器。
【例7-15】
用case語句實現(xiàn)一個四選一電路。
modulemux4_to_1(i0,i1,i2,i3,sel,out);
inputi0,i1,i2,i3;
input[1:0]sel;
outputout;regout;
always@(*)
case(sel)
2′d0:out=i0;
2′d1:out=i1;
2′d2:out=i2;
default:out=i3;
endcase
endmodule
除此之外,如果case語句中的條件(condition)包含了′z′和′x′,那么我們需要用case語句的另外兩種形式:casez和casex。在casex中把所有的x和z當成無關項;而在casez中把所有的z當成無關項,′z′也可以用′?′代替。在casez和casex語句中只把表達式和條件中的非-z和非-x位置的值進行比較。
【例7-16】casex和casez的使用。
casex(encoder)
4′b1xxx:high_lvl=3;
4′b01xx:high_lvl=2;
4′b001x:high_lvl=1;
4′b0001:high_lvl=0;
default:high_lvl=0;endcase
casez(encoder)
4′b1???:high_lvl=3;
4′b01??:high_lvl=2;
4′b001?:high_lvl=1;
4′b0001:high_lvl=0;
default:high_lvl=0;
endcase
上面的代碼完成一個編碼器。
5.循環(huán)語句
在Verilog語言中還提供了四種循環(huán)機制來描述電路的行為:While循環(huán)、Repeat循環(huán)、For循環(huán)以及Forever循環(huán)。循環(huán)的句法形式與C語言非常相似,它們只能用于initial塊和always塊中。
1)While循環(huán)
While語句的語法形式為
While(<expression>)
statement_sequence當<expressio
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024預應力管樁勞務分包合同
- 2025年度智能辦公空間場地租賃合作協(xié)議書4篇
- 專項水電維修分包合同書2024版范例版
- 二零二五年度文化產(chǎn)業(yè)代理注銷合作協(xié)議3篇
- 2024年04月廣州銀行白云支行2024年社會招考筆試歷年參考題庫附帶答案詳解
- 2025年度產(chǎn)學研合作項目資金支持及財務管理合同4篇
- 專業(yè)短駁貨物運輸協(xié)議示范文本版B版
- 2025年度廠房裝修項目環(huán)保評估與治理合同3篇
- 二零二五年度財務共享服務中心建設合同3篇
- 二零二五年度跨境電商供應鏈金融連帶責任擔保協(xié)議3篇
- ICU常見藥物課件
- CNAS實驗室評審不符合項整改報告
- 農(nóng)民工考勤表(模板)
- 承臺混凝土施工技術(shù)交底
- 臥床患者更換床單-軸線翻身
- 計量基礎知識培訓教材201309
- 中考英語 短文填詞、選詞填空練習
- 一汽集團及各合資公司組織架構(gòu)
- 阿特拉斯基本擰緊技術(shù)ppt課件
- 初一至初三數(shù)學全部知識點
- 新課程理念下的班主任工作藝術(shù)
評論
0/150
提交評論