天天看點

FPGA學習筆記(二)——Verilog HDL文法基礎

FPGA學習筆記(二)————Verilog HDL文法基礎

文章目錄

    • FPGA學習筆記(二)————**Verilog** HDL文法基礎
      • 1.Verilog HDL子產品的基本概念
      • 2.子產品(block)的組成
      • 3.常量
      • 4.變量的資料類型
      • 5.端口資料類型
      • 6.運算符與表達式

1.Verilog HDL子產品的基本概念

  • 一個複雜電路的完整Verilog HDL模型是由若個Verilog HDL 子產品構成的,每一個子產品又可以由若幹個子子產品構成。利用Verilog HDL語言結構所提供的這種功能就可以構造一個子產品間的清晰層次結構來描述極其複雜的大型設計。
  • 下面看一個簡單的程式
    module  and2(out,a,b,c); //and2是子產品名稱
      input	a,b;   //端口定義
      output c;
      wire a,b;    //資料類型說明
      reg c;
        [email protected](a or b)  //邏輯功能描述
          out = a & b;
    endmodule
               
FPGA學習筆記(二)——Verilog HDL文法基礎
  • 這就是一個簡單的與門子產品,由此可以看出 Verilog HDL巳程式是由子產品構成的。每個子產品的内容都是嵌在module和endmodule兩個語句之間,每個子產品實作特定的功能,子產品是可以進行層次嵌套的。
  • 每個子產品首先要進行端口定義.并說明輸入(input)和輸出(output),然後對子產品的功能進行邏輯描述。
  • Verilog HDL程式的書寫格式自由,一行可以寫幾個語句,一個語句也可以分多行寫。
  • 除了endmodule語句外,每個語句的最後必須有分号。
  • 一個子產品是由兩部分組成的,一部分描述接口;另一部分描述邏輯功能,即定義輸入是如何影響輸出的。

2.子產品(block)的組成

  • Verilog HDL結構完全嵌在module和endmodule聲明語句之間,每個Verilog程式包括4個主要部分:端口定義,I/O說明,信号類型聲明和功能描述。
    module<子產品名>(<端口清單>);
    	端口說明(input,output,inout)
    	參數定義(可選)
    	資料類型定義
    	連續指派語句(assign)
    	過程塊(initial 和 always)
    		行為描述語句
    		低層子產品執行個體
    		任務和函數
    	延時說明塊
    endmodule
               
    上述的是總體的描述,後面會一一講解每個部分的功能。
  • 子產品聲明

    子產品聲明包括子產品名和端口清單。其格式如下:

    module 子產品名(端口1,端口2,端口3,…);

    ​ 子產品結束的标志為關鍵字:

    endmodule

  • 端口定義

    ​ input(輸入端口),output(輸出端口)和inout(雙向端口)。

    ​ 格式如下:

    input 端口名1,端口名2,………,端口名N; //輸入端口

    output 端口名1,端口名2,………,端口名N; //輸出端口

    inout 端口名1,端口名2,………,端口名N; //輸入輸出端口

    ​ 也可以寫在端口聲明語句裡,其格式如下(為了代碼的可讀性,一般不這麼寫):

    module module_name(input port1,input port2,…output port1,output port2… );

  • 信号類型說明

    信号可以分為端口信号和内部信号;

    • 所有信号都必須進行資料類型的定義,如寄存器類型(reg等),連線類型(wire等);
    • 如果信号沒有定義資料類型,則綜合器将其預設為wire型;
    • 端口的位寬最好定義在端口定義中,不要放在資料類型定義中;
    • 不能将input和inout類型聲明為reg型;
  • 子產品的端口表示的是子產品的輸人和輸出口名,也就是說,它與别的子產品聯系端口的辨別。

    在子產品被引用時,在引用的子產品中,有些信号要輸入到被引用的子產品中,有的信号需要從被引用的子產品中取出來口。在引用子產品時其端口可以用兩種方法連接配接:

    ​ (1)在引用時,嚴格按照子產品定義的端口順序來連接配接,不用标明原子產品定義時規定的端口名,例如:

    子產品名(連接配接端口1信号名,連接配接端口2 信号名,連接配接端口3信号名,……);

    ​ (2)在引用時用“.”符号,标明原子產品是定義時規定的端口名,例如:

    子產品名( . 端口1名(連接配接信号1名),. 端口2名(連接配接信号2名),...);

    ​ 優點:在于可以用端口名與被引用子產品的端口相對應,而不必嚴格按端口順序對應,提高了程式的可讀性和可移植性。

3.常量

  • 關鍵字

    ​ 關鍵字(又稱保留字), 小寫的英文字元串。如: module、endmodule、input、output、wire、reg、and、assign、always等。下面是所有的關鍵字:

    always   and   assign   begin   buf   buf   if0   bufif1   case  casex  casez cmos    deassign   default   defparam  disable  edge  else  end  endcase endmodule    endfunction    endprimitive    endspecify  endtable  endtask event    for   force   forever   fork    function   highz0    highz1   if    ifnone    initial   inout  input   integer   join   large  macrmodule  medium   module 
    nand  negedge  nmos   nor   not   notif0   notif1  or  output   parameter pmos  posedge  primitive  pull0  pull1  pullup  pulldown  rcmos  real realtime  reg  release  repeat  rnmos  rpmos  rtran  rtranif0  rtranif1 scalared  small  specify specparam strong0 strong1 supply0 supply1
    table task time trantranif0 tranif1 tri tri0 tri1 triand trior   trireg   vectored wait wand weak0 weak1 while wire wor xnor xor
               
  • 辨別符

    ​ 辨別符(identifier)是程式代碼中給對象(如子產品、端口、變量等)取名所用的字元串。

    ​ 辨別符的組成:由字母、數字字元、下劃線(_)和美元符号( ) 組 成 , 區 分 大 小 寫 , 其 第 一 個 字 符 必 須 是 英 文 字 母 或 下 劃 線 , 不 能 是 數 字 或 )組成,區分大小寫,其第一個字元必須是英文字母或下劃線,不能是數字或 )組成,區分大小寫,其第一個字元必須是英文字母或下劃線,不能是數字或。以 開 始 的 字 符 串 是 為 系 統 函 數 保 留 的 , 如 “ 開始的字元串是為系統函數保留的,如“ 開始的字元串是為系統函數保留的,如“display”。

    注意:1.關鍵字不能作為辨別符使用。

    ​ 2.用有意義的有效的名字如Sum 、CPU_addr等。

    ​ 3.用下劃線區分詞。

    ​ 4.采用一些字首或字尾,如

    ​ 時鐘采用Clk 字首:Clk_50,Clk_CPU;

    ​ 低電平采用_n 字尾:Enable_n;

    ​ 5.統一定的縮寫如全局複位信号Rst。

    ​ 6.同一信号在不同層次保持一緻性,如同一時鐘信号必須在各子產品保持一緻。

    ​ 7.參數(parameter)采用大寫,如SIZE 。

  • 用下列四種基本的值表示電路的邏輯狀态:

    0:邏輯0或“假”;

    1:邏輯1或“真”;

    x:未知狀态,通常在信号未被指派前;

    z:高阻;

    在輸入或表達式中,“z”的值通常被解釋成“x”;

    z和x是不分大小寫的,如01xz 與01XZ相同;

    Verilog HDL中,有3種類型的常量:整數型常量(整數)、實數型常量(實數)和參數型常量。

  • 整數

    整數的一般表達式為:

    <+/-><size> ’ <base format><number>

    其中 size : 大小,表示二進制位數(bit)。預設為32位。(可有可無);

    ​ base format:數基,可為2(b)、8(o)、10(d)、16(h)進制。預設為10進制;

    ​ number:是所選數基内任意有效數字,包括X、Z。

    ​ 預設數基為10進制

    ​ 當數值number大于指定的大小時,截去高位。2’b1101表示的是2’b01

    ​ 一個數字可以被定義為負數,隻需在位寬表達式前加一個負号,注意必須在數字定義表達式的最前面。

    ​ 下劃線符号_可以自由的在整數或實數中使用;就數值本身而言,它們沒有任何意義。它們能夠用來提高可讀性;唯一的限制是下劃線符号不能用來作為常數的首字元。例:a=8’b0001_0000;

-14             //十進制數-14
16’d255         //位寬為16的十進制數255
8’h9a             //位寬為8的十六進制數9a
’o21               //位寬為32的八進制數21
’hAF               //位寬為32的十六進制數AF 
-4’d10             //位寬為4的十進制數-10
(3+2)’b11001  //非法表示,位寬不能為表達式 
           
  • 實數

    (1)十進制格式,由數字和小數點組成(必須有小數點),例如:

    ​ 0.1, 3.1415, 2.0 √ 3. x

    (2) 指數格式:由數字和字元e(E)組成,e(E)的前面必須要有數字而且後面必須為整數,例如:

    13_5.1e2       //其值為13510.0
    8.5E2          //850.0 (e與E相同)
    4E-4           //0.0004    
               
  • parameter(參數型)

    ​ 在Verilog HDL中為了提高程式的可讀性和可維護性,用parameter來定義一個辨別符代表一個常量,稱為符号常量。

    其說明格式如下:

    parameter 參數名1 = 表達式,參數名2 = 表達式, …,參數名n = 表達式;

    parameter是參數型資料的确認符。确認符後跟着一個用逗号分隔開的指派語句表。常用參數來聲明運作時的常數。可用字元串表示的任何地方,都可以用定義的參數來代替。

    參數是本地的,其定義隻在本子產品内有效。

    舉例說明:

    module md1(out,in1,in2);
       …..
       parameter cycle=20, 
                 p1=8, x_word=16’bx,
                 file = “/user1/jmdong/design/mem_file.dat”;
        wire [p1:0] w1;    //用參數來說明wire 的位寬
        ….
        initial  begin  $open(file);  ……. //用參數來說明檔案路徑
            #20000  display(“%s”,file);  $stop      
        end                 
    endmodule
               
    • 參數型常數經常用于定義延遲時間和變量寬度。在子產品或執行個體引用時,可通過參數傳遞改變在被引用子產品或執行個體中已定義的參數。
    module Decode(A,F);
        parameter Width = 1,Polarity = 1;
        ···
    endmodule
    module Top;
        wire[3:0] A4;
        wire[4:0] A5;
        wire[15:0] F16;
        wire[31:0] F32;
        Decode #(4,0) D1(A4,F16); //可通過參數的傳遞來改變定義時已規定的參數值
        Decode #(5) D2(A5,F32);
        defparam  D2.Width = 5; //在一個子產品中改變另一個子產品的參數時
    endmodule
               
    • 在一個子產品中改變另一個子產品的參數時,需要使用defparam指令。在做布線後仿真時,就是利用這種方法把布線延遲通過布線工具生成的延遲參數檔案反标注(Back-annotate)到門級Verilog網表上。

4.變量的資料類型

  • 線狀網型變量(net)wire(需要被持續的驅動,驅動它的可以是門和子產品)
FPGA學習筆記(二)——Verilog HDL文法基礎

當net驅動器的值發生變化時,Verilog自動的将新值傳送到net上。在例子中,線網out由or門驅動。當or門的輸入信号變化時将傳輸到線網out上。

  • wire型信号定義格式如下:

    wire [n-1:0] 變量名1,變量名2,…變量名n;

    wire [n:1] 變量名1,變量名2,…變量名n;

    wire  a;              //定義了一個1位的wire型資料
    wire [7:0] b;       //定義了一個8位的wire型向量
    wire [4:1] c, d;    //定義了二個4位的wire型向量
               
  • 寄存器型變量 (reg)
    reg  [msb:lsb] 變量名1, 變量名2,…變量名n;
    例如:
    reg  clock;           
    reg [3:0]  regb; 
    reg [4:1]  regc, regd;    
    
               

    可以了解為實際電路中的寄存器,具有記憶性,是資料儲存單元的抽象,在輸入信号消失後它可以保持原有的數值不變。常代表觸發器

    與線網型變量的根本差別在于:register型變量需要被明确地指派,并且在被重新指派前一直保持原值。

    隻能在initial或always指派,預設值是x。

    注意在always和initial塊内被指派的每一個信号都必須定義成reg型。

  • Verilog程式子產品中,被聲明為input或者inout型的端口,隻能被定義為線網型變量,被聲明為output型的端口可以被定義為線網型或者寄存器型變量,輸入輸出信号類型預設時自動定義為wire型。
  • wire型信号可以用作任何方程式的輸入,也可以用作“assign”語句或執行個體元件的輸出,不可以在initial和always子產品中被指派。
  • 字元串的表示:

    是由一對雙引号括起來的字元序列。必須在一行内寫完。如”hello world!”是一個合法字元串。

    每個字元串(包括空格)被看作是8位的ASCII值序列。存儲字元串“hello world!”,就需要定義一個8*12位的變量:

    reg[8*12:1] stringvar;
    initial 
        begin
    		stringvar = “ hello world”;
        end
               
  • memory型

    對存儲器(如RAM、ROM)進行模組化。 通過擴充reg型資料的位址範圍來生成的。

    格式:

    reg [msb:lsb] 存儲器名1[upper1:lower1],存儲器名2 [upper2:lower2],…;

    ​ 例如:reg [7:0] mem[1023:0];
    //在Verilog中可以說明一個寄存器數組。
    integer NUMS [7: 0];        // 包含8個整數數組變量;
    time  t_vals [3: 0];            // 4個時間數組變量;
    reg [15: 0]  MEM [0:1023];   // 1K x 16存儲器MEM;
    //描述存儲器時可以使用參數或任何合法表達式
    parameter wordsize = 16;
    parameter memsize = 1024;
    reg [wordsize-1: 0]  MEM3 [memsize-1: 0];
               
  • 存儲器尋址(Memory addressing)

    存儲器元素可以通過存儲器索引(index)尋址,也就是給出元素在存儲器的位置來尋址。

    mem_name [addr_expr]

    Verilog不支援多元數組。也就是說隻能對存儲器字進行尋址,而不能對存儲器中一個字的位尋址。

    reg [8: 1] mema [0: 255]; // declare memory called mema
    reg [8: 1] mem_word;      // temp register called mem_ word
    . . .
    initial
        begin
            $displayb( mema[5]);        //顯示存儲器中第6個位元組的内容
            mem_word = mema[5];  //将這個位元組指派給men_word  
            $displayb( mem_word[8]);  //顯示第6個位元組的最高有效位
        end
    endmodule
               

    盡管memory型資料和reg型資料的定義格式很相似,但要注意其不同之處。

    如一個由n個1位寄存器構成的存儲器組是不同于 一個n位的寄存器的。

    reg[n-1:0] rega;  //一個n位的寄存器
    reg  mema[n-1:0];//一個由n個1位寄存器構成的寄存器數組
    rega = 0; //合法指派語句
    mema = 0; //非法指派語句
    mema[3] = 0; //合法指派語句      
               

5.端口資料類型

  • 一個端口看成是由互相連接配接的兩個部分組成,一部分位于子產品的内部,另一部分位于子產品的外部。當在一個子產品中調用(引用)另一個子產品時,端口之間的連接配接必須遵守一些規則。
FPGA學習筆記(二)——Verilog HDL文法基礎
  • 輸入端口:從子產品内部來講,輸入端口必須為線網資料類型,從子產品外部來看,輸入端口可以連接配接到線網或者reg資料類型的變量。

    輸出端口:從子產品内部來講,輸出端口可以是線網或者reg資料類型,從子產品外部來看,輸出必須連接配接到線網類型的變量,而不能連接配接到reg類型的變量。

    輸入/輸出端口

    ​ 從子產品内部來講,輸入/輸出端口必須為線網資料類型;從

    ​ 子產品外部來看,輸入/輸出端口也必須連接配接到線網類型的變

    ​ 量。

    位寬比對

    ​ 在對子產品進行調用的時候,verilog允許端口的内、外兩個

    ​ 部分具有不同的位寬。一般情況下,verilog仿真器會對此

    ​ 警告。

  • 未連接配接端口

    ​ Verilog允許子產品執行個體的端口保持未連接配接的狀态。

    例如,如果子產品的某些輸出端口隻用于調試,那麼這些端

    口可以不與外部信号連接配接。

    端口與外部信号的連接配接

    ​ 在對子產品調用的時候,可以使用兩種方法将子產品定義的端

    ​ 口與外部環境中的信号連接配接起來:按順序連接配接以及按名字

    ​ 連接配接。但兩種方法不能混合在一起使用。

    順序端口連接配接:

    ​ 需要連接配接到子產品執行個體的信号必須與子產品聲明時目标端口在

    ​ 端口清單中的位置保持一緻。

  • 端口類型定義舉例
FPGA學習筆記(二)——Verilog HDL文法基礎
  • 輸入端口in1,in2可以由net/register(A,B)驅動,但輸入端口in1,in2隻能是net類型;

    輸出端口out可以是net/register類型,輸出端口隻能驅動net(Y)。

    若輸出端口out在過程塊中指派則為register類型;若在過程塊外指派(包括執行個體化語句),則為net類型。外部信号A,B類型判斷方法與輸出端口相同。

module DUT (O, in1, in2);
 output O;
  input in1, in2;
  wire O, in1, in2;    //隻能為線型
	  and  u1(O, in1, in2) ;
 endmodule

module top;
  wire y;  
  reg a, b; //可以用reg給a、b驅動
  DUT  u1 (y, a, b) ;
  initial   begin
	    a = 0; b = 0;
	    #5 a = 1;   //過程塊中隻能給reg類型指派
      end
  endmodule
           
  • 總結

    a.輸入端口

    從子產品内部來講,輸入端口必須為線網(net)資料類型;

    從子產品外部來看,輸入端口可以連接配接到線網(net)或reg資料類型的變量。

    b.輸出端口

    從子產品内部來講,輸出端口可以為線網(net)或reg資料類型;

    從子產品外部來看,輸出端口必須連接配接到線網(net)資料類型的變量。

    C.輸入/輸出端口

    從子產品内部來講,輸入/輸出端口必須為線網(net)資料類型;

    從子產品外部來看,輸入/輸出端口必須連接配接線網(net)資料類型的變量。

6.運算符與表達式

1.算數運算符

在進行算術運算時,如果操作數的某一位為x或z,則整個表達式運算結果為不确定。 例1 + z = unknown。

兩個整數進行除法運算時,結果為整數,小數部分被截去。如,6/4=1。

在進行加法運算時,如果結果和操作數的位寬相同,則進位被截去。

(+加 -減 *乘 /除 %求模)

  • 在進行算術運算時,Verilog根據表達式中變量的長度對表達式的值自動地進行調整。Verilog自動截斷或擴充指派語句中右邊的值以适應左邊變量的長度。

    将負數指派給reg或其它無符号變量時,verilog自動完成二進制補碼計算。

    reg[3:0] a,b;
    reg[15:0] c;
     a = -1;       //a為無符号數,其值為1111
     b = 8;c=8;//b=c=1000
     b= b+a;    //結果10111截斷,b=0111
     c =c+a;     //c=10111
               
  • 而進行取模運算時,結果值的符号位采用模運算式裡第一個操作數的符号位。見下例:
    模運算表達式 結果 說明
    10%3 1 餘數為1
    11%3 2 餘數為2
    12%3 餘數為0,即無餘數
    -10%3 -1 結果取第一個操作數的符号位。是以餘數為-1
    11%-3 2 結果取第一個操作數的符号位,是以餘數為2

2.位運算符(除了~,其餘都是雙目運算符)

将兩個操作數按對應位分别進行邏輯運算。

如果兩個操作數的位寬不一樣,則仿真軟體會自動将短操作數向左擴充到兩操作數位寬一緻。

如果操作數的某一位為x時不一定産生x結果。

FPGA學習筆記(二)——Verilog HDL文法基礎

3.縮位運算符(單目運算符)

縮位運算符(Reduction Operators):又稱縮減運算符,僅對一個操作數進行運算,按照從右到左的順序依次對所有位進行運算,并産生一位的邏輯值

FPGA學習筆記(二)——Verilog HDL文法基礎
  • 縮減運算是對單個操作數進行或、與、非遞推運算.最後的運算結果是1位的二進制數。
    reg[3:0] B;
    reg C;
    assign C = &B;
    等價于:C = ((B[0]&B[1])&b[2])&B[3]
    
               

4.關系運算符

在進行關系運算時,如果聲明的關系是假,則傳回值是0;如果聲明的關系是真,則傳回值是1;如果操作數的某一位為x或z,則結果為不确定值。

FPGA學習筆記(二)——Verilog HDL文法基礎

5.等式運算符

邏輯相等:==

邏輯不等:!=

全等:===

z, x等位嚴格相等

非全等:!==

例:對于A=2’b1x 和 B=2’b1x,則

​ A == B結果為x, A===B結果為1

  • 相等運算符(==)和全等運算符(===)的差別:

    對于相等運算符,當參與比較的兩個操作數逐位相等,其結果才為1,如果某些位是不定态或高阻值,其相等比較得到的結果就會是不定值。

    對于全等比較(===)是對這些不定态或高阻值的位也進行比較,兩個操作數必須完全一緻,其結果才為1,否則結果是0。

FPGA學習筆記(二)——Verilog HDL文法基礎
  • A== 1’bx ———— 當A為1’bx時,其結果仍為x;
  • A=== 1’bx ———— 當A為1’bx時,其結果仍為1;

6.邏輯運算符

邏輯運算符中,“&&”和“||”是雙目運算符,它要求有兩個操作數。

​ “!”是單目運算符,隻要求一個操作數。

FPGA學習筆記(二)——Verilog HDL文法基礎

7.移位運算符

Verilog HDL的移位運算符隻有左移和右移兩個。其用法為:A>>n

或 A<<n; 表示把操作數A右移或左移n位,同時用0填補移出的位。

例如:
   reg[3:0] start;
   start = 1;
   start = (start<<2);
   //start = 0100;


           

8.位拼接運算符

在Verilog語言中有一個特殊的運算符:位拼接運算符{ }。

位拼接運算符{}可以把兩個或多個信号的某些位拼接起來,表示一個整體信号進行運算操作。其使用方法如下:

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

對于一些信号的重複連接配接,可以使用簡化的表示方式{n{A}}。這裡A是被連接配接的對象,n是重複的次數。

例如:ain = 3’b010; bin = 4’b1100; 
    {ain,bin} = 7’b0101100;
   {3 {2’b10} = 6’b101010;
位拼接還可以用嵌套的方式來表達:
  	 { a, 3'b101, {3{a,b}}}

           

注意:在位拼接表達式中不允許存在沒有指明位數的信号。這是因為在計算機拼接信号的位寬的大小時必須知道其中每個信号的位寬。

9.條件運算符

三目運算符,對3個操作數進行運算,方式如下:

信号 = 條件?表達式1:表達式2

說明:當條件成立時,信号取表達式1的值,反之取表達式2的值。

例如:

assign out= (sel == 0) ? a : b;

例如:條件運算符描述的三态緩沖器

FPGA學習筆記(二)——Verilog HDL文法基礎
module likebufif ( in, en, out);
input in;
input en; 
output out;
   assign out = (en == 1) ? in : 'bz;   
endmodule 

           

10.優先級别

FPGA學習筆記(二)——Verilog HDL文法基礎