?
雖然這是一個(gè)浮躁的社會(huì),充滿著一夜暴富的神話,但是學(xué)習(xí)技術(shù)真的很少存在所謂的捷徑。這么說吧,至少貧僧還沒有那個(gè)本事,完成“三周精通某某某”的本領(lǐng)。如果有聽眾還要速成,某家不得不說您老這票錯(cuò)了。小本經(jīng)營(yíng),概不退票啊。急于見到代碼的“傻弟弟”們,實(shí)際上屬于信心缺失的毛病。和不做系統(tǒng)、結(jié)構(gòu)設(shè)計(jì)就直接上 coding 一樣,根本不是“藝高人膽大”,而是信心缺失。第一講,施主沒見到 Verilog 代碼,這一講里面狀況雖然有所改善,但是也好不到那里去:您老還是別妄圖做能綜合或者仿真的代碼,這個(gè)最少要等到下一講。
1. 標(biāo)準(zhǔn)層次,簡(jiǎn)單說明
關(guān)于 Verilog 語(yǔ)言的官方標(biāo)準(zhǔn)全稱是《IEEE Std 1364-2001:IEEE Standard Verilog? Hardware Description Language》。其中包括 27 章以及 8 個(gè)附錄,真正對(duì)于電路設(shè)計(jì)有用的內(nèi)容大約 1/3 的樣子。
Verilog 是一種硬件編程語(yǔ)言,它既是一種結(jié)構(gòu)描述的語(yǔ)言也是一種行為描述的語(yǔ)言,也就是說對(duì)于同一功能的物理電路,我們可以用 Verilog 中提供的數(shù)字電路中較為形象的門級(jí)結(jié)構(gòu)來描述電路,也可以用更為抽象的一些語(yǔ)句來描述電路,于是乎,我們根據(jù)抽象的程度不同,將不同的描述方式進(jìn)行劃分,得到以下幾種不同抽象級(jí)別的描述方式,其中,從上至下,離真相越來越近,也就是說最形象的是開關(guān)級(jí),其次是門級(jí),依次類推,最抽象的是系統(tǒng)級(jí)。
系統(tǒng)級(jí)(System Level):用高級(jí)語(yǔ)言結(jié)構(gòu)實(shí)現(xiàn)設(shè)計(jì)模塊的外部性能的模型;
算法級(jí)(Algorithm Level):用高級(jí)語(yǔ)言結(jié)構(gòu)實(shí)現(xiàn)設(shè)計(jì)算法的模型;
RTL 級(jí)(Register Transfer Level):描述數(shù)據(jù)在寄存器之間流動(dòng)和如何處理這些數(shù)據(jù)的模型;
門級(jí)(Gate Level):描述邏輯門以及邏輯門之間的連接的模型;
開關(guān)級(jí)(Switch Level):描述器件中三極管和存儲(chǔ)節(jié)點(diǎn)以及它們之間連接的模型。
換言之,不同級(jí)別的抽象,也就是說在不同抽象層次上用 Verilog 語(yǔ)言來描述一個(gè)物理電路,若從行為和功能的角度來描述某一電路,則為行為級(jí)描述,系統(tǒng)級(jí)、算法級(jí)和 RTL 級(jí)屬于行為級(jí)描述方式;若從電路的結(jié)構(gòu)來描述某一電路,則為結(jié)構(gòu)級(jí)描述,門級(jí)和開關(guān)級(jí)屬于結(jié)構(gòu)級(jí)描述方式。在實(shí)際應(yīng)用中,我們要根據(jù)需求對(duì)每個(gè) Verilog 模型進(jìn)行設(shè)計(jì),選用不同抽象級(jí)別的描述,才能使我們的設(shè)計(jì)事半功倍。各個(gè)層次的關(guān)系如圖 1 所示。每個(gè)層次都可以單獨(dú)進(jìn)行設(shè)計(jì),這個(gè)和練“龍象般若功”不同,無需按照等級(jí)一層一層玩。
圖 1 Verilog 邏輯層次及其與工程階段的關(guān)系
很多初學(xué)者感覺學(xué)習(xí) Verilog 語(yǔ)言是老虎吃天 ---- 無從下口呢?這是和 Verilog 的貪心不足密切相關(guān)的。從工程方法學(xué)的角度上說,設(shè)計(jì)和驗(yàn)證是完全不同的兩個(gè)行當(dāng),很少有人能夠做到“昆亂不當(dāng)”的。然而,Verilog 標(biāo)準(zhǔn)里面,確實(shí)體現(xiàn)了完全的五味雜糅,認(rèn)為的造成了混亂,這是所謂“困難”的源頭。
本套數(shù)只會(huì)講 RTL 的那些事兒,其他的內(nèi)容請(qǐng)另找?guī)煾蛋桑像牟环磳?duì)。
?
2. 四值變化,閃展騰挪
先看看 Verilog 語(yǔ)言的值域問題,這是大伙兒作戰(zhàn)的主要陣地,不可不查也。
Verilog 語(yǔ)言是描述數(shù)字硬件電路的;而《數(shù)字電路》/《數(shù)字邏輯設(shè)計(jì)》教材里面,又說數(shù)字電路的理論基礎(chǔ)是布爾代數(shù);布爾這個(gè)就偏門了,幫大家查了一下下,都說這個(gè)是“二值”邏輯的。但是,為什么連維基百科里面會(huì)有如下說法?
“四值邏輯
邏輯值及其解釋
0:邏輯低電平,條件為假
1:邏輯高電平,條件為真
z:高阻態(tài),浮動(dòng)
x:未知邏輯電平
信號(hào)強(qiáng)度(從強(qiáng)到弱)及其屬性:
supply:驅(qū)動(dòng)
strong:驅(qū)動(dòng)
pull:驅(qū)動(dòng)
large:存儲(chǔ)
weak:驅(qū)動(dòng)
medium:存儲(chǔ)
small:存儲(chǔ)
highz:高阻態(tài)
上面列出了 Verilog 采用的具有八種信號(hào)強(qiáng)度的四值邏輯(four-valued logic),數(shù)字電路中的信號(hào)可以用邏輯值、信號(hào)強(qiáng)度加以描述。當(dāng)系統(tǒng)遇到信號(hào)之間的競(jìng)爭(zhēng)時(shí),需要考慮各組信號(hào)的狀態(tài)和強(qiáng)度。如果驅(qū)動(dòng)統(tǒng)一線網(wǎng)的信號(hào)強(qiáng)度不同,則輸出結(jié)果是信號(hào)強(qiáng)度高的值;如果兩個(gè)強(qiáng)度相同的信號(hào)之間連接到同一個(gè)線網(wǎng),將會(huì)發(fā)生競(jìng)爭(zhēng),結(jié)果為不確定值 x。
值“0”和“1”不難理解,這個(gè)在數(shù)電里面,大伙兒接觸的多了,無需詳述。
在 Verilog 語(yǔ)言的仿真中間,存在這種模棱兩可的可能,于是“x”這個(gè)第三者出現(xiàn)了,標(biāo)記輸入出現(xiàn)問題。未知邏輯電平“x”的主要出現(xiàn)情況有兩個(gè)。第一個(gè):上面介紹的情況,多出現(xiàn)于觸發(fā)器等不滿足采樣要求(就是前面時(shí)序分析里面介紹的保持時(shí)間和建立時(shí)間),俗稱為“采到邊沿”;另一個(gè):觸發(fā)器等具有存儲(chǔ)功能的器件未被賦初值(包括:FPGA 賦初值和復(fù)位賦初值),俗稱為“無初值”。大多數(shù)時(shí)序電路的當(dāng)前狀態(tài)(也就是各個(gè)觸發(fā)器的當(dāng)前值的集合)是和電路本真以前的狀態(tài)有關(guān)的,這個(gè)后面會(huì)多次看到。沒有初始值,仿真軟件會(huì)郁悶的,后面的值是什么完全沒譜了。仿真總歸比實(shí)際系統(tǒng)仁慈一些,于是輸出的值是“x”而不是隨機(jī)選擇,這樣容易觀察到。在大多數(shù)仿真軟件輸出的波形里面,“x”會(huì)被標(biāo)為醒目的紅色,于是這種現(xiàn)象也就有了一個(gè)通俗的說法:“全國(guó)江山一片紅”。
高阻態(tài)“z”與邏輯未知電平“x”是一個(gè)“語(yǔ)言造”的概念不同,它是在電路系統(tǒng)中真實(shí)存在的。
在總線連接的結(jié)構(gòu)上??偩€上掛有多個(gè)設(shè)備,設(shè)備與總線以高阻的形式連接。這樣在設(shè)備不占用總線時(shí)自動(dòng)釋放總線,以方便其他設(shè)備獲得總線的使用權(quán)。大部分單片機(jī) I/O 使用時(shí)都可以設(shè)置為高阻輸入。高阻輸入可以認(rèn)為輸入電阻是無窮大的,認(rèn)為 I/O 對(duì)前級(jí)影響極小,而且不產(chǎn)生電流(不衰減),而且在一定程度上也增加了芯片的抗電壓沖擊能力。
“二進(jìn)制無符號(hào)數(shù)、有符號(hào)數(shù)的二進(jìn)制編碼”,應(yīng)該屬于數(shù)電教習(xí)提綱里面的“應(yīng)教、應(yīng)知、應(yīng)會(huì)”的內(nèi)容。且容鄙人偷個(gè)懶,抄一點(diǎn)教科書的內(nèi)容。
“二進(jìn)制是計(jì)算技術(shù)中廣泛采用的一種數(shù)制。二進(jìn)制的數(shù)據(jù)是用 0 和 1 兩個(gè)數(shù)碼來表示的數(shù)。它的基數(shù)為 2,進(jìn)位規(guī)則是“逢二進(jìn)一”,借位規(guī)則是“借一當(dāng)二”,由 17 世紀(jì)德國(guó)數(shù)理哲學(xué)大師萊布尼茲發(fā)現(xiàn)。當(dāng)前的計(jì)算機(jī)系統(tǒng)使用的基本上是二進(jìn)制系統(tǒng),數(shù)據(jù)在計(jì)算機(jī)中主要是以補(bǔ)碼的形式存儲(chǔ)的。計(jì)算機(jī)中的二進(jìn)制則是一個(gè)非常微小的開關(guān),用“開”來表示 1,“關(guān)”來表示 0。
一般來講,若 b 是基底,我們?cè)?b 進(jìn)制系統(tǒng)中的數(shù)表示為 a1bk + a2bk-1 + a3bk-2 + ... + ak+1b0 的形式,并按次序?qū)懴聰?shù)字 a1a2a3 ... ak+1。這些數(shù)字是 0 到 b-1 的自然數(shù)。
若一段文字(譬如這段文字)討論多個(gè)基數(shù),若有歧義時(shí),基數(shù)(本身用十進(jìn)制表示)用下標(biāo)方式寫在數(shù)的右邊。除非有上下文說明,沒有下標(biāo)的數(shù)字視為十進(jìn)制。 通過使用一點(diǎn)(小數(shù)點(diǎn))來將數(shù)字分成兩組,就可以用位置系統(tǒng)來表示小數(shù)。例如,基數(shù) 2 系統(tǒng)中,10.11 表示 1×21+ 0×20 +1×2-1 +1×2-2 = 2.75。
一般來講,b 進(jìn)制系統(tǒng)中的數(shù)有如下形式:
?
對(duì)于常用的二級(jí)制系統(tǒng),b = 2。”
為了方便書寫以及符合工程師的一般習(xí)慣,Verilog 語(yǔ)言里面提供了關(guān)于數(shù)字的多種進(jìn)制的支持,表達(dá)的一般格式如圖 2 所示。除了數(shù)值部分前面已經(jīng)介紹以之外,其他部分的值域和含義見表 1。
圖 2 Verilog 內(nèi)常量的一般格式
表 1 Verilog 內(nèi)常量表達(dá)中各個(gè)部分的含義
名稱 |
符號(hào) |
位寬 |
進(jìn)制與編碼部分 |
含義 |
常量的正負(fù)屬性 |
常量占用的比特寬度 |
進(jìn)制方式 |
值域 |
“+”:正數(shù) “-”:負(fù)數(shù) 如果本部分不存在,則認(rèn)為是正數(shù) |
正整數(shù) 如果本部分不存在,則在賦值時(shí)根據(jù)目的變量位寬轉(zhuǎn)化,例如 666(十進(jìn)制 666),’h3F(十六進(jìn)制 3F16),’033(八進(jìn)制 338) |
“’d”/“’D”:十進(jìn)制無符號(hào)數(shù) “’b”/“’B”:二進(jìn)制無符號(hào)數(shù) “’o”/“’O”:八進(jìn)制無符號(hào)數(shù) “’h”/“’H”:十六進(jìn)制無符號(hào)數(shù) “’s|Sd”/“’ s|SD”:十進(jìn)制符號(hào)數(shù) “’ s|Sb”/“’ s|SB”:二進(jìn)制符號(hào)數(shù) “’ s|So”/“’ s|SO”:八進(jìn)制符號(hào)數(shù) “’ s|Sh”/“’ s|SH”:十六進(jìn)制符號(hào)數(shù) 其中帶“s”/“S”的表示已經(jīng)用補(bǔ)碼表示,否則由系統(tǒng)轉(zhuǎn)化為補(bǔ)碼形式 |
有時(shí)候,數(shù)值表示會(huì)很長(zhǎng),此時(shí)可以使用下劃線“_”分割,參考例 1。
【例 1】常量及其分割
常量 |
含義 |
數(shù)值(轉(zhuǎn)化為十進(jìn)制) |
8’b1001_1000 |
8 比特二進(jìn)制無符號(hào)數(shù) |
152 = (1001, 1000)2 |
16’h11_32 |
16 比特十六進(jìn)制無符號(hào)數(shù) |
4402 = (11, 32)16 |
15’o32_111 |
15 比特八進(jìn)制無符號(hào)數(shù) |
13385 =(32, 111)8 |
?
3. 信號(hào)有名,萬物之始
《論語(yǔ)》上曰:“子路曰:‘衛(wèi)君待子而為政,子將奚先?’子曰:‘必也正名乎!’”,可見名字的重要性。一個(gè)數(shù)字邏輯系統(tǒng)那么復(fù)雜,不命名是不可能的,但是如何命名呢?這就告訴大家。
在電路設(shè)計(jì)中,變量是指一個(gè)包含部分已知或未知數(shù)字、信號(hào)或邏輯(即一個(gè)值)之信號(hào)節(jié)點(diǎn),以及對(duì)應(yīng)之符號(hào)名稱。Verilog 是大小寫敏感的。所謂標(biāo)識(shí)別符就是用戶為程序描述中的。也就是說:counter 和 Counter 會(huì)被作為兩個(gè)不同的變量。為了保證不產(chǎn)生混淆,一般建議對(duì)于變量的首字母的大小寫進(jìn)行一定的規(guī)范,例如:模塊內(nèi)部變量采用小寫字母開頭,同時(shí)模塊端口使用大寫字母開頭。
一些命名規(guī)范是作為 Verilog 語(yǔ)法在語(yǔ)言層面強(qiáng)制執(zhí)行的。
首先,不能用關(guān)鍵詞給變量命名。這個(gè)是非常一般的要求,不詳細(xì)論述。
其次,Verilog 語(yǔ)法規(guī)定,標(biāo)識(shí)符(包括這里的變量,還包含一些后面才會(huì)提到的其他內(nèi)容)應(yīng)該以字母、下劃線(“_”)開頭,中間可以包含字母、數(shù)字以及下劃線和美元符號(hào)(“$”)的字符(串)。例 2.6 里面給出了一些合法與非法的變量命名。
【例 2】變量命名
合法 |
非法 |
Counter counter_statement timer3215 CLK_50M _50M_CLK if_all_0 get_all_$ |
1Counter(數(shù)字開頭) 50M_CLK(數(shù)字開頭) Timer32*1ns(含有非法字母“*”) reg_filter@Chap3(含有非法字母“@”) wire_parameter%32(含有非法字母“%”) if(使用關(guān)鍵詞 if) $_my_love($開頭,會(huì)和后面介紹的系統(tǒng)任務(wù)混淆) |
Verilog 所用到的所有變量都屬于兩個(gè)基本的類型:線網(wǎng)類型(net/wire)和寄存器類型(register)。一般的說法是:
“線網(wǎng)與我們實(shí)際使用的電線類似,它的數(shù)值一般只能通過連續(xù)賦值(continuous assignment),由賦值符右側(cè)連接的驅(qū)動(dòng)源決定。線網(wǎng)在初始化之前的值為 x(trireg 類型的線網(wǎng)是一個(gè)例外,它相當(dāng)于能夠儲(chǔ)存電荷的電容器)。如果未連接驅(qū)動(dòng)源,則該線網(wǎng)變量的當(dāng)前數(shù)值為 z,即高阻態(tài)。線網(wǎng)類型的變量有以下幾種:wire、tri、wor、trior、wand、triand、tri0、tri1、supply0、supply1、trireg,其中 wire 作為一般的電路連線使用最為普遍,而其他幾種用于構(gòu)建總線,即多個(gè)驅(qū)動(dòng)源連接到一條線網(wǎng)的情況,或搭建電源、接地等。
寄存器與之不同,它可以保存當(dāng)前的數(shù)值,直到另一個(gè)數(shù)值被賦值給它。在保持當(dāng)前數(shù)值的過程中,不需要驅(qū)動(dòng)源對(duì)它進(jìn)行作用。如果未對(duì)寄存器變量賦值,它的初始值則為 x。Verilog 中所說的寄存器類型變量與真實(shí)的硬件寄存器是不同的,它是指一個(gè)儲(chǔ)存數(shù)值的變量。如果要在一個(gè)過程(initial 過程或 always 過程)里對(duì)變量賦值,這個(gè)變量必須是寄存器類型的。寄存器類型的變量有以下幾種:reg(普通寄存器)、integer(整數(shù))、time(時(shí)間)、real(實(shí)數(shù)),其中 reg 作為一般的寄存器使用最為普遍。
此外,利用寄存器變量的數(shù)組,還可以對(duì) ROM 進(jìn)行建模。”
最初學(xué)習(xí) Verilog 語(yǔ)言的時(shí)候,在下有一個(gè)粗陋的理解:wire 類型就是對(duì)應(yīng)組合電路,reg 類型對(duì)應(yīng)的則是時(shí)序電路。然后,就是范瑋琪的《最初的夢(mèng)想》里面唱的:“如果驕傲沒被現(xiàn)實(shí)大海冷冷拍下……”。老衲敗了,而且敗得很慘?,F(xiàn)在,鄙人可以舉出很多很多反例來證明當(dāng)年的無知。這個(gè)話題,后文書也會(huì)介紹的,先留個(gè)話頭?,F(xiàn)在,您老只要記?。哼@種說法是錯(cuò)的,大錯(cuò)特錯(cuò)。
?
4. 向量數(shù)組,多位表示
對(duì)于一個(gè)單個(gè)的多比特信號(hào),需要引入“向量”的概念。
向量形式的數(shù)據(jù)是在硬件描述語(yǔ)言中十分重要。在 Verilog 中,標(biāo)量的意思是只具有一比特位寬的變量,而向量表示具有多個(gè)比特位寬的變量。如果沒有特別指明位寬,系統(tǒng)默認(rèn)它為標(biāo)量。
在真實(shí)的數(shù)字電路,例如將兩個(gè)四位二進(jìn)制數(shù)相加的進(jìn)位加法器中,我們可以發(fā)現(xiàn),其中一個(gè)數(shù)是通過四條電線(每條線表示四位中的某一位)連接到加法器上的。我們可以用一個(gè)向量來表示這個(gè)多位數(shù),分別用這個(gè)向量的各個(gè)分量來表示“四條電線”,即四位中的某一位。這樣做的好處是,可以方便地在 Verilog 代碼的其他地方選擇其中的一位(位選)或多位(域選)。當(dāng)然,如果沒有進(jìn)行位選或域選,則這個(gè)多位數(shù)整體被選擇。
【例 3】4 比特 wire 型向量的聲明
wire [3:0] input_add;?? // 聲明名為 input_add 的 4 位 wire 型向量
wire [4:1] input_add1;?? // 也是 4 位 wire 型向量,但是分量序號(hào)從 4 到 1
wire [0:3] input_add2;?? // 也是 4 位 wire 型向量,但是分量序號(hào)從 0 到 3
reg [3:0] output_add;?? // 聲明名為 input_add 的 4 位 reg 型向量
reg [4:1] output_add1;?? // 也是 4 位 reg 型向量,但是分量序號(hào)從 4 到 1
reg [0:3] output_add2;?? // 也是 4 位 reg 型向量,但是分量序號(hào)從 0 到 3
上面的向量聲明之后,我們就可以方便地選擇其中的某幾個(gè)分量進(jìn)行操作。請(qǐng)注意用于域選的方括號(hào)的位置在向量名稱之后,方括號(hào)內(nèi)的數(shù)字為所需的位數(shù)。例如我們可以進(jìn)行如例 4 的操作。
【例 4】對(duì)于向量個(gè)別位的操作
input_add [3] = 1'b1;?? // 將 1 賦值給 input_add 向量的第三位(最高位)
input_add [1:0] = 2'b01;?? // 將 0 和 1 分別賦值給 input_add 向量的第 1、0 位(最低兩位)
對(duì)于 reg 型向量,在 Verilog 2001 中,在聲明時(shí)候也可以定義初始值,見例 5。
【例 5】reg 型向量的聲明與初始值
reg [7:0] counter = 8’h0;? //8 比特計(jì)數(shù)器聲明,同時(shí)定義初始值 0
Verilog 中的幾種寄存器類型的數(shù)據(jù),包括 reg、integer、time、real,以及由這幾種數(shù)據(jù)構(gòu)成的向量,都可以構(gòu)成數(shù)組。聲明數(shù)組時(shí),方括號(hào)位于數(shù)組名的后面,括號(hào)內(nèi)的第一個(gè)數(shù)字為第一個(gè)元素的序號(hào),第二個(gè)數(shù)字為最后一個(gè)元素的序號(hào),中間用冒號(hào)隔開。如果數(shù)組是由向量構(gòu)成的,則數(shù)組的其中某個(gè)元素是向量。同樣,出于習(xí)慣考慮,我們一般讓數(shù)組第一個(gè)元素的序號(hào)為 0,后面元素的序號(hào)依次遞增。此外,和 C 語(yǔ)言類似,用戶可以聲明多維數(shù)組。例 6 是一些數(shù)組聲明的例子。最后說一下,二維數(shù)組是 Verilog 2001 的特性,估計(jì)是為了滿足方興未艾的圖像處理的需求。
【例 6】數(shù)組的聲明與引用
integer number [0:100];? // 聲明一個(gè)有 101 個(gè)元素的整數(shù)數(shù)組
number [25] = 1234;? // 將 1234 賦值給 25 號(hào)(第 26 個(gè))元素
reg [7:0] my_input? [65535:0];? // 聲明一個(gè)有 65536 個(gè)元素的 8 位向量寄存器
my_input [97] = 8'b10110101;? // 將 10110101 分別賦值給 97 號(hào)(第 2 個(gè))元素的 7 至 0 位
reg my_reg [0:3][0:4];? // 聲明一個(gè)具有 20 個(gè)元素的二維寄存器數(shù)組
my_reg [1][2] = 1'b1;? // 將 1 賦值給上述二維數(shù)組的第 2 行、第 3 列元素
表示數(shù)組某個(gè)元素時(shí),允許使用變量來表示元素的索引,但是表示一個(gè)向量的一位或者幾位時(shí),只允許使用數(shù)字來表示位的索引;此外,使用數(shù)組時(shí)一次只能對(duì)一個(gè)元素進(jìn)行操作,而不能向向量那樣同時(shí)對(duì)連續(xù)的幾個(gè)位進(jìn)行操作。
由于數(shù)組和向量的表示都使用了方括號(hào),因此使用時(shí)需要注意這個(gè)變量或向量的名稱在最初被聲明為何種類型的數(shù)據(jù)。由于數(shù)組的索引和向量的索引都是用了方括號(hào)對(duì)“[ ]”,對(duì)于向量數(shù)組的引用采用先數(shù)組索引,后向量索引的順序,這個(gè)需要特別強(qiáng)調(diào)。例 7 給出了一個(gè)同時(shí)索引數(shù)組和向量的情況,可供參考。
【例 7】向量數(shù)組的索引
my_input [65535][7:4] = 4'b1010;? // 將一個(gè) 4 比特二進(jìn)制數(shù)賦值給第 65536 個(gè)元素的高四位。
?
5. 模塊聲明,邊界標(biāo)定
現(xiàn)在遇到了一個(gè)關(guān)鍵的 Verilog 關(guān)鍵詞:module,漢語(yǔ)翻譯就是模塊的意思。這個(gè)關(guān)鍵詞 module 與 endmodule 配對(duì),標(biāo)記代碼中的一個(gè)模塊,也可以說是一個(gè)邏輯的“芯片”。一個(gè)抽象的簡(jiǎn)單模型如下:
module module_name ( ports_table );
ports_decription;
begin
module_behavior description;
end
endmodule;
其中,
“module_name”(模塊名稱)的起名,請(qǐng)遵守有關(guān)的命名規(guī)則。總得原則是,叫人看到這個(gè)名字就大約知道這個(gè)模塊是什么用途的。有些人總是喜歡 U1、U2 之類的名稱,這樣是不好的。這樣說吧,如果將來挨了批評(píng)什么的,乃至因此丟了飯碗,別找貧道拼命。
“ports_table”(輸入輸出端口 / 管腳列表),起到于羅列出芯片的管腳(pin)的作用。理論上說,一個(gè)有意義的模塊,總是對(duì)于輸入數(shù)據(jù)進(jìn)行某種處理(也即功能部分)然后輸出出去。所以呢,輸入輸出總是難免的。在 Verilog 2001 中在輸入輸出端口 / 管腳列表也可以完成是有關(guān)是輸入輸出端口 / 管腳列表定義。
“ports_decription”(輸入輸出端口 / 管腳定義),完成確定端口信號(hào)方向和位寬的作用。端口信號(hào)可以是 1 bit 的,也可以是多位位寬的。如上所述,這部分可能被輸入輸出端口 / 管腳列表收編。端口名稱不能重復(fù)定義否則會(huì)引起混亂,這個(gè)不必細(xì)說,地球人都知道。
“module_behavior description”是模塊真正的功能部分(這部分超出了本章的范圍,在下將會(huì)在后文書給大伙兒詳細(xì)介紹)。
最后值得注意的是 module 那句話后面也有分號(hào)“;”,這個(gè)很多人在最初做代碼的時(shí)候容易忘掉。然后嘛,自然是語(yǔ)法錯(cuò)誤,還比較難查。
對(duì)于如圖 3 中的模塊(這里還是抽象模型,不詳細(xì)說明。工程中的一個(gè)實(shí)例就是半加器,當(dāng)然也可以是其他單元),具有兩個(gè)輸入信號(hào) in_1 和 in_2、兩個(gè)輸出信號(hào) out1 和 out2。例 8 和例 9 就是兩種不同的描述方法(請(qǐng)先忽略信號(hào)的類型,緊接著會(huì)嘮叨得您老吐了為止的)。
圖 3 抽象的雙輸入雙輸出端口
【例 8】具有端口定義部分的模塊描述
module absctraction_module ( in_1, in_2, out_1, out_2 );
//Ports Description
//Inputs:
input in_1;??? //First input signal
input in_2;???? //Second input signal
//Outputs:
output reg out_1;??? //First output signal
output reg out_2;??? //Second output signal
//Module Operation
begin
??? module_behavior description;
end
endmodule;
【例 9】具有端口列表中完成定義的模塊描述
module absctraction_module ( input in_1, input in_2, output reg out_1, output reg out_2 );
//Inputs:
// in_1:?? First input signal
//in_2:??? Second input signal
//Outputs:
// out_1:??? First output signal
// out_2:??? Second output signal
//Module Operation
begin
??? module_behavior description;
end
endmodule
這兩個(gè)例子的有關(guān)模塊定義是等效的,工程師可以根據(jù)自己的喜好選擇。理論上,無需強(qiáng)行規(guī)定。如果有公司有規(guī)定,那是項(xiàng)目管理的需要而非語(yǔ)法的要求。
模塊的例化主要問題是上層信號(hào)與模塊端口的連接,這個(gè)有兩個(gè)方法。第一種:按照模塊端口列表的順序,直接寫上層信號(hào)。第二種,采用端口引用的方法,格式是:.port_name (signal_name),port_name 是模塊端口的名稱,signal_name 是上層信號(hào)的名稱。如果采用第二種方法,姑且稱為對(duì)點(diǎn)名,可以不考慮模塊實(shí)現(xiàn)的端口列表的順序。例 11 和例 12 分別用兩種方法例化了例 10 中的模塊,施主們參考。
【例 10】實(shí)數(shù)加法模塊的抽象實(shí)現(xiàn)
module real_adder ( in_1, in_2, out_result );
//Ports Description
//Inputs:
input[7:0] in_1;??? //Operate number 1, 7 bits
input[7:0] in_2;???? // Operate number 2, 7 bits
//Outputs:
output reg[8:0] out_result;??? //Result = in_1 + in_2, 8 bits
//Module Operation
begin
??? module_behavior description; // Result = in_1 + in_2
end
endmodule
【例 11】復(fù)數(shù)加法模塊:順序引用連接(方法 1)
module real_adder ( real_1, real_2, image_1, image_2, real, image);
//Ports Description
//Inputs:
input[7:0] real_1;??? //Real part of operate number 1, 7 bits
input[7:0] real_2;???? // Real part of operate number 2, 7 bits
input[7:0] image_1;??? //Image part of operate number 1, 7 bits
input[7:0] image_2;???? //Image part of operate number 2, 7 bits
//Outputs:
output[8:0] real;??? //Real part of result, 8 bits
output[8:0] image;??? //Image part of result, 8 bits
//Module Implement
real_adder realpart_adder(real_1, real_2, real);??? //Real part operation
real_adder imagepart_adder(image_1, image_2, image);??? //Image part operation
//Module Operation
begin
??? module_behavior description; // Result = in_1 + in_2
end
endmodule
【例 12】復(fù)數(shù)加法模塊:點(diǎn)名引用連接(方法 2)
module real_adder ( real_1, real_2, image_1, image_2, real, image);
//Ports Description
//Inputs:
input[7:0] real_1;??? //Real part of operate number 1, 7 bits
input[7:0] real_2;???? // Real part of operate number 2, 7 bits
input[7:0] image_1;??? //Image part of operate number 1, 7 bits
input[7:0] image_2;???? //Image part of operate number 2, 7 bits
//Outputs:
output[8:0] real;??? //Real part of result, 8 bits
output[8:0] image;??? //Image part of result, 8 bits
//Module Implement
real_adder realpart_adder(.in_1(real_1), .in_2(real_2), .out_result(real) );??? //Real part operation
real_adder imagepart_adder(.out_result(image), .in_1(image_1), .in_2(image_2));??? //Image part operation
//Module Operation
begin
??? module_behavior description; // Result = in_1 + in_2
end
endmodule
這正是:
“
圣賢也要求正名,老僧難免心不平。層次劃分要正經(jīng),設(shè)計(jì)營(yíng)運(yùn)認(rèn)分明。
四值常量皆有因,真實(shí)系統(tǒng)唯一零。隨機(jī)應(yīng)變變量名,連接有序模塊心。
”
與非網(wǎng)原創(chuàng)內(nèi)容,謝絕轉(zhuǎn)載!
系列匯總: