V² 槓桿,如今交給軟體控制
想像一個人在跑步機上。皮帶慢時,他可以悠閒漫步、幾乎不流汗;皮帶加速時,他得使勁推蹬、心跳隨之飆升。處理器也一樣——但它可以自己選擇跑步機的速度,而且時時刻刻都能改。你在看電子郵件時,核心幾乎閒置,那何必讓它們全速狂奔?動態電壓與頻率調整,也就是 DVFS,就是在工作量輕時降低供應電壓與時脈頻率,並在吃重的任務一到就立刻把兩者拉回來的技術。
為什麼非得降電壓不可——只調慢時脈不行嗎?因為這牽涉到整條學習軌中最重要的一條算式。從第二階我們知道,動態功耗為 P = α·C·V²·f。頻率只出現一次、是線性的,但電壓是平方項。單純把 f 減半確實讓功耗減半,可是完成的工作量也減半,所以每件任務的能量並沒有變——你只是用同樣的焦耳跑得更慢。DVFS 的奧妙在於:較低的頻率讓你也能調低電壓(較慢的邏輯需要的驅動力較小),而那個 V² 項便會以加倍的方式回報你。
Workload light → drop one operating point:
Before: V = 1.00 V, f = 1.8 GHz
After: V = 0.80 V, f = 1.2 GHz
Dynamic power scales as V^2 * f:
P_after / P_before = (0.80/1.00)^2 * (1.2/1.8)
= 0.64 * 0.667
= 0.43
~57% less switching power for ~33% less clock speed.操作點與調速器
晶片並不能提供無限多種 V/f 組合。設計團隊會把一小張經過驗證的配對表特性化出來,稱為操作效能點(OPP,在 x86 世界叫 P-state)。每個點都是一組 (電壓, 頻率) 元組,已用實體晶片證明能在最壞角點下滿足時序。一顆低功耗手機 SoC 的每個叢集可能開放六到十二個這樣的點,從深度閒置的 0.6 V / 300 MHz 慢爬,一路到 1.05 V / 3 GHz 的衝刺。
誰來決定用哪個點?一段叫做調速器的軟體,跑在作業系統核心裡(Linux 的 `cpufreq` 子系統就是經典例子)。調速器在短時間窗口內觀察 CPU 使用率,把晶片沿著 OPP 表往上或往下挪——例如 schedutil 會讀取排程器的負載估計,挑出仍能準時完工的最低點。接著由一個硬體電源管理控制器負責真正執行這次切換的時序。
- 往上(要更多效能): 先升電壓,等晶片上的穩壓器與供電網路穩定下來,然後才升時脈。在電壓還沒升上來時就加快時脈,會違反 setup 時序。
- 往下(要更省電): 先降時脈,然後才降電壓。先降需求再降供應,順序絕不能反過來。
- 切換過程中: 一個快速的晶片內 DC-DC 或 LDO 在數微秒內把電源軌拉到位;許多設計會短暫閘控或拉長時脈,確保電源軌正在飛行途中時沒有任何時脈邊緣抵達。
難題:RTL 說不出口的電源結構
這是到目前為止藏在每一階背後、令人不太舒服的真相。你的 Verilog 描述的是*邏輯*——每個閘計算什麼——但它對*電源*一字未提。Verilog 裡沒有「這個區塊坐在可切換的電源軌上」這個關鍵字,沒有「這個域關掉時把這個輸出鉗在 0」的語法,也沒辦法寫「在斷電期間保住這些正反器」。RTL 在設計上就是對電源視而不見的,而這一直是個優點:同一份 RTL 應該既能在 5 V 板子上跑、也能在 0.6 V 行動製程上跑。
可是第三到第五階的全部機制——閘控一個域的電源開關單元、鉗住其懸空輸出的隔離單元、在睡眠期間保住狀態的保持暫存器、島與島之間的位準移位器——統統屬於*實體電源結構*。如果你試圖靠手工改網表來表達它,合成、佈局繞線、驗證這三套工具會各自做出自己的假設,而它們會彼此矛盾。那種矛盾正是某顆晶片在一萬條跨越中漏掉一個隔離單元就流片、回來變成一塊死矽的原因。
UPF 與 CPF:捕捉意圖的格式
為了表達功耗意圖,長出了兩套標準。CPF(Common Power Format)出自 Cadence;UPF(Unified Power Format)由 Accellera 標準化、後來被批准為 IEEE 1801,也是整個產業最終匯流到的那一套。兩者都是以 Tcl 為基礎的腳本語言——你不是把電源架構畫出來,而是用程式碼寫出一段對它的描述。既然 UPF 是勝出的主流,這就是該掌握的那一套;CPF 大多只殘留在舊有流程裡。
一份 UPF 檔以一套固定詞彙為你電源架構裡的角色命名:`create_power_domain` 把設計切成一個個電源域;`create_supply_net` 與 `create_supply_port` 定義電源軌;`create_power_switch` 描述閘控某個域虛擬供電的頂端或底端開關;而 `set_isolation` / `set_retention` 則宣告*策略*——這條規則告訴工具,在凡是符合條件之處統統插入隔離與保持單元,而你連一個實例名字都不必點到。
# --- A tiny UPF snippet (IEEE 1801) ---------------------------
# 1. Carve out a switchable domain for the modem block
create_power_domain PD_MODEM -elements {u_modem}
# 2. Define the always-on and the switched (virtual) supplies
create_supply_net VDD -domain PD_MODEM
create_supply_net VDD_SW -domain PD_MODEM
create_supply_net VSS -domain PD_MODEM
# 3. A header switch: VDD -> VDD_SW, gated by sleep_n
create_power_switch sw_modem \
-domain PD_MODEM \
-input_supply_port {in VDD} \
-output_supply_port {out VDD_SW} \
-control_port {ctrl sleep_n} \
-on_state {ON in {ctrl}}
# 4. Strategy: clamp every output of PD_MODEM to 0 while it is off
set_isolation iso_modem \
-domain PD_MODEM \
-isolation_power_net VDD \
-clamp_value 0 \
-applies_to outputs
# 5. Strategy: retain the modem's state registers through power-down
set_retention ret_modem \
-domain PD_MODEM \
-retention_power_net VDD一份黃金檔案,貫穿每個工具:收尾
這就是為什麼 UPF 是把整條學習軌綁在一起的收尾。同一份檔案貫穿整條實作鏈。合成讀它,把正確的隔離、位準移位器、保持單元插進網表。佈局繞線讀它,建出實體電源網格、擺好開關單元、把常通電源繞到保持正反器上。而驗證讀它,用以證明轉譯過程中什麼都沒丟。一份黃金描述、三個使用者、三者之間沒有任何彼此矛盾的空間。
最後那個使用者——以 UPF 驅動的驗證——才是真正的前沿,因為電源錯誤對普通邏輯模擬是隱形的。一般模擬器假設每個閘永遠通電,所以它會樂呵呵地模擬一個已斷電的區塊還在產生有效資料。一個懂低功耗的模擬器吃進 UPF 後,反而會把關掉的域的輸出汙染成 X,並盯著它們傳播。只要有 X 抵達一個運作中的正反器,你的隔離策略就有破洞。結構檢查器再加一張網:它靜態地證明網表裡每一道域邊界都確實有一個隔離或位準移位器單元,分毫不差地符合 UPF 的要求。
What a UPF-aware simulation catches that plain RTL sim never could:
sleep_n ____________ ____________________
clean? \__________/ wake
VDD_SW ~~~~~~~~~~~~\__________/~~~~~~~~~~~~ (rail collapses)
modem_out D7 D8 D9 X X X X D10 D11 <- X while OFF
|________|
iso_out D7 D8 D9 [ 0 0 0 0] D10 D11 <- clamped 0
(isolation cell holds the boundary)
If iso_out tracked the X instead of 0, an X corrupts the
downstream always-on logic -> a real silicon bug, caught
in simulation because the UPF told the sim the domain was off.退一步,看清整座階梯。第一階為兩個敵人命名:動態與漏電。第二階給了你 V² 槓桿。第三到第五階打造出零件——閘控、隔離、保持、多條電源軌。這一階用 DVFS 在執行時拉動槓桿,再用 UPF 把每個零件收進一份正式合約,端到端驗證。這就是低功耗設計的紀律:底層是物理洞察,頂層是執行時的控制迴路,中間是一份機器可檢查的描述把兩者扣在一起。