JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

RISC 對 CISC,誠實地說

計算機結構裡最有名的這場對決,其實大致已經結束——而那份停戰協議,比戰爭本身更有趣。看看 RISC 與 CISC 到底是什麼意思、為什麼現代 x86 會把它的複雜指令拆成類似 RISC 的微指令,以及為什麼光憑時脈高,從來沒能決定任何事。

兩種設計哲學,一場老爭論

這一整級,我們都在從內部解剖一份 ISA:指令的契約暫存器與載入/儲存、編碼,以及記憶體模型。現在我們拉遠鏡頭,問一個大家在走廊與論壇上爭論不休的問題。從歷史上看,ISA 分裂成兩種哲學。RISC(精簡指令集電腦,像 RISC-V 或 ARM),保有一小組簡單、定長、載入-儲存的指令,賭的是「一條跑很多細小步驟、又快又規律的管線」會贏過「少數幾條笨重的指令」。CISC(複雜指令集電腦,像 x86),則長出了一大組強而有力、變長的指令,其中有些能在單一條指令裡讀取記憶體、計算、再寫回去。

CISC 指令之所以長得那麼精巧,背後有個被遺忘的歷史細節:在 1970 年代,記憶體又小又慢,而程式設計師常常用手寫組合語言。一條能做很多事的指令,意味著更少的程式位元組、也更少的打字量。RISC 在 1980 年代初帶著相反的賭注登場——賭的是寫程式的會是編譯器而非人類,而一套更簡單、更規律的指令集,配上管線要做得快會容易得多。雙方對自己那個年代都說對了。誠實的問題不是「哪一種哲學贏了」,而是「對於你桌上今天這些晶片,什麼才是真正成立的」。

為什麼時脈更快從來決定不了勝負

在我們評判這兩個陣營之前,必須先解除整個領域裡最常見的一個錯誤:以為時脈更高就代表電腦更快。那個信念——百萬赫茲迷思——賣掉了很多晶片,卻幾乎什麼都沒解釋。解藥是效能鐵律,它告訴我們,一支程式的執行時間,是三個誠實的因素之乘積,而不是只有一個。

run time  =  instruction count  x  CPI  x  cycle time

  instruction count : how many instructions the program executes
  CPI               : average clock cycles per instruction
  cycle time        : seconds per clock cycle  ( = 1 / clock rate )

Clock rate touches only the LAST factor. A 5 GHz chip with a
bloated CPI can lose to a 3 GHz chip that retires more work
per cycle. All three terms count.
效能鐵律。更高的時脈只縮短了週期時間;指令數與 CPI 可以悄悄把這份勝利抵銷掉。

這正是審視 RISC 對 CISC 時該戴上的鏡片。一支 RISC 程式往往有較大的指令數(要好幾條簡單指令,才能做完一條 CISC 指令所做的事),但通常有較低的 CPI、也較容易衝上高時脈。一支 CISC 程式指令較少,但每條指令在歷史上有較高的 CPI。這兩種哲學,其實是在拿同樣的三個項彼此交換。沒有任何單一數字——尤其不是印在盒子上的時脈——能決定這場比賽。

現代 x86 如何把複雜性拆成微指令

這裡有個悄悄結束了戰爭的劇情大逆轉。一塊現代 x86 晶片,並不直接執行它那些龐大、複雜的指令。指令流在表面上仍然是 CISC——那是契約,而且必須被遵守,好讓幾十年來編譯出的程式還能繼續跑。但就在取指單元後面,坐著一個解碼器,它的工作是把每條複雜指令成一小撮簡單、形狀固定的內部操作,叫做微指令(micro-ops)。底下那台快速引擎,從來不會看到一條 CISC 指令;它看到的,是一串類似 RISC 的微指令。

  1. 從記憶體取出一條變長的 x86 指令——比方說,一條把記憶體裡某個值加到暫存器上、再把和寫回去的指令。
  2. 解碼並拆解它:這一條指令變成數條微指令——一條載入微指令、一條加法微指令、一條儲存微指令——每一條都像 RISC 指令一樣簡單而規律。
  3. 把這些微指令餵進一台 RISC 風格的引擎,它把它們排程到管線上、亂序執行、並讓許多條同時在途中重疊進行。
  4. 依原本的程式順序提交(退役)結果,使得可觀察到的結果,就恰恰如同那些 CISC 指令一條一條、依序執行的樣子。

於是,可見的 CISC 契約在外面被守住了,而隱藏的機器在裡面,本質上是一台超純量亂序執行的 RISC 引擎。請仔細留意最後一步:即使這些微指令是亂序執行的,它們仍然依序提交,所以程式被觀察到的結果,依舊維持完美的順序。這份重排是一個看不見的最佳化,而不是對契約所承諾之事的改變。這正是貫穿整個這一級那條教訓最清楚的證明——結構(你看得見的契約)與微結構(執行它的機器),是真真切切分開的兩回事。

真正還有差別的地方——編碼

如果兩種晶片在內部都跑類似 RISC 的微指令,那還剩下什麼真正的差別嗎?有——主要在於指令流本身的編碼。RISC-V 的定長指令坐落在可預測的位元位置上,所以解碼器能便宜地把許多指令平行切開,每週期解好幾條也容易擴展。x86 的變長指令(從 1 到 15 個位元組都有)讓人連「一條指令在哪裡結束、下一條從哪裡開始」都不好找,於是寬解碼要花更多電晶體、更多功率。那份解碼成本相對於整塊晶片是小的,但它是真實的,而且在功率寶貴的地方——例如手機與筆電——最為要緊。

還有一個真實、持續存在的差別:每一份 ISA 是怎麼成長的。因為 ISA 是一份長壽的契約,你幾乎從不更動它——你透過指令集擴充往上添加。RISC-V 從第一天起就被設計成模組化的:一個小小的基底,加上你可以選配栓上去的擴充(乘法用的、浮點用的、向量用的)。x86 則是四十年來一層擴充疊一層擴充地堆積(想想那一長列 SIMD 的增補),這讓舊的二進位檔繼續能跑——那正是二進位相容性在運作——卻也讓編碼變得擁擠而不規律。目標相同,美學卻大不相同。

誠實的結論

那麼,誰贏了?誠實的答案是,這個問題自己消解了。RISC 所倡導的那些微結構想法——管線化、亂序執行、以微指令執行——徹底地贏了,而 CISC 晶片則透過把指令拆成微指令而採納了它們。同時,人們歸功給某一份 ISA 的那些實務優勢,通常歸根究柢是投資與工程心力,而非標籤上的哲學。一塊極為成功的晶片,是數十億美元最佳化、一個好編譯器,以及一個健康軟體生態系的產物,這遠勝於它 ISA 上「RISC 或 CISC」那張貼紙。

這場爭論的餘生所揭示的,是你在後面的階級會一再遇到的更深層趨勢。因為來自單一 ISA 哲學的通用加速,已經撞上了堅硬的物理極限——摩爾定律放緩、Dennard 縮放自 2005 年前後實質終結——真正的戰場移到了別處:移到了多核心、移到了向量與 GPU 式的平行、以及為單一工作打造的領域專用加速器。這個領域的未來,與其說是「RISC 對 CISC」,不如說是「通用對專用」。但那是後面階級的故事了。現在,先握住這份停戰協議:你看得見的契約,與執行它的引擎,是分開的,而對你指的到底是哪一個保持誠實,正是這整門功夫所在。