Intel Thermal Monitor
processor 來實作 Thermal Monitor 和 Thermal Monitor 2,會有一個 thermal sensor 來觸發這兩個 monitor,觸發哪一個在製造處理器時就設定好了,透過 interrupt LVT entry (在 local APIC 裡面)可以了解是否有觸發這個 sensor。
在 Intel Thermal Monitor 中,從 Pentium M 的處理器開始支援 Bi-directional PROCHOT#,他透過外部的 agent 驅動,並且要啟動 TCC( Thermal Control Circuitry) 或是 Enhanced TCC。
另外還有所謂的 Demand Mode,當我們 enable 處理器的 clock modulation,TCC 能透過寫入 IA32_CLOCK_MODULATION Model Specific Register 打開,這個 Register 每一次執行都會被複製,並且 hardware 會選出效能最好的解析。
註:duty cycle 工作週期/負載週期
2008年11月20日 星期四
2008年11月17日 星期一
CPU 的 cache 和 latency
http://www.csie.ntu.edu.tw/~r89004/hive/cache/page_1.html
這篇文章主要是探討現在的 CPU 的 cache 和記憶體系統之間的關係。
CPU 速度的進展,一直比記憶體的速度進展要來得快。在 IBM PC XT 的時代,CPU 和記憶體的速度是差不多的。不過,後來 CPU 的速度就愈來愈快。再加上 DRAM 需要 refresh 才能保存資料的特性,DRAM 很快就跟不上 CPU 的速度了。現在的 CPU 都利用了 pipeline 的方式,可以每個 cycle 都 issue 一個(甚至多個)指令,再加上現在的 CPU 時脈也比記憶體的時脈高,記憶體的速度可說是遠遠落在 CPU 之後了。
為了避免記憶體成為 CPU 速度的瓶頸,現在的 CPU 都有 cache 的設計,甚至還有多層的 cache。Cache 的原理,主要是利用到大部分的程式,在處理資料時,都有一定程度的區域性。所以,我們可以用一小塊快速的記憶體,來暫存目前需要的資料。
例如,幾乎所有的程式,大部分的執行時間是花在一些迴圈中。這些迴圈通常都不大,可能只佔整個程式空間的百分之一。如果一個程式經常要執行這段程式數千、甚至數萬次,那就可以把這一小段程式放在 cache 中,CPU 就不需要每次都到很慢的主記憶體中讀取這段程式了。很多一般用途的程式,在存取資料時,也有類似的特性。因此,cache 的幫助非常大。如果沒有 cache 的話,我們就不需要這麼快的 CPU 了,因為系統的速度會卡在記憶體的速度上面。
現在的 CPU 往往也有多層的 cache。例如,Intel 的 Pentium III 500Mhz CPU,有 32KB 的 L1 cache,和 512KB 的 L2 cache。其中,L1 cache 內建在 CPU 內部,速度非常快,而且它是 Harvard 式,即指令用的空間和資料用的空間是分開的。Pentium III 500Mhz CPU 的 L1 cache 是分成 16KB 的 I-cache 和 16KB 的 D-cache。而 L2 cache 則是在 CPU 外面,以 250Mhz 的速度運作。另外,它和 CPU 之間的 bus 也只有 64 bits 寬。L2 cache 通常就不會區分指令和資料的空間,也就是 unified cache。
Cache 對速度有什麼影響呢?這可以由 latency 來表示。CPU 在從記憶體中讀取資料(或程式)時,會需要等待一段時間,這段時間就是 latency,通常用 cycle 數表示。例如,一般來說,如果資料已經在 L1 cache 中,則 CPU 在讀取資料時(這種情形稱為 L1 cache hit),CPU 是不需要多等的。但是,如果資料不在 L1 cache 中(這種情形稱為 L1 cache miss),則 CPU 就得到 L2 cache 去讀取資料了。這種情形下,CPU 就需要等待一段時間。如果需要的資料也不在 L2 cache 中,也就是 L2 cache miss,那麼 CPU 就得到主記憶體中讀取資料了(假設沒有 L3 cache)。這時候,CPU 就得等待更長的時間。
另外,cache 存取資料時,通常是分成很多小單位,稱為 cache line。例如,Pentium III 的 cache line 長度是 32 bytes。也就是說,如果 CPU 要讀取記憶體位址 0x00123456 的一個 32 bits word(即 4 bytes),且 cache 中沒有這個資料,則 cache 會將 0x00123440 ~ 0x0012345F 之間的 32 bytes 資料(即一整個 cache line 長度)都讀入 cache 中。所以,當 CPU 讀取連續的記憶體位址時,資料都已經讀到 cache 中了。
我寫了一個小程式,用來測試 cache 的行為。這個程式會連續讀取一塊記憶體位址,並量測平均讀取時間。這個 程式的執行結果如下:
測試平台:
Pentium III 500Mhz, PC100 SDRAM, 440BX chipset
Celeron 466Mhz, PC100 SDRAM, VIA Apollo Pro 133 chipset
程式的執行檔和原始碼可在這裡下載。
由上面的結果可以看出,當測試的區塊大小在 16KB 以下時,平均的 latency 都在 1 ~ 3 cycles 左右。這顯示出 16KB 的 L1 D-cache 的效果。在測試區塊為 1KB 和 2KB 時,因為額外的 overhead 較高,所以平均的 latency 變得較高,但是在 4KB ~ 16KB 的測試中,latency 則相當穩定。在這個範圍中,由於 Pentium III 和 Celeron 有相同的 L1 cache,所以測試結果是幾乎完全相同的。
在區塊超過 16KB 之後,就沒辦法放入 L1 D-cache 中了。但是它還是可以放在 L2 cache 中。所以,在 Pentium III 的情形下,從 32KB ~ 512KB,latency 都在 10 cycles 左右。這顯示出當 L1 cache miss 而 L2 cache hit 時,所需要的 latency。而 Celeron 的 L2 cache 只有 128KB,但是 Celeron 的 L2 cache 的 latency 則明顯的比 Pentium III 為低。這是因為 Celeron 的 L2 cache 是 on-die,以和 CPU 核心相同的速度運作。而 Pentium III 的 L2 cache 則是分開的,且以 CPU 核心速度的一半運作。
在區塊超過 512KB 之後,L2 cache 就不夠大了(Pentium III 500Mhz 只有 512KB 的 L2 cache)。這時,顯示出來的就是 L1 cache miss 且 L2 cache miss 時,所需要的 latency。在 1024KB 或更大的區塊中,Pentium III 的 latency 都大約是 28 cycles 左右,而 Celeron 的 latency 則超過 70 cycles。這是 CPU 讀取主記憶體時,平均的 latency。而 Celeron 的 latency 較高,應該是因為其外頻較低,而倍頻數較高的緣故(Pentium III 500Mhz 為 5 倍頻,而 Celeron 466 為 7 倍頻)。另外,晶片組的差異也可能是原因之一。
Cache 的效果十分明顯。不過,有時候 cache 是派不上用場的。例如,當資料完全沒有區域性,或是資料量太大的時候,都會讓 cache 的效果降低。例如,在進行 MPEG 壓縮時,存取的資料量很大,而且資料的重複利用率很低,所以 cache 的幫助就不大。另外,像是 3D 遊戲中,如果每個 frame 的三角面個數太多,也會超過 cache 能夠處理的範圍。
現在的電腦愈來愈朝向「多媒體應用」,需要處理的資料量也愈來愈大,因此,要如何善用 cache 就成了一個重要的問題。一個非常重要的方法,就是把讀取主記憶體的 latency 和執行運算的時間重疊,就可以把 latency「藏」起來。通常這會需要 prefetch 的功能,也就是 AMD 在 K6-2 及之後的 CPU,和 Intel 在 Pentium III 之後的 CPU 加入的新功能。在下一篇文章中,我們會討論 prefetch 的原理和用途。
CPU 的 cache 和 latency [Part 2]
在上一篇文章中,已經簡單討論過 CPU 的 cache 和其對 latency 的影響。在這篇文章中,我們就以一個較為實際的例子,並說明 prefetch 的原理和用途。
這裡要用的「實際例子」,其實還是很理想化的。為了和 3D 繪圖扯上一點關係,這裡就用「4x4 的矩陣和 4 維向量相乘」做為例子。不過,一般在 3D 繪圖中,都是用 single precision 的浮點數(每個數需要 32 bits),而這裡為了讓記憶體的因素更明顯,我們使用 double precision 的浮點數(每個數需要 64 bits),也就是一個 4 維向量剛好需要 32 bytes。
在這個例子中,我們採取一個 3D 繪圖中,相當常見的動作,也就是把一大堆 4 維向量,乘上一個固定的 4x4 矩陣。如果向量的個數非常多,超過 CPU 的 cache 所能負擔,那麼 CPU 的表現就會大幅下降。
為了讓大家心裡有個底,這裡先把執行的結果列出來:
測試平台: Pentium III 500Mhz, PC100 SDRAM, 440BX chipset
在程式集可以下載程式的原始碼和執行檔。
首先,我們來看沒有使用 prefetch 指令的結果。事實上,結果相當符合預測。在 L1 D-cache 的範圍內(即小於 16KB 的情形),平均的運算時間相當的穩定,約在 51 ~ 52 cycles 左右。這也是 Pentium III 在計算一個 4x4 矩陣和 4 維向量相乘時(使用 double precision 浮點數),可能達到的最快速度。當然,這個程式是用 C 寫成的。如果直接用手寫組合語言,可能還可以再快個 5 ~ 10 cycles。
當資料量超過 L1 D-cache 的範圍,但是還在 L2 cache 的範圍之內時,所需的時間提高到約 60 cycles 左右。在 Part 1 中,我們已經知道 Pentium III 500Mhz 的 L2 cache 大約有 10 cycles 的 latency,所以這個結果也是相當合理的。
當資料量超過 L2 cache 的範圍時,所有的資料就需要從主記憶體中取得了。從圖上可以很容易的看到,每次運算所需的時間增加到 145 ~ 150 cycles。這有點出乎意料之外:在 Part 1 中,讀取主記憶體的 latency 只有 30 cycles 左右,但是在這裡,latency 增加了約 100 cycles。不過,這個結果並不奇怪。因為在運算結束後,運算的結果必須要寫回記憶體中,而寫回記憶體的動作,需要很多時間。
從這裡可以看到,在資料量超過 L2 cache 的範圍時,CPU 可說是被記憶體的速度限制住了。事實上,如果記憶體的速度不變,那即使是用兩倍快的 CPU,速度的增加也會非常有限。以 3D 遊戲的角度來說,1024KB 或 2048KB 這樣的資料量並不算少見,因為一個 single precision 浮點數的 4 維向量,就需要 16 bytes 的空間。65,536 個 4 維向量就需要 1MB 的空間了。
事實上,記憶體的速度雖慢,但是要完成一個 32 bytes(一個四維向量的大小)的讀寫動作,也只需要 60 ~ 70 cycles 而已(以 Pentium III 500Mhz 配合 PC100 SDRAM 的情形來算)。而在不用 prefetch 的情形下,CPU 的動作類似下圖所示:
現在,Load/Store Unit 變成全速運作了。Execution Units 還是沒有全速運作,但是這是沒辦法的。這種情形,就表示出瓶頸是在 Load/Store Unit,也就是在主記憶體的速度。已經沒有任何方法可以加快執行的速度了(除非加快記憶體的速度)。
要注意的一點是,上面的情形是很少發生的真實世界中的。實際的程式,通常瓶頸都是在運算單元。不過,我們的例子則剛好不是這樣(因為矩陣和向量相乘是很簡單的運算),而是類似圖中的情形。
要怎麼告訴 CPU,在計算的同時將下一個資料載入到 cache 中呢?這時就要用到 prefetch 的指令了。在我們的程式中,執行向量運算的程式如下:
for(i = 0; i < buf_size; i += 4) {
double r1, r2, r3, r4;
// 執行矩陣乘法
r1 = m[0] * v[i] + m[1] * v[i+1] + m[2] * v[i+2] + m[3] * v[i+3];
r2 = m[4] * v[i] + m[5] * v[i+1] + m[6] * v[i+2] + m[7] * v[i+3];
r3 = m[8] * v[i] + m[9] * v[i+1] + m[10] * v[i+2] + m[11] * v[i+3];
r4 = m[12] * v[i] + m[13] * v[i+1] + m[14] * v[i+2] + m[15] * v[i+3];
// 寫回計算結果
v[i] = r1;
v[i+1] = r2;
v[i+2] = r3;
v[i+3] = r4;
}
現在,我們在矩陣乘法的前面插入一個 prefetch 指令,變成:
for(i = 0; i < buf_size; i += 4) {
double r1, r2, r3, r4;
// 執行矩陣乘法
r1 = m[0] * v[i] + m[1] * v[i+1] + m[2] * v[i+2] + m[3] * v[i+3];
// 前一行執行完後,整個 4 維向量已經載入到 cache 中。
// 所以,現在用 prefetch 指令載入下一個 4 維向量。
prefetch(v + i + 4);
// 繼續進行計算
r2 = m[4] * v[i] + m[5] * v[i+1] + m[6] * v[i+2] + m[7] * v[i+3];
r3 = m[8] * v[i] + m[9] * v[i+1] + m[10] * v[i+2] + m[11] * v[i+3];
r4 = m[12] * v[i] + m[13] * v[i+1] + m[14] * v[i+2] + m[15] * v[i+3];
// 寫回計算結果
v[i] = r1;
v[i+1] = r2;
v[i+2] = r3;
v[i+3] = r4;
}
這段程式中的 prefetch 函式,裡面執行的是 SSE 的 prefetchnta 指令。Pentium III 和 Athlon 都支援這個指令(AMD 的 K6-2 中另外有一個 prefetch 指令,是 3DNow! 指令的一部分)。這個指令會將指定的資料載入到離 CPU 最近的 cache 中(在 Pentium III 即為 L1 cache)。
只不過加上這樣一行程式,執行結果就有很大的不同。回到前面的測試結果,我們可以看出,prefetch 指令,在資料已經存在 cache 中的時候,會有相當程度的 overhead(在這裡是大約 10 cycles)。但是,當資料不在 cache 中的時候,效率就有明顯的改善。特別是在資料量為 1024 KB 時,所需時間約為 70 cycles,說明了瓶頸確實是在 Load/Store Unit。在 1024 KB 之後,所需的 cycle 的增加,則是因為在多工系統中難以避免的 task switch 所產生的 overhead。
由此可知,prefetch 指令對於多媒體及 3D 遊戲等資料量極大的應用,是非常重要的。也可以預料,將來的程式一定會更加善用這類的功能,以達到最佳的效率。
5/24/2000, Ping-Che Chen
這篇文章主要是探討現在的 CPU 的 cache 和記憶體系統之間的關係。
CPU 速度的進展,一直比記憶體的速度進展要來得快。在 IBM PC XT 的時代,CPU 和記憶體的速度是差不多的。不過,後來 CPU 的速度就愈來愈快。再加上 DRAM 需要 refresh 才能保存資料的特性,DRAM 很快就跟不上 CPU 的速度了。現在的 CPU 都利用了 pipeline 的方式,可以每個 cycle 都 issue 一個(甚至多個)指令,再加上現在的 CPU 時脈也比記憶體的時脈高,記憶體的速度可說是遠遠落在 CPU 之後了。
為了避免記憶體成為 CPU 速度的瓶頸,現在的 CPU 都有 cache 的設計,甚至還有多層的 cache。Cache 的原理,主要是利用到大部分的程式,在處理資料時,都有一定程度的區域性。所以,我們可以用一小塊快速的記憶體,來暫存目前需要的資料。
例如,幾乎所有的程式,大部分的執行時間是花在一些迴圈中。這些迴圈通常都不大,可能只佔整個程式空間的百分之一。如果一個程式經常要執行這段程式數千、甚至數萬次,那就可以把這一小段程式放在 cache 中,CPU 就不需要每次都到很慢的主記憶體中讀取這段程式了。很多一般用途的程式,在存取資料時,也有類似的特性。因此,cache 的幫助非常大。如果沒有 cache 的話,我們就不需要這麼快的 CPU 了,因為系統的速度會卡在記憶體的速度上面。
現在的 CPU 往往也有多層的 cache。例如,Intel 的 Pentium III 500Mhz CPU,有 32KB 的 L1 cache,和 512KB 的 L2 cache。其中,L1 cache 內建在 CPU 內部,速度非常快,而且它是 Harvard 式,即指令用的空間和資料用的空間是分開的。Pentium III 500Mhz CPU 的 L1 cache 是分成 16KB 的 I-cache 和 16KB 的 D-cache。而 L2 cache 則是在 CPU 外面,以 250Mhz 的速度運作。另外,它和 CPU 之間的 bus 也只有 64 bits 寬。L2 cache 通常就不會區分指令和資料的空間,也就是 unified cache。
Cache 對速度有什麼影響呢?這可以由 latency 來表示。CPU 在從記憶體中讀取資料(或程式)時,會需要等待一段時間,這段時間就是 latency,通常用 cycle 數表示。例如,一般來說,如果資料已經在 L1 cache 中,則 CPU 在讀取資料時(這種情形稱為 L1 cache hit),CPU 是不需要多等的。但是,如果資料不在 L1 cache 中(這種情形稱為 L1 cache miss),則 CPU 就得到 L2 cache 去讀取資料了。這種情形下,CPU 就需要等待一段時間。如果需要的資料也不在 L2 cache 中,也就是 L2 cache miss,那麼 CPU 就得到主記憶體中讀取資料了(假設沒有 L3 cache)。這時候,CPU 就得等待更長的時間。
另外,cache 存取資料時,通常是分成很多小單位,稱為 cache line。例如,Pentium III 的 cache line 長度是 32 bytes。也就是說,如果 CPU 要讀取記憶體位址 0x00123456 的一個 32 bits word(即 4 bytes),且 cache 中沒有這個資料,則 cache 會將 0x00123440 ~ 0x0012345F 之間的 32 bytes 資料(即一整個 cache line 長度)都讀入 cache 中。所以,當 CPU 讀取連續的記憶體位址時,資料都已經讀到 cache 中了。
我寫了一個小程式,用來測試 cache 的行為。這個程式會連續讀取一塊記憶體位址,並量測平均讀取時間。這個 程式的執行結果如下:
測試平台:
Pentium III 500Mhz, PC100 SDRAM, 440BX chipset
Celeron 466Mhz, PC100 SDRAM, VIA Apollo Pro 133 chipset
程式的執行檔和原始碼可在這裡下載。
由上面的結果可以看出,當測試的區塊大小在 16KB 以下時,平均的 latency 都在 1 ~ 3 cycles 左右。這顯示出 16KB 的 L1 D-cache 的效果。在測試區塊為 1KB 和 2KB 時,因為額外的 overhead 較高,所以平均的 latency 變得較高,但是在 4KB ~ 16KB 的測試中,latency 則相當穩定。在這個範圍中,由於 Pentium III 和 Celeron 有相同的 L1 cache,所以測試結果是幾乎完全相同的。
在區塊超過 16KB 之後,就沒辦法放入 L1 D-cache 中了。但是它還是可以放在 L2 cache 中。所以,在 Pentium III 的情形下,從 32KB ~ 512KB,latency 都在 10 cycles 左右。這顯示出當 L1 cache miss 而 L2 cache hit 時,所需要的 latency。而 Celeron 的 L2 cache 只有 128KB,但是 Celeron 的 L2 cache 的 latency 則明顯的比 Pentium III 為低。這是因為 Celeron 的 L2 cache 是 on-die,以和 CPU 核心相同的速度運作。而 Pentium III 的 L2 cache 則是分開的,且以 CPU 核心速度的一半運作。
在區塊超過 512KB 之後,L2 cache 就不夠大了(Pentium III 500Mhz 只有 512KB 的 L2 cache)。這時,顯示出來的就是 L1 cache miss 且 L2 cache miss 時,所需要的 latency。在 1024KB 或更大的區塊中,Pentium III 的 latency 都大約是 28 cycles 左右,而 Celeron 的 latency 則超過 70 cycles。這是 CPU 讀取主記憶體時,平均的 latency。而 Celeron 的 latency 較高,應該是因為其外頻較低,而倍頻數較高的緣故(Pentium III 500Mhz 為 5 倍頻,而 Celeron 466 為 7 倍頻)。另外,晶片組的差異也可能是原因之一。
Cache 的效果十分明顯。不過,有時候 cache 是派不上用場的。例如,當資料完全沒有區域性,或是資料量太大的時候,都會讓 cache 的效果降低。例如,在進行 MPEG 壓縮時,存取的資料量很大,而且資料的重複利用率很低,所以 cache 的幫助就不大。另外,像是 3D 遊戲中,如果每個 frame 的三角面個數太多,也會超過 cache 能夠處理的範圍。
現在的電腦愈來愈朝向「多媒體應用」,需要處理的資料量也愈來愈大,因此,要如何善用 cache 就成了一個重要的問題。一個非常重要的方法,就是把讀取主記憶體的 latency 和執行運算的時間重疊,就可以把 latency「藏」起來。通常這會需要 prefetch 的功能,也就是 AMD 在 K6-2 及之後的 CPU,和 Intel 在 Pentium III 之後的 CPU 加入的新功能。在下一篇文章中,我們會討論 prefetch 的原理和用途。
CPU 的 cache 和 latency [Part 2]
在上一篇文章中,已經簡單討論過 CPU 的 cache 和其對 latency 的影響。在這篇文章中,我們就以一個較為實際的例子,並說明 prefetch 的原理和用途。
這裡要用的「實際例子」,其實還是很理想化的。為了和 3D 繪圖扯上一點關係,這裡就用「4x4 的矩陣和 4 維向量相乘」做為例子。不過,一般在 3D 繪圖中,都是用 single precision 的浮點數(每個數需要 32 bits),而這裡為了讓記憶體的因素更明顯,我們使用 double precision 的浮點數(每個數需要 64 bits),也就是一個 4 維向量剛好需要 32 bytes。
在這個例子中,我們採取一個 3D 繪圖中,相當常見的動作,也就是把一大堆 4 維向量,乘上一個固定的 4x4 矩陣。如果向量的個數非常多,超過 CPU 的 cache 所能負擔,那麼 CPU 的表現就會大幅下降。
為了讓大家心裡有個底,這裡先把執行的結果列出來:
測試平台: Pentium III 500Mhz, PC100 SDRAM, 440BX chipset
在程式集可以下載程式的原始碼和執行檔。
首先,我們來看沒有使用 prefetch 指令的結果。事實上,結果相當符合預測。在 L1 D-cache 的範圍內(即小於 16KB 的情形),平均的運算時間相當的穩定,約在 51 ~ 52 cycles 左右。這也是 Pentium III 在計算一個 4x4 矩陣和 4 維向量相乘時(使用 double precision 浮點數),可能達到的最快速度。當然,這個程式是用 C 寫成的。如果直接用手寫組合語言,可能還可以再快個 5 ~ 10 cycles。
當資料量超過 L1 D-cache 的範圍,但是還在 L2 cache 的範圍之內時,所需的時間提高到約 60 cycles 左右。在 Part 1 中,我們已經知道 Pentium III 500Mhz 的 L2 cache 大約有 10 cycles 的 latency,所以這個結果也是相當合理的。
當資料量超過 L2 cache 的範圍時,所有的資料就需要從主記憶體中取得了。從圖上可以很容易的看到,每次運算所需的時間增加到 145 ~ 150 cycles。這有點出乎意料之外:在 Part 1 中,讀取主記憶體的 latency 只有 30 cycles 左右,但是在這裡,latency 增加了約 100 cycles。不過,這個結果並不奇怪。因為在運算結束後,運算的結果必須要寫回記憶體中,而寫回記憶體的動作,需要很多時間。
從這裡可以看到,在資料量超過 L2 cache 的範圍時,CPU 可說是被記憶體的速度限制住了。事實上,如果記憶體的速度不變,那即使是用兩倍快的 CPU,速度的增加也會非常有限。以 3D 遊戲的角度來說,1024KB 或 2048KB 這樣的資料量並不算少見,因為一個 single precision 浮點數的 4 維向量,就需要 16 bytes 的空間。65,536 個 4 維向量就需要 1MB 的空間了。
事實上,記憶體的速度雖慢,但是要完成一個 32 bytes(一個四維向量的大小)的讀寫動作,也只需要 60 ~ 70 cycles 而已(以 Pentium III 500Mhz 配合 PC100 SDRAM 的情形來算)。而在不用 prefetch 的情形下,CPU 的動作類似下圖所示:
現在,Load/Store Unit 變成全速運作了。Execution Units 還是沒有全速運作,但是這是沒辦法的。這種情形,就表示出瓶頸是在 Load/Store Unit,也就是在主記憶體的速度。已經沒有任何方法可以加快執行的速度了(除非加快記憶體的速度)。
要注意的一點是,上面的情形是很少發生的真實世界中的。實際的程式,通常瓶頸都是在運算單元。不過,我們的例子則剛好不是這樣(因為矩陣和向量相乘是很簡單的運算),而是類似圖中的情形。
要怎麼告訴 CPU,在計算的同時將下一個資料載入到 cache 中呢?這時就要用到 prefetch 的指令了。在我們的程式中,執行向量運算的程式如下:
for(i = 0; i < buf_size; i += 4) {
double r1, r2, r3, r4;
// 執行矩陣乘法
r1 = m[0] * v[i] + m[1] * v[i+1] + m[2] * v[i+2] + m[3] * v[i+3];
r2 = m[4] * v[i] + m[5] * v[i+1] + m[6] * v[i+2] + m[7] * v[i+3];
r3 = m[8] * v[i] + m[9] * v[i+1] + m[10] * v[i+2] + m[11] * v[i+3];
r4 = m[12] * v[i] + m[13] * v[i+1] + m[14] * v[i+2] + m[15] * v[i+3];
// 寫回計算結果
v[i] = r1;
v[i+1] = r2;
v[i+2] = r3;
v[i+3] = r4;
}
現在,我們在矩陣乘法的前面插入一個 prefetch 指令,變成:
for(i = 0; i < buf_size; i += 4) {
double r1, r2, r3, r4;
// 執行矩陣乘法
r1 = m[0] * v[i] + m[1] * v[i+1] + m[2] * v[i+2] + m[3] * v[i+3];
// 前一行執行完後,整個 4 維向量已經載入到 cache 中。
// 所以,現在用 prefetch 指令載入下一個 4 維向量。
prefetch(v + i + 4);
// 繼續進行計算
r2 = m[4] * v[i] + m[5] * v[i+1] + m[6] * v[i+2] + m[7] * v[i+3];
r3 = m[8] * v[i] + m[9] * v[i+1] + m[10] * v[i+2] + m[11] * v[i+3];
r4 = m[12] * v[i] + m[13] * v[i+1] + m[14] * v[i+2] + m[15] * v[i+3];
// 寫回計算結果
v[i] = r1;
v[i+1] = r2;
v[i+2] = r3;
v[i+3] = r4;
}
這段程式中的 prefetch 函式,裡面執行的是 SSE 的 prefetchnta 指令。Pentium III 和 Athlon 都支援這個指令(AMD 的 K6-2 中另外有一個 prefetch 指令,是 3DNow! 指令的一部分)。這個指令會將指定的資料載入到離 CPU 最近的 cache 中(在 Pentium III 即為 L1 cache)。
只不過加上這樣一行程式,執行結果就有很大的不同。回到前面的測試結果,我們可以看出,prefetch 指令,在資料已經存在 cache 中的時候,會有相當程度的 overhead(在這裡是大約 10 cycles)。但是,當資料不在 cache 中的時候,效率就有明顯的改善。特別是在資料量為 1024 KB 時,所需時間約為 70 cycles,說明了瓶頸確實是在 Load/Store Unit。在 1024 KB 之後,所需的 cycle 的增加,則是因為在多工系統中難以避免的 task switch 所產生的 overhead。
由此可知,prefetch 指令對於多媒體及 3D 遊戲等資料量極大的應用,是非常重要的。也可以預料,將來的程式一定會更加善用這類的功能,以達到最佳的效率。
5/24/2000, Ping-Che Chen
為什麼OS無法識別4GB的記憶體
http://3g.sina.com.cn/3g/tech/index.php?did=634253&cid=827&cpage=3&sid=0&page=3&pwt=rest3&tid=84&vid=44
記憶體控制器的地址總線
與主機板安裝的記憶體直接關聯的是記憶體控制器。記憶體控制器一邊管理記憶體,一邊通過地址總線與CPU通信。記憶體控制器的地址總線決定了可以支援的記憶體地址編碼數量,同時記憶體控制器的實際連接記憶體的地址線決定了可以支援的記憶體容量。Intel把記憶體控制器放在北橋,AMD把記憶體控制器放在CPU。所以要分開介紹。
1、Intel的記憶體控制器
由於Intel的記憶體控制器放在北橋內,記憶體控制器的改變就與北橋密切相關。我們可以看下面的北橋列表:
表1
從上面的北橋地址總線發展表可以看出,從P965開始記憶體控制器已經是36位地址總線,可以編64GB的地址代碼,除系統佔用的地址碼,分配給主機板安裝的4GB記憶體綽綽有餘。所以,從P965開始Intel的北橋支援4GB記憶體是沒有問題的。
2、AMD的記憶體控制器
AMD從支援64位架構的CPU(Athlon64)開始把記憶體控制器集成到CPU。記憶體控制器的地址總線是64位架構的,使用40位,可以支援1000GB的地址編碼。所以,AMD 從Athlon64開始,記憶體控制器支援4GB記憶體也是沒有問題的。
BIOS能支援4GB記憶體
BIOS不是主機板廠家自己開發的,BIOS版權控制在AMI等幾個公司。它們與Intel和AMD合作共同開發BIOS。所以當Intel和AMD提出「映射」方式解決4GB記憶體問題,AMI等廠商就會開發出相應的BIOS。早期的BIOS裡面會顯示出「映射」選項,用戶可以開啟或關閉。現在已經是默認開啟,不再顯示這項設置。所以可以說,對於現在的BIOS來講,在支援4GB記憶體方面是沒問題的。
4GB記憶體的「原罪」:X86架構
CPU和記憶體控制器從硬體上為使用4GB記憶體提供了保障。但是還沒有解決4GB記憶體的問題。障礙來自於個人電腦的體系標準——32位X86架構。早在8086時代,記憶體是銲接在主機板上的,一般也就幾KB的記憶體,IBM規定640KB的地址是最高端,這個地址分配給BIOS,接下來有一段地址分配給系統的顯示設備和I/O設備。電腦的迅速發展很快突破640KB記憶體達到並超過1MB。但是640KB下面這一段地址分配不能改變,因為CPU、DOS操作系統都是從640KB讀取BIOS通過640KB下面的顯示設備暫存地址,I/O設備暫存地址與顯示設備、I/O設備通信、交換數據。如果更改,以前的所有電腦都要作廢。所以必須尋找一個辦法,既不改變640KB地址分配,又可以使用640KB到1MB的記憶體。那就是這種地址分配規則不變,採用「記憶體地址映射」技術,把640KB到500多KB的這一段地址映射到640KB-1MB的空間裡,映射工作由BIOS負責。
操作系統則由兩條DOS命令HIMEM.SYS和EMM386.SYS負責,熟悉DOS的用戶,都會知道這兩條命令。通過映射,就可以讓DOS軟件使用更多的記憶體。記憶體發展到4MB,16MB,都是通過「記憶體映射」技術解決。到現在,個人電腦只要兼容DOS,就必須遵守640KB這種地址記憶體分配規則。
奔騰Ⅱ時代,SDRAM記憶體容量達到128MB。那時候的地址總線是32位,最大地址空間是4GB,這時32位X86架構已經完全形成。除保留以前的記憶體地址分配規則外,還要把BIOS地址映射到地址空間的頂端——4GB。一直到815時代的DDR記憶體,915時代的DDR2記憶體。真正使用的記憶體單條最大容量為512MB,系統使用的記憶體不會超過2GB。所以4GB記憶體問題沒有顯現。 945時代時1GB的DDR2記憶體出現後,記憶體控制器的設計者們開始考慮主機板安裝4GB的記憶體條。但當時很少有用戶使用4GB記憶體,4GB記憶體問題依然沒有凸現。
圖1
其實,Intel在915時期就提出要解決32位X86架構硬體支援4GB記憶體的問題。到P965正式解決時,解決方案還是「記憶體地址映射」。這個方案不是新想出來的,在32位X86架構的服務器系統早已經採用,只是被移植到個人電腦上來。
從64GB的地址空間頂部開始,映射PCI設備的I/O地址,然後映射系統佔用的3GB到4GB的地址。把3GB到4GB的這段地址代碼留給安裝在主機板上的物理記憶體,就可以使用安裝的全部記憶體了。
為什麼必須要採用「映射」的辦法?
因為記憶體的編址必須是連續的,不能斷開。而系統的地址空間(也叫邏輯地址)是可以不連續的。就像我們給街道兩邊的房屋號碼牌一樣,編製方案(相當於邏輯地址)可以規劃很大,可以分割。給到這一條街房屋的號碼牌必須是連續的,這是真實的地址,以便於人們按地址尋找房屋。當然這種「映射」工作還是由BIOS完成。要支援4GB記憶體,還必須要BIOS支援。
圖2
通過記憶體地址重映射把系統佔用的4GB地址還給物理記憶體,是32位X86架構的規則。AMD也要採用這個規則,雖然它的記憶體控制器集成在CPU內。也正是由於記憶體控制器集成在CPU內,北橋不再含有記憶體控制器。主機板廠家開發AMD平台主機板時,會依據市場定位設計主機板支援的記憶體容量。有支援2GB的,也有支援4GB、8GB或更多。所以AMD平台的4GB問題還要看主機板。
操作系統才是「罪魁禍首」
操作系統管理和使用物理記憶體,因此在操作系統內也必須有一個邏輯(虛擬)地址系統,與主機板上的所有存儲地址(包括記憶體的、I/O設備的、BIOS的)對應,也有類似「地址總線」的結構。32位操作系統是按32位地址總線設計,32位的地址暫存器,因此只能管理4GB的地址,去掉系統佔用的,也不能完全使用全部4GB記憶體。個人電腦的32位操作系統都不能支援4GB記憶體,即使是VISTA 32 SP1也不能。VISTA 32 SP1比XP 32 SP3進步一點的是在系統屬性裡面可以顯示實際安裝多少內。
32位的Vista SP1已經能順利識別4GB記憶體,但在任務管理器可以看到系統真正使用的記憶體不到4GB。
那麼哪些操作系統可以支援並使用4GB記憶體?第一是64位操作系統,因為64位操作系統是按64位地址總線設計的。比如Windows XP 64,Vista 64。第二是具有物理地址擴展功能,並且地址暫存器大於32位的服務器操作系統,但有些具備物理地址擴展的服務器操作系統,由於地址暫存器限於32位也不能支援4GB。
寫在最後,我們可以看出,現在的主機板晶片組或記憶體控制器已經不再是吞食我們記憶體的主要原因。而罪魁禍首則是出在我們使用的32位操作系統上。雖然現在的Vista SP1已經能識別到完整的4GB記憶體,但實際使用的記憶體還是和以前的那3GB左右的沒區別。所以現在來談4GB記憶體的普及依然為時過早。另一方面,有的記憶體廠商為了避免出現記憶體浪費的情況發生,推出了三條1GB記憶體的組合套裝,這也是相當貼心的一個設計。
記憶體控制器的地址總線
與主機板安裝的記憶體直接關聯的是記憶體控制器。記憶體控制器一邊管理記憶體,一邊通過地址總線與CPU通信。記憶體控制器的地址總線決定了可以支援的記憶體地址編碼數量,同時記憶體控制器的實際連接記憶體的地址線決定了可以支援的記憶體容量。Intel把記憶體控制器放在北橋,AMD把記憶體控制器放在CPU。所以要分開介紹。
1、Intel的記憶體控制器
由於Intel的記憶體控制器放在北橋內,記憶體控制器的改變就與北橋密切相關。我們可以看下面的北橋列表:
表1
從上面的北橋地址總線發展表可以看出,從P965開始記憶體控制器已經是36位地址總線,可以編64GB的地址代碼,除系統佔用的地址碼,分配給主機板安裝的4GB記憶體綽綽有餘。所以,從P965開始Intel的北橋支援4GB記憶體是沒有問題的。
2、AMD的記憶體控制器
AMD從支援64位架構的CPU(Athlon64)開始把記憶體控制器集成到CPU。記憶體控制器的地址總線是64位架構的,使用40位,可以支援1000GB的地址編碼。所以,AMD 從Athlon64開始,記憶體控制器支援4GB記憶體也是沒有問題的。
BIOS能支援4GB記憶體
BIOS不是主機板廠家自己開發的,BIOS版權控制在AMI等幾個公司。它們與Intel和AMD合作共同開發BIOS。所以當Intel和AMD提出「映射」方式解決4GB記憶體問題,AMI等廠商就會開發出相應的BIOS。早期的BIOS裡面會顯示出「映射」選項,用戶可以開啟或關閉。現在已經是默認開啟,不再顯示這項設置。所以可以說,對於現在的BIOS來講,在支援4GB記憶體方面是沒問題的。
4GB記憶體的「原罪」:X86架構
CPU和記憶體控制器從硬體上為使用4GB記憶體提供了保障。但是還沒有解決4GB記憶體的問題。障礙來自於個人電腦的體系標準——32位X86架構。早在8086時代,記憶體是銲接在主機板上的,一般也就幾KB的記憶體,IBM規定640KB的地址是最高端,這個地址分配給BIOS,接下來有一段地址分配給系統的顯示設備和I/O設備。電腦的迅速發展很快突破640KB記憶體達到並超過1MB。但是640KB下面這一段地址分配不能改變,因為CPU、DOS操作系統都是從640KB讀取BIOS通過640KB下面的顯示設備暫存地址,I/O設備暫存地址與顯示設備、I/O設備通信、交換數據。如果更改,以前的所有電腦都要作廢。所以必須尋找一個辦法,既不改變640KB地址分配,又可以使用640KB到1MB的記憶體。那就是這種地址分配規則不變,採用「記憶體地址映射」技術,把640KB到500多KB的這一段地址映射到640KB-1MB的空間裡,映射工作由BIOS負責。
操作系統則由兩條DOS命令HIMEM.SYS和EMM386.SYS負責,熟悉DOS的用戶,都會知道這兩條命令。通過映射,就可以讓DOS軟件使用更多的記憶體。記憶體發展到4MB,16MB,都是通過「記憶體映射」技術解決。到現在,個人電腦只要兼容DOS,就必須遵守640KB這種地址記憶體分配規則。
奔騰Ⅱ時代,SDRAM記憶體容量達到128MB。那時候的地址總線是32位,最大地址空間是4GB,這時32位X86架構已經完全形成。除保留以前的記憶體地址分配規則外,還要把BIOS地址映射到地址空間的頂端——4GB。一直到815時代的DDR記憶體,915時代的DDR2記憶體。真正使用的記憶體單條最大容量為512MB,系統使用的記憶體不會超過2GB。所以4GB記憶體問題沒有顯現。 945時代時1GB的DDR2記憶體出現後,記憶體控制器的設計者們開始考慮主機板安裝4GB的記憶體條。但當時很少有用戶使用4GB記憶體,4GB記憶體問題依然沒有凸現。
圖1
其實,Intel在915時期就提出要解決32位X86架構硬體支援4GB記憶體的問題。到P965正式解決時,解決方案還是「記憶體地址映射」。這個方案不是新想出來的,在32位X86架構的服務器系統早已經採用,只是被移植到個人電腦上來。
從64GB的地址空間頂部開始,映射PCI設備的I/O地址,然後映射系統佔用的3GB到4GB的地址。把3GB到4GB的這段地址代碼留給安裝在主機板上的物理記憶體,就可以使用安裝的全部記憶體了。
為什麼必須要採用「映射」的辦法?
因為記憶體的編址必須是連續的,不能斷開。而系統的地址空間(也叫邏輯地址)是可以不連續的。就像我們給街道兩邊的房屋號碼牌一樣,編製方案(相當於邏輯地址)可以規劃很大,可以分割。給到這一條街房屋的號碼牌必須是連續的,這是真實的地址,以便於人們按地址尋找房屋。當然這種「映射」工作還是由BIOS完成。要支援4GB記憶體,還必須要BIOS支援。
圖2
通過記憶體地址重映射把系統佔用的4GB地址還給物理記憶體,是32位X86架構的規則。AMD也要採用這個規則,雖然它的記憶體控制器集成在CPU內。也正是由於記憶體控制器集成在CPU內,北橋不再含有記憶體控制器。主機板廠家開發AMD平台主機板時,會依據市場定位設計主機板支援的記憶體容量。有支援2GB的,也有支援4GB、8GB或更多。所以AMD平台的4GB問題還要看主機板。
操作系統才是「罪魁禍首」
操作系統管理和使用物理記憶體,因此在操作系統內也必須有一個邏輯(虛擬)地址系統,與主機板上的所有存儲地址(包括記憶體的、I/O設備的、BIOS的)對應,也有類似「地址總線」的結構。32位操作系統是按32位地址總線設計,32位的地址暫存器,因此只能管理4GB的地址,去掉系統佔用的,也不能完全使用全部4GB記憶體。個人電腦的32位操作系統都不能支援4GB記憶體,即使是VISTA 32 SP1也不能。VISTA 32 SP1比XP 32 SP3進步一點的是在系統屬性裡面可以顯示實際安裝多少內。
32位的Vista SP1已經能順利識別4GB記憶體,但在任務管理器可以看到系統真正使用的記憶體不到4GB。
那麼哪些操作系統可以支援並使用4GB記憶體?第一是64位操作系統,因為64位操作系統是按64位地址總線設計的。比如Windows XP 64,Vista 64。第二是具有物理地址擴展功能,並且地址暫存器大於32位的服務器操作系統,但有些具備物理地址擴展的服務器操作系統,由於地址暫存器限於32位也不能支援4GB。
寫在最後,我們可以看出,現在的主機板晶片組或記憶體控制器已經不再是吞食我們記憶體的主要原因。而罪魁禍首則是出在我們使用的32位操作系統上。雖然現在的Vista SP1已經能識別到完整的4GB記憶體,但實際使用的記憶體還是和以前的那3GB左右的沒區別。所以現在來談4GB記憶體的普及依然為時過早。另一方面,有的記憶體廠商為了避免出現記憶體浪費的情況發生,推出了三條1GB記憶體的組合套裝,這也是相當貼心的一個設計。
2008年11月14日 星期五
GPIO、routing
GPIO(General Purpose I/O),其接腳可以供使用者由程式控制自由使用,PIN 腳依現實考量可作為GPI、GPO、GPIO。
因此,GPIO 的 PIN,我們要注意的是用途、in/out、還有電位的high/low,可以透過HW線路圖幫助了解。而這些狀態,我們可以透過 register 去了解控制。
特定 GPIO 可以發 GPIO event,像是 SCI、SMI,例如我們 notebook lid 的動作,透過 LID 的線傳到 EC,EC 再送一個 GPIO EVENT 給南橋,然後處理。
電位的改變有 edge 和 level。edge 的電會一直持續,當電位改變的時候,狀態也跟著改變,例如 high 到 low 為 1,則 low 到 high 為0。
level 則是當電位在低的時候,表 low,高的時候表 high。PIN是吃不同電的,這點我們要注意。
接下來說 routing,為什麼要 routing 呢?一個南橋下接了一大堆 device,符合 PCI 規格的 device
都有 ABCD 四根 PIN 可以發中斷(如果是 single function,就只有 int A),而我們所知的 8259,扣掉master和slave連接的一根,真的能用的只有十五根,甚至有些已經在早期分配給固定的 device,根本不夠用,為了分配剩下的 IRQ,所以我們就做了 routing 的動作。也就是說,本來要透過硬體直接連接 PIN,但是因為不夠用,INTEL 多做了幾支 PIN,PCI DEVICES就連接到這些 PIN,用軟體模擬的方式分配,解決不夠用的問題,我們把這樣的機制稱為 PIRQ Route Controller。
IRQ 的值,我們可以在 PCI SPE OFFSET 3C 的地方看到,另外我們有一根 serial IRQ,透過電位形狀來分辨不同的中斷。
在作業系統驅動程式支援 IRQ 共享的狀態下,從早期的 PIC 只支援 15 IRQ,現在的 APIC 可以支援的 215 個。
Routing 的實作方面,可以去看_PRT這個 control method。
因此,GPIO 的 PIN,我們要注意的是用途、in/out、還有電位的high/low,可以透過HW線路圖幫助了解。而這些狀態,我們可以透過 register 去了解控制。
特定 GPIO 可以發 GPIO event,像是 SCI、SMI,例如我們 notebook lid 的動作,透過 LID 的線傳到 EC,EC 再送一個 GPIO EVENT 給南橋,然後處理。
電位的改變有 edge 和 level。edge 的電會一直持續,當電位改變的時候,狀態也跟著改變,例如 high 到 low 為 1,則 low 到 high 為0。
level 則是當電位在低的時候,表 low,高的時候表 high。PIN是吃不同電的,這點我們要注意。
接下來說 routing,為什麼要 routing 呢?一個南橋下接了一大堆 device,符合 PCI 規格的 device
都有 ABCD 四根 PIN 可以發中斷(如果是 single function,就只有 int A),而我們所知的 8259,扣掉master和slave連接的一根,真的能用的只有十五根,甚至有些已經在早期分配給固定的 device,根本不夠用,為了分配剩下的 IRQ,所以我們就做了 routing 的動作。也就是說,本來要透過硬體直接連接 PIN,但是因為不夠用,INTEL 多做了幾支 PIN,PCI DEVICES就連接到這些 PIN,用軟體模擬的方式分配,解決不夠用的問題,我們把這樣的機制稱為 PIRQ Route Controller。
IRQ 的值,我們可以在 PCI SPE OFFSET 3C 的地方看到,另外我們有一根 serial IRQ,透過電位形狀來分辨不同的中斷。
在作業系統驅動程式支援 IRQ 共享的狀態下,從早期的 PIC 只支援 15 IRQ,現在的 APIC 可以支援的 215 個。
Routing 的實作方面,可以去看_PRT這個 control method。
2008年11月3日 星期一
ACPI 體系中的重要名詞
http://root.public.blog.163.com/blog/static/31428336200871102434887/
ACPI 體系中的重要名詞
DSDT: DSDT 稱做 Differentiated Definition Block,存在於 BIOS 中,並與當前的硬件平台兼容,提供了系統的硬件特性(例如某些設備的內部暫存器和儲存器)的應用策略和配置,在系統初始化的時候,DSDT 被當前系統啟動時初始化到namespace中。
FADT:Fixed ACPI Description table,FADT 中包含了 ACPI 的硬件寄存器組(GPE)的應用和配置(包含它們的硬件地址)也包括DSDT表的硬件地址。
ACPI Namespace: 對ACPI層來說,記憶體維持了一個目錄形式,指向每個設備及 GPE 的 namespace,這個 namespace structure 在初始化的時候由 DSDT 創建,namespace structure 可以透過 loadtable 方法從 BIOS 中載入 DSDT 改變,而每個設備在 ACPI 層中都被描述成一個對象,包含有對這個設備特性和操作策略的描述列表,系統所有類型設備都是保存在同一個 namespace structure 下。在 ACPI OS 層上調用 _ADR 來獲得 Namesapce 的設備名,Namespace 的例子見例 1-1:
OSPM(OS-directed Power Management):OSPM 操作系統支援 ACPI 的一個部分,操作系統(OS)可以從操作系統下驅動程序的角度控制 ACPI 子模組,同時支持 ACPI 包括 SCI 中斷,設備事件,系統事件模式,這些事件模式可以充分支持 Hot-plug 方式。
SCI 中斷:(System Control Interrupt) 系統控制中斷,SCI 中斷是一種源自 ACPI 相容晶片系統中斷,系統映射不同的 ACPI 事件中斷向量以便共享此中斷,當底層硬體產生 SCI 中斷的時候(例如設備插入事件引發中斷),根據通知 OSPM 層處理相對應的 ACPI 事件,OSPM 層會調用預先安裝的中斷。
GPE Block Device 和 GPE 事件:GPE Block Device 是平台設計者可按照 FADT(Fixed ACPI Descriptor Table) 描述表中對應 GPE 的暫存器組及 GPE 的輸入 pin。GPE 設備描述塊中的地址存在於 FADT 中,每個 GPE Block Device 可以容納 128 個 GPE 事件,ACPI 層上提供兩個通用目標暫存器組–GPE0_BLK 和 GPE1_BLK,(也就是說可以響應 256 個 GPE 事件)每個暫存器組中包含兩個等長度的暫存器 GPEx_STS,GPEx_EN,他們的系統地址(硬體地址)都保存在 FADT 中,作為 GPE Blocks 的行為(或者是操作),描述部分存在 ACPI name space 中,用於指示當前的設備的事件,例如設備插入/拔除事件發生的時候,相關的狀態(GPEx_STS中,硬件設計的時候相關設備的事件信號會連接到對應的狀態位置)會被外部的事件所設,生成 SCI,讓 OSPM 層運行相關的 control method 通知 ACPI 層;GPEx_EN 表示每個事件是否可用,一般說來在南橋(ICH4)中有這幾個暫存器,它們的硬體位址保存在 FADT 中。
GPE 事件就是通過 GPE 暫存器組引發 SCI 中斷後,通知 OSPM 層有關設備的事件,例如下面介紹 Hot-Plug 的時候會詳細或者簡略地介紹到總線枚舉,設備檢查,設備喚醒,設備彈出幾個事件。
ACPI” Source Language(ASL):ASL 語言是 ACPI 層描述特定的 ACPI 對象的 ACPI 專用語言,並且包括了 ACPI 對象的控制方法(Control method),OEM 廠商和 BIOS 設計者在 BIOS 中使用 ASL 定義所有的設備為 ACPI 對象,並且可以生成 ASL 格式的專門的控制方法,1-1 例就是關于 ASL 的例子:
ASL 的語法規參看 ACPI Specification Revision 2.0
AML 和 AML 分析器:AML 是 ACPI 控制方法的虛擬機器語言,AML 執行過程也就是 ACPI 核心驅動層,ACPI 控制方法使用 AML 來進行編寫,但是通常而言對編寫者來說是寫成 ASL 的方式,通過 AML 翻譯器進行翻譯,AML 翻譯器不但具備 ASL 的翻譯的功能,而且可以執行 AML 方法,當用 ASL 編寫的 DSDT 表被載入到名字空間的時候,將會被 AML 翻譯器翻譯成執行時候可以辨別的機器碼,例如關鍵字 SCOPE 在進入 AML 編譯器之前中是以一個 ACSII 編碼保存在 DSDT 中,但 DSDT 被載入名字空間之后將變成 0×10 的單字節數值(AML 操作值為 ScopeOP)。對 AML 的編譯過程和轉換方式,ASL 中的關鍵字可以參看 ACPI Specification Revision 2.0 中 section 17 。
ACPI 體系中的重要名詞
DSDT: DSDT 稱做 Differentiated Definition Block,存在於 BIOS 中,並與當前的硬件平台兼容,提供了系統的硬件特性(例如某些設備的內部暫存器和儲存器)的應用策略和配置,在系統初始化的時候,DSDT 被當前系統啟動時初始化到namespace中。
FADT:Fixed ACPI Description table,FADT 中包含了 ACPI 的硬件寄存器組(GPE)的應用和配置(包含它們的硬件地址)也包括DSDT表的硬件地址。
ACPI Namespace: 對ACPI層來說,記憶體維持了一個目錄形式,指向每個設備及 GPE 的 namespace,這個 namespace structure 在初始化的時候由 DSDT 創建,namespace structure 可以透過 loadtable 方法從 BIOS 中載入 DSDT 改變,而每個設備在 ACPI 層中都被描述成一個對象,包含有對這個設備特性和操作策略的描述列表,系統所有類型設備都是保存在同一個 namespace structure 下。在 ACPI OS 層上調用 _ADR 來獲得 Namesapce 的設備名,Namespace 的例子見例 1-1:
OSPM(OS-directed Power Management):OSPM 操作系統支援 ACPI 的一個部分,操作系統(OS)可以從操作系統下驅動程序的角度控制 ACPI 子模組,同時支持 ACPI 包括 SCI 中斷,設備事件,系統事件模式,這些事件模式可以充分支持 Hot-plug 方式。
SCI 中斷:(System Control Interrupt) 系統控制中斷,SCI 中斷是一種源自 ACPI 相容晶片系統中斷,系統映射不同的 ACPI 事件中斷向量以便共享此中斷,當底層硬體產生 SCI 中斷的時候(例如設備插入事件引發中斷),根據通知 OSPM 層處理相對應的 ACPI 事件,OSPM 層會調用預先安裝的中斷。
GPE Block Device 和 GPE 事件:GPE Block Device 是平台設計者可按照 FADT(Fixed ACPI Descriptor Table) 描述表中對應 GPE 的暫存器組及 GPE 的輸入 pin。GPE 設備描述塊中的地址存在於 FADT 中,每個 GPE Block Device 可以容納 128 個 GPE 事件,ACPI 層上提供兩個通用目標暫存器組–GPE0_BLK 和 GPE1_BLK,(也就是說可以響應 256 個 GPE 事件)每個暫存器組中包含兩個等長度的暫存器 GPEx_STS,GPEx_EN,他們的系統地址(硬體地址)都保存在 FADT 中,作為 GPE Blocks 的行為(或者是操作),描述部分存在 ACPI name space 中,用於指示當前的設備的事件,例如設備插入/拔除事件發生的時候,相關的狀態(GPEx_STS中,硬件設計的時候相關設備的事件信號會連接到對應的狀態位置)會被外部的事件所設,生成 SCI,讓 OSPM 層運行相關的 control method 通知 ACPI 層;GPEx_EN 表示每個事件是否可用,一般說來在南橋(ICH4)中有這幾個暫存器,它們的硬體位址保存在 FADT 中。
GPE 事件就是通過 GPE 暫存器組引發 SCI 中斷後,通知 OSPM 層有關設備的事件,例如下面介紹 Hot-Plug 的時候會詳細或者簡略地介紹到總線枚舉,設備檢查,設備喚醒,設備彈出幾個事件。
ACPI” Source Language(ASL):ASL 語言是 ACPI 層描述特定的 ACPI 對象的 ACPI 專用語言,並且包括了 ACPI 對象的控制方法(Control method),OEM 廠商和 BIOS 設計者在 BIOS 中使用 ASL 定義所有的設備為 ACPI 對象,並且可以生成 ASL 格式的專門的控制方法,1-1 例就是關于 ASL 的例子:
ASL 的語法規參看 ACPI Specification Revision 2.0
AML 和 AML 分析器:AML 是 ACPI 控制方法的虛擬機器語言,AML 執行過程也就是 ACPI 核心驅動層,ACPI 控制方法使用 AML 來進行編寫,但是通常而言對編寫者來說是寫成 ASL 的方式,通過 AML 翻譯器進行翻譯,AML 翻譯器不但具備 ASL 的翻譯的功能,而且可以執行 AML 方法,當用 ASL 編寫的 DSDT 表被載入到名字空間的時候,將會被 AML 翻譯器翻譯成執行時候可以辨別的機器碼,例如關鍵字 SCOPE 在進入 AML 編譯器之前中是以一個 ACSII 編碼保存在 DSDT 中,但 DSDT 被載入名字空間之后將變成 0×10 的單字節數值(AML 操作值為 ScopeOP)。對 AML 的編譯過程和轉換方式,ASL 中的關鍵字可以參看 ACPI Specification Revision 2.0 中 section 17 。
訂閱:
文章 (Atom)