verilog語法實例學習(6)


函數和任務

函數

https://wenku.baidu.com/view/d31d1ba8dd3383c4bb4cd283.html

verilog中函數的目的是允許代碼寫成模塊的方式而不是定義獨立的模塊。函數通常用於計算或描述組合邏輯。如果在模塊內定義一個函數,則既可以用連續賦值語句,也可以用過程賦值語句調用。函數可以有不只一個輸入,但只能有一個輸出,因為函數名本身就充當輸出變量

verilog中函數還有以下幾個特點:

1.函數必須在module塊內調用。

2.函數內不能聲明wire,所有輸入輸出都是局部寄存器(reg, integer)

3.函數執行完成后,才返回結果。

4.函數內不能包含任何時序控制語句

5.函數內部可以調用其它函數,但不能調用任務。

函數的定義如下:

function [range|integer] function_name; //返回值類型和寬度,函數名

[input declaration]  //輸入端口說明

[parameter, reg, integer declaration]  //局部變量或常量聲明

begin

  statement; //行為語句

end

endfunction

下面是一個16選1電路模塊代碼,代碼中使用了函數。

//16選1電路,演示function的用法
module function1(W,S16,f);
   input [15:0] W;
	input [3:0] S16;
	output reg f;
	reg [3:0] M;

	function mux4to1;
	  input [3:0] W;
	  input [1:0] S;

	  if(S==2'b00) mux4to1 = W[0];
	  else if(S==2'b01) mux4to1 = W[1];
	  else if(S==2'b10) mux4to1 = W[2];
	  else if(S==2'b11) mux4to1 = W[3];
	endfunction

   always @(W,S16)
   begin
	   M[0] = mux4to1(W[3:0],S16[1:0]);
		M[1] = mux4to1(W[7:4],S16[1:0]);
		M[2] = mux4to1(W[11:8],S16[1:0]);
		M[3] = mux4to1(W[15:12],S16[1:0]);
		f = mux4to1(M[3:0],S16[3:2]);
   end

endmodule
`timescale 1ns/1ns
`define clock_period 20

module function1_tb;

  reg clk;
  reg [15:0] W;
  reg [3:0]  S;
  wire f;

  function1 function1_0(.W(W),.S16(S),.f(f));
  always #(`clock_period/2) clk=~clk;
  initial
  begin
    clk = 1'b0;
	 W = 16'b1011_1100_1001_0110;
	 S = 4'b0000;
	 #(`clock_period)
	 S = 4'b0001;
	 #(`clock_period)
	 S = 4'b0010;
	 #(`clock_period)
	 S = 4'b0011;
	 #(`clock_period)
	 S = 4'b0100;
	 #(`clock_period)
	 S = 4'b0101;
	 #(`clock_period)
	 S = 4'b0110;
	 #(`clock_period)
	 S = 4'b0111;
	 #(`clock_period)
	 S = 4'b1000;
	 #(`clock_period)
	 S = 4'b1001;
	 #(`clock_period)
	 S = 4'b1010;
	 #(`clock_period)
	 S = 4'b1011;
	 #(`clock_period)
	 S = 4'b1100;
	 #(`clock_period)
	 S = 4'b1101;
	 #(`clock_period)
	 S = 4'b1110;
	 #(`clock_period)
	 S = 4'b1111;
	 #(`clock_period)
    $stop;
  end


endmodule


image


任務

任務具有輸入輸出變量,但沒有返回值,更像一個模塊。任務具有以下特點

1.任務只能自always(initial)塊內調用

2.任務可以具有任意個輸入、輸出以及雙向端口(包括0個)。

3.在任務中可以使用延時、事件和時序控制結構,可以自定義時鍾。

4.任務中可以調用其它函數和任務。

5.任務中不能出現過程塊(always, initial)。

任務的定義;

task <任務名>;

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

  <語句1>

  ...

  <語句n>

endtask

下面是用task實現16選1模塊的代碼。

//16選1電路,演示task的用法
module task1(W,S16,f);
   input [15:0] W;
	input [3:0] S16;
	output reg f;
	reg [3:0] M;

	task mux4to1;
	  input [3:0] W;
	  input [1:0] S;
	  output Result;

	  if(S==2'b00) Result = W[0];
	  else if(S==2'b01) Result = W[1];
	  else if(S==2'b10) Result = W[2];
	  else if(S==2'b11) Result = W[3];
	endtask

   always @(W,S16)
   begin
	   mux4to1(W[3:0],S16[1:0],M[0]);
		mux4to1(W[7:4],S16[1:0],M[1]);
		mux4to1(W[11:8],S16[1:0],M[2]);
		mux4to1(W[15:12],S16[1:0],M[3]);
		mux4to1(M[3:0],S16[3:2],f);
   end

endmodule
`timescale 1ns/1ns
`define clock_period 20

module task1_tb;

  reg clk;
  reg [15:0] W;
  reg [3:0]  S;
  wire f;

  task1 task1_0(.W(W),.S16(S),.f(f));
  always #(`clock_period/2) clk=~clk;
  initial
  begin
    clk = 1'b0;
	 W = 16'b1011_1100_1001_0110;
	 S = 4'b0000;
	 #(`clock_period)
	 S = 4'b0001;
	 #(`clock_period)
	 S = 4'b0010;
	 #(`clock_period)
	 S = 4'b0011;
	 #(`clock_period)
	 S = 4'b0100;
	 #(`clock_period)
	 S = 4'b0101;
	 #(`clock_period)
	 S = 4'b0110;
	 #(`clock_period)
	 S = 4'b0111;
	 #(`clock_period)
	 S = 4'b1000;
	 #(`clock_period)
	 S = 4'b1001;
	 #(`clock_period)
	 S = 4'b1010;
	 #(`clock_period)
	 S = 4'b1011;
	 #(`clock_period)
	 S = 4'b1100;
	 #(`clock_period)
	 S = 4'b1101;
	 #(`clock_period)
	 S = 4'b1110;
	 #(`clock_period)
	 S = 4'b1111;
	 #(`clock_period)
    $stop;
  end


endmodule

image

      函數和任務對於設計verilog代碼不重要,但可以大大方便模塊化設計。使用函數和任務的一個好處是它們可以從一個always塊中調用,而這些塊中不允許包含例化語句。隨着代碼量的增多,verilog的這些特點顯得尤其重要。

系統函數和任務總結

為了仿真控制和對仿真結果進行比較,verilog中提供了大量的系統功能調用。這些調用分為兩類:系統任務和系統函數

verilog中系統函數和系統任務都是以$開頭的標識符。一般在initial和always語句中調用系統函數和系統任務。

系統函數和系統任務的主要區別:

系統任務可以沒有返回值或者有多個返回值,系統函數只有一個返回值;系統任務可以帶延遲,而系統函數不可以,在0時刻立即執行

依照功能不同,可以分為以下幾類:

顯示任務

$display 和 $write 任務

格式:

$display (<format>,signal0,signal1,…);

$write ((<format>,signal0,signal0,…);

     這兩個系統任務作用是用來輸出信息,format是雙引號括起來的字符串,用來定義后面要顯示信號的顯示格式,后面是逗號隔開的若干個信號。這兩個任務語法和c語言的printf函數很相似

     這兩個系統任務的區別:$display自動的在輸出后進行換行,而$write不會自動換行

format可以包含以下兩種信息:

1)格式說明,由“%”和格式字符組成。它的作用是將輸出的數據轉換成指定的格式輸出。格式說明總是從%開始的。常見的幾種輸出格式

輸出格式 說明 輸出格式 說明
%h或%H 以十六進制形式輸出 %d或%D 以十進制形式輸出
%o或%O 以八進制形式輸出 %b或%B 以二進制形式輸出
%c或%C 以ASCII碼形式輸出 %v或%V 輸出網格型數據信號輕度
%m或%M 輸出等級層次名字 %s或%S 以字符串的形式輸出
%e或%E 以指數形式輸出實型數 %f或%F 以十進制的形式輸出實型數
%g或%G

以指數或者十進制數輸出實型數,但是

無論何種格式都以較短的結果輸出

%t或%T 輸出當前的時間格式

2)普通字符,即需要原樣輸出的字符。其中一些特殊的字符可以通過轉換序列來輸出:

換碼序列 功能 換碼序列 功能
\n 換行 \'' 雙引號字符"
\t 橫向跳格 \o 1-3位八進制數代表的字符
\\ 反斜杠字符 %% 百分符號%

下面是代碼示例:

`timescale 1ns/1ns
`define clock_period 20

module vdisplay_tb;

   reg [7:0] a;
   reg [31:0] b;
   reg [15:0] c;

   initial
   begin
	   a = 8'b00101010;
	   b = 32'h12345678;
	   c = 16'hf01f;
	   #(`clock_period);
	   //normal char
	   $display("hello word,");
	   $display(" gkd");
	   $write("hello word,");
	   $write(" gkd");
	   //display simulation time
	   $display("\nsim time is %d",$time);
	   $display("hex: a=%h, oct: a=%o, bin: a=%b",a, a, a);
	   $display("hex: a=%h, oct: a=%o, bin: a=%0b",a, a, a);//not show high bits 0
	   $display("\\\t%%\n\"\123\"");
	   #(`clock_period);
	   $finish;

   end

endmodule

Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 10:25 2019
hello word,
  gkd
hello word, gkd
sim time is                   20
hex: a=2a, oct: a=052, bin: a=00101010
hex: a=2a, oct: a=052, bin: a=101010
\       %
"S"

$finish called from file "vdisplay.v", line 27.

如果在輸出列表中表達式的值包含不確定的值或高阻值,其結果遵循以下規則:

輸出為十進制的情況下:

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

b)如果表達式中所有的位均為高阻值,則輸出結果為小寫的z;

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

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

輸出為十六進制和八進制的情況下:

a)每4位二進制數為一組代表一位十六進制數,每3位二進制數為一組代表一位八進制數。

b)如果表達式值相對應的某進制的所有位均為不定值,則輸出為小寫的x;

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

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

e)如果表達式值相對性的某進制數的部分位位高阻值,則該位輸出的結果為大寫的Z;

3)對於二進制的情況:表達式的值每一位的輸出結果都用0,1,x,z表示。

verilog中還有幾種標准輸出格式,用來輸出固定格式:

$displayb/$writeb  //輸出2進制格式

$displayo/$writeo //輸出8進制格式

$displayh/$writeh //輸出16進制格式

%m用來輸出module的層次結構,比如下面的代碼:


`timescale 1ns/1ns
`define clock_period 20

module test;
  initial
    $display("displaying in %m");
endmodule
module vtop_tb;

   test test1();
   test test2();
   test test3();
   initial
   begin
	   #(`clock_period);
	   $finish;

   end

endmodule


Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 10:40 2019
displaying in vtop_tb.test1
displaying in vtop_tb.test2
displaying in vtop_tb.test3

$finish called from file "vtop.v", line 16.

探測任務

     $strobe屬於探測監控任務,用來在某時刻所有的事件都執行完畢后,在時間步的末尾將數據輸出。更多用來顯示用非阻塞賦值的變量的值。

     探測任務和顯示任務的區別是,顯示任務遇到語句開始執行,而探測任務要等到時間步的末尾才執行

代碼示例:

`timescale 1ns/1ns
`define clock_period 20

module vtrobe_tb;
   reg [7:0] a;
   reg [7:0] b;

   initial
   begin
	   a = 8'b01010101;
	   $strobe("strobe,a = %b",a);
	   $display("display,a = %b",a);
	   a = 8'b11110000;
	   #(`clock_period*2);
	   $finish;
   end
   initial
   begin
      b <= 8'h11;
      $strobe("strobe,b = %b",b);
      $display("display1,b = %b",b);
      #(`clock_period);
      $strobe("strobe,b = %b",b);
      $display("display2,b = %b",b);
      b <= 8'h22;
   end

endmodule

注意以下的輸出順序:

Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 10:54 2019
display,a = 01010101
display1,b = xxxxxxxx
strobe,b = 00010001
strobe,a = 11110000
display2,b = 00010001
strobe,b = 00100010

$finish called from file "vstrobe.v", line 15

監控任務

      $monitor, 一旦調用后,將隨時對輸出變量名表項中列出的各個變量進行監控,如果其中任何一個發生變化,就會啟動$monitor任務,在時間步結束時候,按既定的格式輸出所有變量。如果在同一時刻,多個變量或表達式發生變化,則該時刻只輸出顯示一次。可以通過$monitoron,$monitoroff打開和關閉監控任務。在多模塊調試時,可以有多個模塊調用$monitor,但任意時刻只有一個monitor被啟動。缺省狀態下,監控任務是打開的。

代碼示例:

`timescale 1ns/1ns
`define clock_period 20

module vmonitor_tb;
   integer a, b;
   initial
   begin
	   a = 2;
	   b = 4;
	   forever begin
		   #(`clock_period) a = a + b;
		   #(`clock_period) b = a - 1;
	   end

   end
   initial
   begin
     $monitor($time," a=%d,b=%d",a,b);
   end
   initial
   begin
	   #(`clock_period*10)
	   $finish;
   end

endmodule




Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 13:22 2019
                    0 a=          2,b=          4
                   20 a=          6,b=          4
                   40 a=          6,b=          5
                   60 a=         11,b=          5
                   80 a=         11,b=         10
                  100 a=         21,b=         10
                  120 a=         21,b=         20
                  140 a=         41,b=         20
                  160 a=         41,b=         40
                  180 a=         81,b=         40

$finish called from file "vmonitor.v", line 23.

控制類系統任務

格式:$finish;$finish(n);

系統任務$finish的作用是退出仿真器,返回主操作系統,也就是結束仿真過程。根據參數的值輸出不同的特征信息。如果不帶參數,默認其值為1

格式:$stop;$stop(n);

$stop任務的作用是將EDA工具設置為暫停模式,在仿真環境下給出一個交互式的命令,將控制權交給用戶。

n的取值如下:

0 不輸出任何信息。

1 輸出當前的仿真時間和模擬文件的位置;

2 輸出當前的仿真時間、模擬文件位置和仿真過程中所用memory和CPU的時間統計。


代碼例子:

`timescale 1ns/1ns
`define clock_period 20

module vfinish_tb;
   initial
   begin
	   #(`clock_period*10)
	   $display("time = %d",$time);
	   $stop;
	   #(`clock_period*10)
	   $finish;
   end

endmodule


比如上面代碼用vcs編譯后,運行simv,程序將暫停在ucli界面,我們輸入quit,則退出simulation。

Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 13:44 2019
time =                  200
$stop at time 200 Scope: vfinish_tb File: vfinish.v Line: 9
ucli%
ucli% quit
            V C S   S i m u l a t i o n   R e p o r t
Time: 200 ns
CPU Time:      0.560 seconds;       Data structure size:   0.0Mb
Thu Jan  3 13:44:57 2019

仿真時間

在Verilog HDL中有兩類型的時間系統函數,$time和$realtime。用這兩個系統函數可以得到當前的仿真時間。

$time可以返回一個64位的整數來表示當前仿真時刻值,該時刻是以模塊的仿真時間尺度為基准的。

$realtime返回的時間數字是一個實型數。該數也是以時間尺度為基准的。

`timescale 1ns/1ns
`define clock_period 20

module vtime_tb;
   integer i;
   initial
   begin
	   $monitor("time = %d,%f, i=%d",$time,$realtime,i);
	   #(2.6)
	   i = 0;
	   #(3.2)
	   i = 1;
	   #(4.6)
	   i = 3;
	   #(1)
	   $finish;
   end

endmodule
輸出結果為:

Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 14:07 2019
time =                    0,0.000000, i=          x
time =                    3,3.000000, i=          0
time =                    6,6.000000, i=          1
time =                   11,11.000000, i=          3

$finish called from file "vtime.v", line 16.

修改`timescale 為 1ns/100ps,則realtime時間單位可以精確到0.1ns

Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Jan  3 14:10 2019
time =                    0,0.000000, i=          x
time =                    3,2.600000, i=          0
time =                    6,5.800000, i=          1
time =                   10,10.400000, i=          3

$finish called from file "vtime.v", line 16.

系統任務$random(隨機函數)

這個系統函數提供了一個產生隨機數的手段。當函數被調用時返回一個32位的隨機數。這是一個帶符號的整型數。

$random的一般用法是:$random%b,其中b>0.他給出了一個范圍在(-b+1):(b-1)中的隨機數。下面給出例子:

reg [23:0]rand;

rand=$random%60;            //生成-59~59之間的隨機數

rand={$random}%60;       //生成0~59之間的隨機數

通常我們在testbench當中,用$random來產生隨機激勵。

文件輸入輸出任務

1)打開文件:

文件可以用系統任務$fopen打開,用法:

文件句柄=$fopen("文件名",mode);//mode可以省略

      任務$fopen返回一個被稱作多通道描述符(multichannel descriptor)的32位值。mode為w/w+/a/a+。

      w:打開文件並從文件頭開始寫,文件不存在,則創建文件。

     w+:打開文件並從文件頭開始讀寫,文件不存在,則創建文件。

      a:打開文件並從文件尾開始寫,文件不存在,則創建文件。

     a+:打開文件並從文件尾開始讀寫,文件不存在,則創建文件。

2)寫文件:

監控,顯示,寫入,探測任務都有相應的寫文件版本,$fmonitor,$fdisplay、$fwrite,$strobe等。用法:

$fdisplay(文件描述符,p1,p2,..pn)

$fmonitor(文件描述符,p1,p2,...pn)

p1,p2,…pn可以是變量,信號名或者帶引號的字符串。文件描述符是一個多通道描述符,他可以是一個文件句柄或者多個文件句柄的按位組合。Verilog會把輸出寫到與文件描述符中值為1 的文件中。

3)關閉文件

文件可以用系統任務$fclose來關閉。用法:

$fclose(文件描述符);  如:$fclose(handle1);文件一旦被關閉,多通道描述符中的相應位被設置為0,下一次的fopen的調用可以重用這一位


系統任務$readmemb $readmemh

在Verilog中有兩個系統任務$readmemb和$readmemh,並用來從文件中讀取數據到存儲器中。這兩個系統任務可以在仿真的任何時刻都被執行使用。

(1)$readmemb("<數據文件名>",<存儲器名>);

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

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

(4)$readmemh("<數據文件名>",<存儲器名>);

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

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

在這兩個系統函數中,被讀取的數據文件的內容只能包括:空白字符(空格換行和制表格) 注釋行(//和/**/) 二進制和十六進制數字。當地址出現在數據文件中時,其格式為@FF...F。

在上面6種系統任務格式,需補充說明一下幾點:

(1)如果系統任務和數據文件都沒有說明地址。則從默認的存儲器地址開始寫入數據,直至數據寫完或者存儲器存滿。

(2)如果系統任務說明了起始地址,沒有說明結束地址,則數據從起始地址開始存放,直至存儲器的結束地址為止。

(3)如果系統任務說明了起始地址和結束地址。那么久按章任務說明中的地址進行存儲,不考慮存儲器的默認起始地址。

(4)如果系統任務和數據文件都說明了地址。那么數據文件中的地址說明必須包含在任務地址說明語句中,否則將出現錯誤信息,並且停止存儲。

(5)如果數據文件中的數據個數和系統任務中起始地址和結束地址暗示的數據個數不同,也會報錯。

verilog文件讀寫的例子參照:

https://www.cnblogs.com/mikewolf2002/p/10158575.html

值變存儲文件

  $dumpfile(“dump.vcd”); //把信號寫入vcd格式波形文件dump.vcd

  $dumpvars;   //沒有參數dump所有信號

  $dumpvars(level,start_module); //要記錄的信號,level=0表示記錄所有信號

  $dumpflush; //將VCD數據保存到磁盤

  $dumpoff; //停止記錄

  $dumpon; //重新開始記錄

  $dumplimit(size); //限制VCD文件的大小(以字節為單位)

  $dumpall;  //記錄所有指定的信號值

下面的示例代碼,將會把所有的信號dump到dump.vcd文件中。

module adder4(cout, sum, ina, inb, cin,clk);
output [3:0] sum;
output cout;
input [3:0] ina, inb;
input cin,clk;
reg[3:0] tempa, tempb, sum;
reg cout;
reg tempc;

always @(posedge clk)
begin
	tempa = ina;
	tempb = inb;
	tempc = cin;
end

always @(posedge clk)
begin
 {cout, sum} = tempa+ tempb + tempc;
end
endmodule


`timescale 1ns/10ps
`include "adder4.v"

module adder_tp;
reg[3:0] ina,inb;
reg cin;
reg clk = 0;
wire[3:0] sum;
wire cout;

always #10 clk =~ clk;

initial
begin
	ina=0;
	repeat(20)
	#20 ina = $random;
end

initial
begin
	inb=0;
	repeat(10)
	#40 inb = $random;
end

initial
begin
	cin=0;
	repeat(2)
	#200 cin = {$random} % 16;
end

adder4 adder_te(
	       .clk(clk),
	       .sum(sum),
	       .cout(cout),
	       .ina(ina),
	       .inb(inb),
	       .cin(cin)
       );
initial
begin
	$monitor($time,,,"%b + %b + %b = {%b,%b}", ina, inb, cin,cout,sum);
	#400 $finish;
end

initial
begin
	 $dumpfile("dump.vcd");
	 $dumpvars;
end
endmodule




編譯指令

     Verilog HDL語言和C語言一樣也提供編譯預處理的功能。在Verilog中為了和一般的語句相區別,這些預處理語句以符號"`"開頭,注意,這個字符位於主鍵盤的左上角,其對應的上鍵盤字符為"~",這個符號並不是單引號"'".這里簡單介紹最常用的`define `include `timescale.

1)宏定義`define

用一個指定的標識符(名字)來代表一個字符串,其的一般形式為: `define 標識符(宏名) 字符串(宏內容) 如:`define  SIGNAL string

其作用是在后面程序中用SIGNAL替代所有的string字符串,在編譯預處理時,將程序中該命令后面所有的SIGNAL替換為string。這種替代過程稱作宏展開。

說明:

a)宏名可以是大寫字母,也可以是小寫字母。一般用大寫字母,防止與后面的變量名重復。

b)`define可以出現在模塊定義里面,也可以出現在外邊。其有效范圍是從該命令行開始至源文件結束。

c)在引用已定義的宏名時,必須在宏名的前面加上符號`,表示該名字是一個經過宏定義的名字。

d)宏定義是用宏名代替一個字符串,只做簡單替換不檢查語法。

e)宏定義不是Verilog HDL語句,不必在后面加分號。

f)在進行宏定義時,可以引用已經定義的宏名,可以層層替換。

g)宏名和宏內容必須在同一行進行聲明。如果在宏內容中包含有注釋行,注釋行不會作為被置換的內容。

注意:組成宏內容的字符串不能夠被以下的語句記號分隔開。注釋行+數字+字符串+確認符+關鍵詞+雙目或三目運算符

如下面的宏定義聲明和引用就是非法的:

`define first_half "start of string

$display(`first_half end of string")

2)文件包含處理`include

所謂文件包含是指處理一個源文件可以將另一個源文件的全部內容包含進來,即將另外文件包含到本文件之中。一般格式為: `include"文件名"

在執行命令時,將被包含文件的全部內容復制插入到`include命令出現的地方,然后繼續進行下一步的編譯。關於文件包含的幾點說明:

1)一個文件包含命令只能制定一個被包含的文件,如果需要包含n個文件,要用n個`include命令。

2)`include命令可以出現在Verilog程序的任何位置。被包含文件名可以是相對路徑名,也可以是絕對路徑名。

3)可以將多個包含命令卸載同一行,可以出現空格和注釋行。

4)如果文件1 包含文件2,文件2需要用到文件3的內容,可以在文件一種用兩個`include命令分別將文件2和文件3包含進去,而且文件3要在文件2之前。

5)在一個被包含文件中又可以包含其他的文件,即文件的包含是可以嵌套的。

3)時間尺度`timescale

`timescale命令用來說明跟在該命令后面的模塊的時間單位和精度。使用`timescale命令可以在同一個設計中包含不同的時間單位的模塊。一般的命令格式如下:`timescale<時間單位>/<時間精度>

在這條命令中,時間單位參量是用來定義模塊中的仿真時間和延遲時間的基准單位的。時間精度是用來聲明該模塊的仿真時間的精確程度的,該參量被用來對延遲時間值進行取證操作,因此又可以稱作是取整精度。如果在同一個程序設計里,存在多個`timescale一樣的命令,則用最小的時間精度值來決定仿真的時間單位。另外時間精度不能大於時間單位值。

使用`timescale時應該注意,`timescale的有效區域為`timescale語句處直至下一個`timescale命令或者`resetall語句為止。當有多個`timescale命令時,只有最后一個才起作用,多以在同一個源文件中`timescale定義的不同的多個模塊最好分開編譯,不要包含在一起以免出錯。

`timescale 1ns/1ps         //時間值都為1ns的整數倍,時間精度為1ps,因此延遲時間可以表達為帶三位小數的實型數。

`timescale 10μs/100ns   //時間單位為10μs的整數倍,時間精度位100ns,因此延遲時間可以表達為帶兩位小數的實型數。

時間尺度

1)根據時間精度,參數p的值從1.55取整為1.6;

2)因為時間單位是10ns,時間精度為1ns,所以延遲時間#p作為事件單位的整數倍為16ns;

3)可以用$printtimescale函數來輸出顯示一個模塊的時間單位和時間精度。

4)條件編譯命令`ifdef `else `endif

一般情況下,Verilog HDL源程序中所有的航都參加編譯。但是有時希望對其中的部分內容只有在滿足編譯條件時才進行編譯。也就是對一部分內容指定編譯條件,即條件編譯。

條件編譯命令有以下幾種形式:

     `ifdef 宏名 (標識符)

      程序段1

    `else

      程序段2

    `endif

它的作用是當宏名已經被定義過(`define定義),則對程序1進行編譯,程序段2被忽略。其中else部分可以沒有。注意:忽略掉的程序段也要符合語法規則


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM