首頁 > 軟體

考古20年前的國產CPU:方舟一號和龍芯一號

2021-05-16 02:30:50

20年前,準確地說是2001年7月和2002年9月,嵌入式CPU「方舟一號」和通用CPU「龍芯一號」相繼釋出,分別在嵌入式和通用CPU領域結束了我國無芯歷史。方舟一號設計用途是網路通訊處理器,因為無需軟體生態,也不追求通用效能,所以自己設計了指令集。龍芯一號的目標是桌面計算機,軟體生態很重要,各種各樣的應用軟體更需要CPU具有均衡的通用效能,於是採用了當時在高效能伺服器中使用較多的MIPS III指令集。

這兩款CPU在不同的領域代表著我國自主CPU的第一步,承載著一段歷史,承載著發展自主CPU技術的希望。但我更感興趣的是它們的技術特點和差異,想要弄明白為什麼方舟一號分明誕生得更早,但結束「只能使用進口CPU製造計算的歷史」的卻是龍芯一號。人云亦云不是我的風格,我的疑惑只能自己解決。這兩款CPU太老了,資料很難查詢,但我還是成功收集到了足夠的資訊,終於弄明白了這個問題。

下面我先把它們的一些參數列一個表格,然後再細細說明它們的特點和差異。

兩者封裝大小差不多,但方舟一號的管腳數量更多,這是因為它是嵌入式設計,許多的裝置管理功能都整合在晶片內部,更多的引腳可以直聯更多類型的的外部裝置和低速匯流排。龍芯一號因為製程相對先進一些,並且作為通用CPU不需在晶片內部整合各種附加功能,頻率更高反而功耗更低。快取大小兩者一樣,功耗也差不多,整數效能看起來也差不多,那為什麼仍然說方舟是嵌入式CPU,而龍芯是通用CPU呢?

兩者的整數效能雖然看起來接近,但實際的評價標準卻不相同。方舟一號是設計為處理網路資料的嵌入式CPU,要求低成本低功耗,因此設計十分簡化,比如指令集中沒有包含除法指令,只支援加、減、乘的整數計算,除法和餘數計算都只能用軟體方式處理。所以說方舟一號的200MIPS指標是不包含除法的,這在當時也是許多嵌入式CPU都有的特徵。方舟一號與當時絕大多數的嵌入式CPU共有特徵還包括不支援硬體浮點運算,以及不像通用CPU那樣通過動態排程、亂序執行、分支預測等方式來提高程式的運行效率。

後來的方舟二號和一號相比,在設計上區別不大,主要還是通過使用更先進的工藝製程,改進物理設計來提高工作頻率。二號的主頻達到了400MHz,但指令集仍然只有78條指令。而龍芯一號則完整地實現了MIPS III的全部指令,在設計上也是以通用CPU為目標。MIPS架構(指令集)的資料比較多,不需要詳細說明,方舟架構的資料很少,我也是偶然從一個網友那裡得到了它的指令集參考手冊。通過對方舟指令集手冊的閱讀,並與龍芯一號進行比較,我總算明白了方舟不適合作為通用CPU的原因。

首先是特權等級,方舟架構並沒有像通用CPU那樣進行特權指令和使用者指令的區分,也就是說應用軟體可以為所欲為,只有在軟體完全可控的嵌入式環境中,才可以保證整個系統的安全性。方舟架構雖然分為使用者模式和監督模式,但監督模式只是用於處理異常和中斷,與安全無關。龍芯一號除了實現了MIPS-III中定義的特權等級之外,還額外地實現了抵禦緩衝區溢位類攻擊的硬體安全設計,整個計算機系統的安全具有較高的保障。

然後是指令集的設計,為了降低CPU的設計複雜度,減少電晶體數量,方舟架構總共只有78條指令。雖然遠不如通用CPU指令集豐富,但與其它的嵌入式CPU相比則是同一水平。方舟架構也是繼承了RISC思想的典型設計,指令字長32位,有32個通用寄存器,記憶體訪問是Load/Store的模式,其它指令的操作數都來自寄存器和立即數,而不直接訪問記憶體。下圖是方舟指令集參考手冊中的指令列表,從圖中可以看到許多適用於嵌入式而不適用於通用CPU的指令設計。

立即數(直接寫在程式碼中的數字)載入只支援21bit的無符號數,而沒有載入有符號立即資料的指令。有符號數只能先放在記憶體中,再用Load類指令載入到寄存器,對於有大量立即數參與的計算,運行效率偏低。直接跳轉指令支援兩種定址方式,J指令跳轉目標地址由21bit有符號立即數直接指定,這種在程式碼中固化絕對地址的跳轉方式,只在嵌入式應用中才會出現。JA指令的寄存器+偏移量定址倒是通用處理器中常見的方式,但偏移量只支援10bit無符號數,偏移範圍很小,只有4K(1024<<2)位元組。10bit的範圍是0~1023,僅1K位元組大小,但由於指令字長32bit(4位元組),指令會隱含地把立即數左移2bit,因此實際範圍擴大了4倍。4K長度可以適用於簡單的嵌入式程式,但桌面程式需要的跳轉範圍一般要大得多,如果要適應複雜的桌面應用程式,就需要接力跳轉。Branch類是分支跳轉指令,也就是根據大於、小於等各種條件跳轉到不同的程式碼分支。但跳轉的偏移範圍是用10bit的有符號立即數表示的,有效範圍是±2K位元組(512<<2),對於桌面應用程式來說這個跳轉偏移範圍太小了。MIPS III的分支跳轉範圍是16bit有符號數,範圍是±128K位元組,對於20年前的應用程式還夠用,到了現在就成了影響程式效能的因素之一。方舟架構的整數運算指令只有4個,其中加法分為寄存器加寄存器和寄存器加立即數兩條指令,乘法和減法各一條,沒有支援立即數的格式。實際程式中有大量的使用固定數字參與計算的表示式,在方舟架構以及其它類似架構的CPU上,就需要從記憶體中把數字讀入寄存器再進行計算,比常見的通用CPU要多花費一條指令。而且沒有除法指令,所有的除法和餘數計算都要使用軟體方式來處理,比如最簡單的軟體除法就是用被除數減去除數,把結果再賦值給被除數,在迴圈中統計減了多少次之後結果為負數,次數減一就是商。雖然演算法很簡單,但完成這樣一次迴圈至少需要十幾條指令,迴圈多少次需要執行的指令數就翻多少倍,而硬體除法只需要一條指令。雖然可以優化軟體除法的程式碼,但仍然會遠遠低於硬體指令的效率。在簡單的嵌入式程式中這種效率是可以接受的,不過如果與通用CPU相比,即使80286這樣古老的CPU,也是有硬體除法指令的。在當時,不只是方舟,還有許多同類的嵌入式CPU也是這樣的設計。缺少浮點指令,這也是當時各種嵌入式CPU的共同點。因為不支援基本的浮點加減乘除,那麼更高階的三角函數、對數、指數等各種與浮點計算相關的指令也是不存在的。缺少硬體浮點計算的能力對於嵌入式CPU不是問題,無論是路由器、交換機這類網路通訊裝置,還是電子詞典、學習機這樣的消費產品,都不需要進行大量浮點計算,使用軟體浮點就能滿足要求。但在2000年之後,沒有硬體浮點的CPU已經不可能用於通用計算裝置,即使386都可以額外配置387浮點協處理器,486的滿血版本已內建了浮點單元,何況當時已經進入了Pentium 4的時代,桌面環境中大量的圖形影象計算都非常考驗CPU浮點計算的能力。在Linux命令列下工作的專業軟體雖然不需要軟體介面,但在科研領域對浮點計算的效能要求卻遠高於普通的桌面軟體,作為通用處理器的龍芯一號雖然有不弱的硬體浮點效能,但事實上也滿足不了當時對CPU效能的要求,畢竟龍芯一號只有相當於Pentium 2的效能,與當時Intel最高效能CPU差距極大。方舟架構的其它指令在當時也同樣都只能適用於嵌入式應用場景,主要是指令的數量太少,有許多較複雜的計算必須分拆成多條指令來執行,無法高效地運行通用應用程式。只是單從指令集分析,我無法確切知道方舟一號與龍芯一號的效能差距。其實把它們倆放在一起對比效能是不公平的,因為方舟一號本身就是為嵌入式應用而設計,並不擅長通用計算,假如測試程式中有大量除法和浮點計算,或者邏輯比較複雜有大量的條件判斷和分支跳轉,方舟的弱勢就會非常明顯。方舟一號除了在指令集方面不能承載通用應用,在CPU的設計上也儘量簡化,比如龍芯一號中那些現代通用CPU的特徵,方舟一號就沒有。但方舟一號屬於嵌入式CPU的大量特徵也是龍芯一號沒有的,比如SoC擴展能力、功耗管理單元、定時器單元、片上系統匯流排和裝置匯流排等等,都表現出方舟一號是一款設計成熟的嵌入式CPU,能夠滿足當時國內對嵌入式CPU的大部分要求。

一年半之後的方舟二號也使用了0.18um的製程,通過更好的工藝和改進的設計把功耗降低了四分之三,也就是300mW的樣子,頻率則達到了400MHz,加上把指令快取和資料快取增加一倍,CPU整體效能估計應是方舟一號的2.5倍左右。這與方舟架構參考手冊中提到的目標相符:「The instruction set was designed to allow a very small with very low power consumption, yet highperformance implementation. 」——該指令集的設計允許一個非常小、功耗非常低但效能很高的實現。只可惜方舟3號沒有繼續完成,方舟的領頭人自己放棄了,沒有堅持到底!!!

從資料中我明白了方舟系列CPU確實是專為嵌入式應用而設計,無法作為通用CPU使用。而龍芯一號無論是指令集還是結構設計,都是以通用CPU為目標,雖然效能只相當於Pentium 2,但確實能夠適用於各種應用場景,運行任何應用程式都沒有明顯的短板。能夠用來製造包括PC在內的通用計算裝置,大概就是「通用」的本意。後來的龍芯二號效能達到了龍芯一號的3~5倍,雖然仍然與當時的主流CPU有很大差距,但在一些對效能要求不高的場合也有了成批量的使用。當前龍芯最新型號3A5000的效能已經踏進了主流CPU的門檻,並使用了自主設計的LoongArch架構(指令集),龍芯CPU的軟體生態也在有序發展,終於堅持到了朝陽升起。


IT145.com E-mail:sddin#qq.com