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

單週期與多週期

你剛打造的單週期中央處理器誠實卻浪費:它的時脈必須慢到能容下最長的那條指令,於是每條快指令都得跟著乾等。本篇就正面迎擊這個限制,把一條指令拆成數個短週期,並認識打造那顆發號施令的「大腦」的兩種途徑。

回顧:一條指令,時脈的一下滴答

在前三篇裡,你接好了一條完整的資料路徑——程式計數器指令記憶體暫存器檔ALU資料記憶體、一個符號擴展器,以及一把多工器——還有一個讀取運算碼並設定每一個控制訊號控制單元。你最後得到的機器是一台單週期處理器:每條指令都在時脈的一下滴答之內開始並結束。取指、解碼、讀暫存器、ALU、存取記憶體、寫回——整趟旅程都在一個漫長的時脈週期裡,隨著訊號在線路間漣漪般傳開而完成。

這種設計推敲起來簡單得讓人愉快:沒有任何一條指令會跟另一條重疊,而每個暫存器在每次滴答結束時的值,都正是你能預測到的那個。它是一台中央處理器最乾淨的可能畫面,這也正是教科書先建它的原因。但簡單是有代價的,而這代價就明擺在「一個漫長的時脈週期」這句話裡。

單週期的限制:時脈得放慢去遷就最差情況

問題就在這裡。在單週期設計中,時脈週期必須長到足夠讓最慢的那條指令完成,因為所有指令共用這唯一的時脈。想想訊號得跑多遠。一條加法只走過指令記憶體、暫存器檔、ALU,再回到暫存器檔。但一條載入要走過指令記憶體、暫存器檔、ALU(去算位址),接著是資料記憶體,再回到暫存器檔——明顯更長的一串。所有這些路徑中最長的那條,就是關鍵路徑,而光憑它一條就決定了時脈。

後果是浪費的。假設一條載入需要 8 奈秒的訊號傳遞時間,但一條加法只要 4 奈秒。在單週期機器裡,時脈週期被釘死在所有人都是 8 奈秒,於是每條加法都白白浪費了它週期的後半段、盛裝打扮卻無處可去。快指令被拖慢到跟慢指令一樣的速度。這就是單週期限制:你在每一條指令上都付出最差情況的延遲,連最微不足道的那些也不例外。

多週期的點子:把工作剁成短而等長的步驟

出路是把時脈調快,讓一條指令花上好幾下滴答。一條多週期資料路徑把漫長的旅程切成幾個短階段——取指、解碼與讀暫存器、執行、存取記憶體、寫回——並讓每個階段在自己的一個短時脈週期裡跑。如今時脈週期只需要容得下最長的「單一」階段(比方說記憶體存取),而不是整條指令。最關鍵的是:一條加法可以在 4 個週期內結束,而一條載入要 5 個——每條指令只花它真正需要的那麼多個短週期,而不是大家都付最差情況。

為了讓這行得通,資料路徑會多長出幾個保存用的暫存器。因為工作如今橫跨數個週期,中間值——取出的指令、從暫存器檔讀出的兩個值、ALU 的輸出——都必須被「鎖存」進微小的內部暫存器,好讓它們在時脈滴答時不會蒸發、能撐到下一個週期。作為交換,多週期機器現在能跨週期重複使用同一個單元:一個 ALU 在某個週期算 PC+4、在另一個週期算分支目標,於是你不再需要那些額外的專用加法器了。硬體單元更少,而每個都被用上更多次。

Same load, two designs (illustrative latencies):

  single-cycle:  | fetch . decode . read . ALU . MEM . write |   one 8 ns tick
                 add wastes half of that 8 ns tick (only needs ~4 ns)

  multi-cycle:   |fetch|decode|ALU |MEM |write|   five ~2 ns ticks
                 add finishes in 4 of those short ticks, not 5

  iron law:  run time = instruction count x CPI x cycle time
             single-cycle:  CPI = 1   but cycle time = worst case (slow)
             multi-cycle:   CPI > 1   but cycle time = one short stage (fast)
單週期每條指令付一下慢滴答;多週期付好幾下快滴答,且只付每條指令需要的那麼多下。

這是一筆交易,不是白吃的午餐

對多週期買到什麼要誠實。它並不會讓任何一條指令在絕對時間上更早完成——它只是讓快指令不再被慢指令綁架,並讓硬體得以重複使用。記分的正確方式是效能鐵律:執行時間等於指令數乘以每指令週期數乘以週期時間。單週期的 CPI 剛好是 1,但週期時間長得殘酷。多週期的 CPI 大於 1(每條指令 4 或 5 下滴答),但週期時間短得多。它到底贏不贏,取決於實際的數字——光是時脈高從不保證快;真正要緊的,永遠是這三個因子的乘積。

而這裡有個更深的觀察,它推動了本課程接下來的一切。在多週期機器裡,當一條指令待在記憶體階段時,取指硬體是閒著的。當另一條指令在用 ALU 時,記憶體單元是閒著的。各階段輪流上場,但大多時候只是站著乾等。如果我們能讓每一個階段同時都忙起來——取出這一條的同時解碼前一條、再同時執行更前一條——我們就能得到一次做五件事的吞吐量。那種重疊正是管線化,也就是下一階所建立其上的那條「洗衣流水線」點子。多週期,就是帶你抵達那裡的橋。

由誰發出訊號?硬體連線控制與微程式控制

多週期資料路徑需要一個更聰明的控制單元。在單週期裡,控制是一張扁平的查表:給定運算碼,就在整下滴答內設定這固定的一束訊號。但多週期控制必須在每個週期產生不同的一束訊號——這個週期讀暫存器、下個週期驅動 ALU、再之後寫記憶體——而且它必須記得自己進行到哪一步。於是控制單元變成了一台小小的有限狀態機:每個狀態是某種指令類型的某一步,而狀態轉移會從取指走到解碼、走到執行、再走到那個運算碼接下來該走的步驟。

打造那台機器有兩種經典途徑。硬體連線控制(hardwired control)把狀態機直接烤進邏輯閘與正反器裡——一個手工設計或合成出來的客製電路,它的輸出就是控制訊號。它快又精簡,但僵硬:修一個臭蟲或加一條指令,就意味著重新設計電路。另一種選擇,微程式設計(microprogramming),則把控制訊號當成資料看待。每一步那一束訊號被存成一個字——一條微指令(microinstruction)——存在一塊小小的內部控制記憶體裡,再由一個微小的定序器把它們一條接一條讀出來,就像一個「程式中的程式」在驅動真正的資料路徑。

兩者各有歸宿。微程式設計讓豐富而複雜的 CISC 指令集變得可行:一條繁複的指令不過是一段較長的微程式,而你可以靠改寫微碼來修補控制,不必重新流片。硬體連線控制則適合精簡的 RISC 機器,其小而規律的指令集讓邏輯保持簡單又快。不過更廣的啟示,在於資料路徑與控制的分工本身:資料路徑是搬運與轉換資料的管路,而控制是那位決定每根管子何時開啟的樂團指揮。無論指揮是手工打造的電路還是儲存的微程式,那道分隔正是一種中央處理器設計結束、下一種開始的接縫。