目錄
- 0 前言
- 1 輸出端口的設計
-
- 1.1 門級描述和資料流描述
- 1.2 行為級描述
- 2 三種描述方式的整體架構
-
- 2.1 門級描述
- 2.2 資料流描述
- 2.3 行為級描述
- 2.4 補充:獨立的語句
- 2.5 小結
- 3 了解三種描述方式的本質
-
- 3.1 門級描述
- 3.2 資料流描述
- 3.3 行為級描述
- 4 了解不同抽象層級描述方式與功能設計之間的聯系
-
- 4.1 需求分析 & 行為級描述
- 4.2 求邏輯表達式 & 資料流描述
- 4.3 畫邏輯電路圖 & 門級描述
- 4.4 小結
- 5 激勵塊的特殊設定
- 6 善用科技黑箱:利用行為級描述和內建器件快速完成設計
0 前言
本文從整體上帶你完成Verilog HDL語言的三種不同描述方式,讓你從宏觀上有所把握。
最核心的原則:一切設計實際需求而定,需要存儲變量就用
reg
,需要有符号數就用
integer/real/reg signed
……
1 輸出端口的設計
端口的設計,差別主要在于輸出端口是
預設的wire
還是
自定義的reg
,本篇将以1位四選一資料選擇器為例進行說明。
1.1 門級描述和資料流描述
這兩種描述的時候,使用預設的
wire
即可。
這兩種描述方式,本質上都是直接使用邏輯門
- 門級描述是顯式地使用了門級原語
- 資料流描述其實是隐式地使用門級原語,因為他是直接描述資料在寄存器直接的流動關系,本質上,還是在闡述邏輯門的使用
門級描述與資料流描述,就好比結繩記事和使用符号記事的差別,用一連串的符号标志,代替了繩子,減少了許多麻煩。
- 門級描述是以門級原語為基石的描述方式,必須使用線網類型
- 資料流描述是以連續指派語句為基石的描述方式,其左值必須是線網類型,右值無要求。
以下是四選一資料選擇器的端口聲明,關注
output out
語句
module choose_4to1(
input d0,d1,d2,d3,
input add1,add0,
output out // 注意輸出端口的設定
);
endmodule
你需要記住Verilog描述形式
需要記住,門級描述的輸出和資料流描述的連續指派語句的左值,必須是線網類型,是以必須使用預設的輸出端口
1.2 行為級描述
行為級描述,輸出端口類型應該使用
output reg OUT
,使用
reg
類型。
因為過程指派語句的左值必須是寄存器類型
ANSI C風格的描述如下
module choose_4to1(
input d0,d1,d2,d3,
input add1,add0,
output reg out // 注意輸出端口的設定
);
endmodule
你也可以将輸出端口初始化
output reg out = 0
另外一種端口風格,但是不推薦
module choose_4to1(d0,d1,d2,d3,add1,add0,out);
input d0,d1,d2,d3;
input add1,add0;
// 以下兩條語句才能将out聲明為reg類型的輸出端口
output out;
reg out;
endmodule
2 三種描述方式的整體架構
就像蓋房子那樣,同樣是樓房,使用不同的材料,建造的方式不同,速度也不同。
下面我對這幾種描述進行一個近似比喻:
- 門級描述:手裡隻有基本材料,需要先燒制磚頭再蓋房子
- 資料流描述:已經有了現成的磚頭,隻需要将其以合理的方式組合起來
- 行為級描述:已經有了內建的房子,隻需要拼接起來,就像火神山醫院那樣
2.1 門級描述
門級原語:
and
、
or
……
門級描述與門級原語為基本單元
2.2 資料流描述
連續指派語句:
assign
資料流描述以連續指派語句為基本單元
2.3 行為級描述
結構化過程語句:
initial
和
always
行為級描述以結構化過程語句為基本單元
2.4 補充:獨立的語句
獨立的語句指的是
- 輸入輸出端口的聲明,特别的,reg類型輸出端口可以定義的時候初始化,但是輸入端口不允許
module Example (
input a,b,
output reg OUT = 0 //【這裡是關鍵點!】
);
<其他内容>
endmodule
- 内部線網的設定,可以在定義的時候初始化:
wire a = 1;
- 内部變量的聲明,可以在定義的時候初始化:
reg b = 0;
2.5 小結
- 門級描述:輸出部分必須是net類型,門級原語本質是子產品執行個體調用,符合端口連接配接規則
- 資料流描述:左值必須是net類型,右值無要求
- 行為級描述:左值必須是reg類型,右值無要求,這裡的重點是過程指派語句的要求,因為它是行為描述的基本單元,就像C語言的變量那樣。
3 了解三種描述方式的本質
3.1 門級描述
門級描述,使用門級原語對硬體設計進行描述,它直接反應了邏輯門直接的關系,更加接近底層,接近硬體。
3.2 資料流描述
資料流描述,描述了輸出資料與輸入資料之間的邏輯關系,通過邏輯表達式來建立輸入輸出資料的聯系。
邏輯表達式可以了解為對硬體設計功能的數學表達形式。
3.3 行為級描述
行為級描述,直接描述硬體設計所能實作的功能,相當于:設計者告訴軟體需要實作怎樣的功能,由軟體自動生成其門機描述。當然,沒有那麼智能。
4 了解不同抽象層級描述方式與功能設計之間的聯系
此處,我将會以1位四選一資料選擇器的設計為例
4.1 需求分析 & 行為級描述
- 輸入四個資料,從四個裡面選擇一個:d0,d1,d2,d3
- 通過位址控制選擇哪個:s1,s0
其行為描述是:
- 對于輸入的資料
- 如果位址是
,則輸出00
d0
- 否則,如果位址是
,則輸出01
d1
- 否則,如果位址是
,則輸出10
d2
- 否則,如果位址是
,則輸出11
d3
- 否則,輸出
x
設計塊如下:
if語句版本的設計塊
module mux_4to1 (
input d0,d1,d2,d3,
input s1,s0,
output reg out = 0
);
always @(*)
begin
if ({s1,s0} == 2'b_00)
out = d0;
else if ({s1,s0} == 2'b_01)
out = d1;
else if ({s1,s0} == 2'b_10)
out = d2;
else if ({s1,s0} == 2'b_11)
out = d3;
else
out = 1'bx;
end
endmodule
case語句版本的設計塊
module mux_4to1 (
input d0,d1,d2,d3,
input s1,s0,
output reg out = 0
);
always @(*)
begin
case({s1,s0})
2'b00: out = d0; // 也可寫成【2'd0】
2'b01: out = d1; // 【2'd1】
2'b10: out = d2; // 甚至于你可以直接寫【2】
2'b11: out = d3; // 【3】
default: $display("錯誤!\n"); // 千萬别忘記這個
endcase
end
endmodule
激勵塊如下:
module test4;
reg d0 = 0,d1 = 1,d2 = 0,d3 = 1;
reg s1,s0;
wire out;
mux_4to1 MT0 (d0,d1,d2,d3,s1,s0,out);
initial
$monitor("s1 = %b, s0 = %b, out = %b\n",s1,s0,out);
initial
begin
#1 s1 <= 0; s0 <= 0;
#1 s1 <= 0; s0 <= 1;
#1 s1 <= 1; s0 <= 0;
#1 s1 <= 1; s0 <= 1;
end
endmodule
輸出結果為:

事實上,行為級描述,不僅僅可以适用于1位位寬,更可以直接設定為32位位寬,這是其他描述方式做不到的,他們需要将1位的子產品組合成32位的。
4.2 求邏輯表達式 & 資料流描述
- 列出真值表
- 求邏輯表達式:
out = (~s1 & ~s0 & d0) | (~s1 & s0 & d1) | (s1 & ~s0 & d2) | (s1 & s0 & d3)
邏輯表達式,表示了輸出與輸入直接的邏輯關系,可以直接使用資料流描述。
事實上,隻有你寫得出邏輯表達式,就能使用資料流描述,但是,對于複雜問題往往很難将其邏輯表達式寫清楚,并且當今時代有很多內建的子產品,完全可以直接調用他們,而沒有必要再自己設計,這一點我在後面再進行闡述。
設計塊:
邏輯表達式版本的設計塊
module mux_4to1(
input d0,d1,d2,d3,
input s1,s0,
output out
);
assign out = (~s1 & ~s0 & d0) |
(~s1 & s0 & d1) |
(s1 & ~s0 & d2) |
(s1 & s0 & d3);
endmodule
條件操作符版本的設計塊,這個其實已經和行為級描述類似了。
module mux_4to1 (
input d0,d1,d2,d3,
input s1,s0,
output out
);
assign out = s1? (s0? d3:d2):(s0? d1:d0);
endmodule
激勵塊與仿真結果和行為級一樣,不再贅述。
4.3 畫邏輯電路圖 & 門級描述
- 選擇器件
- 根據邏輯表達式畫出邏輯電路圖
此處選用基本的邏輯門作為器件。
相比之下,門級描述顯得非常複雜,這裡不再贅述,請讀者自行查閱資料。
當今時代也很少有人再使用門級描述。
4.4 小結
當今時代人們會使用資料流描述和行為級描述,對于某些必要的部分使用門級描述,但是這種情況非常少。
通常我們使用的是RTL級描述,也就是資料流和行為級描述的混合描述方式。
我們來觀察兩條線對比以下
結果顯而易見,行為級描述更加簡單,提高了效率,但是,由于行為級描述目前沒有足夠智能,有些事情不能完成,是以我們依然需要資料流描述,但是門級描述幾乎已經不需要了。
5 激勵塊的特殊設定
首先,采用分治思想,将激勵塊和設計塊分開看,激勵塊的輸出顯示結果,是由激勵信号的類型決定的,在符合端口對接規則的前提下,需要對激勵信号的資料類型加以修飾,以達到驗證輸出結果的目的。
目前我們的激勵塊是這樣是:
reg d0 = 0,d1 = 1,d2 = 0,d3 = 1;
reg s1,s0;
wire out;
如果,我們需要輸入的是有符号數,則可以改為
reg signed d0;
或者
integer d0;
或者
real d0;
,請記住,輸入端口的reg類型,代表的是一組寄存器類型,而不單單是reg。
如果我們需要輸出的結果顯示為十進制的負數,則需要設定為
wire signed out;
,代表其是有符号數。
這也充分展現了開篇所說的:一切設計由需求決定。
6 善用科技黑箱:利用行為級描述和內建器件快速完成設計
科技黑箱就是其他設計者已經開發好的功能,你可以直接拿來使用,以提高開發效率。它也可以是C++中的STL庫,Python的庫等等。
同時,我想你也已經感受到三種描述方式在開發效率方面的差别,多多使用RTL級描述,會大大提高設計者的開發效率。
簡而言之,就是把别人做好的東西直接拿來用,幫助你快速完成你設計的東西。