單元到預(yù)取、DQS與刷新機(jī)制)
很多硬件工程師第一次翻開(kāi)DDR顆粒手冊(cè)時(shí)多半會(huì)有一種“單詞都認(rèn)識(shí)、連起來(lái)不知道在說(shuō)什么”的挫敗感。CL、tRCD、tRP、tRAS、prefetch、DQS、refresh、training……這些詞每一個(gè)都能查到解釋但真正要回答“DDR到底是怎么把數(shù)據(jù)讀出來(lái)、寫進(jìn)去的”很多人其實(shí)講不清楚。我在做DDR控制器驗(yàn)證和系統(tǒng)調(diào)試的幾年里最深的感受是DDR的很多詭異現(xiàn)象比如帶寬上不去、跑一段時(shí)間出偶發(fā)錯(cuò)誤、溫度一高就崩潰根源往往不是某個(gè)參數(shù)配錯(cuò)了而是對(duì)工作原理的理解停留在表面。這篇系列第二篇我想把DDR的工作原理從頭到尾捋一遍不堆手冊(cè)只講那些真正影響你調(diào)板子、寫代碼、做仿真的核心機(jī)制。1. 存儲(chǔ)單元與尋址結(jié)構(gòu)一個(gè)bit到底被存在哪里1.1 從DRAM單元說(shuō)起電容和晶體管的小作坊DDR的本質(zhì)是DRAMDynamic Random Access Memory動(dòng)態(tài)隨機(jī)存取存儲(chǔ)器。叫“動(dòng)態(tài)”是因?yàn)樗鎯?chǔ)數(shù)據(jù)的方式很不穩(wěn)定——每個(gè)bit靠一個(gè)電容上的電荷來(lái)表示。電容里有電荷代表1沒(méi)電荷代表0旁邊配一個(gè)晶體管當(dāng)開(kāi)關(guān)控制這個(gè)電容是否連到外部電路上。這就是所謂的“1T1C”結(jié)構(gòu)一個(gè)晶體管加一個(gè)電容。你可以把它想象成一個(gè)極小的水桶。往桶里灌水就是寫1把水倒掉就是寫0晶體管相當(dāng)于水龍頭。問(wèn)題在于這個(gè)桶做得再小也會(huì)漏水。電容上的電荷會(huì)隨著時(shí)間逐漸流失所以DRAM必須不停地“補(bǔ)水”也就是刷新Refresh。這就是DDR系統(tǒng)里刷新機(jī)制存在的最底層原因后面我會(huì)專門展開(kāi)講。這個(gè)結(jié)構(gòu)還帶來(lái)一個(gè)更隱蔽的問(wèn)題讀操作本身是會(huì)破壞數(shù)據(jù)的。當(dāng)你把電容上的電荷引出來(lái)測(cè)量時(shí)電荷會(huì)被放掉相當(dāng)于桶里的水被舀出來(lái)看了一勺桶就空了。所以DRAM的讀是破壞性讀讀完必須立刻把原來(lái)的值寫回去Restore。這也是為什么行激活之后不能馬上換行必須等一段時(shí)間讓數(shù)據(jù)穩(wěn)定下來(lái)。1.2 Channel、Rank、Bank、Row、Column五級(jí)尋址到底在說(shuō)什么電容和晶體管構(gòu)成了基本存儲(chǔ)單元但幾億個(gè)單元怎么組織起來(lái)才是DDR尋址的核心。從系統(tǒng)往下看DDR的地址層級(jí)依次是Channel通道→ Rank列組→ Bank存儲(chǔ)體→ Row行→ Column列。理解這一串概念最直觀的方式是把內(nèi)存想象成一個(gè)大型圖書(shū)館。Channel是圖書(shū)館的入口你的內(nèi)存控制器有幾套獨(dú)立的總線接口就有幾個(gè)通道它們可以同時(shí)訪問(wèn)互不干擾。Rank相當(dāng)于圖書(shū)館里的不同樓層共用同一套數(shù)據(jù)總線但通過(guò)片選信號(hào)CS#決定當(dāng)前哪一層在響應(yīng)。Bank是每一層里的書(shū)架區(qū)通常一個(gè)Rank里有8個(gè)或16個(gè)Bank。Row是書(shū)架上某一層格子Column是這層格子里第幾本書(shū)的位置。這里有個(gè)讓很多人困惑的問(wèn)題為什么DDR的地址線那么少卻能訪問(wèn)到幾十GB的空間因?yàn)镈DR是分時(shí)復(fù)用地址線的。先發(fā)一個(gè)行地址Row Address再發(fā)一個(gè)列地址Column Address同樣的地址引腳用兩次配合Bank地址和Rank選擇信號(hào)就把尋址空間擴(kuò)展了幾十倍。這也是DDR手冊(cè)里地址引腳數(shù)量看起來(lái)“不成比例”的原因。1.3 行激活A(yù)CT和Sense Amplifier為什么要等tRCD搞清楚了尋址層級(jí)再看DDR的讀操作流程就順理成章了。假設(shè)要讀取某個(gè)地址的數(shù)據(jù)控制器會(huì)先發(fā)一條ACTActivate命令把某個(gè)Bank的某一行激活。激活是什么意思就是把這一整行所有存儲(chǔ)單元的電荷同時(shí)送到一個(gè)叫Sense Amplifier感知放大器的暫存區(qū)里。這個(gè)感知放大器非常關(guān)鍵。它本質(zhì)上是一組高靈敏度的差分放大器能感知每個(gè)電容上微小的電荷差異把它放大成標(biāo)準(zhǔn)的0/1邏輯電平。你可以把它理解成圖書(shū)館里的一個(gè)大型閱覽桌你要讀某一層的書(shū)管理員會(huì)先把整層格子里的書(shū)都搬到閱覽桌上然后你想看哪本直接從桌上拿就行。所以DDR實(shí)際讀到的數(shù)據(jù)是從Sense Amplifier里出來(lái)的不是直接從電容里讀的。這就解釋了為什么行激活之后不能立刻發(fā)讀命令——把整行數(shù)據(jù)從存儲(chǔ)陣列搬到感知放大器需要時(shí)間這個(gè)時(shí)間就是tRCDRAS to CAS Delay行激活到列讀取的延遲。tRCD的本質(zhì)不是某個(gè)憑空定義的參數(shù)而是存儲(chǔ)陣列電荷共享、電壓建立等物理過(guò)程所需的最小時(shí)間。理解了這一點(diǎn)你就不會(huì)再把tRCD當(dāng)成一個(gè)“需要死記硬背的數(shù)字”而是能理解為什么它和工藝、電壓、溫度都相關(guān)。2. 雙倍速率的本質(zhì)預(yù)取架構(gòu)與那條DQS信號(hào)2.1 為什么叫DDR上下邊沿都不浪費(fèi)DDR的全稱很簡(jiǎn)單Double Data Rate雙倍數(shù)據(jù)速率。和傳統(tǒng)SDRSingle Data Rate相比DDR在時(shí)鐘的上升沿和下降沿都傳輸數(shù)據(jù)。這就像一個(gè)人原本只在邁左腳時(shí)喊一聲現(xiàn)在左腳右腳都喊單位時(shí)間內(nèi)的信息量直接翻倍。但問(wèn)題來(lái)了如果僅僅是在時(shí)鐘上下邊沿都傳數(shù)據(jù)為什么DDR的內(nèi)存頻率看起來(lái)沒(méi)有翻倍那么多DDR4-3200的傳輸速率是3200MT/s每秒兆次傳輸?shù)芏嗳税阉`解為“工作頻率3200MHz”。實(shí)際上DDR4-3200的I/O時(shí)鐘頻率是1600MHz因?yàn)樯舷逻呇馗鱾饕淮蝹鬏斔俾史兜?200MT/s。而內(nèi)存核心的工作頻率更低只有400MHz。這中間隔著的“8倍關(guān)系”就是預(yù)取Prefetch架構(gòu)的手筆。2.2 Prefetch的演進(jìn)從2n到16n一次拿更多再慢慢往外送預(yù)取架構(gòu)是DDR能實(shí)現(xiàn)高傳輸速率的物理基礎(chǔ)。核心思路很簡(jiǎn)單內(nèi)存核心的工作頻率受制于存儲(chǔ)陣列的充放電速度很難做得太高但I(xiàn)/O接口可以做得快。既然核心跑不快那就讓核心一次多拿一些數(shù)據(jù)然后由I/O接口分多次快速送出去。具體來(lái)說(shuō)DDR從核心陣列中每次讀取的數(shù)據(jù)寬度是I/O接口寬度的2倍、4倍、8倍甚至16倍。這就是手冊(cè)里說(shuō)的2n Prefetch、4n Prefetch、8n Prefetch。以DDR3/DDR4的8n Prefetch為例核心時(shí)鐘是400MHz時(shí)一次內(nèi)部讀取會(huì)拿出8個(gè)bit對(duì)每個(gè)DQ引腳而言然后I/O接口在1600MHz下用4個(gè)時(shí)鐘周期、8個(gè)邊沿把這8個(gè)bit依次送出去。數(shù)據(jù)總量沒(méi)變但通過(guò)“內(nèi)部并轉(zhuǎn)串”實(shí)現(xiàn)了更高的接口帶寬。各代DDR的預(yù)取寬度演進(jìn)如下表DDR世代預(yù)取寬度核心時(shí)鐘頻率示例I/O時(shí)鐘頻率傳輸速率DDR12n100MHz200MHz400MT/sDDR24n100MHz400MHz800MT/sDDR38n100MHz800MHz1600MT/sDDR48n100MHz1600MHz3200MT/sDDR516n100MHz3200MHz6400MT/s看這張表會(huì)發(fā)現(xiàn)一個(gè)規(guī)律每一代DDR升級(jí)預(yù)取寬度翻倍I/O頻率也翻倍但核心頻率相對(duì)穩(wěn)定。這也是為什么DDR5可以把傳輸速率推到很高但核心存儲(chǔ)陣列的工作壓力并沒(méi)有指數(shù)級(jí)增加。理解了預(yù)取你去看DDR5那種“16n Prefetch 32個(gè)Bank組”的設(shè)計(jì)就不會(huì)覺(jué)得只是堆頻率了。2.3 DQS為什么數(shù)據(jù)要跟著自己的時(shí)鐘走DDR數(shù)據(jù)傳輸速率上去了隨之而來(lái)的問(wèn)題是接收端怎么準(zhǔn)確知道應(yīng)該在哪個(gè)時(shí)刻采樣數(shù)據(jù)如果還用全局時(shí)鐘數(shù)據(jù)從發(fā)送端到接收端的走線延時(shí)不同高速情況下根本對(duì)齊不上。DDR的解決方案是源同步時(shí)鐘Source Synchronous Clock。也就是說(shuō)發(fā)送數(shù)據(jù)的一方同時(shí)發(fā)送一條專門的選通信號(hào)DQSData Strobe數(shù)據(jù)怎么走DQS就怎么走讓DQS和數(shù)據(jù)一起傳輸?shù)浇邮斩?。接收端只需要用DQS的邊沿去采樣數(shù)據(jù)就能保證采到的是正確的bit。這就像你給朋友寄一箱水果不依賴郵局統(tǒng)一配送時(shí)間而是派專人押運(yùn)跟著箱子走保證貨物和押運(yùn)員同時(shí)到達(dá)。DQS在讀和寫時(shí)使用方式不同。讀操作時(shí)DRAM讓DQS和數(shù)據(jù)對(duì)齊邊沿對(duì)齊控制器用DQS的邊沿采樣數(shù)據(jù)寫操作時(shí)控制器需要把DQS的中心對(duì)齊到數(shù)據(jù)眼圖中間中心對(duì)齊保證數(shù)據(jù)穩(wěn)定。所以DDR控制器里必須做寫調(diào)平Write Leveling之類的訓(xùn)練目的之一就是校準(zhǔn)DQS和數(shù)據(jù)的相位關(guān)系。實(shí)際調(diào)試中如果示波器上看到DQS毛刺或者數(shù)據(jù)眼圖不張開(kāi)第一反應(yīng)就應(yīng)該是DQS的相位和走線補(bǔ)償出了問(wèn)題而不是懷疑芯片壞了。3. 讀操作逐拍拆解從ACT到數(shù)據(jù)返回要花多少時(shí)間3.1 一條讀命令的完整生命周期理解了基礎(chǔ)結(jié)構(gòu)之后我們來(lái)把一次讀操作放到時(shí)間軸上逐拍拆解。假設(shè)控制器想讀某個(gè)地址的數(shù)據(jù)完整流程是控制器發(fā)送ACT命令激活目標(biāo)Bank的指定行數(shù)據(jù)從存儲(chǔ)陣列搬運(yùn)到Sense Amplifier這個(gè)動(dòng)作需要tRCD時(shí)間。等tRCD滿足后控制器發(fā)READ命令同時(shí)給出列地址。DRAM根據(jù)列地址從Sense Amplifier中選出對(duì)應(yīng)的數(shù)據(jù)片段。READ命令發(fā)出后經(jīng)過(guò)CLCAS Latency列選通延遲數(shù)據(jù)才從DQ引腳上輸出。CL表示從READ命令到第一筆數(shù)據(jù)出現(xiàn)在總線上的間隔。數(shù)據(jù)開(kāi)始連續(xù)輸出按突發(fā)長(zhǎng)度Burst Length依次送出。DDR3/DDR4通常默認(rèn)BL8也就是一次突發(fā)輸出8個(gè)位置的數(shù)據(jù)。如果接下來(lái)還要訪問(wèn)其他行控制器必須先發(fā)PREPrecharge把Sense Amplifier里的數(shù)據(jù)寫回存儲(chǔ)陣列并準(zhǔn)備下一次行激活這個(gè)操作需要tRP。這里有一個(gè)很多人容易混淆的計(jì)算點(diǎn)讀延遲不只是CL而是從“行已經(jīng)激活”狀態(tài)下發(fā)出READ命令到數(shù)據(jù)返回的延遲。如果行壓根沒(méi)激活你還得先加上tRCD。如果再算上隊(duì)列里命令排隊(duì)的等待時(shí)間實(shí)際延遲會(huì)遠(yuǎn)大于手冊(cè)上的“CL”數(shù)值。以DDR4-3200為例假設(shè)一個(gè)典型時(shí)序配置CL22tRCD22tRP22tRAS52時(shí)鐘周期為0.625ns。行未命中Row Miss時(shí)從ACT到數(shù)據(jù)出現(xiàn)的理論時(shí)間大約是tRCDCL即(2222)個(gè)周期換算成時(shí)間是27.5ns。而如果行已經(jīng)激活Row Hit從READ到數(shù)據(jù)返回只需要CL即13.75ns。兩者相差整整一倍。這直接解釋了為什么DDR控制器的調(diào)度策略對(duì)系統(tǒng)性能影響如此巨大為什么“訪問(wèn)順序好不好”有時(shí)候比內(nèi)存頻率本身還重要。3.2 行命中、行未命中、行沖突三種情況的延遲差別順著上面的計(jì)算我們把讀訪問(wèn)分成三種情況這是做DDR性能調(diào)優(yōu)時(shí)最基本的分診框架場(chǎng)景含義需要等待的時(shí)間相對(duì)延遲Row Hit要訪問(wèn)的行已經(jīng)在Sense Amplifier中只有CL低Row Miss要訪問(wèn)的行未激活但所在Bank空閑tRCD CL中Row Conflict所在Bank當(dāng)前有其他行被激活必須先預(yù)充電換行tRAS tRP tRCD CL高Row Conflict是最耗時(shí)的場(chǎng)景。因?yàn)楫?dāng)前Bank里已經(jīng)有別的行被激活你想訪問(wèn)的新行不在感知放大器里控制器必須先發(fā)PRE命令把舊行寫回去再發(fā)ACT激活新行然后再READ。三條命令之間都有最小時(shí)間間隔累加起來(lái)就是肉眼可見(jiàn)的延遲。這也是為什么要引入多Bank的深層原因。多個(gè)Bank意味著多個(gè)獨(dú)立的Sense Amplifier區(qū)不同的行可以同時(shí)處于激活狀態(tài)控制器可以在Bank之間輪流訪問(wèn)用隱藏延遲的方式提高吞吐率。DDR4進(jìn)一步引入Bank Group把Bank分組每組有獨(dú)立的讀寫總線允許更細(xì)粒度的并行調(diào)度本質(zhì)上都是為了緩解單Bank串行等待的壓力。3.3 讀延遲對(duì)AXI系統(tǒng)設(shè)計(jì)的影響如果你在做SoC集成一定會(huì)遇到AXI總線讀寫DDR的場(chǎng)景。AXI協(xié)議給內(nèi)存控制器發(fā)出的讀請(qǐng)求經(jīng)過(guò)隊(duì)列、仲裁、Bank管理最終映射到DDR命令序列中間每一步都在消耗時(shí)間。AXI的outstanding能力允許未完成讀請(qǐng)求的數(shù)量設(shè)計(jì)得越大越能掩蓋行切換和刷新帶來(lái)的延遲但也越考驗(yàn)控制器的調(diào)度能力。我在實(shí)際項(xiàng)目中碰到過(guò)一個(gè)典型問(wèn)題AXI讀帶寬比預(yù)期低了近一半排查到最后發(fā)現(xiàn)是Bank策略配置太保守頻繁的Row Conflict導(dǎo)致大量時(shí)間花在預(yù)充電和重新激活上。后來(lái)把控制器配置成優(yōu)先保持行打開(kāi)Page Policy設(shè)為Open Page對(duì)順序訪問(wèn)場(chǎng)景效果立竿見(jiàn)影。但如果訪問(wèn)模式完全是隨機(jī)的Open Page反而會(huì)因?yàn)轭l繁“開(kāi)錯(cuò)行”而更慢。這就是為什么理解行命中和行沖突的原理比單純記住某個(gè)寄存器配置值重要得多。4. 寫路徑為什么比讀更麻煩數(shù)據(jù)掩碼、寫恢復(fù)與總線轉(zhuǎn)向4.1 寫命令與數(shù)據(jù)的關(guān)系不只是“反過(guò)來(lái)的讀”很多人以為寫操作就是讀操作的鏡像理解了讀就理解了寫。實(shí)際上寫路徑的心思更重。讀操作時(shí)數(shù)據(jù)是從DRAM肚子里吐出來(lái)的數(shù)據(jù)在什么時(shí)候出現(xiàn)DRAM說(shuō)了算控制器被動(dòng)接收就行。而寫操作不一樣數(shù)據(jù)和命令都來(lái)自控制器控制器必須保證“數(shù)據(jù)到了DRAM面前DRAM才把門打開(kāi)”。具體來(lái)說(shuō)DDR的寫命令發(fā)出后數(shù)據(jù)并不是立刻跟上而是要經(jīng)過(guò)一個(gè)寫延遲WLWrite Latency一般等于AL加上CWLCAS Write Latency。CWL是為了匹配寫數(shù)據(jù)選通和命令在DRAM內(nèi)部的傳播時(shí)間而定義的參數(shù)。也就是說(shuō)控制器發(fā)完WRITE命令后要等一段設(shè)計(jì)好的時(shí)間再把DQS和數(shù)據(jù)放到總線上確保DRAM內(nèi)部準(zhǔn)備好接收。這里面的相位對(duì)齊精度直接決定了寫操作能不能成功。如果用生活類比讀操作像是你打電話訂餐等外賣員送過(guò)來(lái)就行寫操作則是你自己開(kāi)車去取路上幾個(gè)紅綠燈都得算好不能早也不能晚。4.2 tWR和tWTR在講什么寫路徑上有兩個(gè)關(guān)鍵的時(shí)序參數(shù)很多初學(xué)者容易混淆。tWRWrite Recovery Time寫恢復(fù)時(shí)間表示最后一個(gè)數(shù)據(jù)寫入存儲(chǔ)單元后到允許對(duì)該Bank發(fā)預(yù)充電命令之間的最小間隔。為什么需要這個(gè)時(shí)間因?yàn)閿?shù)據(jù)從外部總線上被讀入DRAM后還要寫入到存儲(chǔ)單元的電容里這個(gè)物理過(guò)程需要時(shí)間。如果數(shù)據(jù)剛寫進(jìn)去就立刻預(yù)充電電荷還沒(méi)穩(wěn)定數(shù)據(jù)可能就丟了。DDR手冊(cè)里tWR一般給的是ns值換算成時(shí)鐘周期后的具體數(shù)值就是你在寄存器里看到的那串?dāng)?shù)。tWTRWrite to Read Delay寫后讀延遲表示寫命令結(jié)束后至少要等多久才能在同一Bank上發(fā)起讀命令。這個(gè)時(shí)間是為了處理總線方向的翻轉(zhuǎn)。DQS總線在寫操作時(shí)由控制器驅(qū)動(dòng)在讀操作時(shí)由DRAM驅(qū)動(dòng)雙方切換驅(qū)動(dòng)權(quán)需要時(shí)間不能讓兩邊同時(shí)搶一根線。這兩個(gè)參數(shù)在系統(tǒng)性能上的體現(xiàn)是連續(xù)寫后緊跟讀的混合訪問(wèn)場(chǎng)景效率往往會(huì)下降。如果你的控制器調(diào)度器不聰明沒(méi)能把同方向的訪問(wèn)盡量排在一起總線翻轉(zhuǎn)開(kāi)銷會(huì)成為實(shí)際帶寬里的一塊隱性損耗。4.3 DM引腳和DBI寫數(shù)據(jù)的校驗(yàn)與信號(hào)完整性再往細(xì)看DDR的DQ總線旁邊通常還有DM引腳Data Mask數(shù)據(jù)掩碼。你不要把它理解成“屏蔽寫”那么少見(jiàn)它其實(shí)是寫操作里非常重要的一部分。當(dāng)控制器只想寫64bit中的32bit時(shí)可以通過(guò)DM引腳把另外32bit“屏蔽”掉讓DRAM忽略對(duì)應(yīng)位置的數(shù)據(jù)。這避免了讀改寫Read-Modify-Write操作效率提升非常明顯。從DDR4開(kāi)始引入了DBIData Bus Inversion數(shù)據(jù)總線翻轉(zhuǎn)這是一個(gè)智能編碼機(jī)制當(dāng)一字節(jié)數(shù)據(jù)中0的個(gè)數(shù)比1多時(shí)發(fā)送端會(huì)把整字節(jié)反轉(zhuǎn)并置DBI信號(hào)減少總線上低電平的比例。因?yàn)镈RAM的I/O在輸出0時(shí)消耗的功耗顯著高于輸出1這是由POD接口特性決定的DBI能有效降低功耗和信號(hào)壓擺導(dǎo)致的噪聲。DM和DBI在pin腳上有時(shí)會(huì)共用同一個(gè)物理引腳具體功能由模式寄存器配置。工程上最容易踩的坑是某些主控默認(rèn)把DM功能開(kāi)著寫數(shù)據(jù)時(shí)序檢查時(shí)發(fā)現(xiàn)EMI超標(biāo)以為是PCB問(wèn)題折騰半天才發(fā)現(xiàn)是DM沒(méi)配對(duì)導(dǎo)致數(shù)據(jù)總線翻轉(zhuǎn)頻繁。所以做DDR仿真時(shí)一定要在信號(hào)完整性工具里把DM/DBI的翻轉(zhuǎn)模型和實(shí)際配置對(duì)上否則仿真結(jié)果和實(shí)測(cè)會(huì)差很遠(yuǎn)。4.4 讀寫總線轉(zhuǎn)向Turnaround的效率陷阱說(shuō)到總線翻轉(zhuǎn)不得不提DDR性能評(píng)測(cè)里一個(gè)經(jīng)典的坑混合讀寫比例下的帶寬測(cè)算。假設(shè)某系統(tǒng)宣稱DDR4理論帶寬25.6GB/s跑純讀或純寫可以接近這個(gè)數(shù)但一旦變成讀50%、寫50%的隨機(jī)混合實(shí)測(cè)帶寬可能掉到14GB/s以下這時(shí)很多人會(huì)懷疑是控制器效率低但根因其實(shí)在DDR總線的物理工作機(jī)制。讀寫切換時(shí)DQS總線的驅(qū)動(dòng)方向要從控制器切到DRAM讀方向或從DRAM切回控制器寫方向每一次切換都有額外的總線空閑周期tWTR、tRTW等。這些周期被計(jì)入延遲但不產(chǎn)生任何有效數(shù)據(jù)傳輸??刂破饕档颓袚Q損耗只有兩條路一是盡量把相同方向的訪問(wèn)聚成更長(zhǎng)的連續(xù)塊再派發(fā)二是依靠多Bank并行讓一個(gè)Bank在切換總線方向時(shí)另一個(gè)Bank還能繼續(xù)干活。理解了這一點(diǎn)你在調(diào)高性能計(jì)算場(chǎng)景時(shí)就會(huì)主動(dòng)去看訪問(wèn)流量的“局部性”而不是一味把DDR頻率往上拉。5. 刷新、預(yù)充電與Bank管理看不見(jiàn)的“家務(wù)活”決定系統(tǒng)性能5.1 電容漏電和刷新周期為什么7.8us就要停下來(lái)補(bǔ)一次回到1.1節(jié)講的物理基礎(chǔ)。DRAM電容會(huì)漏電如果不定期補(bǔ)充電荷數(shù)據(jù)就會(huì)消失。JEDEC標(biāo)準(zhǔn)規(guī)定在正常工作溫度≤85℃下整個(gè)內(nèi)存陣列每一行必須在64ms內(nèi)被刷新至少一次。聽(tīng)起來(lái)64ms很長(zhǎng)但內(nèi)存里行數(shù)動(dòng)輒上萬(wàn)分?jǐn)傁聛?lái)平均每隔7.8us就要刷新一行。這就是tREFIRefresh Interval的由來(lái)。假如某次刷新正趕上你的實(shí)時(shí)計(jì)算任務(wù)讀取關(guān)鍵數(shù)據(jù)這7.8us里內(nèi)存是無(wú)法響應(yīng)的對(duì)某些微控制器系統(tǒng)而言這是不可接受的延遲尖峰。JEDEC的解決辦法是允許控制器把刷新操作“聚集”執(zhí)行也就是等攢夠一批要刷新的行一次刷完中間空出較長(zhǎng)的不刷新時(shí)間窗口。代價(jià)是聚集刷新期間內(nèi)存完全不可訪問(wèn)的時(shí)間會(huì)更長(zhǎng)系統(tǒng)的最大延遲反而變大了。這里有一個(gè)非常實(shí)用的工程經(jīng)驗(yàn)如果你在做一個(gè)對(duì)中斷延遲敏感的實(shí)時(shí)系統(tǒng)不要用“一次性刷完所有行”的靜態(tài)刷新策略而應(yīng)該用分布刷新Distributed Refresh把刷新操作均勻分布到時(shí)間軸上讓每個(gè)刷新引起的暫停窗口盡量短。反之如果你的系統(tǒng)更看重平均吞吐聚集刷新反而能減少刷新命令間的調(diào)度開(kāi)銷。5.2 tRFC、2x Refresh與自刷新溫度是刷新策略的隱形指針tRFCRefresh Cycle Time表示執(zhí)行一次刷新操作本身需要多長(zhǎng)時(shí)間也就是DRAM從收到刷新命令到能重新接受其他命令之間的間隔。DDR4顆粒的tRFC從幾百ns到近1us不等取決于芯片密度。別小看這個(gè)參數(shù)它直接決定了刷新操作對(duì)帶寬的占用比例。以DDR4-3200、64ms刷新2048行、tRFC350ns為例粗略算下來(lái)刷新本身大約占用內(nèi)存時(shí)間的1%~3%。這個(gè)比率看似不高但在高密度顆粒上會(huì)明顯放大也是低壓工藝下漏電加劇時(shí)的隱患。溫度對(duì)刷新的影響比大多數(shù)人想象得更大。電容漏電速率隨溫度升高呈指數(shù)級(jí)增長(zhǎng)所以JEDEC規(guī)定當(dāng)內(nèi)存溫度超過(guò)85℃時(shí)必須把刷新周期減半也就是2x Refresh模式意味著tREFI從7.8us縮短到3.9us。很多工業(yè)級(jí)系統(tǒng)在夏天高溫老化時(shí)出現(xiàn)偶發(fā)數(shù)據(jù)錯(cuò)誤排查下來(lái)往往不是芯片壞了而是刷新策略沒(méi)有跟隨溫度切換存儲(chǔ)單元電荷已經(jīng)低于可靠閾值。自刷新Self Refresh則是另一個(gè)層面的機(jī)制。在系統(tǒng)休眠時(shí)DDR控制器會(huì)停止所有外部訪問(wèn)讓內(nèi)存進(jìn)入自刷新模式。在這種模式下DRAM芯片內(nèi)部的刷新電路自己按固定節(jié)奏刷新所有行不需要外部控制器干預(yù)。此時(shí)CK時(shí)鐘可以停掉DQS和三態(tài)引腳全部進(jìn)入低功耗狀態(tài)整個(gè)內(nèi)存只剩下少量電路在維持電荷。這就是為什么筆記本合蓋休眠一晚上數(shù)據(jù)還在。理解了自刷新你在做低功耗設(shè)備調(diào)試時(shí)就知道即便CPU停了DRAM的功耗也不是零而是體現(xiàn)在自刷新電流里。5.3 Bank交錯(cuò)和打開(kāi)頁(yè)策略調(diào)度器的潛規(guī)則前面說(shuō)Row Hit和Row Conflict的延遲差距超過(guò)一倍那控制器如何盡量多命中除了等待應(yīng)用程序自然提供的順序訪問(wèn)模式控制器本身還有一項(xiàng)重要手段Bank交錯(cuò)Bank Interleaving。想象你在洗衣房洗衣服如果只有一臺(tái)洗衣機(jī)每次都等洗完再放進(jìn)烘干機(jī)一次只能走一條流水線。如果有多臺(tái)洗衣機(jī)你可以分批把衣服放進(jìn)不同洗衣機(jī)一臺(tái)洗的時(shí)候另一臺(tái)在甩干整體吞吐就上去了。DDR的多個(gè)Bank就像多臺(tái)獨(dú)立運(yùn)轉(zhuǎn)的洗衣機(jī)允許其中一個(gè)Bank在做預(yù)充電或刷新時(shí)另一個(gè)Bank還能執(zhí)行讀寫命令。DDR4引入Bank Group設(shè)計(jì)本質(zhì)上是把這套并行策略又推進(jìn)了一步。每個(gè)Bank Group內(nèi)部有獨(dú)立的Sense Amplifier和局部數(shù)據(jù)線可以同時(shí)執(zhí)行不同命令的粒度更細(xì)減小了Bank之間爭(zhēng)搶數(shù)據(jù)總線的沖突。這在新近的DDR5上體現(xiàn)得更加明顯Bank數(shù)量從16個(gè)增加到32個(gè)配合16n預(yù)取帶寬和并行度都上了一個(gè)臺(tái)階。對(duì)軟件工程師而言理解Bank交錯(cuò)最直接的價(jià)值在于如果你寫代碼時(shí)能意識(shí)到“訪問(wèn)地址里哪些bit決定了Bank、哪些bit決定了Row”那你可以用簡(jiǎn)單的地址填充Padding技巧讓熱數(shù)據(jù)分布在不同的Bank里減少?zèng)_突性能提升可能比換一顆更高速率的DDR芯片還明顯。我在優(yōu)化一個(gè)圖像處理管線時(shí)遇到過(guò)類似案例只是把兩個(gè)大數(shù)組的起始地址錯(cuò)開(kāi)半個(gè)Bank大小幀率就提升了好幾個(gè)百分點(diǎn)代價(jià)只是幾行代碼和一點(diǎn)點(diǎn)內(nèi)存碎片。6. 從pin腳到仿真弄懂原理后才看得懂的工程細(xì)節(jié)6.1 關(guān)鍵pin腳速查不要只認(rèn)識(shí)DQ和CLKDDR顆粒的pin腳看似很多但核心信號(hào)類別并不多。列一張速查表把每個(gè)信號(hào)到底是干什么的弄清楚你再看原理圖和數(shù)據(jù)手冊(cè)就不會(huì)迷茫了。信號(hào)類型引腳名方向作用差分時(shí)鐘CK_t / CK_c控制器→DRAM提供命令/地址采樣基準(zhǔn)時(shí)鐘使能CKE控制器→DRAM控制DRAM內(nèi)部時(shí)鐘是否運(yùn)行關(guān)掉可進(jìn)入低功耗模式片選CS#控制器→DRAM選中當(dāng)前正在通信的Rank命令/地址ACT_n, A[17:0], BA, BG控制器→DRAM攜帶ACT/READ/WRITE/PRE等命令及行列地址數(shù)據(jù)DQ[63:0]雙向讀寫數(shù)據(jù)總線數(shù)據(jù)選通DQS_t / DQS_c雙向源同步時(shí)鐘用于采樣DQ數(shù)據(jù)掩碼/反轉(zhuǎn)DM_n / DBI_n雙向?qū)懷诖a、數(shù)據(jù)總線翻轉(zhuǎn)控制片內(nèi)終結(jié)ODT控制器→DRAM動(dòng)態(tài)控制DRAM內(nèi)部終端電阻接入改善信號(hào)反射阻抗校準(zhǔn)ZQ外部電阻→DRAM通過(guò)外部240Ω精密電阻校準(zhǔn)輸出驅(qū)動(dòng)強(qiáng)度參考電壓VREFCA, VREFDQ外部輸入命令/地址和數(shù)據(jù)總線的參考電平這里特別說(shuō)下ODT。高速信號(hào)在PCB走線末端會(huì)產(chǎn)生反射如果不做端接信號(hào)質(zhì)量會(huì)嚴(yán)重劣化。DDR系統(tǒng)里這個(gè)“終端電阻”可以設(shè)計(jì)在DRAM芯片內(nèi)部通過(guò)ODT信號(hào)動(dòng)態(tài)開(kāi)啟或關(guān)閉。麻煩在于讀和寫時(shí)正確的ODT配置完全不同讀操作時(shí)DRAM是發(fā)送端控制器是接收端終端電阻應(yīng)該加在控制器一側(cè)寫操作時(shí)反過(guò)來(lái)。所以DDR控制器會(huì)根據(jù)當(dāng)前總線的傳輸方向動(dòng)態(tài)調(diào)整ODT的使能位置。做SI仿真時(shí)如果ODT模型配錯(cuò)眼圖結(jié)果會(huì)完全失真這是仿真和實(shí)測(cè)對(duì)不上的高頻原因。6.2 IBIS模型與Sigrity仿真初學(xué)者最常踩的三個(gè)坑DDR高速信號(hào)設(shè)計(jì)離不開(kāi)仿真而仿真輸入的基礎(chǔ)就是IBIS模型。IBISI/O Buffer Information Specification是一種行為級(jí)建模語(yǔ)言用V-I曲線和V-T曲線描述芯片引腳在特定條件下的驅(qū)動(dòng)能力和轉(zhuǎn)換速率。在Sigrity等工具里做DDR仿真時(shí)有幾點(diǎn)容易踩坑。第一IBIS模型不是萬(wàn)能的。它不包含芯片內(nèi)部電源網(wǎng)絡(luò)、封裝寄生、ESD結(jié)構(gòu)等高頻效應(yīng)所以仿真的絕對(duì)電壓值并不可靠更多是用來(lái)比較不同拓?fù)?、不同ODT配置下的相對(duì)趨勢(shì)。不要拿仿真結(jié)果里的某個(gè)過(guò)沖尖峰去和示波器實(shí)測(cè)做數(shù)值對(duì)比那是自找煩惱。第二IBIS模型里通常有幾個(gè)cornerSlow/Typical/Fast對(duì)應(yīng)工藝角的不同驅(qū)動(dòng)強(qiáng)度。做DDR仿真時(shí)至少要跑一次全部corner組合只跑Typical的仿真報(bào)告在評(píng)審會(huì)議上基本沒(méi)有說(shuō)服力因?yàn)榱慨a(chǎn)時(shí)最怕的就是SS慢工藝角下時(shí)序裕量不夠。第三仿真結(jié)果好不好選擇關(guān)鍵的驗(yàn)證點(diǎn)比建模精度影響更大。DDR信號(hào)質(zhì)量看的核心就是Setup/Hold裕量、眼圖高度/寬度、串?dāng)_導(dǎo)致的抖動(dòng)這幾個(gè)指標(biāo)。如果PCB拓?fù)浔旧碛袊?yán)重的stub過(guò)長(zhǎng)或參考平面不連續(xù)問(wèn)題仿真模型再準(zhǔn)也救不回來(lái)。我看到過(guò)不少項(xiàng)目把大量時(shí)間花在調(diào)仿真參數(shù)上最后發(fā)現(xiàn)根因是DDR走線跨了分割的地平面——這屬于舍本逐末。6.3 DDR和PSRAM同為隨機(jī)存取脾氣完全不同順著搜索引擎里經(jīng)常出現(xiàn)的“DRAM和DDR PSRAM的區(qū)別”這個(gè)話題聊一句。PSRAMPseudo SRAM偽靜態(tài)隨機(jī)存取存儲(chǔ)器的名字很有迷惑性。它的存儲(chǔ)單元本質(zhì)上是DRAM也就是電容存儲(chǔ)需要刷新但芯片內(nèi)部集成了自動(dòng)刷新電路對(duì)外呈現(xiàn)的接口行為完全像SRAM不需要外部控制器發(fā)送刷新命令也不存在tREFI這類定時(shí)要求。DDR則完全不同刷新是外部控制器的職責(zé)。如果你的系統(tǒng)在選型時(shí)把PSRAM當(dāng)成普通SRAM來(lái)用那確實(shí)省心但如果把DDR當(dāng)成“快一點(diǎn)的PSRAM”以為接上電源和地址線就能跑你會(huì)發(fā)現(xiàn)系統(tǒng)必須經(jīng)過(guò)一整套復(fù)雜的初始化和訓(xùn)練流程寄存器沒(méi)配好連讀寫都進(jìn)行不了。另一個(gè)隱蔽的差異在隨機(jī)訪問(wèn)延遲上PSRAM內(nèi)部因?yàn)樽詭⑿逻壿嫼洼^寬的內(nèi)部總線隨機(jī)讀延遲往往比DDR的Row Miss場(chǎng)景更穩(wěn)定沒(méi)有那種“碰運(yùn)氣”的Bank命中波動(dòng)。6.4 訓(xùn)練失敗原理清楚才能定位的經(jīng)典故障DDR系統(tǒng)上電后都有一個(gè)訓(xùn)練Training過(guò)程包括ZQ校準(zhǔn)、寫調(diào)平、讀寫DQS掃描、電壓窗口搜索等。訓(xùn)練的目的是為每根信號(hào)找到可靠的采樣窗口補(bǔ)償PCB走線長(zhǎng)度差異和芯片工藝偏差。這個(gè)過(guò)程對(duì)設(shè)計(jì)余量極其敏感因?yàn)橛?xùn)練本質(zhì)上是在“找邊界”。調(diào)試中最常見(jiàn)的問(wèn)題是100塊板子里有幾塊卡在訓(xùn)練階段或者訓(xùn)練通過(guò)但高溫環(huán)境下偶發(fā)錯(cuò)誤。如果不懂原理很容易懷疑是顆粒品質(zhì)或焊縫問(wèn)題換芯片換了一輪還是復(fù)現(xiàn)。實(shí)際排查時(shí)第一優(yōu)先檢查的是CLK和DQS之間的走線長(zhǎng)度差以及各DQ信號(hào)之間的等長(zhǎng)控制。訓(xùn)練失敗往往就是某根走線比其他線長(zhǎng)了一截導(dǎo)致訓(xùn)練掃描窗口被壓到一個(gè)非常窄的范圍內(nèi)。用示波器做單端測(cè)量看不出問(wèn)題要用真差分探頭看DQS和CK的相位關(guān)系配合控制器的訓(xùn)練日志里報(bào)出的fail bit位置才能快速圈定問(wèn)題信號(hào)。另一個(gè)常被忽略的點(diǎn)是電源紋波。DDR訓(xùn)練時(shí)VDD/VDDQ上如果存在特定頻率的大紋波會(huì)影響電壓窗口掃描的結(jié)果表現(xiàn)為“同一批板子在不同的老化狀態(tài)下訓(xùn)練結(jié)果不一致”。處理辦法是先把電源紋波壓到規(guī)格書(shū)要求的范圍內(nèi)再談其他信號(hào)質(zhì)量問(wèn)題。永遠(yuǎn)記住訓(xùn)練是通過(guò)時(shí)序窗口變窄來(lái)懲罰所有設(shè)計(jì)缺陷的它是個(gè)放大器不是故障根源。寫到這兒DDR的工作原理從存儲(chǔ)單元一路聊到了訓(xùn)練和仿真。回頭看看從1T1C的電容水桶到預(yù)取和DQS的并轉(zhuǎn)串機(jī)制再到行命中和刷新的調(diào)度博弈這條邏輯線其實(shí)是自洽的所有復(fù)雜的時(shí)序參數(shù)、訓(xùn)練流程和控制器設(shè)計(jì)都是在給一個(gè)物理缺陷——電容漏電和破壞性讀——打補(bǔ)丁。我自己最大的體會(huì)是遇到DDR相關(guān)的疑難問(wèn)題時(shí)不要急著翻手冊(cè)調(diào)寄存器先把“此刻DRAM內(nèi)部正在執(zhí)行哪個(gè)物理動(dòng)作”想明白答案往往自己就浮現(xiàn)了。這套思路在后續(xù)寫DDR控制器、做DDR系統(tǒng)硬件調(diào)試時(shí)都值得反復(fù)回看。