Verilog 語言基礎


Verilog 語言基礎

三種描述方式

1.數據流描述
通常指采用assign語句進行連續賦值(continous assignment),連續賦值意味着輸入的變化會立即導致輸出的變化,這正是組合邏輯電路的特點。注意:assgin是不能用在always或者initial語句塊中的,且通常搭配wire或者tri變量

	assign #3 result = (Sel_in)? B_in:A_in;//when Sel_in,B_in or A_in changed, result changed immediately

2.行為描述
行為描述通常用於描述電路中的行為,行為描述適用於實現順序執行,從而實現時序邏輯電路,通常通過always或者initial代碼塊的方式來寫。注意:begin end塊只能出現在行為描述的代碼塊中,硬件描述和C語言程序的顯著區別在於C語言是默認順序執行的,而硬件描述語言則是默認並行執行的。通常搭配reg變量,reg即寄存器只有執行相應代碼塊時才能改變,其余時候無論輸入變化都不改變。

//一個2-4譯碼器的代碼塊
always@(result)
begin
	case(result)
	2'b00 : begin
				{eq3,eq2,eq1,eq0} = #2 4'b0001;
				$display("At time %t -",$time,"eq0=1");
			end
	2'b01 : begin
				{eq3,eq2,eq1,eq0} = #2 4'b0010;
				$display("At time %t -",$time,"eq1=1");
			end
    2'b10 : begin
				{eq3,eq2,eq1,eq0} = #2 4'b0100;
				$display("At time %t -",$time,"eq2=1");
			end
    2'b11 : begin
				{eq3,eq2,eq1,eq0} = #2 4'b1000;
				$display("At time %t -",$time,"eq3=1");
			end       
    default:;
    endcase
end

3.結構化描述
結構化描述指的是通過實例化已有的功能模塊進行硬件描述,這其實很像C語言中的函數調用,同樣結構化地描述也為多人合作開發大規模硬件實現了可能。需要注意的是,如果在描述中反復使用了同一個模塊,需要分別命名各個模塊,因為在實際電路中對應着若干個實際模塊而非一個,module的使用稱為實例化(Instantiate)。

//假設已經存在了一個一位加法器模塊 module add1(input a,input b,cin,cout,sum)
//兩位加法器的擴展
module add2(input[1:0] in1,input[1:0] in2,output[1:0] out)
	wire cout;
	add1 ADD1(in1[0],in2[0],0,cout,out[0]);
	add1 ADD2(in1[1],in2[1],cout, ,out[1]);//兩個一位加法器可以擴展為兩位加法器
endmodule

4.一些簡單的規范
Verilog同C一樣對大小寫敏感,因而在信號命名上也應盡量規范。一般而言:推薦所有信號和線網名用小寫,單詞間使用下划線連接,而宏變量則應該全部用大寫。
在一個Verilog文件推薦指存放一個module定義,並且使得module名字與文件名相同;

模塊與端口

1.module通常是具有輸入和輸出的(有一些特殊的用於仿真的module是沒有的),從語法上說也接近於C語言中的函數。
2.端口列表類似於C語言函數中的函數參數列表,也是由端口類型於名字組成,例如:input[1:0] in1,output[1:0] out, inout[1:0] io1 等等。其中[1:0]表示的是對應端口的位寬,即兩位分別為in[0],in[1],類似於數組或者向量vector,也可以通過in[i]調用特定的位進行計算
3.通常來說輸入是wire類型,輸出是reg類型,inout雙向信號多用於總線管理是tri類型(即三態門,含有高阻態以阻斷電氣連接)
4.特別要強調的是:module中的內容在沒有特殊說明時是並行的,就好像原理圖是先畫任意一個門一樣,不影響結果。

module 模塊名稱(端口列表)
//聲明:
	reg,wire,parameter,
	input,output,inout,
	function,task
//語句:
	initial 語句
	always 語句
	module 實例化
	門實例化
	用戶定義原語實例化(UPD)
	連續賦值 assign ...

編譯指令

類似於C語言中的 #include<stdio.h>等的預指令,Verilog中也存在一些編譯指令來指導編譯器工作,對應於C中的”#“,Verilog的編譯指令前需要加反引號“`"以下介紹幾個常見的編譯指令:
1."`timescale"用於表示時間延遲的單位和精度,在module文件前加上該指令可以保證該模塊中的延遲信息采用這個單位,否則則是使用缺省值或者沿用上一個模塊的延遲值;舉例:

`timescale 1ns/100ps //1ns為延遲時間,100ps為時間精度,即處理時1.23ns≈1.2ns

2.”`define"同C語言中一樣用於定義宏與之相對的有“`undef”,遇到之后取消前一個定義的宏

`define BUS_WIDTH 16 //定義總線寬度
module(...);
	reg[BUS_WIDTH:0] data;
	...
endmodule

3.“`ifdef, `else, `endif”同C語言中一樣是條件編譯符,條件發生時執行編譯指令

`ifdef NARROW	//若已經定義了NARROW宏則執行
	parameter BUSWIDTH=16;
`else
	parameter BUSWIDTH=32;
`endif

4."`include"表示嵌入某個文件內容,同C語言中也是一樣的,編譯時使用相應文件的內容替換該行代碼

`include "HEADFILE.h"

5."`resetall"將所有的編譯指令的值設置為缺省值

邏輯值與常量的表示

1.邏輯值:主要有0,1,Z(高阻態),X(不定態,對應CMOS中上下均導通時)
2.常量:注意常量的表示方法,b,d,o,h分別代表二進制,十進制,八進制,十六進制
常量包含整數型,實數型,字符串型

	//[位寬]'進制 數字
	4'b1011//數值等於十進制下的11
	5'd0011//十進制11,但是占5位寬
	13_2.18e2//表示13218
	reg[1:8*11] message = "Hello World";//需要11個字節存儲

變量類型

Verilog中主要有線網類型和寄存器類型兩大變量類型
凡是用assgin賦值的一定是線網類型,凡是在always或者initial代碼塊中賦值的一定是寄存器類型

線網型:表示物理連線,仿真時也不占用仿真內存

主要有幾種子類
1.wire、tri:電路間聯線,tri用於多驅動源
2.wor、trior、wireand、triand:實現線與、線或
3.trireg:表示該聯線有總線保持功能

准確的說,線網是被驅動(drive)而非賦值,驅動是指在每一個仿真步進上都要重新計算,即連續驅動(continuous assignment)

寄存器類型:一個抽象的數據存儲單元,仿真時占用內存

寄存器類型即對應了實際的寄存器器件需要滿足相應條件才能改變其中的值,不會隨着輸入變化而持續地變化。
reg:常用的寄存器類型數據
integer:整型數據,至少32位
time:整型時間,至少64位
realtime,real:實數時間與實數寄存器

寄存器是可以以寄存器組的形式定義和使用的

	reg[3:0] Mem[0:7];//定義一個存儲單元地址為0到7,每個單元四位
	always@(eq1 or eq0)
		reg xor = #1 eq0^eq1;//實際上就是一個異或門
	initial
		begin 
		integer i;//integer可以輔助循環,同C語言是一樣的
		for(i=0;i<7;i++)
			begin
				Mem[i]=i;
			end
		end

注意:代碼中的reg不一定總是對應着實際中的寄存器

參數

參數也是一種常量,但是通常有一些特殊的用途,比如狀態機的狀態,總線的帶寬等等。同時參數也可以在編譯時就通過編譯指令進行改變。特性即類似於C語言中的宏

`define BUS_WIDTH 16;
module();
	parameter BUS_WIDTH;
endmodule

並發與順序

這是硬件描述與程序設計語言差別最大的地方,硬件描述總是默認是並行執行的,但是在always和initial塊中可以產生順序或者並發執行。
begin... ...end:順序執行語句
fork... ...join:並發執行語句

操作數、操作符與表達式

1.操作符
這里說幾個需要注意的算符:
&m:只對m數按位作歸約與的結果(每一位相與,1111結果為1,1110結果為0)或,而m&n則是兩變量之間按位與(11&10為10,01&10結果為00,注意位數)
sel?m:n:條件運算符,與C語言相同,可以代替一個if操作
{}:連接運算符,{n,m}結果為二者連接即更長的一個數,{n{m}}結果為n個m相連接,可以代替一些循環操作。

2.操作數
操作數的類型前文全部都介紹過了,這里要說明兩個問題:
多位操作數是可以類似於數組和向量按位操作的(wire[3:0] in ,可以直接操作 in[0]),也可以對模塊返回值進行操作,類似於C語言中函數的返回值

特別注意,操作數的極性(正負):
線網變量,一般寄存器變量,基數格式表示的整數常數是沒有正負的;
整型寄存器變量於十進制整型常量是有正負的(補碼表示前面全1)。

系統任務與系統函數

1.顯示任務
$display使用即類似於C語言中的printf

$display("At time %t -",$time,"eq0=1");//%t表示時間,通過time系統函數產生時間
$display("The value of ABC is %d",ABC);

2.文件輸入輸出任務
$fopen 打開文件並返回該文件指針
$fdisplay可以使用文件指針寫入信息
$fclose關閉文件

integer Write_Out_File;
Write_out_File=$fopen("Write_out_File.txt");
$fdisplay(Write_Out_File,"@%h\n%h",Mpi_Add,Data_in);
//向指定文件中的指定地址(@的內容是地址Mpi_Add),后面的是內容(Data_in)
$fclose(Write_Out_File);//關閉指定文件

3.仿真控制任務
$finish仿真器退出
$stop仿真器掛起
2.時序驗證任務與時間仿真函數
$setup檢查建立時間
$hold檢查保持時間
$time返回一個64位的模擬時間
3.概率分布函數
$random產生一個32位的有符號整型隨機數

主要內容和示例來源:《輕松稱為設計高手 Verilog HDL實用精解》;北京航空航天大學出版社;
推薦練習網站:https://hdlbits.01xz.net/wiki


免責聲明!

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



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