?
自打說了《玩轉 IP Core》和寫了《IP 核芯志》之后,老衲就沉淪了,沉迷于“秋風功”修煉。俗話說:“坐吃山空”,見到荷包漸漸干癟,和尚我不得不再次出山了。施主們多多捧場為好。本想說說理論的事情,奈何在下道行還淺,就只得簡單的講講 Verilog 語言這個事情了,大伙兒見諒。
這個語言本不難,道和歪嘴念經的太多,念著念著就成了 C 語言的附屬了,這個著實的大謬也??纯凑讜念}目便知:從電路里來,到 Verilog 里去!
老僧一貫不喜歡說古,對于 Verilog 語言的歷史,施主只需要知道幾個事實:
1)1983 年誕生,此時 EDA 設計尚處于幼年,難免有很多誤區(qū)。所以,Verilog 語言里面也存在許多“擰巴”的地方。
2)1995 年,首次被 IEEE 標準化,這就是所謂的 Verilog 95 版本。
3)2001 年,IEEE 對于 Verilog 重大更新,Verilog? 2001 面世。
4)2005 年,IEEE 又進行了細微更正,出品了 Verilog 2005。
本書里面介紹了 2001 版本,也就是應用最廣、軟件兼容性最強的版本。
1. 模塊為本,鏈接系統
在概念設計過程中,設計人員總是將復雜的功能劃分為簡單的功能,模塊是提供每個簡單功能的基本結構。設計人員可以采取“自頂向下”的思路,將復雜的功能模塊劃分為低層次的模塊。這一步通常是由系統級的總設計師完成,而低層次的模塊則由下一級的設計人員完成。自頂向下的設計方式有利于系統級別層次劃分和管理,并提高了效率、降低了成本。在實際代碼編寫過程中,會采用“自下向上”的工作流程。也就是先從前面劃分好的最下層的模塊開始寫作代碼以及完成相應的單元測試,逐次聯線打包和測試,直至完成最高層模塊及其測試。這個“自頂向下”再“自下向上”的過程,是項目管理研究的范疇,這里稍帶提一下。
Verilog 語言被設計用來描述復雜的硬件電路。由于上述項目管理模式的普遍采用,使用 Verilog 描述硬件的基本設計單元是模塊(module)。構建簡單的子電路,然后通過子電路的連接形成較為復雜的上層電路,最終達到系統的設計需求。實際的自電路元件,Verilog 語言能夠提供輸入、輸出端口,可以實例調用其他模塊,也可以被其他模塊實例調用。模塊中可以包括組合邏輯部分、過程時序部分。
一個模塊如圖 1 所示,模塊一般用方框表示,但是也有例外。圖中,方框內的名字為模塊名,指向模塊的帶肩頭線表示輸入信號,由模塊向外的箭頭線表示模塊的輸出信號。輸入信號和輸出信號上面一般標記信號名稱。例如,圖 1.3 中就是一個具有三個輸入信號(“輸入 11”,“輸入 12”和“輸入 13”)和兩個輸出信號(“輸出 11”和“輸出 12”)的模塊,模塊被命名為“模塊 1”。
圖 1 模塊的圖例
模塊之間的連接如圖 2 所示,如果模塊的輸出為另一個模塊的輸入,在圖中會合并兩個聯線(也就是說,用一個從第一個模塊指向第二個模塊的帶箭頭線來表示)。例如,圖 2 中“模塊 1”的兩個輸出連接到了“模塊 2”的兩個輸入。沒有在模塊之間連接的信號,則表示該信號是外部信號,例如“模塊 2”的輸入 3 信號。
圖 2 模塊之間的連接
多個模塊可以打包為一個上層的模塊,如圖 3 所示。圖中,把圖 3 里面的兩個模塊打包成為了一個上層模塊:“模塊 3”。生成的上層模塊的輸入和輸出一定包含低層模塊之間未連接的信號,但是也可以包括低層模塊之間的連接信號。
圖 3 模塊打包為上層模塊
具體這些模塊設計、模塊連接以及模塊打包如何完成,后文書自有交待。
?
2. 電路設計,二虎擋道
在任何一本《數字電子技術》教材的某個犄角旮旯,總有類似下面的論述。
“組合邏輯電路中,同一信號經不同的路徑傳輸后,到達電路中某一會合點的時間有先有后,這種現象稱為邏輯競爭,而因此產生輸出干擾脈沖的現象稱為冒險。
競爭(Competition)定義為:在組合邏輯電路中,某個輸入變量通過兩條或兩條以上的途徑傳到輸出端,由于每條途徑延遲時間不同,到達輸出門的時間就有先有后,這種現象稱為競爭。把不會產生錯誤輸出的競爭的現象稱為非臨界競爭。把產生暫時性的或永久性錯誤輸出的競爭現象稱為臨界競爭。
冒險(Risk)定義為:信號在器件內部通過連線和邏輯單元時,都有一定的延時。延時的大小與連線的長短和邏輯單元的數目有關,同時還受器件的制造工藝、工作電壓、溫度等條件的影響。信號的高低電平轉換也需要一定的過渡時間。由于存在這兩方面因素,多路信號的電平值發(fā)生變化時,在信號變化的瞬間,組合邏輯的輸出有先后順序,并不是同時變化,往往會出現一些不正確的尖峰信號,這些尖峰信號稱為‘毛刺’。如果一個組合邏輯電路中有‘毛刺’出現,就說明該電路存在冒險。
競爭冒險都是由于延遲時間的存在,當一個輸入信號經過多條路徑傳送后又重新會合到某個門上,由于不同路徑上門的級數不同,或者門電路延遲時間的差異,導致到達會合點的時間有先有后,從而產生瞬間的錯誤輸出?!?/p>
為什么每次讀教科書,都覺得是大筒木輝夜的驚天陰謀呢?有一種不讓讀者進入無限月讀,誓不罷休的霸氣外露(典故見《火影忍者疾風傳》)。當然這是題外話,大家一樂一樂(非拉面廣告?。?。列位稍安勿躁,待貧道說人話解釋一番。
競爭就是三字經“人之初,性本善。性相近,習相遠”的道理。同一個服務器的數據包,有的是電驢 P2P(點對點,point? to point)幾乎及時到達,有的卻莫名其妙被發(fā)配去糧食基地米國周游了一圈五分鐘才到您老的計算機網口。如果這個是上網瀏覽一點網頁,還倒罷了,這就是非臨界的。假使這個是看視頻,這個就卡那里了,用戶會很不爽,這就算臨界競爭了。
冒險的情況,壞就壞在“分進合擊”上面。一組本來好好的輸入,非要經過不同道路到達器件,結果可好有了時間差了,再被已處理后果不堪設想。
3. 時序器件,建立保持
問題從最簡單的開始解決,這是一個原則。先來瞧瞧一個 D 觸發(fā)器對于輸入信號的要求,就是耳朵都聽出繭子的建立時間和保持時間問題。建立時間(英文 Set up time,簡寫 Tsu),是指觸發(fā)時鐘沿(一般為時鐘信號的上升沿,本書中也沿用這個約定)到達 D 觸發(fā)器之前,要求輸入信號必須已經達到穩(wěn)定的時間。對應的,保持時間(英文 Hold time,簡寫 Th),是指觸發(fā)時鐘沿到達 D 觸發(fā)器之后,要求輸入信號還需要保持必須穩(wěn)定的時間。建立時間、保持時間相對于觸發(fā)時鐘沿的關系,如圖 4 所示。
圖 4 建立時間、保持時間相對于觸發(fā)時鐘沿的關系
“我們都是木頭人,不許說話不準動”,建立時間和保持時間就是輸入信號的“木頭人時間”。做游戲的時候,“木頭人時間”內有了晃動或者出聲,那游戲就輸了。電路里面,如果輸入信號在建立時間或者保持時間里面發(fā)生了變化,那就是仿真(尤其是時序仿真)里面所謂“全國山河一片紅”了,那個絕對是災難(聲明:貧道與中國臺灣沒有關系)。
不推導“復雜”公式,直接給結論:要滿足建立與保持時間,時序系統才能穩(wěn)定工作。
對于 FPGA 設計,這個“滿足”是靠寫時序約束,來教導綜合軟件和布局布線軟件實現的。
首先,這里解答“什么是布局布線”這個問題。簡單理解,“布局布線”就是在器件(FPGA/ASIC)里面畫 PCB。布局是把器件放到相應的位置上,布線是把有關聯的器件連接起來。
?
機器都是笨的,即使是號稱“電腦”的計算機,需要人來操作才能完成需要的任務。如果僅僅把設計給了設計環(huán)境,不做任何設計上的說明(也即所謂的“時序約束”),機器絕對會搞出一些工程師不希望的結果出來。記?。喝魏喂ぞ叨疾粫⒅貒L試尋找到達最快的布局布線結果。這個正如畫 PCB 的工程師絕對不會使用軟件提供的所謂“自動功能”。
最常用的時序約束有時鐘、輸入輸出時延和“虛假路徑”幾種,下面一一介紹:
時鐘的頻率和性質決定了其他時延的上限。時鐘頻率越高、時鐘抖動越大,允許的布局布線時延以及組合邏輯時延也就越小。
時鐘信號包括三個性質:周期與占空比、時鐘間的偏移和時鐘的抖動。如圖 5 所示,時鐘的周期定義為理想時鐘的兩個觸發(fā)沿之間的時間間隔;時鐘的占空比定義為一個周期內,理想時鐘高電平“1”信號占整個時鐘周期的比例;時鐘之間的偏移定義為兩個同源時鐘之間的、固定的出發(fā)沿的時間差;時鐘的抖動定義為一個時鐘信號相對于理想時鐘,上升沿與下降沿可能變換的前后范圍。最后多嘴一句,這些實際系統中的時鐘與理想時鐘的差別是芯片內的“時鐘樹”造成的。
圖 5? 時鐘的時序約束參數
下面兩折比較類似,現在合并演出(臺下:偷工減料,退票?。狠斎?/ 輸出路徑時延表標記芯片的前端 / 后端芯片的時序特性 / 要求。這個基本上就是,把前端芯片看作 D 觸發(fā)器,告訴工具前端芯片的輸出時延,這樣可以保證系統對于輸入可以可靠采樣。同樣的,把后端芯片看作 D 觸發(fā)器,通知工具后端芯片的建立時間和保持時間,可以保證可靠的信號輸出。整個系統的鏈接情況,如圖 6 所示。
圖 6 輸入 / 輸出路徑時延
下一出是《珍珠塔》,“皇帝家也有三門草鞋親,謝謝”(這就完了???臺下騷動:“退票!退票!”)。實際系統中,很少有必須工作時間都一致的,總會存在一些“急先鋒”遇到的“慢郎中”的。別抬杠,您老沒遇到,只能說明您還毛嫩。多周期的時序約束,實際上是減少布局布線壓力的,這個和前面 存在差異。對于這些需要計算較慢的單元 / 路徑,可以降低要求,把好的資源讓渡給需要快速的部分使用。圖 7 就是一個例子,上面是需要快速解決的單元們,下面是可以“慢慢來”的部分。多周期約束定義了到底可以多慢做完這個工作。
圖 7 多路徑約束
最后出場的就是“虛假路徑”這個草包,主要表現時鐘域之間路徑和測試邏輯,工具對這類任務也采取不聞不問、聽之任之的態(tài)度。
?
4. 定制器件,細節(jié)入手
FPGA 才是“上得廳堂,下得廚房,安得系統,打得流氓”的多面手,其結構如圖 8 所示。
圖 8 某 FPGA 的功能結構圖
其中包括可編程輸入輸出單元(IOB,Input Output Block)、可配置邏輯塊(CLB,Configurable Logic Block)、數字時鐘管理模塊(DCM,Digital Clock Management) 和嵌入式塊 RAM(BRAM,Block RAM) 等部分。這個里面與 Verilog 語言設計電路有關的部分是 CLB,揭開 CLB 的蓋頭來,您老將會看到如圖 9 所示的一副尊容。以 Xilinx 公司的 FPGA 器件為例,CLB 由多個(一般為 2 個或 4 個)相同的 Slice(這個詞還真不好翻譯,查了半天度娘,看到唯一靠點譜的說法是邏輯片)和附加邏輯構成。其中,Slice 是基本的邏輯電路實現單元,屬于中等后面介紹;外圍電路中,開關網絡主要完成一般信號的可配置連接,快速連接線進行時鐘和復位等關鍵信號的連接。
圖 9 Xilinx 公司 FPGA 中 CLB 的結構圖
Slice 的結構如圖 10 所示,一個 Slice 由兩個 4/6 輸入的 LUT(查找表,Look Up Table)、進位算術邏輯、D 觸發(fā)器和函數復用器組成。算術邏輯包括一個異或門和一個專用與門,一個異或門可以使一個 Slice 實現 2bit 全加操作,專用與門用于提高乘法器的效率(這個后文書有詳細講解,這里屬于“看熱鬧”的內容);進位邏輯由專用進位信號和函數復用器(MUXC)組成,還包括兩條快速進位鏈,用于提高 CLB 模塊的處理速度,用于實現快速的算術加減法操作。4 輸入 LUT 用于實現組合邏輯運算。
圖 10 Xilinx 公司某款 FPGA Slice 的結構
同學們有沒有感到驚訝呢?如果有,說明你的《數字電子技術》的學費沒白交。說好的用于組合邏輯的門級電路呢?還有編碼器、譯碼器等等,等等?這些器件都沒有,怎么設計組合邏輯???“風蕭蕭兮易水寒,虞兮虞兮奈若何?”
LUT 本質上就是一個 RAM,里面存著真值表。目前 FPGA 中,多數采用 4 輸入的 LUT,所以每一個 LUT 可以看成一個有 4 位地址線的 的 RAM。 當用戶通過原理圖或 HDL 語言描述了一個邏輯電路以后,EDA 軟件會自動計算邏輯電路的所有可能結果,并把真值表事先寫入 RAM。這樣,每輸入一個信號進行邏輯運算就等于輸入一個地址進行查表,找出地址對應的內容,然后輸出即可。對于輸入高于 4 比特的輸入,EDA 軟件會自動把輸入拆分成若干 LUT,最后聯合輸出。(真值表是什么,這個不用講了吧。不懂的人,數電考試肯定作弊的,回去重修!)官方說法是:“由于基于 LUT 的 FPGA 具有很高的集成度,其器件密度從數萬門到數千萬門不等,可以完成極其復雜的時序與邏輯組合邏輯電路功能,所以適用于高速、高密度的高端數字邏輯電路設計領域” 。所以本書介紹的結構竟然是流行趨勢,好極好極!
最后來看一看開發(fā)流程里面的“綜合”這個過程,那些“優(yōu)化”什么的亮瞎鈦合金狗眼的概念,對于 FPGA 的組合邏輯方面還存在嗎?我們估計獨立思考。貧道聞到了退化的味道。這也不是說 EDA 軟件沒用,LUT 組合方面的算法還是可圈可點的嘛。
?
5. 語言缺陷,電路子集
Verilog 設計之初就號稱可以一次打兩只鳥:設計和驗證,殊不知這兩個方向的思路卻相差很大。數字邏輯的設計是基于數電的,受限制于電路器件的特性;反觀數字邏輯系統的驗證,這是一個純粹軟件仿真的活計,工程師更加喜歡一般程序設計語言的思路。在老衲參與的很多技術討論里面發(fā)現,這“兩鳥”不僅僅沒有打到,這把“米”是一定“蝕”了。大多數初學者完全分不清那些可以綜合,那些不可以。
老僧也在總結這個現象的原因,吾稱之為:“教不得法,學不得法”。“教不得法”是指,很多關于 Verilog 的書繼承了程序語言教材的結構,把語句分為:算術運算、條件判斷和循環(huán)等等部分,完全不區(qū)分可綜合性,這樣有誤導的嫌疑;“學不得法”是一個歷史原因,大多數學習者實際上具有很強的程序語言,例如 C 語言,的基礎,這反而是有害的。人的思維是有習慣性的,Verilog 的形式又與 C 語言很類似,所以多數人都把 C 語言設計里面的習慣不自覺的帶入了 Verilog 語言的電路實現。于是乎,綜合軟件上報的錯誤“如滔滔江水,綿綿不絕”,實現與想象不一致也是“如黃河泛濫,一發(fā)不可收拾”。以上是一家之言啊,切勿對號入座,否則必有受傷者,老衲不負責醫(yī)藥費!
數字電路和程序語言的區(qū)別,別告訴我您不知道。下面姑且總結幾條,叫大家以后面試的時候,可以說得頭頭是道。
1. 對應于仿真:C 語言的代碼是一行一行執(zhí)行的,屬于順序結構;而 Verilog 是一種硬件描述語言,語句同時進行,屬于并行結構。
這個特點說起來有點抽象,我們舉一個例子吧。就對于某家上面舉出的代碼,減震器記得時刻到了。
表 1 兩種語言的仿真方式差別
? |
|
Verilog |
代碼 |
int a, b, c; …… c? = a; a = b; b = c; …… |
reg [0:7] a, b, c; …… always @ (posedge Clock) begin …… c <= a; a <= b; b <= c; …… end |
初始值 |
a = 1; b = 2; c =3 |
|
結果 |
a = 2; b = 1; c = 1 |
第一節(jié)拍:a = 2; b = 3; c = 1; 第二節(jié)拍: a = 3; b = 1; c = 2; 第三節(jié)拍:? a = 1; b = 2; c = 3; 第四節(jié)拍:a = 2; b = 3; c = 1; …… |
“不看不知道,世界真奇妙”,套用以前《正大綜藝》的臺詞。見到黃河了?佛主說:回頭是岸,南無阿彌陀佛。
避繁就簡,結合網上度娘出來的資料,老衲針對 Verilog 可綜合性設計,分別 FPGA 和 ASIC 的情況,給列位總結出了表 2(內部資料,注意保密)。表里面可能有一些超前的概念,例如 always、循環(huán)和阻塞 / 非阻塞賦值等,這些會在后文書里面介紹,這里先說聲對不起。
表 2 Verilog 可綜合性設計原則匯總表
原則 |
FPGA 適用 |
ASIC 適用 |
不使用初始化賦值 |
不適用 |
適用 |
不使用時延 |
適用 |
適用 |
不使用循環(huán)次數不確定的循環(huán)語句 |
適用 |
適用 |
不使用移位次數不確定的移位操作 |
不適用 |
適用 |
不使用復雜運算,如乘法、除法,冪等 |
依賴于綜合軟件 |
適用 |
不使用用戶自定義原語 |
適用 |
適用 |
盡量使用同步方式設計電路 |
適用 |
適用 |
除非是關鍵路徑的設計,一般不采用調用門級元件來描述設計的方法,建議采用行為語句來完成設計 |
適用 |
不適用 一些組合邏輯優(yōu)化可使用門電路簡化 |
用 always 過程塊描述組合邏輯,應在敏感信號列表中列出所有的輸入信號 |
僅適用于 Verilog 95 |
僅適用于 Verilog 95 |
所有的內部寄存器都應該能夠被復位,在使用 FPGA 實現設計時,應盡量使用器件的全局復位端作為系統總的復位 |
適用 |
適用 |
對時序邏輯描述和建模,應盡量使用非阻塞賦值方式 |
適用 |
適用 |
對組合邏輯描述和建模,既可以用阻塞賦值,也可以用非阻塞賦值 |
適用 |
適用 |
同一個過程塊中,最好不要同時用阻塞賦值和非阻塞賦值 |
適用 |
適用 |
不能在一個以上的 always 過程塊中對同一個變量賦值 |
適用 |
適用 |
對同一個賦值對象不能既使用阻塞式賦值,又使用非阻塞式賦值 |
適用 |
適用 |
避免混合使用上升沿和下降沿觸發(fā)的觸發(fā)器 |
適用 |
適用 |
同一個變量的賦值不能受多個時鐘控制,也不能受兩種不同的時鐘條件(或者不同的時鐘沿)控制 |
適用 |
適用 |
避免在 case 語句的分支項中使用 x 值或 z 值 |
與綜合軟件有關 |
與綜合軟件有關 |
話說兩頭,老衲從來不提倡先寫代碼,然后去看能不能綜合的設計步驟。老僧把那叫做“C Style”、“邏輯派”或者“語法黨”,某家提倡的是“電路門”。早在《IP 核芯志》里面,吾就說過了:“看圖說話基本法,電路映射程序中?!?,這是不二法門。聽不懂嗎?就是先畫電路 / 時序 / 狀態(tài)轉移圖,再去寫代碼的意思!還不懂?完全無語了,容我冷靜一下。
這正是:
“
遠看石塔黑乎乎,上面細來下面粗。有朝一日翻過來,下面細來上面粗。
都曉倒著很懸乎,重心不穩(wěn)難以扶。不知語言學習路,也要數電加基礎。
”
?
與非網原創(chuàng)內容,謝絕轉載!
如果有任何技術問題,歡迎留言提問~~