DRAM 的運作 (Computer Architecture 側)
本文算是 advanced computer architecture (ACA) 的筆記,會有這篇文章的原因是 ACA 時明明老師上課講得頗清楚,我應該也是有聽懂。但是常常一陣子之後要用發現完全想不起來,所以又找個時間重新閱讀並記錄下來,方便下次又忘記的時候使用。
DRAM 基本運作方式
要了解 DRAM 就要從基本的 DRAM array 架構講起,這牽涉到一些大學電子學的內容。但是如果我把這些內容全部放進來,文章會變得非常長,所以本文只提及「理解這篇需要的部份」 ,絕對不是因為作者的電子學&積電早就忘光了所以在找藉口,如果讀者真的這麼想看電子學的話就去看 wiki 吧。
DRAM array 本質上就是把 MOS (簡化表示為圖中的小圈圈)排成長方形的 2D array,而每個 MOS 都有能力存 1 bit:
在一個 DRAM array 中 ,一次讀寫的單位是 1 bit,而想要在這個 2D array 正確讀出 1 bit 並不像在 C++ 寫個 a[0][0]
這麼簡單,而是必須透過以下這五個指令,分為幾個步驟完成:
- Activate/Refresh
- Read/Write
- Precharge
接下來的內容中,將會分別解釋這五個指令。
Activate/Precharge
DRAM 的讀寫之所以複雜,需要五種指令才能完成,主要的原因是因為讀寫 DRAM 使用到的額外電路:
在第一張圖中顯示了,要讀寫資料的時候我們會先給 row address,接著透過左方的 DEMUX,只讓一條 row 的資料根直的電線導通。實際上效果就是把該 row 跟下方的 row buffer 同步,而這個動作就是 Activate。
Precharge 是把 row buffer 跟 DRAM array 解除同步,就是 Activate 的相反。
Read/Write
請見第二張圖,當一個 row 跟 row buffer 同步時,接著就能透過 Read/Write 指定想讀寫的 column。 如果是 Read 指令,controller 就會把你要 bit 從 row buffer 傳送給你。而 Write 指令也類似,controller 會把你寫進 row buffer 的 bit 同步回 DRAM array 裡面。
例如我們想讀取前例中右下的 bit 1 就要 Activate(3) → Read(3),如果之後馬上想讀取左下的 bit 1,不需要再 Activate(3) 一次,只要再 Read(0) 就好了。然而如果試想讀取右上的 bit 1,就需要 Precharge → Activate(0) → Read(3) 三步驟。
另外,以上這些指令都不是一個 cycle 可以完成的,像是一般買 DRAM 時很常看 DRAM 的時序,其中 CL 值,也就是給定 column address 要 Read 之後,到資料真的從出來需要的 cycle 數量。
Refresh
Refresh 指令對於資料的讀寫並沒有功能,然而但因為 DRAM 的物理特性,所以一陣子沒 Activate 的 row 得 Refresh 才不會讓 DRAM 資料消失。
電腦 (CPU) 看到的 DRAM
一般對 CPU 來說電腦裡的 DRAM 看起來可分成這幾個階級:
- Channel
- Rank
- Bank
一個 DRAM 系統有數個 channel,一個 channel 有數個 rank,一個 rank 有數個 bank。不同的 channel 的頻寬是獨立的,同 channel 下的不同的 rank 可以平行操作,但是共享頻寬。同 rank 下的不同的 bank 則無法平行操作。
(註:因為 channel 享有獨立的頻寬,這代表這些資料信號必須在封裝、PCB 版上都有獨立的信號線,這對於整體成本非常高,因此 2020 年家用級 CPU 普遍支援 2-channel,唯有 server 級才會出現 4-channel, 8-channel。)
最底層的 bank 就如前面介紹,不同的地方是每個 cell 有很多 bits(一般電腦裡是 64 bits):
這樣設計是因為 DRAM 跟 CPU 的速度相比很慢,現代的 CPU 會用 cache 來避免每次都要從 DRAM 拿資料。當 cache 沒有需要的資料 (cache miss) 時,CPU 才會向 DRAM 要資料。而因為 data locality 的性質,相鄰的資料很容易被同時用到,所以每次抓資料進來 cache 時通常時候會一次抓一大把連續的資料近來,在大部分的 64 bit 系統中,這個大小是 64 bytes。
然而,根據上面的說明,一個 bank 只有 64 bits 的 IO,但是我們一次要抓的是 64 bytes,所以實際上會把連續 8 columns 的資料分成 8 cycles 連續吐出來,這個行為我們稱為 DRAM burst。
舉例而言
我們以一個 4 GB 的系統為例,他的 address 是 32 bits。
- 系統下面有 2 channel
- 1 channel 有 2 rank
- 1 rank 有 4 rank
- 1 bank 由 $2^{15}$ rows 跟 $2^{10}$ columns,每一個位置有 64 bits (8 bytes),因此是 $2^{15}\times2^{10}\times8\times2^{-20} = 256$ MB。
假設 CPU 向 DRAM 要的 byte address 是 1011_1101_0111_1010_1101_0000_1100
。首先因第 1 個 bit 是 1
,所以 DRAM controller 會找 channel 1,而第 2 個 bit 是 0
,所以會再去找 channel 1 下的 rank 0,接下來的 2 bits (11
) 指定了 bank 3。
接著的 15 bits 跟 10 bits 指定了要 Activate 哪個 row 跟要讀寫哪個 column。 而前面也提到,因為要 DRAM 的讀寫都要花上 8 cycles 的 burst,所以 10 bits 之中的最後 3 bits 是 counter。
總而言之就是:
(1b channel)+(1b rank)+(2b rank)+(15b row)+(10b column)+(3b unused) = 32b
column 的後 3 bits 是 counter,所以也算 unused。總共有 6 unused bits,這是理所當然的,因為一個 cache 的大小就是 DRAM burst 的大小,是 $2^6=64$ bytes。
最後,可以注意 DRAM Activate 一次之後,就算有 burst,每個讀寫只使用了 row buffer 的 $\frac{8}{1024} = 0.8$%,沒使用到的讀寫會花費掉大量的無用電力,而這也是 DRAM 一個很大的問題。
系列文連結
-
DRAM 的運作 (Computer Architecture 側)
-
DRAM 的運作 (Computer Architecture 側)(二)
- DRAM 的運作 (Computer Architecture 側)
- DRAM 的運作 (Computer Architecture 側)(二)