verilog任務和函數(shù)課件例程_第1頁
verilog任務和函數(shù)課件例程_第2頁
verilog任務和函數(shù)課件例程_第3頁
verilog任務和函數(shù)課件例程_第4頁
verilog任務和函數(shù)課件例程_第5頁
已閱讀5頁,還剩61頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第七講

主要內(nèi)容:

Verilog任務

Verilog函數(shù)系統(tǒng)任務和函數(shù)7.1任務和函數(shù)在行為級設計中,經(jīng)常需要在程序的多個不同地方實現(xiàn)同樣的功能。這說明有必要把這些公共的局部提取出來,將其組成子程序,然后在需要的地方調(diào)用這些子程序,以防止重復編碼。絕大多數(shù)程序設計語言都提供了過程或子程序來到達這個目的。同樣,verilog語言提供的任務和函數(shù)可以將較大的行為級設方案分為較小的代碼段,允許verilog設計者將在多個地方位用的相同代碼提取出來,編寫成任務和函數(shù)。Verilog的任務及函數(shù)區(qū)別和聯(lián)系任務〔task)通常用于調(diào)試,或?qū)τ布M行行為描述可以包含時序控制〔#延遲,@,wait〕可以有input,output,和inout參數(shù)可以調(diào)用其他任務或函數(shù)函數(shù)(function)通常用于計算,或描述組合邏輯不能包含任何延遲;函數(shù)仿真時間為0只含有input參數(shù)并由函數(shù)名返回一個結(jié)果可以調(diào)用其他函數(shù),但不能調(diào)用任務區(qū)別任務和函數(shù)必須在module內(nèi)調(diào)用在任務和函數(shù)中不能聲明wire所有輸入/輸出都是局部存放器任務/函數(shù)執(zhí)行完成后才返回結(jié)果。例如,假設任務/函數(shù)中有forever語句,那么永遠不會返回結(jié)果共同點7.1Verilog任務“任務(task)”類似于其它編程語言中的“過程”。任務的使用包括任務定義和任務調(diào)用。任務既可表示組合邏輯又可表達時序邏輯,定義的形式如下task<任務名>;<端口及數(shù)據(jù)類型聲明語句>begin<語句1><語句2>.....<語句n>endendtask任務可以沒有或有一個或多個參數(shù)。值通過參數(shù)傳入和傳出任務。除輸入?yún)?shù)外〔參數(shù)從任務中接收值〕,任務還能帶有輸出參數(shù)〔從任務中返回值〕和輸入輸出參數(shù)。任務的定義在模塊說明局部中編寫。其中:關鍵詞task和endtask將它們之間的內(nèi)容標志成是一個任務定義。其中關鍵詞task標志著一個任務定義結(jié)構(gòu)的開端,其后的“<任務名>”是為被定義任務所取的一個名稱。在“<任務名>”后面不能出現(xiàn)輸入輸出端口列表。

“端口與類型說明”用于對任務各個端口的寬度和類型進行說明,其中端口類型由關鍵詞input,output和inout?(分別表示:輸入、輸出和雙向端口)指定,該說明語句的語法與進行模塊定義時的相應說明語句語法是一致的。

“局部變量說明”用來對任務內(nèi)用到的局部變量進行寬度和類型說明,這個說明語句的語法與進行模塊定義時的相應說明語句語法是一致的。由“begin”和“end”關鍵詞界定的一組行為語句指明了任務被調(diào)用時需要進行的操作。在任務被調(diào)用時,這些行為語句將按串行方式得到執(zhí)行。任務定義與“過程塊”、“連續(xù)賦值語句”及“函數(shù)定義”這三種成份以并列方式存在于行為描述模塊中,它們在層次級別上是相同的。任務定義結(jié)構(gòu)不能出現(xiàn)在任何一個過程塊的內(nèi)部。

【例7-1】任務的定義。taskread_mem;

//任務定義結(jié)構(gòu)的開頭,指定任務名為“read_mem”input[15:0]address; //輸入端口說明output[31:0]data; //輸出端口說明reg[3:0]counter; //局部變量說明reg[7:0]temp[1:4]; //局部變量說明begin //語句塊,指明任務被調(diào)用時需要進行的操作for(counter=1;counter<=4;counter=counter+1)temp[counter]=mem[address+counter-1];data={temp[1],temp[2],temp[3],temp[4]};endendtask//任務定義結(jié)構(gòu)的結(jié)尾

上例定義了一個名為“read_mem”的任務,該任務有一個16位的輸入端口“address”、一個32位的輸出端口“data”、一個4位的局部變量“counter”和一個8位的存儲器“temp”。當上例所定義的任務被調(diào)用時,begin和end中間的語句得到執(zhí)行,它們用來執(zhí)行對存儲器“mem”進行的四次讀操作,將其結(jié)果合并后輸出到端口“data”。在定義任務時必須注意如下幾點:(1)在第一行“task”語句中不能列出端口名列表。(2)在任務定義結(jié)構(gòu)中的“行為語句”局部可以有延時語句、敏感事件控制語句等時間控制語句出現(xiàn)。(3)一個任務可以沒有輸入、輸出和雙向端口,也可以有一個或多個輸入、輸出和雙向端口。(4)一個任務可以沒有返回值,也可以通過輸出端口或雙向端口返回一個或多個返回值。(5)在一個任務中可以調(diào)用其它的任務或函數(shù),也可以調(diào)用該任務本身。(6)在任務定義結(jié)構(gòu)內(nèi)不允許出現(xiàn)過程塊(initial或always過程塊)。(7)在任務定義結(jié)構(gòu)內(nèi)可以出現(xiàn)“disable中止語句”,這條語句的執(zhí)行將中斷正在執(zhí)行的任務。當任務被中斷后,程序流程將返回到調(diào)用任務的地方繼續(xù)向下執(zhí)行。2.任務的調(diào)用任務的調(diào)用是通過“任務調(diào)用語句”來實現(xiàn)的。任務調(diào)用語句的語法如下:<任務名>(端口1,端口2,……,端口n);其中,“(端口1,端口2,……,端口n)”組成了一個端口名列表。在調(diào)用任務時必須注意:(1)任務調(diào)用語句只能出現(xiàn)在過程塊內(nèi)。(2)任務調(diào)用語句就像一條普通的行為語句那樣得到處理。(3)當被調(diào)用的任務具有輸入或輸出端口時,任務調(diào)用語句必須包含端口名列表,這個列表內(nèi)各個端口名出現(xiàn)的順序和類型必須與任務定義結(jié)構(gòu)中端口說明局部的端口順序和類型相一致,注意只有存放器類的變量才能與任務的輸出端口相對應。例如,例7-2所示模塊對例7-1中定義的任務“read_mem”進行了調(diào)用?!纠?-2】對任務進行調(diào)用。moduledemo_task_invo;reg[7:0]mem[128:0];reg[15:0]a;reg[31:0]b;initialbegina=0;read_mem(a,b);//第一次調(diào)用#10;a=64;read_mem(a,b);//第二次調(diào)用end<任務“read_mem”定義局部>endmodule

在上面的模塊中,任務“read_mem”得到了兩次調(diào)用,由于這個任務在定義時說明了輸入端口和輸出端口,所以任務調(diào)用語句內(nèi)必須包含端口名列表“(a,b)”,其中變量a與任務的輸入端口“address”相對應,變量b與任務的輸出端口“data”相對應,并且這兩個變量在寬度上也是與對應的端口相一致的。這樣,在任務被調(diào)用執(zhí)行時,變量a的值通過輸入端口傳給了address;在任務調(diào)用完成后,輸出信號data又通過對應的端口傳給了變量b。任務的調(diào)用具有以下特點:(1)在任務內(nèi)定義的局部變量都具有局部和靜態(tài)的特點。也就是說,如果同時對同一任務進行兩次調(diào)用,那么兩個調(diào)用進程使用的將是相同物理地址處的同一個局部變量。在這種情況下要注意防止內(nèi)存使用沖突。(2)在一個任務中可以直接訪問上一級調(diào)用模塊中的任何存放器,例如上例中我們可以在任務“read_mem”中對存儲器變量mem進行訪問,這個mem變量是在上一級模塊(調(diào)用模塊)“demo_task_invo”中定義的。(3)由于任務內(nèi)部可以包含時間控制語句,所以調(diào)用執(zhí)行一個任務所需的時間可以是非零時間單位,也就是說任務啟動時刻可以是不同于任務結(jié)束時刻的。(4)可以通過一個disable語句來中斷任務的執(zhí)行。任務被中斷后,程序流程將返回到調(diào)用任務的地方繼續(xù)往下執(zhí)行。下面我們舉幾個例子說明任務的調(diào)用?!纠?-3】用任務來實現(xiàn)一個8位加法器。moduletask_example(a,b,c);input[7:0]a,b;output[7:0]c;reg[7:0]c;taskadder; //任務定義局部input[7:0]a,b;output[7:0]adder;regc; //此處的變量c是任務內(nèi)的局部變量integeri; //任務內(nèi)局部變量說明beginc=0; //?c存儲著上一位數(shù)字相加時的進位for(i=0;i<=7;i=i+1)beginadder[i]=a[i]^b[i]^c;//求一位數(shù)字相加的結(jié)果c=(a[i]&b[i])|(a[i]&c)|(b[i]&c);endendendtask //任務定義局部結(jié)束always@(aorb)adder(a,b,c); //任務調(diào)用語句endmodule上例所示的模塊由“任務定義局部”和“always過程塊”兩局部組成,其中定義的任務“adder”實現(xiàn)了一個8位加法器的運算功能,它有兩個輸入端口a和b,有一個輸出端口adder。在任務被調(diào)用時,模塊中的變量a,b,c分別和任務中的端口a,b,adder相互對應,這樣在任務執(zhí)行完畢后運算結(jié)果(即adder的值)可以通過輸出端口傳遞給變量c。要注意在模塊和任務內(nèi)都定義了變量“c”,它們是兩個不同的變量,在任務內(nèi)定義的局部變量只能在任務內(nèi)部使用。所以在這種情況下,出現(xiàn)在任務定義結(jié)構(gòu)內(nèi)的標識符“c”都代表局部變量,而在任務定義結(jié)構(gòu)外出現(xiàn)的“c”那么代表著模塊內(nèi)定義的變量c。下面是一個具體的、實現(xiàn)交通燈控制的例子,在該模塊中使用任務可以使程序簡潔易懂。

【例7-4】交通燈控制模塊。moduletraffic_lights;regclock,red,amber,green;parameteron=1,off=0,red_tics=350,amber_tics=30,green_tics=200;//交通燈初始化

initial red=off;initial amber=off;initial green=off;//交通燈控制時序alwaysbeginred=on; //開紅燈

light(red,red_tics); //調(diào)用等待任務

green=on; //開綠燈

light(green,green_tics); //等待

amber=on; //開黃燈

light(amber,amber_tics); //等待end//定義交通燈開啟時間的任務tasklight;outputcolor;input[31:0]tics;beginrepeat(tics)@(posedgeclock);//等待tics個時鐘的上升沿

color=off;//關燈

endendtask//產(chǎn)生時鐘脈沖的always塊alwaysbegin#100clock=0;#100clock=1;endendmodule任務舉例1modulealutask(code,a,b,c);input[1:0]code;input[3:0]a,b;output[4:0]c;reg[4:0]c;taskmy_and;//任務定義,注意無端口列表input[3:0]a,b;//a,b,out名稱的作用域范圍為task任務內(nèi)部output[4:0]out;integeri;beginfor(i=3;i>=0;i=i-1)out[i]=a[i]&b[i];//按位與endendtaskalways@(codeoraorb)begincase(code)2'b00:my_and(a,b,c);/*調(diào)用任務my_and,需注意端口列表的順序應與任務定義中的一致,這里的a,b,c分別對應任務定義中的a,b,out*/2'b01:c=a|b;//或2'b10:c=a-b;//相減2‘b11:c=a+b;//相加default:c=2’bx;endcaseendendmodule任務舉例2modulesort4(ra,rb,rc,rd,a,b,c,d);output[3:0]ra,rb,rc,rd;input[3:0]a,b,c,d;reg[3:0]ra,rb,rc,rd;reg[3:0]va,vb,vc,vd;always@(aorborcord)begin{va,vb,vc,vd}={a,b,c,d};sort2(va,vc);//va與vc互換。sort2(vb,vd);//vb與vd互換。sort2(va,vb);//va與vb互換。sort2(vc,vd);//vc與vd互換。sort2(vb,vc);//vb與vc互換。{ra,rb,rc,rd}={va,vb,vc,vd};endtasksort2;inout[3:0]x,y;reg[3:0]tmp;if(x>y)begintmp=x;//x與y變量的內(nèi)容互換,要求順序執(zhí)行,所以采用阻塞賦值方式。

x=y;y=tmp;endendtaskendmodule任務舉例3下面的任務中含有時序控制和一個輸入,并引用了一個module變量,但沒有輸出、輸入輸出和內(nèi)部變量,也不顯示任何結(jié)果。moduletop;regclk,a,b;DUTu1(out,a,b,clk);always#5clk=!clk;

taskneg_clocks;input[31:0]number_of_edges;repeat(number_of_edges)@(negedgeclk);

endtaskinitialbeginclk=0;a=1;b=1;

neg_clocks(3);//任務調(diào)用

a=0;neg_clocks(5);b=0;endendmodule時序控制中使用的信號〔例如ck〕一定不能作為任務的輸入,因為輸入值只向該任務傳送一次。任務舉例4下面的任務中有輸入,輸出,時序控制和一個內(nèi)部變量,并且引用了一個module變量。但沒有雙向端口,也沒有顯示。任務調(diào)用時的參數(shù)按任務定義的順序列出。modulemult(clk,a,b,out,en_mult);

inputclk,en_mult;

input[3:0]a,b;

output[7:0]out;

reg[7:0]out;

always

@(posedgeclk)multme(a,b,out);//任務調(diào)用

taskmultme;//任務定義

input[3:0]xme,tome;

output[7:0]result;

wait(en_mult)result=xme*tome;

endtaskendmodule歸納1.任務的定義與引用都在一個module模塊內(nèi)部2.任務的定義與module的定義有些類似,同樣需要進行端口說明與數(shù)據(jù)類型說明。另外,任務定義的內(nèi)部沒有過程塊,但在塊語句中可以包含定時控制局部。3.當任務被引用時,任務被激活。4.一個任務可以調(diào)用別的任務或函數(shù)。禁止命名塊和任務moduledo_arith(out,a,b,c,d,e,clk,en_mult);

inputclk,en_mult;input[7:0]a,b,c,d,e;

output[15:0]out;

reg[15:0]out;

always@(posedgeclk)begin:arith_block//***命名塊***

reg[3:0]tmp1,tmp2;//***局部變量***

{tmp1,tmp2}=f_or_and(a,b,c,d,e);//函數(shù)調(diào)用

if(en_mult)multme(tmp1,tmp2,out);//任務調(diào)用

endalways@(negedgeen_mult)begin//中止運算

disablemultme;//***禁止任務***

disable

arith_block;//***禁止命名塊***

end//下面[定義任務和函數(shù)

……endmodule禁止命名塊和任務disable語句終結(jié)一個命名塊或任務的所有活動。也就是說,在一個命名塊或任務中的所有語句執(zhí)行完之前就返回。語法:disable<塊名稱>或disable<任務名稱>當命名塊或任務被禁止時,所有因他們調(diào)度的事件將從事件隊列中去除disable是典型的不可綜合語句。在前面的例子中,只禁止命名塊也可以到達同樣的目的:所有由命名塊、任務及其中的函數(shù)調(diào)度的事件都被取消。任務的使用如果子程序滿足下面任何一個條件,那么必須使用任務而不能使用函數(shù)。1.子程序中包含有延遲,時序或者事件控制結(jié)構(gòu)2.沒有輸出或者輸出變量超過一個3.沒有輸入變量7.2Verilog函數(shù)函數(shù)(function)類似于其它編程語言中的函數(shù)概念。與任務一樣,VerilogHDL語言中的函數(shù)使用包括了函數(shù)的定義和函數(shù)的調(diào)用。

1.函數(shù)的定義函數(shù)定義的語法如下:function<返回值類型或返回值寬度><函數(shù)名>;<輸入端口說明><局部變量說明>begin<行為語句1;><行為語句2;>……<行為語句n;>endendfunction其中:關鍵詞function和endfunction表示這局部語句是一個函數(shù)定義結(jié)構(gòu),function語句標識著這個函數(shù)定義結(jié)構(gòu)的開頭;endfunction語句標識著函數(shù)定義結(jié)構(gòu)的結(jié)尾?!?lt;函數(shù)名>”是為被定義函數(shù)所取的一個名稱,對被定義函數(shù)的調(diào)用是通過這個函數(shù)名來進行的。這個函數(shù)名在函數(shù)定義結(jié)構(gòu)內(nèi)部還代表著一個內(nèi)部變量,函數(shù)調(diào)用后的返回值是通過這個函數(shù)名變量傳遞給調(diào)用語句(調(diào)用語句就是對函數(shù)進行了調(diào)用的語句)的?!?lt;返回值類型或返回值寬度>”是可選的,它用來對函數(shù)調(diào)用返回數(shù)據(jù)的類型或?qū)挾冗M行說明(這個數(shù)據(jù)是通過函數(shù)名返回的),它可以有如下三種形式:(1)“[msb:lsb]”:這種形式說明函數(shù)名所代表的返回數(shù)據(jù)變量是一個多位的存放器變量,它的位數(shù)由[msb:lsb]指定,比方如下函數(shù)定義語句:function[7:0]adder;就定義了一個函數(shù)“adder”,它的函數(shù)名“adder”還代表著一個8位寬的存放器變量,其最高位為第7位,最低位為第0位。(2)“integer”:這種形式說明函數(shù)名代表的返回變量是一個整數(shù)型變量。(3)“real”:這種形式說明函數(shù)名代表的返回變量是一個實數(shù)型變量。如果在函數(shù)的聲明語句中<返回值類型或返回值寬度>這一項缺省,那么認為函數(shù)名代表的變量是一個一位的存放器?!?lt;輸入端口說明>”用來對函數(shù)各個輸入端口的寬度和類型進行說明,在函數(shù)定義中必須至少有一個輸入端口;該輸入端口說明語句的語法與模塊定義時的輸入端口說明語句的語法是一致的。要注意在函數(shù)定義結(jié)構(gòu)中不允許出現(xiàn)任何輸出端口(output)和輸入/輸出端口(inout)?!?lt;局部變量說明>”是對函數(shù)內(nèi)部局部變量進行的寬度和類型說明?!靶袨檎Z句”局部由關鍵詞“begin”和“end”界定,這局部語句指明了函數(shù)被調(diào)用時要執(zhí)行的操作,它們決定著函數(shù)實現(xiàn)的運算功能。在函數(shù)被調(diào)用時,這些行為語句將按串行方式得到執(zhí)行。函數(shù)的主要特性函數(shù)定義中不能包含任何時序控制語句。函數(shù)至少有一個輸入,不能包含任何輸出或雙向端口。函數(shù)只返回一個數(shù)據(jù),其缺省為reg類型。傳送到函數(shù)的參數(shù)順序和函數(shù)輸入?yún)?shù)的說明順序相同。函數(shù)在模塊〔module)內(nèi)部定義。函數(shù)不能調(diào)用任務,但任務可以調(diào)用函數(shù)。雖然函數(shù)只返回單個值,但返回的值可以直接給信號連接賦值。這在需要有多個輸出時非常有效。{o1,o2,o3,o4}=f_or_and(a,b,c,d,e);

【例7-5】函數(shù)的定義。function[7:0]getbyte;

//函數(shù)定義結(jié)構(gòu)的開頭,注意此行中不能出現(xiàn)端口名列表input[63:0]word; //說明第一個輸入端口(輸入端口1)input[3:0]bytenum;//說明第二個輸入端口(輸入端口2)integerbit; //局部變量說明reg[7:0]temp; //局部變量說明beginfor(bit=0;bit<=7;bit=bit+1)temp[bit]=word[((bytenum-1)*8)+bit];//第一條行為語句getbyte=temp;

//第二條行為語句:將結(jié)果賦值給函數(shù)名變量getbyteendendfunction //函數(shù)定義結(jié)束上例定義了一個名為“getbyte”的函數(shù),該函數(shù)有兩個輸入端口:一個64位的輸入端口“word”和一個4位的輸入端口“bytenum”。同時該函數(shù)還定義了兩個局部變量bit(整數(shù)型變量)和temp(8位存放器變量)。上例所定義的函數(shù)被調(diào)用時,begin和end之間的行為語句局部得到執(zhí)行,其中第一條for循環(huán)語句實現(xiàn)了將64位存放器word的一局部位的值賦給變量temp,需要賦值的位由輸入bytenum指定。第二條賦值語句將得到的temp值賦給函數(shù)名變量“getbyte”。這樣就可以通過這個函數(shù)名變量將結(jié)果值返回給調(diào)用語句。在進行函數(shù)定義時必須注意:(1)與任務一樣,函數(shù)定義結(jié)構(gòu)只能出現(xiàn)在模塊中,而不能出現(xiàn)在過程塊內(nèi)。(2)函數(shù)至少必須有一個輸入端口。(3)函數(shù)不能有任何類型的輸出端口(output端口)和雙向端口(inout端口)。(4)在函數(shù)定義結(jié)構(gòu)中的行為語句局部內(nèi)不能出現(xiàn)任何類型的時間控制描述,也不允許使用disable終止語句。(5)與任務定義一樣,函數(shù)定義結(jié)構(gòu)內(nèi)部不能出現(xiàn)過程塊。(6)在一個函數(shù)內(nèi)可以對其它函數(shù)進行調(diào)用,但是函數(shù)不能調(diào)用其它任務。(7)在第一行“function”語句中不能出現(xiàn)端口名列表。function[7:0]get0;input[7:0]x;reg[7:0]count;integeri;begincount=0;for(i=0;i<=7;i=i+1)if(x[i]=1'b0)count=count+1;get0=count;endendfunction

2.函數(shù)的調(diào)用函數(shù)調(diào)用的格式如下:

<函數(shù)名>(<輸入表達式1>,<輸入表達式2>,……,<輸入表達式m>);其中,m個“<輸入表達式>”與函數(shù)定義結(jié)構(gòu)中說明的各個輸入端口一一對應,它們代表著各個輸入端口的輸入數(shù)據(jù)。這些輸入表達式的排列順序及類型必須與各個輸入端口在函數(shù)定義結(jié)構(gòu)中的排列順序及類型保持嚴格一致。在調(diào)用函數(shù)時必須注意如下兩點:(1)函數(shù)的調(diào)用不能單獨作為一條語句出現(xiàn),它只能作為一個操作數(shù)出現(xiàn)在調(diào)用語句內(nèi)。例如,下面這條語句對前面所定義的函數(shù)“getbyte”進行了調(diào)用:out=getbyte(input1,number);在這條調(diào)用語句中,函數(shù)調(diào)用局部“getbyte(input1,number)”被看作是一個操作數(shù),這個操作數(shù)的取值就是函數(shù)調(diào)用的返回值。在整個調(diào)用語句中,函數(shù)調(diào)用局部是作為“賦值表達式”出現(xiàn)在整條過程賦值語句中的,函數(shù)調(diào)用局部不能單獨地作為一條語句出現(xiàn),這就是說語句“getbyte(input1,number);”是非法的。(2)函數(shù)調(diào)用既能出現(xiàn)在過程塊中,也能出現(xiàn)在assign連續(xù)賦值語句中。比方語句:wire[7:0]net1;reg[63:0]input1;assignnet1=getbyte(input1,3);中的函數(shù)調(diào)用就出現(xiàn)在一條連續(xù)賦值語句內(nèi),這條語句指定由函數(shù)調(diào)用返回值對8位連線型變量net1進行連續(xù)驅(qū)動。進行函數(shù)調(diào)用后,上述函數(shù)調(diào)用格式中的函數(shù)名將代表返回值參與調(diào)用語句(對函數(shù)進行調(diào)用的語句)的執(zhí)行。舉例來說,對上面定義的函數(shù)“getbyte”進行調(diào)用的模塊可以是例7-20所示的模塊:【例7-6】函數(shù)的調(diào)用。moduledemo_function_call;reg[7:0]call_output;reg[63:0]input1;reg[3:0]input2;initialbegininput1=64'h123456789abcdef0;input2=3;call_output=getbyte(input1,input2); //第一次調(diào)用$display("afterthefirstcall,thereturnedvalueis:%b",call_output);#100;$display(“secondcall,returnvalue:%b”,getbyte(input1,6)); //第二次調(diào)用end<函數(shù)getbyte定義局部>endmodule上例模塊中的initial過程塊對函數(shù)“getbyte”進行了兩次調(diào)用:函數(shù)getbyte的第一次調(diào)用是作為過程賦值語句“call_output=getbyte(input1,input2);”右端的賦值表達式出現(xiàn)的,調(diào)用時的輸入表達式分別為兩個存放器變量input1和input2,它們將與函數(shù)定義結(jié)構(gòu)中的第一個和第二個輸入端口相對應,因此這兩個存放器變量的取值將分別被傳遞給函數(shù)輸入端口“word”和“bytenum”。函數(shù)調(diào)用完成后,過程賦值語句中的“getbyte”將具有函數(shù)調(diào)用的返回值,這個返回值將作為“賦值表達式”參與對變量call_output進行的過程賦值操作。函數(shù)getbyte的第二次調(diào)用是作為系統(tǒng)任務$display語句內(nèi)的“輸出變量表項”出現(xiàn)的,調(diào)用時的輸入表達式分別是一個存放器變量“input1”和一個常數(shù)“6”,它們的值將被分別被傳遞給函數(shù)定義中的兩個輸入端口“word”和“bytenum”。函數(shù)調(diào)用完成后,$display語句中的“getbyte”將具有函數(shù)調(diào)用的返回值,這個返回值將作為“輸出變量表項”參與$display語句的執(zhí)行。由以上所給出的函數(shù)定義和函數(shù)調(diào)用的例子可以看出,在函數(shù)定義中必須有一條賦值語句來對函數(shù)名變量進行賦值,這樣才能通過這個函數(shù)名變量來將函數(shù)調(diào)用的結(jié)果(返回值)傳遞給調(diào)用語句。在例7-5給出的函數(shù)定義中,語句“getbyte=temp;”就是這么一條賦值語句,它將函數(shù)調(diào)用的運算結(jié)果(變量temp的取值)賦值給函數(shù)名變量getbyte。函數(shù)的每一次調(diào)用只能通過函數(shù)名變量返回一個值。在有些時候我們要求一次函數(shù)調(diào)用能返回多個值,可以通過在函數(shù)定義和函數(shù)調(diào)用中使用合并操作符“{”、“}”來解決這一問題。

【例7-7】由一個函數(shù)返回多個值的方法。moduledemo_multiout_function;reg[7:0]a,b,c,d;initialbegina=8'h54;b=8'h32;{c,d}=multiout_fun(a,b);

//語句S1,進行了函數(shù)調(diào)用的過程賦值語句$display("thevalueofcis:%hdis:%h",c,d);endfunction[15:0]multiout_fun;input[7:0]in1,in2;reg[7:0]out1;reg[7:0]out2;beginout1=in1&in2;out2=in1|in2;multiout_fun={out1,out2};

//語句S2,對函數(shù)名變量進行賦值endendfunctionendmodule

上例中定義了一個函數(shù)multi_fun,我們想從這個函數(shù)中同時得到兩個返回值out1和out2,由于函數(shù)調(diào)用時只能由函數(shù)名返回一個值,因此out1和out2的取值不可能同時獨立地被返回,但是可以借助于合并操作符“{,}”來實現(xiàn)多個輸出值的同時輸出:在函數(shù)定義內(nèi),語句S2通過合并操作符把兩個輸出值out1和out2合并成一個值并將它賦值給函數(shù)名變量“multiout_fun”。這樣,雖然函數(shù)在形式上還是只有multiout_fun變量這一個返回值,但是在這個返回值內(nèi)實際上包含了兩個輸出數(shù)據(jù)。在對函數(shù)進行了調(diào)用的過程賦值語句S1中,函數(shù)調(diào)用返回值“multiout_fun”被賦值給由兩個變量c和d組合而成的一個合并變量。這樣,在執(zhí)行了賦值語句S1后,函數(shù)調(diào)用返回值“multiout_fun”中所包含的兩局部輸出值將分別被賦值給變量c和d,這樣也就是實現(xiàn)了將函數(shù)輸出out1和out2的值分別傳遞給變量c和d。在使用函數(shù)時必須注意:由于在函數(shù)定義結(jié)構(gòu)中不能出現(xiàn)任何類型的時間控制語句,所以函數(shù)調(diào)用執(zhí)行所需的時間只能是零仿真時間,也就是說,函數(shù)調(diào)用啟動時刻和函數(shù)調(diào)用返回時刻是相同的。

函數(shù)中不能有時序控制,但調(diào)用它的過程可以有時序控制。函數(shù)名f_or_and在函數(shù)中作為register使用moduleorand(a,b,c,d,e,out);input[7:0]a,b,c,d,e;output[7:0]out;reg[7:0]out;always

@(aorborcordore)out=f_or_and(a,b,c,d,e);//函數(shù)調(diào)用

function[7:0]f_or_and;

input[7:0]a,b,c,d,e;

if(e==1)f_or_and=(a|b)&(c|d);

elsef_or_and=0;

endfunctionendmodule函數(shù)返回值可以聲明為其它register類型:integer,real,或time。在任何表達式中都可調(diào)用函數(shù)modulechecksub(neg,a,b);

outputneg;

regneg;

inputa,b;

function

integer

subtr;

input

[7:0]in_a,in_b;

subtr

=in_a-in_b;//結(jié)果可能為負

endfunction

always

@(aorb)

if(subtr(a,b)<0)neg=1;

elseneg=0;endmodule從函數(shù)返回的值函數(shù)的定義蘊含聲明了與函數(shù)同名的、函數(shù)內(nèi)部的存放器。如在函數(shù)的聲明語句中<返回值的類型或范圍>為缺省,那么這個存放器是一位的,否那么是與函數(shù)定義中<返回值的類型或范圍>一致的存放器。函數(shù)的定義把函數(shù)返回值所賦值存放器的名稱初始化為與函數(shù)同名的內(nèi)部變量。通過對兩次調(diào)用函數(shù)getbyte的結(jié)果值進行位拼接運算來生成一個字。word=control?{getbyte(msbyte),getbyte(lsbyte)}:0;

【例7-8】乘加器。`timescale1ns/10psmodulemult_acc(out,ina,inb,clk,clr);input[7:0]ina,inb;inputclk,clr;output[15:0]out;wire[15:0]mult_out,adder_out;reg[15:0]out;parameterset=10;parameterhld=20;assignadder_out=mult_out+out;//描述了加法器assignmult_out=mult(ina,inb);

//進行了函數(shù)調(diào)用,實現(xiàn)了乘法器always@(posedgeclkorposedgeclr) //描述了時序邏輯,實現(xiàn)清零功能及輸出鎖存beginif(clr)out=16'h0000;elseout=adder_out;endfunction[15:0]mult;//函數(shù)定義局部input[7:0]a,b;reg[15:0]r;integeri;beginif(a[0]==1)r=b;elser=0;for(i=1;

i<=7;

i=i+1)beginif(a[i]==1)r=r+b<<i;endmult=r;endendfunctionendmodule圖7.2乘加器結(jié)構(gòu)上例所示模塊由兩條連續(xù)賦值語句、always過程塊、函數(shù)定義和延時說明塊等幾局部組成。其中:第一條連續(xù)賦值語句描述了一個加法器,其輸入端為multi_out和out,輸出端為adder_out。第二條連續(xù)賦值語句通過對函數(shù)mult的調(diào)用實現(xiàn)了一個乘法器,其輸入端為ina和inb,輸出端為mult_out,其中的函數(shù)調(diào)用實現(xiàn)了乘法運算功能。always過程塊對乘法器的時序邏輯進行了描述,實現(xiàn)了異步清零和輸出數(shù)據(jù)鎖存功能,每當清零信號clr變?yōu)楦唠娖骄瓦M入清零操作狀態(tài),對輸出鎖存器進行清零操作;在正常工作狀態(tài)下輸出鎖存器將在時鐘clk的每個上升沿得到刷新。函數(shù)定義局部對函數(shù)mult進行了定義,該函數(shù)實現(xiàn)了一個8位乘法運算功能,它有兩個輸入變量a和b,返回一個16位的運算結(jié)果。用函數(shù)和case語句描述的編碼器〔不含優(yōu)先順序〕modulecode_83(din,dout);input[7:0]din;output[2:0]dout;function[2:0]code;//函數(shù)定義input[7:0]din;//函數(shù)只有輸入,輸出為函數(shù)名本身casex(din)8'b1xxx_xxxx:code=3'h7;8'b01xx_xxxx:code=3'h6;8'b001x_xxxx:code=3'h5;8'b0001_xxxx:code=3'h4;8'b0000_1xxx:code=3'h

溫馨提示

  • 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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論