什么是專用處理器?
先說一般的處理器概念,wiki定義是“ In computing, a processor is an electronic circuit which performs operations on some external data source, usually memory or some other data stream ”。專用處理器就是針對特定應用或者領域的處理器,類似于是我們經常說的Domain Specific Architecture的概念。
最為通用的處理器當然是CPU(比如intel的桌面CPU,ARM的嵌入式CPU),可以運行任何程序,處理各種數據。但問題是CPU對某些應用效率太低(處理能力不夠,無法實時處理,或者是能耗太大)。比如,處理graphic不行,于是出現了GPU;信號處理不行,于是出現了DSP。GPU可以做圖像處理,也可以做DNN的training和inference,但是在處理某些DNN應用的時候效率不高,于是有了專用針對這些應用處理器,也就是我最近討論的AI/ML/DL處理器。所以說,專用處理器也是個相對概念,相對CPU而言,別的類型處理器都可以認為是專用處理器。而我在本文里主要討論的是相對GPU/DSP而言更為“ 專用 ”的處理器。
專用處理器的覆蓋范圍也很廣,有的能夠運行標準的C程序,比如很多ASIP處理器(Application Specific ISA Processor);有的只有很簡單的可編程性,比如一些可配置的硬件加速器(Configurable Hardware Accelerators),極端的例子就是“只運行一條fft指令的“FFT硬件加速器。當然具體的硬件設計里可能并沒有指令的概念,只有配置的概念。我討論的重點是至少具有一定可編程能力,可以(并需要)運行程序的專用處理器。
指令集設計
這里先簡單說一下指令集的概念。指令集就是一個處理器的硬件可以支持的基本操作(符號化的抽象描述)的集合。(wiki:“ An instruction set, with its instruction set architecture (ISA), is the interface between a computer's software and its hardware, and thereby enables the independent development of these two computing realms; it defines the valid instructions that a machine may execute. ”)。借用Patterson老爺子最近講演里了一張圖,ISA就是傳統上軟件和硬件的分界線。
通常,處理器的指令集架構(ISA:Instruction Set Architecture)決定了處理器的功能(編程模型)。最著名的x86就是intel CPU的指令集。一個通用處理器,為了適應所有的應用,其指令集必須考慮最大的靈活性。這種靈活性主要表現在指令功能是不是完備和粒度是不是足夠細。
舉個例子,大家都知道FFT運算是由蝶形運算組成的;而蝶形運算是由復數乘法和加法組成;復數的乘法和加法又是由普通的乘法和加法組成。如果你設計一個可以處理FFT的處理器,可以有幾種方法設計指令集。最簡單的就是用一個通用指令集,指令集里有最基本的乘法和加法就沒問題。FFT的處理分解為這些基本運算,一步一步完成。這樣,你的處理器具有最高的靈活性,如果這個處理器不做FFT,還可以做其它的運算。還有一種方法,指令集里只設計一條指令,fft指令,執行這條指令就可以完成所有操作。當然,這樣顯然沒什么靈活性。即使是要做一個“1+1”的操作,你的處理器也干不了。這個例子比較極端,實際設計中一般是折中的處理。但是后者就是我想討論的專用處理器的一個重要特點,一條指令完成更多的處理。
由于專用處理器這個名稱可以用在很多地方,我想再明確一下本文說的專用處理器設計的范圍:1. 我們主要討論IP級的設計,也就是說專用處理器設計最終作為一個SoC(System-on-Chip)芯片中的IP出現。它需要和其它模塊合作完成整個芯片要實現的功能(下圖為一個簡化模型)。2. 我們主要討論的專用處理器是要運行程序的,有自己的指令集(可能很簡單,比如Google第一代TPU,主要指令不超過10條),需要有存儲程序的空間和讀取指令,執行指令的機制。
專用處理器雖然強調專用二字,但實際上還是一個處理器。因此,設計一個專用處理器,和設計通用處理器的內容和過程類似。簡單來說,這一過程覆蓋指令集(ISA),微結構(硬件)和工具鏈(軟件)的設計和實現。下面先討論一下指令集的問題。
對專用處理器來說,指令集的設計直接反映了對應用需求的理解。比如,第一篇中介紹的例子,如果我們的專用處理器只是為了加速256點的FFT用的,那么指令集里只有FFT指令就夠用了。考慮到數據搬移的需求,再加上幾條數據搬移的指令,比如讀取數據,寫回數據。于是可以得到一個有三條指令的指令集(fft,load,store)。這個處理器執行的匯編(Assembly)程序大概就是這樣的。
當然,這里做了很多簡化,但看起來這個指令集已經可以work了。同時,這也是一個“高效”的設計,沒有多余的東西。如果你要循環做8次fft,那么可能需要增加一條loop(循環)指令,要不然你就得把上面的代碼copy八次。加了loop指令,匯編代碼可能是下面這樣。
設計指令集除了確定每條指令的功能和操作數(比如上面的例子里的寄存器的名字,循環次數等等),還有一個重要工作就是設計指令編碼。像“load”這樣的指令名稱只是個抽象的描述,而處理器的硬件看到的實際上是二進制的指令編碼。還是上面這個例子,由于我們的指令集有4條指令,則需要2個比特來區分,比如,00:fft;01:load:10;store;11:loop。再具體看load指令,還需要幾個bit來說明目標寄存器,假設一共有8個寄存器(R0-R7),區分他們又需要3個bit;另外需要一個bit來說明數據的來源:是一個立即數還是來自內存;如果來源是內存,還需要幾個bit表示內存地址,或者指示存放內存地址的寄存器編號,等等。你會發現,可能對于一個load指令,一共需要32個bit的指令編碼。上面的匯編程序第三行對應的機器碼可能是這樣的。
最后,把所有的情況列出來,就形成一個指令和指令編碼的列表。這就是一個完整的指令集架構(ISA)了。實際上的ISA當然比這個復雜很多,但不管多復雜,主要也就是這幾大類功能:第一是執行運算或處理功能的,比如算數運算;第二類是控制程序流的,比如循環,分支和跳轉;第三類實現數據搬移的,比如內存到寄存器,寄存器之間;最后還有一些輔助功能,比如debug,中斷,cache之類的指令。這里就不展開講了,有興趣的同學可以自己研究一下現在很火的開源指令集RISC-V。個人感覺,仔細看明白一個好的指令集的設計思想,比看教科書收獲要多得多。
以上算是指令集的背景知識吧,回到設計專用處理器的問題。當我們有了一個應用需求,怎么來設計和優化一套專用的指令集呢?我想這個問題可能很難有個統一的答案,這里就說說我的個人經驗吧。
1. 確定評價標準
我們設計專用處理器都是有明確目的性的,先把目標弄清楚至關重要。評價一般的通用處理器有一些成熟的benchmark。還有一些benchmark更面向專用領域,比如多媒體,DSP,或者針對特殊結構的,比如cache。
那么評價專用處理器的標準是什么呢?很簡單,目標應用。 所以,最好在開始設計之前,就把目標應用定量化。如果目標應用已經有程序代碼,就可以直接用這些程序代碼做benchmark,來評價你的設計。如果還沒有完整的應用程序代碼,最好也要把關鍵算法部分寫出來。當然,這一條不只是針對指令集,而是針對完整的專用處理器,包括工具鏈的設計(后續再介紹)。對于專用處理器設計來說,評價標準一般是有限而明確,是正是它能夠在一個領域做的比通用處理器效率高的最重要因素。
2. 選擇一個參考指令集作為基礎
從零開始做專用處理器相當于“重新發明輪子”,存在很大的風險。那么我們能否把問題變成“優化輪子設計”呢(是不是看起來要簡單了很多)?在多數情況下都是可以,而且有效的。對于大部分應用來說,其合理的指令集都需要一些基本的指令,比如基本的算術指令和跳轉控制指令等,這一部分完全可以參考已有的設計。這樣可以大大降低設計的風險。
比如,我們現在有一個應用,在通用處理以外需要大量的FFT操作。一種方法是自己設計一套指令集,即包括通用指令,又包括特殊指令,比如專門的蝶形運算(butterfly)操作。另一種方法是參考一個成熟的指令集,在它的基礎上做優化工作,增加butterfly指令,并減少一些不常用的指令。相比第一種方法,這樣顯然風險要小的多。還有一個好處,我們 可以重用參考處理器的工具鏈 ,或者只要少量改動,進一步降低的工作量。
結合第1點,一般我們可以先把目標應用的程序在參考的處理器上跑一下,做一些評估,找到瓶頸。針對瓶頸問題設計或改進指令集,以及后面要介紹的微結構和工具鏈。這也說明在開始的時候就有一個明確的評價標準的好處。
3. 充分利用工具
實際上,不管是指令集還是微結構,設計和優化過程就是一個在優化目標指導下的設計空間探索問題。如果你足夠厲害,你當然可以采用“pencil & paper”的方法。但對于我們大部分設計者來說,人肉探索這個設計空間幾乎是不可能的。能不能充分利用工具幫忙,往往決定我們是不是能夠盡快得出一個比較好的設計。在第2點里,我們先把應用在一個現有的處理器上跑一下,然后根據profiling結果做優化設計,實際就是借助工具幫助我們分析問題。
如果你有足夠的資金,還可以借助一些商用的工具。比如,有的DSP IP支持一些擴展和定制的功能和工具,你可以在一個基礎設計上針對你的應用設計你自己的專用處理器;還有專門設計ASIP(專用指令處理器)的工具,你甚至可以用一些高層次的語言來描述處理器,工具自動生成工具鏈和硬件設計(RTL代碼),并且評估設計的好壞,幫忙進行優化。當然,這些IP或者工具一般價格昂貴,也有一定的技術門檻。以后有機會在詳細介紹吧。
微結構
下面我們來看看上述指令集的硬件實現,微結構(microarchitecture)。wiki對微結構的定義如下:
“In electronics engineering and computer engineering, microarchitecture, also called computer organization and sometimes abbreviated as μarch or uarch, is the way a given instruction set architecture (ISA) is implemented in a particular processor. A given ISA may be implemented with different microarchitectures; implementations may vary due to different goals of a given design or due to shifts in technology.”
如果說指令集是一個處理器的功能規范,那么微結構可以認為是實現ISA的硬件架構。對于不同的優化目標,相同的一個ISA可能用不同的微結構來實現。換句話說,微結構是最終實現性能指標要求的途徑。當然,一個優秀合理的ISA的在設計的時候肯定也考慮了微結構實現的問題。在我們設計一個專用處理器的時候,ISA和微結構的設計和優化往往是一個交織進行的過程。先設計一個ISA,然后在做微結構實現的過程中再修改ISA也是很常見的。
微結構的設計和優化又是一個巨大的話題,也涉及很多知識。我還是先通過FFT專用處理器的例子來說明一下基本概念。為了實現上一部分設計的ISA,我們可以設計這樣一個處理器微結構。
如果讀者您一看就明白了這個圖的意思,請跳過下面這段簡要說明,直接看微結構優化的討論。
首先,我們要執行的關鍵指令是fft指令,這里假設fft指令就是做一次蝶形運算(buffterfly)。所以我們要有一個做蝶形運算的硬件單元(圖中的4)。而這個功能單元FU(Functional Unit)需要輸入和輸出數據。數據了來源可能是通用寄存器堆RF(Register File,圖中的3),也可能是memory或者流水線寄存器。同樣,數據的輸出也有很多可能。因此,需要一些MUX來進行選擇。簡單說,圖中的3和4就構成了處理器中的數據通道(datapath),也就是處理數據的通路。另外,為了把數據從數據存儲器(data memory)中讀進來進行處理(load),或者將處理的結果再寫回到存儲器,還需要一個“load store單元”(圖中的5)。
但是,數據通道要正確運行,需要很多控制信息。比如,在寄存器堆中倒底哪個存放的是輸入數據;哪個應該存放運算結果?FU的數據來源倒底來自RF還是memory;結果要寫回哪里?等等。而這些信息實際上就包含在程序指令里。我們假想匯編程序,每行指令都包含對datapath的控制信息。因此,在一個處理器里還需要有一條控制通路(control path),根據程序指令實現對datapath的設置和控制。
我們先要把指令從程序存儲器(PM:program memory)讀進來。這需要一個取指令的功能模塊(fetch);取指模塊的功能是向PM發出地址,執行“讀”操作。這個地址是根據一個特殊的寄存器:程序計數器(PC:program counter)產生的。PC也可以看作是指向程序存儲空間的一個指針,它實際控制著程序執行的流程。如果程序按正常順序執行,則PC = PC + 1。如果需要改變程序流,比如跳轉,則需要改變PC的值,指向要跳轉的新地址,PC = PC + offset。這樣取指模塊讀出的就是跳轉目標位置的指令。
上篇文章已經介紹了,指令經過編碼以后形成一個二進制的機器碼。取指模塊讀進來的正是這個機器碼。要確定這條指令要執行的具體操作,就需要進行譯碼(decode)。比如,在咱們的例子中,根據機器碼的頭兩個bit就可以判斷倒底是那一條指令。
分辨出具體是什么指令,就可以執行該指令的操作了。通常這個過程稱為指令發射(issue)或者執行(execution)。其結果包括,對數據通路的控制,比如“fft”指令;對PC的修改,比如指令“loop”和對訪的控制“load和store”指令,等等。
到此為止,我們已經有了一個workable的硬件架構了,在這個硬件上可以運行前面說的匯編程序并且輸出結果。但實際上,這是一個“極簡”微結構,忽略了很多重要內容。為了后面討論的方便,下面介紹幾個和微結構相關的名詞。
指令周期(Instruction cycle):
一條指令一般會經歷“取指”,“譯碼”,“發射/執行”和“寫回”這些操作。處理器執行程序的過程就是不斷重復這幾個操作。
指令流水線(Instruction pipeline):
當一條指令,完成了“取指”操作,開始進行“譯碼”的時候,取指模塊就可以取下一條指令了,這樣可以讓這些模塊不至于閑著沒用。wiki對指令流水線的示例如下(IF:取指;ID:指令譯碼;EX:執行;MEM:訪存;WB:寫回):
指令并行(Instruction-level parallelism):
同時執行多條指令。比如,一邊從memory讀數據,一邊進行fft處理。我們經常聽到的超標量(Superscalar),超長指令字(VLIW),亂序執行( Out-of-order execution)等等技術都是發掘指令級并行的技術。
數據并行(Data parallelism):
同時處理多個數據。我們常聽到的向量處理器(vector procesor),張量處理器(Tensor processor)多數都是利用了SIMD(一條指令可以處理多個數據,比如一個向量乘法)技術。
存儲層次(memory hierarchy):
處理器相關的存儲實際是由多種類型的存儲器組成。一般訪問速度越快(離datapath的“距離”越近),成本越高;相應的容量也越小。按從快到慢的順序,包括芯片內的存儲器:寄存器(Register),TCM(Tightly Coupled Memory),L1 cache,L2 cache和芯片外的存儲器,DDR,硬盤等等。
實際上,對處理器微結構的研究到今天為止已經非常非常成熟,想有很大的創新幾乎不太可能了。做一個專用處理器無非是怎么針對應用的特點,利用好這些經驗的問題。當然,這也是一種創新。下面談一些做專用處理器的個人感受吧。
1. 通用處理器的背景知識
既然專用處理器只是一種特殊的處理器,那么處理器的一般性知識還是非常重要的。如果你對處理器設計的常用技術和技巧都非常熟悉,那么你設計專用處理器肯定也是游刃有余。比如指令級并行和數據并行是微結構設計的兩個重要方向,你是否能準確的了解每一種并行技術的優勢,劣勢和代價呢?最好你能夠在腦子里就有一個對比的表格,隨時可以拿出來和目標應用放在一起做評估。另外,還是要跟蹤這個領域的最新進展,也許能給你帶來很大的啟發。
2. 突破通用處理器的思維
雖然做專用處理器要以處理器的一般知識為基礎。但也要敢于做出突破。實際上,我們看到的處理器設計經典知識往往針對通用處理器。畢竟它的應用范圍廣,討論的也比較多。而面向某個領域的專用處理器通常都是by design的優化,可能就只有你自己或者很少的人做,討論的也比較少。這種時候就要相信自己對應用的理解,敢于做出一些“奇怪”的設計。當然,前提是我們有嚴謹的定量分析做支撐。這一點我會在后續介紹方法學和工具鏈的文章里進一步說明。
3. 發掘歷史的寶藏
從最近兩年AI硬件熱潮中我們發現,很多在歷史上曇花一現的架構重新獲得了成功,或者至少獲得了新的關注,Google TPU中使用的脈動陣列架構就是最好的例子。在歷史上有過體系結構百花齊放的年代,當時很多有趣的設計只是由于生不逢時而被遺忘了。對于專用處理器來說,重點是高效解決特定問題,因此歷史上很多當時看起來”非主流“的設計可能反而是最合適的。所以我們不妨經常做做“考古”工作,能發現金礦也說不定。
設計方法和工具
前面我們分別討論了專用處理器的指令集和微結構的問題。其實,在指令集和微結構方面,專用處理器用的技術基本上都是在通用處理器發展過程中探索過的東西。要說專用處理器設計最為特殊的地方,我個人認為應該是設計方法(方法學)和工具。專用處理器設計成功與否完全由目標應用來檢驗,而應用的多樣性也決定了專用處理器的多樣性。這種多樣性不僅反映在軟硬件設計本身,也反映在設計方法和工具上。
上面這副圖展示的domain-specific computing的概念既包括了專用處理器(圖中的ASP,Application Specific Processor)設計和也包括了相應的工具開發。下面我們就結合這副圖,把DNN作為一個domain,討論一下專用處理器的設計方法和各種工具。
Domain Modeling
首先是對特定領域(domain,比我們說的目標應用的概念要更廣泛一下)進行建模,把需求模型化和量化,作為后續工作的評價標準。建模可能會使用特殊的語言擴展或者數據流圖的形式,比如在DNN領域經常使用的Tensorflow就是典型的例子。
Domain Model是后續開發的基礎,據此可以得到兩個重要的中間描述:一個是用于硬件架構設計的Domain Characteristics;另一個是用于生成C/C++應用代碼(當然也可能是其它語言)的Application Model。這里的具體名稱并不太重要,重要的是一個domain model需要經過處理,分離出指導硬件設計和生成應用軟件代碼的兩部分信息。
HW Architecture design和Architecture Model
硬件架構設計的主要工作是設計專用的計算引擎(Customized Computing Engine)和互連機制(Customized Interconnection)。比如在CNN加速器中比較常見的由PE(Processing Engine)組成的2D mesh網絡,PE就是專用的計算引擎,2D網絡就是適應CNN 2D卷積特征的互連機制。
硬件架構設計還要輸出一個架構模型。而這個硬件架構模型也是整個設計方法中重要的一環。一方面,這個架構模型可以生成虛擬原型系統(Virtual Prototyping);另一方面,它也是程序代碼映射工具(Source-to-source mapper)的輸入,而代碼映射功能用于將一些特殊的模型轉換為C/C++這類傳統的編程語言(這類語言有很好的工具進行處理),同時輸出Analysis Annotations,用于指導硬件設計和軟件工具鏈的前端設計。
虛擬原型(Virtual Prototyping)
我們通常說的Prototyping一般指基于FPGA或者測試芯片(testchip)系統原型,即用于驗證硬件設計,又可以debug固件,操作系統和應用程序。但是開發硬件原型系統本身也是一項費時的工作,并且要等等所有硬件設計完成了才能實現。虛擬原型則是個純軟件的仿真器。最常見的方式是使用SystemC這樣語言(抽象層次更高)來對硬件進行建模,而不是直接使用RTL級的硬件模型。建模的抽象層次提高雖然會損失一些細節,但好處是開發便捷(C++編程),仿真速度快。和硬件的原型系統相比,虛擬原型可以在項目開始階段就開發完成,提供給軟件開發人員,而不需要等到硬件準備好。最后,虛擬原型是純軟件仿真,很容易debug,也很容易部署。虛擬原型是個有趣的話題,以后有機會可以專門講一下。
計算引擎硬件實現
這里把計算引擎分為三種:專用處理器(ASP),硬件加速器(HW Accelerators)和可編程陣列(Programing fabric)。前兩種我們都介紹過,第三種的硬件結果類似于FPGA,差別是這里的邏輯電路陣列也是根據應用定制的。實現這三類計算引擎可以靠工程師完成,也可以借助專門的工具,比如,High-level Synthesizer(高層次綜合工具,也有叫行為級綜合的)可以把C,systemC甚至Matlab代碼(當然有一定的約束)自動綜合成硬件設計(RTL代碼)。也有一些工具可以根據特殊的處理器描述語言,如Synopsys的LISA,NML和RISC-V處理器用的Bluespec等,自動生成RTL代碼。
這里插一句,自動生成RTL代碼看起來高大上,實際也沒那么難。記得10年前在SiliconHive(也是一個做專用處理器和工具的公司,后來被Intel收購了)實習做NoC的時候,RTL代碼就是從XML描述里自動生成的。其實就是大家平時形成的好習慣:RTL代碼盡量用腳本生成,積累起來也就成了自己的自動化工具。
這之后的工作主要就是將計算引擎和互連機制集成在一起,并且實現硬件的原型系統。互連機制的設計也有很多內容,這里就暫不深入了。
軟件開發工具鏈
圖的右半部分就是軟件開發的工具鏈,這個和我們傳統上說的工具鏈基本是類似的,即從C/C++的源代碼,經過一系列的工具,生成運行在最終硬件上的機器代碼(可以有很多形式)。工具鏈主要包括,前端(front end)后端(back end)和runtime。這里和通用CPU的工具鏈的主要差別在于back end和runtime,因為這兩部分和硬件架構(指令集和微結構)關系密切。對應專用處理器的硬件,主要體現在customized和adaptive這種特征。不過這里還有一些輔助性的工具,比較典型的比如debuger,就不細說了。
小結一下:
1.專用處理器雖然特殊,但設計方法和工具是有普遍性的,這也是研究方法學的價值所在。2. 設計方法往大說是方法學,但在實際的工程中體現為任務,流程和工具,設計專用處理器的過程也是優化方法學的過程。3. 專用處理器設計面向應用,往往有比較高的Time to Market要求,因此從架構探索到RTL生成到原型驗證,都要盡量利用自動化工具提高設計的效率,自己設計小工具并且不斷積累是很好的實踐;4. 采用專用處理器的系統往往是軟硬件緊密協同的系統,設計方法上最重要的理念是軟硬件的聯合優化:在設計硬件的時候充分利用對應用軟件的分析;而在設計軟件工具鏈的時候也要充分結合硬件架構的特點;Architecture Model和Analysis Annotations就是軟硬件設計和工具間的橋梁。
“自己動手”設計專用處理器
最后實戰一下專用處理器的設計項目吧。我們先從結果說起,也就是這項任務的最終交付物。這里不妨參考ARM處理器核的deliverables。當然,如果只是一個自己用的專用處理器,不一定要有這么完整的交付物。
硬件 :主要是處理器相關的RTL代碼,驗證環境,EDA工具的腳本,文檔等等。
工具軟件 :主要包括編譯工具(compiler),調試工具(debugger),仿真工具(simulator)和性能分析工具(profiler)。下圖是ARM的編譯工具的例子,主要包括armclang(C編譯器),armasm(匯編器),armlink(鏈接器)和fromelf(image工具)。
source: arm.com
仿真工具一般至少包括一個指令仿真器 instruction set simulator (ISS)。
模型 :此外,現在一般的處理器IP還會提供一些處理器的模型來支持系統級設計,比如用于前面介紹的虛擬原型的處理器模型(類似于ARM的Fast Model)。專用的處理器模型是虛擬平臺的重要組成部分,和總線模型以及其它IP模型一起模擬系統的功能。
看到這一大堆工作,如果你沒有膽怯,而是覺得很有意思。那么我也很愿意給你點幫助,看看是不是可以把你的想法變成現實。其實方法也很簡單 -- 自己做不了就“找別人幫忙唄”。具體來說,根據你的預算情況,可以分為“ 窮 ”和“ 富 ”兩種玩法。
我先說說有錢的玩法吧。其實,不止你一個人想做專用處理器,很多大公司也有這樣的需求。所以,就有人為這種需求專門提供了解決方案,比如Synopsys的ASIP-designer工具就是為了滿足定制處理器的需求而設計的。ASIP designer支持從零開始設計和實現一個專用處理器。你可以非常自由的設計指令集和微結構,覆蓋從Extensible processor,到Application-specific uP/DSP,到Programmable datapath這樣一個更大的架構空間,如下圖所示。這里也可以看出,這個工具的目標并不是設計通用處理器。
source:synopsys.com
下圖是該工具完整的方法學。
source: synopsys.com
它的輸入就是兩個,算法(C/C++代碼)和處理器模型(Processor Model),輸出則是一個處理器相關的所有設計和工具鏈。從輸入到輸出的過程同樣是自動化完成的。當然,這個過程并不像看起來那么簡單,處理器建模的門檻不低。而且,工具賦予你的靈活性越高,掌握這種工具的門檻也越高。ASIP designer的處理器建模需要使用一種專門的語言,即nML,對處理器的指令集和架構進行高層次建模;此外還需要很多和編譯器相關的設計。所以,即使你能買得起,要玩好這套工具,還得具備兩個條件:第一,是你必須熟悉處理器架構和編譯方面知識;第二,是要學習這套建模語言和工具。
總的來說,如果你有專用處理器設計的需求,足夠的資金和學習的耐心,可以考慮引入這類輔助設計工具。在經歷過一定的學習周期后,你不僅可以完成一個設計,還能獲得快速、高效設計處理器的能力。
下面再看看“ 窮玩法 ”。如果你沒有足夠的資金來購買上述工具,或者是你的目標收益還不值得做出這樣的投資。這種情況下,我建議你從開源免費的處理器(或者指令集)開始做你自己的專用處理器。其實這也算是廢話吧。
假設你想在RSIC-V的基礎上做定制處理器吧。RSIC-V是現在一個相對成熟的開源處理器指令集,也有開源的處理器實現和非常活躍的社區。相信大家都聽說過,就不科普了。這里得說明一下,我并沒有對RISC-V進行過深入的研究和嘗試,以下的說法基本上是紙上談兵,不對的地方請大家批評指正。
首先,你要好好學習一下RISC-V指令集手冊中的“Chapter 10 Extending RISC-V”,這里明確介紹了給RISC-V指令集擴展指令的規則。包括標準的擴展和非標準擴展兩個方面。
第二,在現有的RISC-V的硬件實現基礎上,增加新指令對應的硬件。可能需要增加專用的寄存器,運算單元,pipeline寄存器,控制信號等等。或者,你可以按照新的指令集(假設叫“RISC-V++ ISA”)自己做完整的硬件實現。其實我覺得第二種方法還更靠譜一點。很多時候,修改別人的東西,要比自己做困難的多。
第三,在RISC-V原有的工具鏈(比如GNU或者LLVM的編譯器)基礎上做出修改,支持新的指令。相對來說,這項工作是有比較完善的規則的,只要按照編譯工具的規則就可以把新增的指令加進去。當然,如果你增加的指令比較特殊,比如是向量操作,那么工具鏈的設計會困難很多。這種情況下的一個選擇是在高級程序語言的編譯器中不增加對新指令的支持,這些新的指令以匯編或者intrinsic的方法實現。
最后,這套方法是不是也能支持在前面提到的快速design space exploration呢?基本的思路也是差不多的。你可以先用基本指令集來仿真你的算法;根據profiling的結果(比如性能指標,指令效率,code size等)考慮對指令集進行的修改;然后更新相應的微架構設計,硬件實現和工具鏈,再編譯和測試你的算法,并不斷迭代。如果這個過程沒有自動化工具的幫忙,可能需要比較長的時間才能完成,特別是需要對功耗面積進行詳細優化的情況。
這種方法看起來行的通,不過中間的坑可能非常多,要求你對基礎處理器(比如RISC-V)非常熟悉。適合那些已經完整的做過RISC-V實現的玩家嘗試。否則,也許有的坑你根本過不去。
設計專用處理器常見的”坑“
做專用處理器是個復雜工程,坑很多,以下僅舉幾例。
我們并不真的了解目標應用
在我們做一個面向特定應用的專用處理器的時候,也許沒有想象中那么了解這個應用。我傾向于用這樣問題來判斷:“1.你是否已經有了全部目標應用或者算法的軟件(程序)?2. 你是否有定量的約束條件?”。如果有,那么你就可以保證對你的設計進行客觀和定量的評價(驗證)。如果在對設計進行評估的時候,能夠覆蓋目標應用的軟件程序還不到80%,或者具體的約束條件還不明確,那么就有很大風險。一種可能是,你為不確定性做出一些over design;另一種可能是你的優化目標和實際情況并不相符。不管是那一種情況,實際上都沒有能夠很好的發揮專用處理器的優勢。
不知道什么不應該做
如果我們不具備自己做專用處理器的能力,往往覺得它很神秘,會夸大設計的難度和風險。而當我們具備了這種能力,一個可能的傾向是夸大專用處理器的優勢,什么地方都想用專用處理器來搞定。實際上,掌握了設計專用處理器的能力,相當于一個團隊有了一件強有力的武器。至于是否使用和怎樣使用則是一種更強的能力。一個好的SoC架構,往往是各種類型的處理器和硬件加速器配合工作的。能夠得到這樣的架構,或者是通過了多次迭代和優化,或者是以定量分析和仿真為基礎(再次強調這一點)。
忽視工具鏈的開發
設計一個專用處理器,要經歷需求分析,架構設計,硬件實現和工具鏈開發等多項工作。一個比較常見的問題是忽視工具鏈的開發。但正如我在對方法和工具的討論中指出的,工具鏈(包括處理器開發工具和應用開發工具)對于專用處理器開發和使用是至關重要的。即使你的架構設計和硬件實現做的再好,如果沒有一個完善的工具鏈,這些硬件就沒法發揮最大的效能。從另一個角度來說,如果沒有好的開發工具,架構設計和硬件實現也很難做好。個人認為,比較好的實踐是在項目開始的時候就能夠對工具鏈設計做出規劃并配置專職的人員。
評論
查看更多