如果你有軟件工程師背景,想找一份數(shù)字設(shè)計(jì)工程師的工作,那么你需要做的第一件事就是盡可能早的學(xué)習(xí)時(shí)鐘概念。對(duì)很多從軟件工程師轉(zhuǎn)來(lái)的初級(jí)硬件設(shè)計(jì)工程師來(lái)說(shuō),時(shí)鐘概念都是一件惱人的事情。如果沒(méi)有時(shí)鐘,他們就可以將 HDL(Hardware Description Language,硬件描述語(yǔ)言)轉(zhuǎn)換為一種編程語(yǔ)言,如 $display,if 和 for 循環(huán),如同其他的任何編程語(yǔ)言一樣。 然而,這些初級(jí)設(shè)計(jì)師所忽視的時(shí)鐘,通常是數(shù)字設(shè)計(jì)中最基礎(chǔ)的部分。
沒(méi)有什么時(shí)候會(huì)比在審查初級(jí) HDL 設(shè)計(jì)工程師第一次設(shè)計(jì)的產(chǎn)品的時(shí)候,所發(fā)現(xiàn)的問(wèn)題更多。現(xiàn)在,我已經(jīng)和幾位在我參與的論壇上發(fā)表過(guò)問(wèn)題的人交談過(guò)了。而當(dāng)深入了解后,發(fā)現(xiàn)他們正在做的是什么時(shí),我為他們感到很尷尬。
以遇到的一個(gè)學(xué)生為例,他不理解為什么網(wǎng)絡(luò)上沒(méi)有人重視他的高級(jí)加密標(biāo)準(zhǔn) (AES) 的HDL實(shí)現(xiàn)。此處,為了不讓他因?yàn)槊只蝽?xiàng)目而尷尬,暫且將他稱(chēng)之為學(xué)生。(不,我不是教授。)這個(gè)“學(xué)生”創(chuàng)建了一個(gè) Verilog 設(shè)計(jì),進(jìn)行不止一輪的 AES 加密,但每一輪都是組合邏輯,且兩者之間沒(méi)有時(shí)鐘。 我不記得他是在做 AES-128、AES-192 還是 AES-256,但 AES 需要進(jìn)行 10 到 14 輪計(jì)算。 我記得,他的加密引擎在模擬器中運(yùn)行完美,然而他只使用一個(gè)時(shí)鐘來(lái)加密或解密他的數(shù)據(jù)。 他為自己的工作感到自豪,但不明白為什么那些看過(guò)這個(gè)項(xiàng)目的人都對(duì)他說(shuō),他的思考方式像一個(gè)軟件工程師,而不是一個(gè)硬件設(shè)計(jì)師。
事實(shí)上,我現(xiàn)在有機(jī)會(huì)給像這個(gè)“學(xué)生”一樣的 HDL 新手軟件工程師解釋疑惑。 他們中的許多人對(duì)待 HDL 語(yǔ)言,就像對(duì)象另一種軟件編程語(yǔ)言一樣。 在編程之前,他們?nèi)ふ胰魏诬浖幊陶Z(yǔ)言的基礎(chǔ)知識(shí):如何聲明變量,如何創(chuàng)建一個(gè) if 語(yǔ)句或 case 語(yǔ)句,如何編寫(xiě)循環(huán)等等。然后,他們編寫(xiě)代碼就像編寫(xiě)一個(gè)計(jì)算機(jī)程序——一切都是順序執(zhí)行(圖1),而完全忽略了數(shù)字設(shè)計(jì)中的基本事實(shí),即所有運(yùn)行都是并行的。
圖1:軟件執(zhí)行是順序的
有時(shí)這些程序員會(huì)使用模擬器,如 Verilator,iverilog 或者 EDA 平臺(tái)。 然后,他們?cè)谶壿嫶a中使用一堆$ display命令,將它們視為順序的“printf”,并通過(guò)這些命令來(lái)使代碼運(yùn)行,而不是使用時(shí)鐘。 他們的設(shè)計(jì)在模擬器中只是被單獨(dú)地“執(zhí)行”組合邏輯代碼。
這些學(xué)生向我描述他們的設(shè)計(jì),并解釋稱(chēng)他們的設(shè)計(jì)“不需要時(shí)鐘就能執(zhí)行”。
天啊,這都是什么想法?
實(shí)際上,任何數(shù)字邏輯設(shè)計(jì)如果使用沒(méi)有時(shí)鐘都是不能工作的??傆幸恍┪锢磉^(guò)程會(huì)創(chuàng)建輸入。而 這些輸入必須在某個(gè)開(kāi)始時(shí)間都有效 ——這個(gè)時(shí)間在其設(shè)計(jì)中形成第一個(gè)時(shí)鐘刻度。 同樣地,在接收這些輸入一段時(shí)間后就要輸出。 對(duì)于給定的一組輸入,所有輸出的有效時(shí)間在“無(wú)時(shí)鐘”設(shè)計(jì)中形成下一個(gè)“時(shí)鐘”。 或許第一個(gè)時(shí)鐘刻度是當(dāng)他們調(diào)整好電路板上的最后一個(gè)開(kāi)關(guān)的時(shí)候,而最后一個(gè)時(shí)鐘刻度是當(dāng)他們讀取到結(jié)果的時(shí)候。時(shí)鐘是如何形成的沒(méi)關(guān)系:有一個(gè)時(shí)鐘就可以。
而這導(dǎo)致的結(jié)果就是,那些聲稱(chēng)他們的設(shè)計(jì)“沒(méi)有時(shí)鐘”的人解釋他正在以不切實(shí)際的方式使用模擬器,或者設(shè)計(jì)中存在一個(gè)外部時(shí)鐘用于設(shè)置輸入和讀取輸出 ——而這正是另外一種方式,表明設(shè)計(jì)中的確存在一個(gè)時(shí)鐘。
如果你發(fā)現(xiàn)你自己正試圖以這種方式理解數(shù)字邏輯必須有一個(gè)時(shí)鐘才能執(zhí)行,或你認(rèn)識(shí)的某人也是這么嘗試?yán)斫獾?,那么本文正適合你們。
接下來(lái),讓我們花一兩分鐘來(lái)討論時(shí)鐘,以及為什么圍繞時(shí)鐘來(lái)構(gòu)建和設(shè)計(jì)你的數(shù)字邏輯很重要。
硬件設(shè)計(jì)是并行的
硬件設(shè)計(jì)學(xué)習(xí)中的第一部分也是最難的部分,就是硬件設(shè)計(jì)是并行設(shè)計(jì)。所有的代碼指令并不是依次執(zhí)行,如同一條指令連著下一條指令(如圖1所示),就像計(jì)算機(jī)程序一樣。相反,所有的指令在同一時(shí)刻執(zhí)行,如圖2所示。
圖2:硬件邏輯并行運(yùn)行
正是這一點(diǎn),讓很多東西變得不一樣。
首先需要改變的是開(kāi)發(fā)人員。你需要學(xué)習(xí)以并行的方式思考。
如果要通過(guò)舉例說(shuō)明兩者的區(qū)別,硬件循環(huán)也許會(huì)是個(gè)不錯(cuò)的例子。
軟件設(shè)計(jì)中,一個(gè)循環(huán)是由一連串的指令構(gòu)成,如圖3所示。這些指令構(gòu)造了一組初始化條件,而真正的邏輯在循環(huán)內(nèi)部執(zhí)行。通過(guò)使用一個(gè)循環(huán)變量來(lái)構(gòu)造和定義一個(gè)循環(huán)邏輯,并且這個(gè)變量在每次循環(huán)中通常都是增加的。計(jì)算機(jī)CPU不停地重復(fù)執(zhí)行循環(huán)中的指令和邏輯,直到循環(huán)變量達(dá)到了終止條件。循環(huán)運(yùn)行的次數(shù)越多,它在程序中運(yùn)行的時(shí)間也就越長(zhǎng)。
圖3:軟件循環(huán)
而基于硬件的硬件描述語(yǔ)言循環(huán)與軟件循環(huán)完全不同。恰恰相反,HDL 合成工具使用循環(huán)來(lái)使得所有邏輯的副本同時(shí)并行運(yùn)行。而用來(lái)構(gòu)造循環(huán)邏輯的代碼,如定義索引、索引增長(zhǎng)、檢查索引是否達(dá)到終止條件等等,是不需要合成的,通常會(huì)被移除。此外,由于合成工具正在構(gòu)建物理線路和邏輯塊,所以執(zhí)行循環(huán)的次數(shù)在合成時(shí)間之后不能改變。之后,硬件的數(shù)量是固定的,不能再改變。
導(dǎo)致的結(jié)果便是,硬件循環(huán)結(jié)構(gòu)(如下圖4所示),與軟件循環(huán)結(jié)構(gòu)(如上圖3所示)有很大的區(qū)別。
圖4:HDL循環(huán)
這有幾個(gè)后果。例如,硬件循環(huán)迭代與軟件循環(huán)迭代不同,它不必依賴(lài)前期的循環(huán)迭代的輸出。這導(dǎo)致的結(jié)果是,運(yùn)行一個(gè)包含一組數(shù)據(jù)的邏輯循環(huán)很難在下一個(gè)時(shí)鐘得到響應(yīng)。
但是…現(xiàn)在讓我們?cè)俅位氐綍r(shí)鐘概念。
時(shí)鐘是任何 FPGA 設(shè)計(jì)的核心。一切都圍繞著它展開(kāi)。事實(shí)上,我認(rèn)為所有的邏輯設(shè)計(jì)開(kāi)發(fā)都應(yīng)該從時(shí)鐘開(kāi)始。時(shí)鐘不應(yīng)該在設(shè)計(jì)完成后添加, 而是在你一開(kāi)始思考如何設(shè)計(jì)架構(gòu)時(shí)就要考慮。
為什么時(shí)鐘很重要?
第一步,你要理解數(shù)字邏輯設(shè)計(jì)的一切操作在硬件上執(zhí)行時(shí)都是需要時(shí)間的。不僅如此,不同的操作需要的時(shí)間總量也是不同的。從芯片上的一部分移動(dòng)到另一部分也要花費(fèi)時(shí)間。
或許用圖表的方式能更直觀的解釋這一點(diǎn)。我們將輸入置于算法的頂部,邏輯放在中間,而輸出則放在底部。時(shí)間為軸,從上到下運(yùn)行,從一個(gè)時(shí)鐘到下一個(gè)時(shí)鐘。這種視覺(jué)效果看起來(lái)就如下圖 5 所示:
圖5:三個(gè)操作的邏輯耗時(shí)
圖例 5 展示了幾個(gè)不同的操作:加法、乘法、以及多輪的 AES 算法——盡管為了討論的目的,它可以是多輪任意其它算法。我在垂直方向上使用了方框的尺寸,以表示每個(gè)操作可能需要多少時(shí)間。此外,將依賴(lài)于其它操作的方框堆疊起來(lái)。因此,如果你想要在一個(gè)時(shí)鐘里面做很多輪的 AES 算法,你要明白第二輪算法在第一輪算法結(jié)束后才會(huì)開(kāi)始。因此,適應(yīng)這一邏輯將會(huì)增加時(shí)鐘之間的時(shí)間間隔,并減慢整體的時(shí)鐘頻率。
現(xiàn)在讓我們關(guān)注這個(gè)粉色方框。
這個(gè)粉色框表示在硬件電路中浪費(fèi)的運(yùn)行能力,即你本可以用來(lái)做更多事情的時(shí)間,但因?yàn)樾枰却龝r(shí)鐘,或者等待輸入被處理,而導(dǎo)致你什么也不能做。例如,在上面的概念圖中,完成乘法運(yùn)算所花費(fèi)的時(shí)間不需要長(zhǎng)達(dá)一輪 AES 算法的時(shí)間,加法也是。然而,當(dāng) AES 算法正在執(zhí)行時(shí),你不能夠?qū)@兩個(gè)操作結(jié)果進(jìn)行任何的動(dòng)作,因?yàn)檫@些操作都需要等待下一個(gè)時(shí)鐘來(lái)獲取他們的下一個(gè)輸入。這就是圖 5 中粉色方框所表達(dá)的:空閑電路。另外,由于每一輪 AES 算法都會(huì)推遲下一個(gè)時(shí)鐘的到來(lái),所以圖 5 中存在大量的空閑電路。因此,該設(shè)計(jì)的運(yùn)行速度不會(huì)像硬件允許的那么快。
如果我們只使用 AES 算法,那么每一個(gè)時(shí)鐘都正好完成一輪的 AES 計(jì)算。如此一來(lái),就可以減少運(yùn)行能力的浪費(fèi),從而讓整個(gè)設(shè)計(jì)運(yùn)行得更快。
圖 6 展示了這種設(shè)計(jì)思想。
圖6:分解操作加快時(shí)鐘頻率
由于我們將操作分解為更小的操作,每一個(gè)都能在時(shí)鐘單元內(nèi)完成,因此,我們提高了運(yùn)行能力。甚至,我們可以通過(guò)管道加密算法,而不是一次只加密一個(gè)數(shù)據(jù)塊。這種邏輯設(shè)計(jì)的結(jié)果不會(huì)比上圖 5 所示的更快,但是如果可以保持管道充滿(mǎn),則可以提高 AES 加密吞吐量至 10-14x 之間。
所以,這個(gè)設(shè)計(jì)更贊。
還可以有其它更好的方案嗎?當(dāng)然!如果你熟悉 AES ,你就知道 AES 算法的每一輪計(jì)算中都有一些獨(dú)立的步驟。這些步驟可再次分解,從而可以再次提高每輪邏輯算法的整體時(shí)鐘速度。而這可以增加你能執(zhí)行的加法和乘法運(yùn)算的次數(shù),以及加密引擎的微管道,以便你能在每個(gè)時(shí)鐘的基礎(chǔ)上運(yùn)行更多的數(shù)據(jù)。
設(shè)計(jì)不錯(cuò)。
不過(guò),上圖 6 中還有些其它的東西。
首先,箭頭表示路由延遲。(這個(gè)數(shù)字不是按比例繪制的,它僅僅是這個(gè)討論例子的示例。)每一塊邏輯都需要上一塊邏輯將結(jié)果傳遞給它。這意味著即使某個(gè)邏輯塊不需要時(shí)間執(zhí)行——例如,只是重新排列線路或其它等等,將邏輯塊從一個(gè)芯片的末端移動(dòng)到另一塊也是需要花費(fèi)時(shí)間的。所以,即使你將操作極簡(jiǎn)化了,每一輪數(shù)據(jù)的傳遞仍舊存在延遲。
其次,你可能注意到,沒(méi)有一個(gè)箭頭的起始處在時(shí)鐘刻度上,即沒(méi)有一個(gè)邏輯塊一直運(yùn)行到下個(gè)時(shí)鐘開(kāi)始。這是為了演示 啟動(dòng)時(shí)間和維持時(shí)間的概念。觸發(fā)器電路,即一種捕獲數(shù)據(jù)并同步到時(shí)鐘的電路結(jié)構(gòu),在下一個(gè)時(shí)鐘到達(dá)前需要一定的時(shí)間,此刻數(shù)據(jù)也已經(jīng)是固定和確定的。另外,盡管時(shí)鐘通常被認(rèn)為是瞬時(shí)的,但它從來(lái)都不是。它在不同的時(shí)刻到達(dá)芯片的不同部位。而這再次要求操作之間需要一些緩沖。
通過(guò)以上討論,我們可以得出哪些結(jié)論呢?
邏輯實(shí)現(xiàn)需要花費(fèi)時(shí)間。
邏輯越多花費(fèi)的時(shí)間也越多。
完成兩個(gè)時(shí)鐘刻度之間的邏輯所花費(fèi)的時(shí)間總和(包含例行的延遲、啟動(dòng)和維持時(shí)間、時(shí)鐘不確定性等),限制了時(shí)鐘速度。時(shí)鐘之間的邏輯處理越多,時(shí)鐘速率就越慢。
完成最慢操作所需的時(shí)鐘速度,限制了最快操作的速度。正如上述例子中的加法操作。它的執(zhí)行速度本可以比乘法以及任何一輪單獨(dú)的 AES 算法都更快,但它的速度在該設(shè)計(jì)中被其余的邏輯拖慢了。
硬件定義也會(huì)限制時(shí)鐘速度。即使操作中不包含任何的邏輯,也是需要花費(fèi)時(shí)間的。
因此,平衡的設(shè)計(jì)嘗試在整個(gè)設(shè)計(jì)中將大量相同的邏輯放在時(shí)鐘之間。
時(shí)鐘之間應(yīng)該放多少邏輯量?
現(xiàn)在你已經(jīng)知道你必須處理時(shí)鐘,那么根據(jù)上述信息你該怎么修改和構(gòu)思你的設(shè)計(jì)?答案是限制時(shí)鐘之間的邏輯數(shù)量。但問(wèn)題是,這個(gè)數(shù)量是多少呢?你又該如何得到這個(gè)數(shù)量呢?
得出時(shí)鐘之間你能放置多少邏輯數(shù)量的一個(gè)方法便是,將時(shí)鐘速度設(shè)置為任意速度,然后在與你需要的硬件配套的工具套件中構(gòu)建你的設(shè)計(jì)。無(wú)論何時(shí),當(dāng)你的設(shè)計(jì)無(wú)法滿(mǎn)足其計(jì)時(shí)需求時(shí),都需要返回并拆分設(shè)計(jì)中的組件,或減慢時(shí)鐘速度。通過(guò)使用設(shè)計(jì)工具,你最終能夠找到那條最長(zhǎng)的路徑。
如果你這樣做了,你將自學(xué)到一些探索方法,然后通過(guò)使用這些方法,就可以找到在運(yùn)行的硬件的時(shí)鐘之間可以放置的具體邏輯數(shù)量。
例如,我傾向于在 Xilinx 7 系列零件中進(jìn)行 100MHz 時(shí)鐘速率的設(shè)計(jì)。這些設(shè)計(jì)通常運(yùn)行在大約 80MHz 速率的Spartan-6 上,或者50MHz的 iCE40上——盡管這些都不是硬性關(guān)系。把在一個(gè)芯片上正常執(zhí)行的程序放在另一個(gè)上執(zhí)行,可能會(huì)超載,亦可能會(huì)時(shí)鐘檢查失敗。
下面有一些我曾經(jīng)在使用時(shí)鐘時(shí)得到的一些粗略的探索性經(jīng)驗(yàn)。由于只是個(gè)人經(jīng)驗(yàn),這些方法并不適合所有的設(shè)計(jì):
1.通常,我在設(shè)計(jì)一個(gè)32 位的加法時(shí),會(huì)使用一個(gè)時(shí)鐘內(nèi)有 4-8個(gè)條目的多路復(fù)用器。
如果要使用一個(gè)較快的時(shí)鐘,例如頻率為 200 MHz,可能就需要將加法操作從多路復(fù)用器上剝離下來(lái)。
ZipCPU 的最長(zhǎng)路徑,實(shí)際上是從 ALU 的輸出到 ALU 的輸入。
這聽(tīng)起來(lái)很簡(jiǎn)單。它甚至符合前面的經(jīng)驗(yàn)法則。
但 ZipCPU 的問(wèn)題在于,如何在較快的速度下將輸出路由回輸入。
讓我們跟蹤一下這個(gè)路徑:跟隨 ALU,邏輯路徑首先通過(guò)一個(gè)4路多路復(fù)用器來(lái)決定是否ALU,內(nèi)存或分頻輸出需要回寫(xiě)。 然后將該回寫(xiě)結(jié)果饋送到旁路電路中,以確定是否需要將其立即傳入 ALU 作為其兩個(gè)輸入之一。 只有在該多路復(fù)用器末端并且旁路路徑執(zhí)行 ALU 操作時(shí),多路復(fù)用器才會(huì)產(chǎn)生。 因此,所有這些邏輯步驟都會(huì)在通過(guò) ALU 時(shí)造成壓力。 然而,由于ZipCPU的設(shè)計(jì)結(jié)構(gòu),任何在此路線的時(shí)鐘都可能會(huì)按比例減緩 ZipCPU 運(yùn)行速度。 這意味著有可能這條最長(zhǎng)線路仍然是 ZipCPU 中最長(zhǎng)的一段線路。
我曾經(jīng)對(duì)以更高的速度運(yùn)行 ZipCPU 感興趣,這是我嘗試分解和優(yōu)化的第一個(gè)邏輯路徑。
2.16×16位乘法器需要一個(gè)時(shí)鐘。
有時(shí),在某些硬件上,我可以在一個(gè)時(shí)鐘上運(yùn)行 32×32 位的乘法。而在其他硬件上,我需要分解這個(gè)操作。 因此,如果我需要一個(gè)簽名的 32×32 位乘法,我使用我專(zhuān)門(mén)為此建立的流水線例程。 該例程包含其中的幾種乘法方法,允許我從適合我目前正在工作的硬件的選項(xiàng)中進(jìn)行選擇。
你的硬件可能也還支持 18×18 位乘法。 一些 FPGA 還支持在一個(gè)優(yōu)化的硬件時(shí)鐘內(nèi)進(jìn)行乘法和累加。只要你對(duì)使用的硬件足夠熟悉,你就知道你能用它做什么。
3. 訪問(wèn)任何 RAM 塊都需要一個(gè)時(shí)鐘。
如果可以的話,應(yīng)盡量避免在該時(shí)鐘周期調(diào)整索引。 同樣,避免在此時(shí)鐘期間做任何有關(guān)輸出的事情。
盡管我認(rèn)為這是一條很好的規(guī)則,但我已經(jīng)在 100MHz 的 Xilinx 7 系列設(shè)備上違反了其中的兩個(gè)部分,而沒(méi)有產(chǎn)生(嚴(yán)重的)影響。 (在 iCE40 設(shè)備上有問(wèn)題。)
例如,ZipCPU 從寄存器讀取數(shù)據(jù),給結(jié)果加上一個(gè)即時(shí)數(shù),然后從結(jié)果中選擇是否應(yīng)該在寄存器、PC上,還是條件代碼寄存器中加上即時(shí)數(shù)——都在一個(gè)時(shí)鐘內(nèi)。
另外一個(gè)例子就是,長(zhǎng)期以來(lái) Wishbone Scope 根據(jù)當(dāng)前時(shí)鐘是否從存儲(chǔ)器進(jìn)行讀取,確定從緩沖區(qū)內(nèi)讀取的地址。 從這個(gè)依賴(lài)中斷它,需要添加另一個(gè)延遲時(shí)鐘,所以當(dāng)前版本不會(huì)再破壞這個(gè)(自我強(qiáng)加的)規(guī)則。
這些規(guī)則只是我隨著時(shí)間積累下來(lái)的方法經(jīng)驗(yàn),用來(lái)判定單個(gè)時(shí)鐘內(nèi)可容納的邏輯數(shù)量。 這些經(jīng)驗(yàn)法則與設(shè)備和時(shí)鐘速度有關(guān),因此它們可能不適用于你的設(shè)計(jì)開(kāi)發(fā)。 我建議你積累自己的探索經(jīng)驗(yàn),以便你知道在時(shí)鐘周期之間能做些什么。
下一步
也許我能夠提供給任何新的 FPGA 開(kāi)發(fā)人員的最后建議,就是學(xué)習(xí) HDL 時(shí)要在實(shí)際硬件上進(jìn)行練習(xí),而不僅僅是在模擬器上。與實(shí)際硬件組件相關(guān)聯(lián)的工具,其在檢查代碼和計(jì)算所需時(shí)間方面都很出色。 此外,以高速時(shí)鐘構(gòu)建設(shè)計(jì)的想法是好的,但這不是硬件設(shè)計(jì)的最終結(jié)果。
記住,硬件設(shè)計(jì)是并行的。 一切都從時(shí)鐘開(kāi)始。
-
FPGA
+關(guān)注
關(guān)注
1625文章
21620瀏覽量
601232 -
時(shí)鐘
+關(guān)注
關(guān)注
10文章
1714瀏覽量
131274 -
硬件設(shè)計(jì)
+關(guān)注
關(guān)注
18文章
394瀏覽量
44517
原文標(biāo)題:學(xué)數(shù)字設(shè)計(jì)的軟件工程師該了解的時(shí)鐘知識(shí)
文章出處:【微信號(hào):mcuworld,微信公眾號(hào):嵌入式資訊精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論