聲明:本篇文章部分參考
https://www.cnblogs.com/protogenoi/p/8926993.html Verilog筆記.1.基本語法 作者:Protogenoi
一、Verilog語言整體印象
1、模塊是基本描述單位。端口默認是線網數據類型。端口長度聲明,默認1位。output [0:3] Z;4位
實例化:指調用軟件自帶的模塊(如內置門級元件)和自己編寫的模塊。
2、描述設計:有四種方式
1. 數據流描述方式:assign:連續賦值語句,語句併發。編譯器指令:` timescale 1ns /100ps 時間單位、時間精度
2. 行爲描述方式:過程語句initial、always。只有reg(寄存器)類型能在兩種語句中賦值。順序執行。
always=事 件控制(判斷條件)+順序過程。always語句塊可以理解爲while語句嗎?
3. 結構化描述方式:原語,硬件級, xor、and和or的實例語句
4. 混合設計描述方式:門實例語句,模塊實例語句、連續賦值語句,過程語句。
過程賦值vs連續賦值:
1.過程賦值改變寄存器的狀態,是時序邏輯,用在initial和always裏面;
2.連續賦值是組合邏輯,驅動線型變量(wire)
3、設計模擬:激勵、控制、存儲響應、設計驗證
1. 激勵和控制可以由初始化語句產生
4、抽象模型分級
系統級:用高級語言結構實現設計模塊的外部性能的模型。
算法級:用高級語言結構實現設計算法的模型。
RTL級:描述數據在存儲器之間流動和如何處理這些數據的模型。
門級:描述邏輯門與邏輯門之間的連接的模型。
開關級:描述器件中三極管和存儲節點以及它們連接的模型。
二、Verilog語言要素
1、Verilog內置的12個門級元件,模塊可以實例引用門級模型, 對結構進行實例化描述。
2、運算符
(1) 算術運算符 +,-,*,/,%
(2) 賦值運算符 =,<=
賦值語句:組合邏輯,順序執行,阻塞賦值,使用=賦值。時序邏輯,並行執行,非阻塞賦值,使用<=賦值。
(3) 關係運算符> ,<,>=,<=
(4) 邏輯運算符 &&, ||, ! (與或非)
(5) 條件運算符 ?:
(6) 位運算符 ~, | , ^ ,& ,^~ (取反、或、異或、與、同或)
(7) 移位運算符 << ,>>
(8) 拼接運算符 {}
3、特殊標識符
$開始的標識符表示系統任務/函數 。
ps: 函數vs任務。任務可以返回0或多個值,函數返回一個值。函數在0時刻執行,不允許延遲,任務可以帶有延遲。
'開始的標識符是編譯器指令。編譯器指令在整個編譯過程中有效(類似於宏定義)
4、操作數
四種基本值:0,1,x,z:假,真,未知,高阻態。
三類常量:整形、實數型、字符串型。
整形表示法:
(1)十進制表示:<數字> 默認採用十進制
(2)基數表示法:<位寬>'<進制><數字> 位寬表示佔用二進制位數 (bodh:二八十十六)
5、數據類型
(1)線網和寄存器
Verilog兩大類數據類型:線網和寄存器,線網有11鍾類型,寄存器有5鍾類型。
線網類型:表示結構化元件間的物理連線,值由驅動元件決定。
寄存器類型:在always和initial語句賦值過程中的存儲單元。五種寄存器類型:reg,integer,time,real,realtime。
區別:wire只能由assign連續賦值語句中賦值,reg只能在initial/always過程賦值語句中賦值。
更多參考:https://www.cnblogs.com/wzd5230/p/3847481.html verilog中wire與reg類型的區別
reg [msb:lsb] reg1 msb:lsb表示位數範圍,大小方向都可以。
reg [0:3] MyMem [0:64] 存儲器(寄存器數組)MyMem爲64個4位寄存器的數組。線網類型沒有對應點的存儲器類型。
(2)參數
定義一個標誌符代表一個常量(三種類型,如上),常用於定義延遲時間和變量寬度。
parameter <標誌符> = <常量>
三、語句、子程序
1、賦值語句:Verilog中信號有兩種賦值方式
(1)連續賦值語句:assign 用於對線網進行賦值,等價於門級描述。
- 左值必須爲一個線網類型的變量或向量,不能是寄存器類型。
- 輸出值隨輸入值變化而隨時變化。
- 操作數可以是線網或寄存器或函數調用。
- 必須用“=”阻塞賦值進行賦值。
(2)過程賦值語句:=,<=
- 非阻塞賦值方式( 如 b <= a; )
- 塊結束後才完成賦值操作。
- b的值並不是立刻就改變的。
- 這是一種比較常用的賦值方法。(特別在編寫可綜合模塊時)
- 阻塞賦值方式( 如 b = a; )
- 賦值語句執行完後,塊才結束。
- b的值在賦值語句執行完後立刻就改變的。
- 可能會產生意想不到的結果。
2、塊語句:將多條語句結合在一起。塊語句有兩種,一種是begin_end語句,通常用來標識順序執行的語句,用它來標識的塊稱爲順序塊。一種是fork_join語句,通常用來標識並行執行的語句,用它來標識的塊稱爲並行塊。
3、條件語句:if_else語句、case語句。略。
4、過程語句:initial、always。
initial語句常用於仿真中的初始化,initial過程塊中的語句僅執行一次;always語句則是不斷重複執行的。
每一條initial語句和always語句都是獨立的執行過程,彼此並行執行,執行順序於在模塊內的書寫順序無關,並且,每條initial和always語句過程語句都是在仿真時間0時刻同時開始的。
5、編譯預處理 `與系統指令#
1)宏定義 `define
2)“文件包含”處理`include
3)時間尺度 `timescale
4)條件編譯命令`ifdef、`else、`endif
6、循環語句:forever,repeat,while,for
參考文獻:https://www.cnblogs.com/SYoong/p/5857367.html Verilog學習筆記基本語法篇(六)········ 循環語句
7、子程序:task、function
參考文獻:https://blog.csdn.net/HengZo/article/details/49688677 Verilog之function使用說明
參考文獻:https://www.cnblogs.com/SYoong/p/5865546.html Verilog學習筆記基本語法篇(九)任務和函數
8、實例語句
模塊實例語句:<模塊名> <標誌符>(<對應端口1>,<對應端口2>...)
內置門實例語句:<關鍵字> <標誌符>(<輸出端口>,<輸入端口1>...) 這裏的關鍵字也叫內置門原語xor等,標誌符也叫實例名稱,括號裏是信號列表。信號列表有位置管理和名稱關聯兩種。
四、demo
1、全加器:邏輯:A加數 B被加數 Cin低位進位 S和 Cout高位進位
2、行爲描述方式:
// 行爲描述,全加器
module FA(a,b,ci,s,co);
input a,b,ci;
output s,co;
reg s,co,t1,t2,t3;
always @(a or b or ci) begin
s=(a ^ b)^ci;
t1=a & b;
t2=a & ci;
t3=b & ci;
co=(t1|t2)|t3;
end
endmodule
`timescale 1 ns/ 1 ns
module FA_test();
reg Pa,Pb,Pci;
wire Ps,Pco;
FA F1(Pa,Pb,Pci,Ps,Pco); //模塊實例語句:待測模塊名 引用名(信號端口一一對應,位置關聯)
initial begin: ONLY_ONCE
reg [3:0] i;
for (i=0;i<8;i=i+1)
begin
#20 {Pa,Pb,Pci}=i;
end
end
endmodule
3、流水燈
module waterled(
input clk,
input rst,
output reg [3:0] led
);
reg [7:0] times;
always @ (posedge clk or negedge rst) // 時鐘信號計數
begin
if(!rst)
times<=1'b0; // 電路未復位,計數器鎖定爲0
else
if(times<8'd10) // 電路復位開始計數,計數到10重置
times<=times+1'b1;
else
times<=8'd0;
end
always @ (posedge clk or negedge rst) // 計數滿10,四位數組中的1進位一次
begin
if(!rst)
led<=4'b0001; // 電路未復位 led[0]=1
else
if(times==8'd10) // 計數滿10,led高位到低位,1向前進位
led<={led[2:0],led[3]};
else
led<=led;
end
endmodule
`timescale 1 ns/ 1 ns
module waterled_test;
wire [3:0] led;
reg rst,clk10;
waterled i1 (clk10,rst,led); //例化語句
always #10 clk10=~clk10; // 產生時鐘信號
initial begin
clk10=1'b0;
rst=1'b0;
#100 rst=1'b1; // 100ns時,電路復位
#1000 $stop; // 1000ns時,仿真暫停
end
endmodule
4、function demo
module comb15;
function ADD;
input A, B;
ADD = A ^ B;
endfunction
initial begin
$display("Hello %b",ADD(1'b1,1'b0));
end
endmodule
輸出1
module comb15;
function signed [1:0] ADD;
input A, B;
reg S;
S = A ^ B;
endfunction
reg [31:0] N,M;
reg H;
initial begin
N = 100;
M = 100;
H = 32'd100;
$display("Hello",100);
$display("Hello",32'd100);
$display("Hello%b",32'd100);
$display("Hello%b",8'd100);
$display("Hello\n",100);
$display("Hello",N);
$display("Hello",M);
$display("Hello",H);
end
endmodule
display需要begin..and, 超過1句也需要begin..and。
其他參考資料:
https://wenku.baidu.com/view/0d8a1bd4195f312b3169a59c.html verilog中reg和wire類型的區別
https://zhidao.baidu.com/question/135703718.html 請Verilog高手幫助!wire賦值問題
http://bbs.eetop.cn/thread-313513-1-1.html signed的用法
https://vlab.ustc.edu.cn/guide/doc_verilog.html Verilog語法
https://zhidao.baidu.com/question/437300882386090484.html 綜合和仿真
Verilog這門語言真的是。。。語法臃腫代碼效率低。。。這把設計和驗證分開是爲啥子。。。不能斷點調試看變量的值。。。沒有ide。。。 不重視縮進。。。函數名與返回值是一個。。。線網和寄存器類型奇奇怪怪。。。魔!鬼!啊!