天天看點

【FPGA篇章三】FPGA常用語句:Verilog基本文法要素

歡迎大家關注我的微信公衆賬号,支援程式媛寫出更多優秀的文章

Verilog中總共有十九種資料類型,我們先介紹四個最基本的資料類型,他們是:

reg型、wire型、integer型、parameter型

1 常量

  1.1 數字integer

    整數:b二進制   d十進制   h十六進制   o八進制

      表達方式:<位寬=default><進制=d><數字>

      Eg. 8‘b10100100,2'h0a3,3'o455,4’d2435

      注意,當僅有位寬被忽略時,即'b, 'd, 'o'等形式,資料預設位寬為目前機器的位元組寬度,常為32位。

    X與Z值:x代表不定值,z代表高阻值

      可以用于定義目前進制數的1位(如h下可表達1位十六進制數)。

    負數:位寬前加減号

    下劃線:分割數的表達,提高可讀性,無意義

  1.2 參數parameter

    定義一個辨別符代表一個常量,即辨別符形式的常量。提高可讀性。格式如下:

    parameter para1=3'b010, para2=4'd1432,...,paran=2'h6a;

    parameter ave_delay = (r+f)/2;

    常用于定義延遲時間和變量寬度,以及改變在被引用子產品或執行個體中已定義的參數。如:

1       module Decode(A,F);
 2            parameter Width=1, Polarity=1;
 3            ...
 4       endmodule
 5 ​
 6       module Top;
 7            wire[3:0] A4;
 8            wire[4:0] A5;
 9            wire[15:0] F16;
10            wire[31:0] F32;
11            Decode #(4,0) D1(A4,F16);//w=4,p=0
12            Decode #(5) D2(A5,F32);//w=5
13       endmodule      

    在執行個體時使用 #() 的方式來更改引用子產品參數。

2 變量

  2.1 net(default)

  網絡資料類型net表示結構實體(如門)之間的實體連接配接,它不能儲存值,而且必須受到驅動器的驅動。如無驅動器連接配接,則呈現高阻Z态。

    wire(default)

    單門驅動或連續指派語句驅動的網絡型資料。

    常用來表示以assign關鍵字指定的組合邏輯信号。

    tri

    多驅動器驅動的網絡型資料。

    (多驅動源下,若無定義邏輯強度,邏輯值會發生沖突産生不确定值X)

1     wire [n-1:0] name1, name2, ... , namei;
2     wire [n:1] name1, name2, ... , namei;
3     wire name;      

  2.2 register

  寄存器是資料儲存單元的抽象,通過指派語句可以改變寄存器儲存的值,作用與改變觸發器儲存的值相當。

  常用來表示always塊内的指定信号,代表觸發器。

  always塊中被指派的每一個信号都必須定義成reg型。

  reg被指派如同一組觸發器存儲單元的值被改變。

1     reg [n-1:0] name1, name2, ... , namei;
2     reg [n:1] name1, name2, ... , namei;
3     reg rega;      

  預設初始值為x。可以賦正負值,但當該reg是一個表達式中的操作數時,被作為無符号數處理。

  reg型隻表示被定義的信号将用在always塊内,雖常為寄存器、觸發器的輸出,但并非總是如此。

  2.3 memory

  Verilog通過建立reg型變量的數組來對存儲器進行模組化,描述RAM/ROM型存儲器和reg檔案。

  Verilog中不存在多元數組,memory型資料通過擴充reg型資料的位址範圍來生成。

1     reg [n-1:0] mem1[m-1:0];
 2 
 3     reg [n-1:0] mem2[m:1];
 4 
 5     reg [7:0] mem[255:0];   //定義了一個名為mem 的存儲器,該存儲器擁有 256個 資料位寬為8 存儲器,位址範圍是從0到255​
 6 
 7     reg [n-1:0] rega;      // rega 是一個n位的寄存器
 8     rega = 0;          // rega 可以由一個指派語句指派
 9     reg mema[n-1:0];            // mema 是一個由n個1位寄存器單元構成的存儲器
10     mema[0] = 0;
11     mema[1] = 0;
12     ...
13     mema[n-1] = 0;               // mema 必須一個一個單元地指派      

  如果想對memory中的存儲單元進行讀寫操作,必須指定該單元在存儲器中的位址。

3 基本運算符号

  按操作數個數: 有單目、雙目、三目運算符,分别可帶一個、兩個、三個操作數。

  按功能:

    1) 算術運算符+、-、×、/、%

       加、減、乘、除、求餘

       整數除法結果值略去小數部分,取模運算符号位采用模運算式中第一個操作數的符号位。

    2) 指派運算符=、<=

       同一個always塊中,隻能全使用阻塞指派或全使用非阻塞指派。

      * 非阻塞指派<=:目前語句的執行不會阻塞下一語句的執行。

      在塊語句結束時才完成指派操作,塊内的指派語句同時指派。

      可以看作兩個步驟的過程:

        指派時刻開始時,計算非阻塞指派右操作數表達式。

        指派時刻結束時,更新非阻塞指派左操作數。

1     reg a=1, b=2, c=3, d=4;
2     always @(posedge clk)
3     {
4        a <= b;
5        b <= c;
6        c <= d;
7     }      

      并行,電路實作往往與觸發沿有關,常被綜合成時序邏輯電路。

      * 阻塞指派=:完成目前語句後才能做下一句的操作

      在該語句結束時就完成指派操作,塊内的阻塞指派語句順序執行。

      順序執行,一般不能設定有延遲,常被綜合成組合邏輯電路。

    3)關系運算符>、<、>=、<=

    4)邏輯運算符&&、||、!

      &&和 || 是雙目運算符,優先級低于算術運算符

      ! 是單目運算符,優先級高于算術運算符

1     (a>b) && (x>y) 相當于 a>b && x>y
2     (a==b) || (x==y) 相當于 a==b || x==y
3     (!a) || (a>b) 相當于 !a || a>b      

    5)條件運算符 ? :

    6)位運算符~、|、^、&、^~

      取反、或、異或、與、同或

1       // 除相應雙目位運算外還可用作單目運算符縮減運算
2 
3     reg [3:0] A = 0101;
4        reg B;
5     B = &A;
6     // 相當于B = 0 & 1 & 0 & 1
7     // 即将A的所有位進行位運算      

     7)移位運算符<<、>>

      a>>n;   // 将操作數a右移n位,去尾,縮小

      a<<n;   // 将操作數a左移n位,補0  ,放大

    8)拼接運算符{ }

      把兩個/多個信号的某些位拼接起來運算。

1      a = 1'b0;
 2      b = 8'b11101100;
 3      c = 1'b1;
 4 
 5      //用法1
 6      r = {a, b[3:0], c, 3'b101};
 7      //此時r = 0 1100 1 101
 8 
 9      //用法2
10      r = {4{a}};
11      //此時r = 0000
12      //嵌套用法
13      r = {b[7:5], {3{c,a}}};
14      //此時r = 111 101010      

易混知識點:

位運算符:按位進行運算,原來的操作數有幾位,結果就有幾位,若2個操作數位數不同,則位短的資料左端會自動補0

邏輯運算符:如果操作數是多位的,則将操作數看作整體,若操作數中每一位都是0值,則為邏輯0值,若操作數中有1,則為邏輯1值

4 塊語句

  4.1 順序塊

    塊内語句順序執行,上一條語句行完畢後,下一條語句才能執行

    每條語句的延遲時間是相對于前一條語句的仿真時間而言的(也就是說,順序塊内一條語句的延遲時間是指從前一條語句仿真完畢到目前語句仿真完畢的間隔)

    直到最後一條語句執行完,程式流程控制才跳出該語句塊。

1     begin
 2        語句1;
 3        語句2;
 4     end
 5 
 6 ​    begin:block_name
 7        assignments;
 8        語句1;
 9        語句2;
10     end      

  4.2 并行塊

    1)塊内語句同時執行,程式流程控制一進入到該并行塊,塊内語句則開始同時并行地執行,

    2)塊内每條語句的延遲時間是相對于程式流程控制進入到塊内的仿真時間的(也就是說,并行塊内一條語句的延遲時間是指從程式流程控制進入到塊内到該條語句執行完畢的間隔;這個延遲時間是用來給指派語句提供執行時序的),

    3)當按延遲時間的時序中排在最後的語句執行完畢或一個disable語句執行時,程式流程控制跳出該程式塊。

1       fork
 2          語句1;
 3          語句2;
 4       join
 5 
 6 ​      fork:塊名
 7        assignments;
 8          語句1;
 9          語句2;
10       end      

  4.3 生成塊

  generate生成塊的本質是使用循環内的一條語句來代替多條重複的Verilog語句,簡化使用者的程式設計

    用法:

    1. generate 文法有 generate for 、genreate if 和 generate case 三種

    2. generate for 語句必須有 genvar 關鍵字定義 for 的變量

    3. for 的内容必須加 begin 和 end

    4. 必須給 for 語段起個名字

1 1. generate for例子:
 2 generate
 3 genvar i; //generate 8 samll fifo for in_data[i] 8X72
 4     for(i=0; i<NUM_QUEUES; i=i+1) 
 5         begin: in_arb_queues //NUM_QUEUES = 8
 6             small_fifo
 7             #( .WIDTH(DATA_WIDTH+CTRL_WIDTH), .MAX_DEPTH_BITS(2))
 8             in_arb_fifo
 9             (// Outputs
10             .dout ({fifo_out_ctrl[i], fifo_out_data[i]}),
11             .full (),
12             .nearly_full (nearly_full[i]),
13             .prog_full (),
14             .empty (empty[i]),
15             // Inputs
16             .din ({in_ctrl[i], in_data[i]}),
17             .wr_en (in_wr[i]),
18             .rd_en (rd_en[i]),
19             .reset (reset),
20             .clk (clk));
21         end // block: in_arb_queues
22 endgenerate
23 
24 2.generate if例子:
25 generate
26     if (REG_WIDTH == WRITE_WIDTH) 
27         begin : new_data_a_generation
28             assign new_data_a = merge_update ? merge_wr_data : held_wr_data_a;
29         end
30     else begin
31             assign new_data_a = merge_update ?
32 {{(REG_WIDTH - WRITE_WIDTH - 1){merge_wr_data_sign}}, merge_wr_data} :
33 {{(REG_WIDTH - WRITE_WIDTH){held_wr_data_sign_a}}, held_wr_data_a};
34         end
35 endgenerate
36 
37 3.generate還可以進行多個assign指派!
38 module anytest_v(
39 input clk,
40 input[7:0] datain,
41 output[7:0] dataout,
42 output finish
43 );
44 
45 wire[7:0] mem[31:0];
46 wire[32*8-1:0] xxx;
47 //reg[7:0] i;
48 
49 generate
50     genvar i;
51         for(i=0;i<=31;i=i+1)
52             begin :wiertech
53                 assign mem[i]= 8'b0;
54             end
55 endgenerate
56 
57 endmodule