1 模塊結構
端口: module 模塊名(端口1, 端口2, 端口3)
內容:
I/O說明:
input 端口名;
output 端口名;
內部信號:
reg [width-1:0] r變量1,r變量2;
wire [width-1:0] w變量1,w變量2;
功能定義:
a. assign 連線
assign a = b&c;
b. 實例化其他元件
and and_inst(q, a, b);
c. always模塊
always @(posedge clk or posedge clr)
begin
if(clr)
q <= 0;
else
if(en)
q <= d;
end
2.數據類型 常量 變量
常量:
整數:<位寬 num'><進制 b|o|d|h><數字>,例如 4'b1010
x值(不定值)和z值(高阻值,也可用?代替)
x和z可以標識某一位或者某一個數字
4'b10x0,4'bx,4'b101z,4'bz,4'b?
負數:整數最前面加-
下劃線:分割數字部分,更加易讀(8'b1000_1000)
參數:parameter
parameter 參數名=表達式;
表達式只能是數字或者定義過的參數
變量:
wire型:wire [n-1:0] 數據名;
wire表示信號,常用來表示assign關鍵字指定的組合邏輯信號
wire型信號可以用作輸入,輸出
reg型:reg [n-1:0] 數據名;
對存儲單元的抽象
常用來表示always模塊內的指定信號,常代表觸發器
always塊內被賦值的每一個信號都必須定義爲reg型
memory型:reg [n-1:0] 存儲器名[m-1:0];
reg [n-1:0]表示基本存儲單元的大小
存儲器名[m-1:0]表示基本存儲單元的個數,存儲空間的容量
對存儲器進行地址索引的表達式必須是常數表達式
一個n位寄存器可以在一條賦值語句裏進行賦值,而一個完整的存儲器不行
運算符及表達式:
基本運算符:+ - * / %
位運算符:~ & | ^ ^~
邏輯運算符:&& || !
關係運算符:< > <= >=
等式運算符:== != (不管x、z,結果可能是不定值)
=== !==(對參數的x、z都進行比較)
移位運算符:<< >>
位拼接運算符:{ },將幾個信號拼接起來,例如{a,b[3:0],w,3'b100}
縮減運算符:C =&B;C =|B;C =^B;
優先級別:和c語言差不多,加括號
賦值語句:
1)非阻塞賦值方式(b <= a)
a.塊結束才完成賦值
b.b的值不是立刻就改變的
c.在可綜合的模塊中常用
2)阻塞賦值方式(b = a)
a.賦值語句執行完成後,塊才結束
b.b的值在賦值語句執行後立刻改變
c.可能會產生意想不到的結果
簡單理解:
非阻塞賦值用了多個觸發器,每次時鐘到達,所有觸發器都觸發一次
阻塞賦值連到同一個觸發器上,時鐘到達,導致所有寄存器被賦值
塊語句:
順序塊:
1)塊內順序執行
2)每條語句的延遲是相對於前一條語句的仿真時間(語句前#num)
3)直到最後一句執行完,流程控制才跳出該塊
begin
語句1;
...
語句n;
end
或
begin:塊名:
塊內聲明;
語句1;
...
語句n;
end
並行塊:
1)塊內是同時執行的
2)語句的延遲是相對於程序流程控制進入塊內時的仿真時間
3)延遲時間是用來給賦值語句提供時序的
4)時序最後的語句執行完,或者disable語句執行時,跳出程序塊
fork
語句1;
...
語句n;
join
或
fork:塊名:
塊內聲明;
語句1;
...
語句n;
join
塊名:可以給每一塊取名,將名字加在begin和fork之後
1)可以在塊內定義局部變量
2)可以被其他語句調用
3)在verilog中,所有變量靜態(都有唯一地址)
起始時間和結束時間:
並行塊和順序塊中有起始時間和結束時間
條件語句:
1)if...else 語句
if(表達式)
語句|語句塊
else
語句|語句塊
2)case語句
case|casez(case?)|casex,最常用的casez
case(控制表達式)
分支表達式1:語句|語句塊
...
分支表達式n:語句|語句塊
default: 語句
endcase
分支表達式的值的位寬必須相等,需要指明位寬
使用if時,最好也要使用else
使用case時,最好用上default
循環語句:
1)forever 連續的執行語句
forever
begin
多條語句
end
常用來生成周期型波形,用來作爲仿真測試信號
不能獨立寫在程序中,必須寫在initial塊中
2)repeat 執行一條語句n次
repeat(常量表達式)
begin
多條語句
end
3)while:執行一條語句直到某個條件不滿足(如果一開始條件不滿足,則一次也不執行)
while(表達式)
begin
多條語句
end
4)for
a) 循環次數變量初始值
b) 循環表達式判斷
c) 執行語句修正循環次數變量
使用方法和c語言基本一致
for(表達式1;表達式2;表達式3)
begin
多條語句
end
結構說明:
initial語句:
initial在仿真一開始就執行,但是隻執行一次
initial
begin
多條語句
end
always語句:
always <控制時序> <語句>
always 在仿真一開始就執行,always語句會不斷重複執行,所以需要時序的控制
不加時序控制,會不停重複執行,形成仿真死鎖
//邊沿觸發
always @(postedge clock or postedge reset)
begin
多條語句
end
//電平觸發,只要a,b任何一個發生變化(上升/下降),就會執行
always @(a or b)
begin
多條語句
end
邊沿觸發的always塊常常用來描述時序邏輯
一個模塊中可以有多個always塊,他們並行執行
task語句:
任務定義:
task <任務名>;
<端口及數據類型聲明語句>
<語句1>
...
<語句n>
endtask
任務調用:
<任務名> (端口1,...端口n)
例子:
//定義
task mytask;
input a,b;
inout c;
output d,e;
...
<語句> //執行任務工作相應的語句
...
c=foo1;
d=foo2;
e=foo3;
endtask
//調用
mytask(v,w,x,y,z);
function語句:
function定義:
function <返回值的類型或範圍> (函數名);
<端口說明語句>
<變量類型說明語句>
begin
多條語句;
end
endfunction
函數調用:
<函數名> (<表達式1>,...,<表達式n>)
函數的使用規則:
1)函數定義中不能包含有任何的時間控制語句
2)函數不能啓動任務
3)定義函數時至少有一個輸入參數
4)在函數的定義中必須有一條賦值語句給函數中的一個內部變量賦以函數的結果值
該函數變量具有和函數名相同的名字
例子:
//函數定義
function [7:0] getbyte;
input [15:0] address;
begin
<說明語句>
getbyte = result_expression;
end
endfunction
//函數調用:
word = control ? {getbyte(mybyte),getbyte(mybyte)} : 0;
系統函數和任務:
verilog語言中每個系統函數和任務前面都用一個標識符$來加以確認
notice:參數爲",,",表示空參數,輸出時顯示空格
1)$display 和 $write
作用:按照指定格式輸出,p1給出格式,p2...pn按序輸出
$display輸出後會自動換行,$write不換行
用法基本和c語言的printf一致
格式:
$display(p1,p2,...pn);
$write(p1,p2,...pn);
例子:
$display("rval=%h hex %d decimal",rval,rval);
2)系統任務 $monitor
用處:
提供了監控和輸出參數列表中的表達式或變量值的功能
仿真器建立了一種機制,使得每當參數列表中變量或者表達式的值發生變化時,
整個參數列表中變量或表達式的值都將輸出顯示。
任何時刻只能有一個$monitor起作用,因此需配合$monitoron和$monitoroff使用,
把需要監視的模塊用$monitoron打開,在監視完畢後及時用$monitoroff關閉
格式:
$monitor(p1,p2,...pn);
$monitor;
$monitoron;
$monitoroff;
例子:
$monitor($time,,"rxd=%b txd=%b",rxd,txd);
3)時間度量系統函數$time
verilog語言中支持兩種時間函數$time和$realtime
$time返回一個64比特值的整數來表示當前仿真時刻值
返回的總是時間尺度的倍數,並且會取整數
例子:
`timescale 10ns/1ns
module test
reg set;
parameter p=1.6;
initial
begin
$monitor($time,,"set=",set);
#p set=0;
#p set=1;
end
endmodule
$realtime返回的時間數字是個一個實型數
和$time一樣都是以時間尺度爲單位
4)系統任務 $finish
$finish的作用是退出仿真器,返回主操作系統
$finish有3個參數,輸出的特徵信息一次變多
參數:
0:不輸出信息
1:輸出當前的仿真時刻和位置
2:輸出當前的仿真時刻和位置,在仿真過程中
所用的memory及CPU時間的統計
5)系統任務 $stop
把EDA工具(如仿真器)設置成暫停模式,在仿真環境中給出一個交互式的
命令提示符,將控制權交給用戶
和$finish一樣,參數爲0,1,2,數越大,信息越多
6)系統任務 $readmemb,$readmemh
用來從文件中讀取數據到寄存器
讀取的文件有格式要求(具體查書)
數據文件的每個被讀取的數字都被存放到地址連續的存儲器單元中
每個數據的存放地址在數據文件中進行說明
二進制數字讀取
$readmemb("<數據文件名>",<存儲器名>);
$readmemb("<數據文件名>",<存儲器名>,<起始地址>);
$readmemb("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
16進制數字讀取
$readmemh("<數據文件名>",<存儲器名>);
$readmemh("<數據文件名>",<存儲器名>,<起始地址>);
$readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>);
例子:
reg [7:0] mem[1:256];
initial $readmemh("mem.data",mem);
initial $readmemh("mem.data",mem,16);
initial $readmemh("mem.data",mem,128,1);
7)系統任務 $random
一個產生隨機數的手段,函數返回一個32bit的隨機數
$random的一般用法 $random % num,返回一個在(-num+1,num-1)範圍
內的隨機數
reg [23:0] rand;
rand = {$random} % 60; //利用拼接返回一個0到59之間的數
編譯預處理:
宏定義 `define
`define 標識符(宏名) 字符串內容(宏內容)
“文件包含”處理 `include
一個源文件可以將另外一個源文件全部包含起來
時間尺度:
`timescale <時間單位>/<時間尺度>
條件編譯:
`ifdef
`else
`endif
重點:
wire表示信號,常用來表示assign關鍵字指定的組合邏輯信號
always塊內被賦值的每一個信號都必須定義爲reg型
非阻塞賦值方式(b <= a)
阻塞賦值方式(b = a)