FPGA筆記之verilog語(yǔ)言(基礎語(yǔ)法篇)

發(fā)布時(shí)間:2020-3-19 15:02    發(fā)布者:dameihuaxia
FPGA筆記之verilog語(yǔ)言(基礎語(yǔ)法篇)
寫(xiě)在前面:
verilogHDL語(yǔ)言是面向硬件的語(yǔ)言,換句話(huà)說(shuō),就是用語(yǔ)言的形式來(lái)描述硬件線(xiàn)路。因此與C語(yǔ)言等軟件語(yǔ)言不同,如果想要在實(shí)際的電路中實(shí)現,那么在進(jìn)行verilog語(yǔ)言編寫(xiě)時(shí),就需要提前有個(gè)硬件電路的構思和想法,同時(shí),在編寫(xiě)verilog語(yǔ)言時(shí),應該采用可綜合的語(yǔ)句和結構。

1. verilog 的基礎結構
1.1 verilog設計的基本單元——module
在數字電路中,我們常常把一些復雜的電路或者具有特定功能的電路封裝起來(lái)作為一個(gè)模塊使用。以后在運用這種模塊化的封裝時(shí),我們只需要知道:1.模塊的輸入是什么;2.模塊的輸出是什么;3.什么樣的輸入對應什么樣的輸出。而中間輸入是經(jīng)過(guò)什么樣的電路轉化為輸出就不是我們在使用時(shí)需要特別重視的問(wèn)題。當很多個(gè)這樣的模塊相互組合,就能構成一個(gè)系統,解決一些復雜的問(wèn)題。verilog語(yǔ)言的基礎結構就是基于這種思想。verilog中最基本的模塊是module,就可以看做是一個(gè)封裝好的模塊,我們用verilog來(lái)寫(xiě)很多個(gè)基本模塊,然后再用verilog描述多個(gè)模塊之間的接線(xiàn)方式等,將多個(gè)模塊組合得到一個(gè)系統。
那么一個(gè)module應該具有哪些要素呢?首先對于一個(gè)module,我們應該設計好其各個(gè)I/O,以及每個(gè)I/O的性質(zhì),用于與模塊外部的信號相聯(lián)系,讓使用者知道如何連線(xiàn)。其次,作為開(kāi)發(fā)者,我們需要自己設計模塊內部的線(xiàn)路來(lái)實(shí)現所需要的功能。因此需要對模塊內部出現的變量進(jìn)行聲明,同時(shí)通過(guò)語(yǔ)句、代碼塊等實(shí)現模塊的功能。綜上所述,我們把一個(gè)module分成以下五個(gè)部分:

模塊名
端口定義
I/O說(shuō)明
內部信號的聲明
模塊功能實(shí)現
例:
/////////////////////////////////////////////////////////////////
//module    模塊名 (端口1,端口2,端口3);
//I/O說(shuō)明
//內部信號說(shuō)明
//模塊功能實(shí)現
//endmodule
////////////////////////////////////////////////////////////////

////////////////////////////////////
//module    模塊名 (端口1,端口2,端口3);
////////////////////////////////////
module      FreDevider    (                  
                                        Clock,
                                        rst,
                                        Clkout
                                        );


////////////////////////////////////
//I/O說(shuō)明
////////////////////////////////////
input Clock;
input rst;
output Clkout;


////////////////////////////////////
//內部信號說(shuō)明
////////////////////////////////////
reg Clkout;


////////////////////////////////////
//模塊功能實(shí)現
////////////////////////////////////
    always@(posedge Clock or posedge rst)
    begin
        if(rst)
            Clkout<=0;
        else
            Clkout<=~Clkout;
    end


////////////////////////////////////
//endmodule
////////////////////////////////////
endmodule


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1.2 module的使用
當我們已經(jīng)寫(xiě)好了一種類(lèi)型的module,那我們在使用的時(shí)候,就可以直接調用module。使用方法是 模塊名+實(shí)例名+端口聲明+信號聲明。一個(gè)模塊可以定義多個(gè)實(shí)例。
例如:使用上述已經(jīng)寫(xiě)好的module

//已經(jīng)定義過(guò)一個(gè)叫FreDevider的module
FreDevider    uut1(                                            //模塊名:FreDevider    實(shí)例名:uut1
                  .Clock(clock_signal),           // 端口聲明: .端口名     信號聲明:  (信號名)
                  .rst(rst_signal),
                  .Clkout(clkout_signal)
                  );                                
1
2
3
4
5
6
這里涉及到了之前module定義和變量聲明等問(wèn)題,首先module的定義決定了模塊名和端口名,其次module中的信號的處理方式?jīng)Q定了這里的信號名是reg還是wire型。信號可以看做是一個(gè)大的模塊的輸入輸出或中間變量。

1.3 I/O的說(shuō)明
I/O的類(lèi)型共有3類(lèi):input,output,inout
前兩個(gè)比較好理解,分別是輸入和輸出
而inout則是雙向端口,既可以當做輸入,也可以當做輸出,這種雙向端口具有雙向傳輸的能力,比較節約端口,同時(shí)適合作為總線(xiàn)等需要但是要保證在某一時(shí)刻,其只進(jìn)行某一方向的傳輸,也就是說(shuō),應避免兩個(gè)方向由需要傳輸這種情況。因此在實(shí)際工程實(shí)例中,我們在比較底層的模塊編寫(xiě)時(shí),是比較少的用inout端口,而是在較高一層的模塊,通過(guò)控制信號來(lái)實(shí)現inout端口的使用。同時(shí)inout端口在實(shí)際使用時(shí)還有許多問(wèn)題,對于初學(xué)者,先理解整個(gè)架構,再對細節補充,所以這部分內容放在高級語(yǔ)法篇講述。
I/O說(shuō)明的形式:
I/O的說(shuō)明可以放在端口定義后,也可以在端口定義時(shí)同時(shí)說(shuō)明。例:

module   FreDevider    (                  
                       input  Clock,
                       input  rst,
                       output  Clkout
                       );
1
2
3
4
5
同時(shí),也可以在說(shuō)明I/O口的時(shí)候,同時(shí)說(shuō)明信號的位數
例:

module    FreDevider    (                  
                        input  Clock,
                        input  rst,
                        input    [15:0]     x;      //16位輸入
                        output  [31:0]     y;      //32位輸出
                        );

1
2
3
4
5
6
7
1.3 內部信號的聲明
如果說(shuō)端口的定義連接了模塊與外部世界,是一個(gè)模塊世界中可進(jìn)可出的若干個(gè)大門(mén),那么信號就是一個(gè)個(gè)行人。要實(shí)現模塊的功能,就要對各個(gè)信號進(jìn)行處理和變換。有些信號是外部輸入的,有些信號是要輸出給外部的,還有些信號是信號變換的中間變量。就像行人有些是外面進(jìn)來(lái)的,有些是要去往外面世界的,有些是住在模塊世界里的。這些參與到模塊功能實(shí)現的所有信號,都要對其信號的屬性進(jìn)行規定,就像每個(gè)行人都有各自的身份?偠灾,分清楚端口和信號的區別,端口是固定的,信號是變化的。端口是門(mén),信號是人。
信號的屬性有reg、wire、paramater三種種,其中reg又稱(chēng)為寄存器型,wire又稱(chēng)為線(xiàn)性,每個(gè)信號都要定義其屬性,但是對于模塊的輸入信號,其屬性必須不是reg型,一般為wire型。又因為對于沒(méi)有聲明的信號,其默認為wire型,因此在定義時(shí),我們只需要定義輸出信號的類(lèi)型和中間變量的類(lèi)型即可。

reg   a;
wire  b;
1
2
1.4 模塊功能的實(shí)現
對于一個(gè)硬件電路來(lái)說(shuō),已經(jīng)有了模塊名,端口和端口名,信號與信號屬性,剩下的就是通過(guò)硬件電路來(lái)實(shí)現各個(gè)信號之間的邏輯功能。這比部分的知識就和我們在大學(xué)時(shí)期學(xué)的數電的知識聯(lián)系緊密,通?梢苑譃闆](méi)有時(shí)間,只有邏輯轉換的邏輯電路和有時(shí)間和狀態(tài)轉換的時(shí)序邏輯電路兩種形式,再加上通過(guò)調用已經(jīng)模塊化的實(shí)例元件來(lái)參與更高一級的模塊設計。所以在一個(gè)模塊功能的實(shí)現方法中,通常有三種類(lèi)型:

用assign聲明語(yǔ)句
assign語(yǔ)句用于驅動(dòng)線(xiàn)網(wǎng)型的變量,聲明語(yǔ)句右邊表達式的變量是敏感信號,當右邊的值發(fā)生改變時(shí),立即計算左邊的結果,并進(jìn)行表達。也就是說(shuō),當輸入變化時(shí),輸出也隨之變化。這種特性就像是數字電路里的組合邏輯電路。
assign   a_not=~a;
assign   c=a&b;
1
2
采用實(shí)例化的元件
采用實(shí)例的元件方法已經(jīng)在前面講過(guò),除了采用module的實(shí)例化元件以外,還可以采用IP核的形式來(lái)實(shí)現。
采用always語(yǔ)句塊
always語(yǔ)句塊既能描述組合邏輯電路,又能描述時(shí)序邏輯電路。與assign不同的是,always語(yǔ)句后面的觸發(fā)條件是持續敏感,也就是每時(shí)每刻都在執行或者判斷的。后面也會(huì )更加詳細的區別assign和always語(yǔ)句塊。
//生成時(shí)鐘信號
always #5 clk=~clk;

//組合邏輯電路:二選一多路器
reg c_out;
always @(a_in or b_in or sel)
    if(sel)
        c_out=a_in;
    else
        c_out=b_in;

//時(shí)序邏輯電路:二分頻模塊
reg d;
always @(posedge clk or posedge rst)
begin
     if(rst)
         d<=1'b0;
     else
         d=~d;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.5 第一章學(xué)習筆記
verilog是一門(mén)描述硬件電路的語(yǔ)言,在語(yǔ)言結構上和C語(yǔ)言有相同的地方,所以學(xué)習起來(lái)比較容易,但是verilog終究還是要最終用硬件的方法去實(shí)現,因此在編程時(shí),不能空想內部的邏輯,而是通過(guò)電路圖、時(shí)序圖等方式,將功能先用硬件的方法表示出來(lái),然后再用軟件的語(yǔ)言來(lái)實(shí)現。
verilog的使用離不開(kāi)對數字電路基礎知識的掌握,所以在進(jìn)行verilog的學(xué)習的同時(shí),應該建立在對數字電路基礎知識的學(xué)習之上。語(yǔ)言是描述思想的工具,思想才是解決問(wèn)題的關(guān)鍵。

2. verilog 的數據類(lèi)型
verilog的數據類(lèi)型主要分為四類(lèi),整數型、實(shí)數型、字符串型、參數型,這四種類(lèi)型都可以在編程中出現,但是在實(shí)際硬件層面綜合時(shí),卻并不能保證我們所寫(xiě)的數據類(lèi)型能夠被表達。因為在實(shí)際的電路中,無(wú)論是哪種類(lèi)型的數據,最后都要轉化為1、0、X、Z(X、Z分別是未知態(tài)和高阻態(tài))這四種信號狀態(tài)。因此掌握verilog的數據類(lèi)型,最根本的就是掌握各種數據類(lèi)型在實(shí)際電路中的表達。

2.1 整數型
2.1.1 數制
在verilog中,整數有四種數制,分別是
十進(jìn)制:代號d/D
二進(jìn)制:代號b/B
八進(jìn)制:代號o/O
十六進(jìn)制:代號h/H
一個(gè)整數對于進(jìn)制的不同表達,只是數的表達形式不同,但是數字本身代表的數學(xué)含義是相同的。而在硬件電路中,所有的數字都是通過(guò)二進(jìn)制來(lái)進(jìn)行表達的。因此在編程過(guò)程中,對于數字的數學(xué)表示,我們可以采用不同的進(jìn)制,但是對于數字的物理實(shí)現,我們一定是采用二進(jìn)制的方式來(lái)進(jìn)行硬件上的實(shí)現。因此在實(shí)際編程過(guò)程中出現的數字,我們應該從二進(jìn)制的表達中理解其變化的規律。
這種思想可以在verilog的數字表達中得到體現,一般來(lái)說(shuō),我們通過(guò)以下的方式來(lái)表示一個(gè)整數:
<位寬><′><進(jìn)制><數字> <位寬><'><進(jìn)制><數字>
<位寬><

><進(jìn)制><數字>

舉例說(shuō)明:

8'd23                                          //位寬8  十進(jìn)制  數字23
8'b00010111                                    //位寬8  二進(jìn)制  數字23  
8'o27                                          //位寬8  八進(jìn)制  數字23
8'h17                                          //位寬8  十六進(jìn)制  數字23
1
2
3
4
對于任何一個(gè)數字,無(wú)論其后面是什么進(jìn)制,什么數字,最后都要轉化為指定位寬的二進(jìn)制數字來(lái)表達。因此有可能在進(jìn)制表達時(shí),出現實(shí)際的二進(jìn)制數字和我們編程所寫(xiě)的二進(jìn)制數字不同;蛘咂渌菢藴实谋磉_方法。下面我們說(shuō)明幾種常見(jiàn)的情況:

位寬大于實(shí)際數字二進(jìn)制的寬度
位寬大于實(shí)際二進(jìn)制的寬度時(shí),有四種可能:
1.二進(jìn)制數字最高位為1,高位部分用0補全
2.二進(jìn)制數字最高位為0,高位部分用0補全
3.二進(jìn)制數字最高位為X,高位部分用X補全
4.二進(jìn)制數字最高位為Z,高位部分用Z補全
例如:
6'b101      //實(shí)際上是  000101
6'b001      //實(shí)際上是  000001
6'bx11      //實(shí)際上是  xxxx11
6'bz11      //實(shí)際上是  zzzz11
1
2
3
4
位寬小于實(shí)際二進(jìn)制的寬度
當位寬小于實(shí)際二進(jìn)制寬度時(shí),一般情況下是將超過(guò)的位數舍去,只保留給定位寬內的數,例如:
4'b101011        //實(shí)際上是  1011
1
位寬省略不寫(xiě)
一般情況下,位寬省略不寫(xiě),默認為是32位寬的數,或者根據操作系統和編程軟件的設定來(lái)定義。例如:
'b10111     //位寬為32的二進(jìn)制數 代表數字23
1
數制位寬都省略不寫(xiě)
這種情況下,默認為數字是32位寬的十進(jìn)制數。例如
23          //位寬為32的十進(jìn)制數 代表數字23
1
下劃線(xiàn)表達法
當需要表達的數字位數較多時(shí),為了書(shū)寫(xiě)和觀(guān)察方便,常常使用下劃線(xiàn)符號來(lái)輔助表達。采用下劃線(xiàn)將相鄰若干個(gè)數字分隔開(kāi),使其表達更清晰。但是注意下劃線(xiàn)只能出現在數字中,不能出現在位寬和進(jìn)制中,并且數字的第一位不能是下劃線(xiàn)。例如:
16'b0100_1011_1101_0110                      //正確
16'b_1110_1101_0101_0001                     //錯誤
1
2
2.1.2 負數
負數在verilog中的表達是很簡(jiǎn)單的,直接在數字的前面添加符號就表示負數。但是在實(shí)際的二進(jìn)制編碼中,負數是通過(guò)其正數的補碼的形式進(jìn)行實(shí)現的。

-8'd23      //就是-23,但是在二進(jìn)制代碼中 是用8'b11101001來(lái)表示
1
此時(shí)對于一個(gè)8位的二進(jìn)制數,其第一位為符號位,后7位才為有效的數字位。
由此可見(jiàn),一個(gè)二進(jìn)制,當首位為1時(shí),有可能表示的是一個(gè)正數,也有可能表示的是一個(gè)負數,那么在實(shí)際硬件電路中,如何區分這兩種情況呢?
一般來(lái)說(shuō),對于硬件中的信號,硬件處理時(shí)是默認為正整數的,因此當我們輸入一個(gè)負值,實(shí)際上產(chǎn)生的是我們輸入的值的正數部分的補碼所表示的正值(這里有點(diǎn)繞,距離來(lái)說(shuō),我輸入-8’d23,得到的是23的補碼8’b11101001,這個(gè)補碼被硬件默認是正數,即8’d233)。那么我們在進(jìn)行二進(jìn)制的數據的變換時(shí),就應該回歸其硬件中的表達,然后在此基礎上通過(guò)自己的程序來(lái)實(shí)現當為負數時(shí)的轉化。
例如:我之前寫(xiě)過(guò)的粗插補算法

                    if(x_rough[15]==0)                //當插補數據為正數時(shí),將粗插補數據進(jìn)行四分,并將余數添加到第一個(gè)精插補結果中
                    begin
                        lx[1:0]=x_rough[1:0];
                            x4=(x_rough>>2);
                            x3=(x_rough>>2);
                            x2=(x_rough>>2);
                            x1=((x_rough>>2)+lx);
                        end
               else                              //當插補數據為負數時(shí),將插補數據求補碼,進(jìn)行四分等操作后,再將結果求補碼得到負數(對絕對值進(jìn)行操作)
                    begin
                        x_complement[15:0]=(~(x_rough[15:0]-8'b0000000000000001));
                        lx[1:0]=x_complement[1:0];
                            x4=((~(x_complement>>2))+8'b0000000000000001);
                            x3=((~(x_complement>>2))+8'b0000000000000001);
                            x2=((~(x_complement>>2))+8'b0000000000000001);
                            x1=((~((x_complement>>2)+lx))+8'b0000000000000001);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
這里就是根據最高位是1和0來(lái)決定進(jìn)行什么樣的數據處理?偠灾,我們要明白,數據在硬件中的儲存是默認為正整數的二進(jìn)制儲存方式,但是如何取理解這個(gè)數,卻是使用這個(gè)數據的人自己規定的。這種思想不僅在處理負數時(shí)是這樣的,在碰到小數、字符等都是這么一個(gè)思想。0和1的世界是死的,但是解讀他們的規則卻是活的。

2.1.3 X和Z
我們都知道0和1代表的含義,但是對于verilog語(yǔ)言來(lái)說(shuō),還有X和Z兩種獨立于0和1之外的狀態(tài)。這兩種狀態(tài)分別是未知態(tài)和高阻態(tài)。
未知態(tài)X是指,無(wú)法確定此時(shí)信號的狀態(tài)是1還是0,但是能確定信號是有狀態(tài)的,不是1就是0,且這個(gè)狀態(tài)是能夠影響到與其相連的后續電路的,當我們用電表測量時(shí),其值可能是1,可能是0,取決于被測當時(shí)硬件電路的當前狀態(tài)。而高阻態(tài)Z是指,當前的信號狀態(tài)既不是1,也不是0,而是沒(méi)有狀態(tài),或者可以認為是斷開(kāi),即此時(shí)信號的狀態(tài)已經(jīng)無(wú)法再影響到后續的電路。
而在實(shí)際電路中,某一時(shí)刻時(shí)只有1、0、高阻態(tài)三種狀態(tài)。
盡管X和Z表示的狀態(tài)不是傳統的1和0,但是X和Z也能參與到二進(jìn)制的邏輯運算中來(lái)。在邏輯運算中,X和Z滿(mǎn)足如下的規律:

0 && X = 0 ;
1 && X = X ;
0 || X = X ;
1 || X = 1 ;

0 && Z = 0 ;
1 && Z = X ;
0 || Z = X ;
1 || Z = 1 ;
1
2
3
4
5
6
7
8
9
2.2 實(shí)數型和字符型
實(shí)數型和字符型放在一起,因為這兩種數據的表達有相似的地方。那就是實(shí)數型或者字符型的數據可以在verilog語(yǔ)言中出現,但是卻不能通過(guò)硬件表達出來(lái)。而是常常出現在命令、顯示等非硬件參與的操作中。這與上面的整數的表達方式和意義是不同的。

2.2.1 實(shí)數
實(shí)數可以用十進(jìn)制來(lái)表示,也可以用科學(xué)計數法來(lái)表示,例如:

12          //表示12
23e-3       //表示0.0023
23E4        //表示230000
1
2
3
雖然我們可以在verilog中寫(xiě)出這些數據,但是并不是所有我們寫(xiě)出來(lái)的數據都能在硬件中表達。在實(shí)際的仿真過(guò)程中,所有的科學(xué)計數的表達例如23e-3或者23E4,在硬件中都是0,而硬件中也不能直接表達小數。也就是直接在verilog中寫(xiě)出來(lái)的小數,會(huì )被硬件識別為0。
但是小數或者指數的表達,可以通過(guò)使用者自己規定來(lái)獲得。例如我們常聽(tīng)說(shuō)的浮點(diǎn)數等,就是通過(guò)一些算法轉換,來(lái)將二進(jìn)制的代碼表達成帶有小數或者指數的數字。

3. verilog 的變量類(lèi)型
4. verilog 的運算符
5. verilog 的語(yǔ)句塊
點(diǎn)贊 10
————————————————
版權聲明:本文為CSDN博主「Dobolong」的原創(chuàng )文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/DBLLLLLLLL/article/details/84306098

本文地址:http://selenalain.com/thread-579372-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
freeloopfpga 發(fā)表于 2020-3-24 15:29:34
感謝大佬分享,學(xué)習了!
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页