文章目錄
- 1.1.1 從軟體的角度理解端模式
- 1.1.2 從系統的角度理解端模式
端模式(Endian)的這個詞出自Jonathan Swift書寫的《格列佛遊記》。這本書根據將雞蛋敲開的方法不同將所有的人分為兩類,從圓頭開始將雞蛋敲開的人被歸為Big Endian,從尖頭開始將雞蛋敲開的人被歸為Littile Endian。小人國的內戰就源於吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。在電腦業Big Endian和Little Endian也幾乎引起一場戰爭。在電腦業界,Endian表示資料在儲存空間中的存放順序。下文舉例說明在電腦中大小端模式的區別。
如果將一個32位的整數0x12345678存放到一個整型變數(int)中,這個整型變數採用大端或者小端模式在記憶體中的儲存由下表所示。為簡單起見,本書使用OP0表示一個32位元據的最高位元組MSB(Most Significant Byte),使用OP3表示一個32位元據最低位元組LSB(Least Significant Byte)。
地址位移 |
大端模式 |
小端模式 |
0x00 |
12(OP0) |
78(OP3) |
0x01 |
34(OP1) |
56(OP2) |
0x02 |
56(OP2) |
34(OP1) |
0x03 |
78(OP3) |
12(OP0) |
如果將一個16位的整數0x1234存放到一個短整型變數(short)中。這個短整型變數在記憶體中的儲存在大小端模式由下表所示。
地址位移 |
大端模式 |
小端模式 |
0x00 |
12(OP0) |
34(OP1) |
0x01 |
34(OP1) |
12(OP0) |
由上表所知,採用大小模式對資料進行存放的主要區別在於在存放的位元組順序,大端方式將高位存放在低地址,小端方式將低位存放在高地址。採用大端方式進行資料存放符合人類的正常思維,而採用小端方式進行資料存放利於電腦處理。到目前為止,採用大端或者小端進行資料存放,其孰優孰劣也沒有定論。
有的處理器系統採用了小端方式進行資料存放,如Intel的奔騰。有的處理器系統採用了大端方式進行資料存放,如IBM半導體和Freescale的PowerPC處理器。不僅對於處理器,一些外設的設計中也存在著使用大端或者小端進行資料存放的選擇。
因此在一個處理器系統中,有可能存在大端和小端模式同時存在的現象。這一現象為系統的軟硬體設計帶來了不小的麻煩,這要求系統設計工程師,必須深入理解大端和小端模式的差別。大端與小端模式的差別體現在一個處理器的寄存器,指令集,系統匯流排等各個層次中。
1.1.1 從軟體的角度理解端模式
從軟體的角度上,不同端模式的處理器進行資料傳遞時必須要考慮端模式的不同。如進行網路資料傳遞時,必須要考慮端模式的轉換。有過Socket介面編程經驗的程式員一定使用過以下幾個函數用於大小端位元組序的轉換。
¨ #define ntohs(n) //16位元據類型網路位元組順序到主機位元組順序的轉換
¨ #define htons(n) //16位元據類型主機位元組順序到網路位元組順序的轉換
¨ #define ntohl(n) //32位元據類型網路位元組順序到主機位元組順序的轉換
¨ #define htonl(n) //32位元據類型主機位元組順序到網路位元組順序的轉換
其中互連網使用的網路位元組順序採用大端模式進行編址,而主機位元組順序根據處理器的不同而不同,如PowerPC處理器使用大端模式,而Pentuim處理器使用小端模式。
大端模式處理器的位元組序到網路位元組序不需要轉換,此時ntohs(n)=n,ntohl = n;而小端模式處理器的位元組序到網路位元組必須要進行轉換,此時ntohs(n) = __swab16(n),ntohl = __swab32(n)。__swab16與__swab32函數定義如下所示。
#define ___swab16(x) { __u16 __x = (x); ((__u16)( (((__u16)(__x) & (__u16)0x00ffU) << 8) | (((__u16)(__x) & (__u16)0xff00U) >> 8) )); } #define ___swab32(x) { __u32 __x = (x); ((__u32)( (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); } |
PowerPC處理器提供了lwbrx,lhbrx,stwbrx,sthbrx四條指令用於處理位元組序的轉換以最佳化__swab16和__swap32這類函數。此外PowerPC處理器中的rlwimi指令也可以用來實現__swab16和__swap32這類函數。在Linux PowerPC中,定義了一系列有關位元組序轉換的函數,其詳細定義在./include/asm-powerpc/byteorder.h檔案中。
程式員在對普通檔案進行處理也需要考慮端模式問題。在大端模式的處理器下對檔案的32,16位讀寫操作所得到的結果與小端模式的處理器不同。讀者單純從軟體的角度理解上遠遠不能真正理解大小端模式的區別。事實上,真正的理解大小端模式的區別,必須要從系統的角度,從指令集,寄存器和資料匯流排上深入理解,大小端模式的區別。
1.1.2 從系統的角度理解端模式
除了4.2.1節中,軟體上對不同端模式編程上的差異,處理器在硬體上也由於端模式問題在設計中有所不同。從系統的角度上看,端模式問題對軟體和硬體的設計帶來了不同的影響,當一個處理器系統中大小端模式同時存在時,必須要對這些不同端模式的訪問進行特殊的處理。
PowerPC處理器主導網路市場,可以說絕大多數的通訊裝置都使用PowerPC處理器進行協議處理和其他控制資訊的處理,這也可能也是在網路上的絕大多數協議都採用大端編址方式的原因。因此在有關網路通訊協定的軟體設計中,使用小端方式的處理器需要在軟體中處理端模式的轉變。而Pentium主導個人機市場,因此多數用於個人機的外設都採用小端模式,包括一些在網路裝置中使用的PCI匯流排,Flash等裝置,這也要求硬體工程師在硬體設計中注意端模式的轉換。
本書中的小端外設是指這種外設中的寄存器以小端方式進行儲存,如PCI裝置的配置空間,NOR FLASH中的寄存器等等。
對於有些裝置,如DDR顆粒,沒有以小端方式儲存的寄存器,因此從邏輯上講並不需要對端模式進行轉換。在設計中,只需要將雙方資料匯流排進行一一對應的互連,而不需要進行資料匯流排的轉換。
如果從實際應用的角度說,採用小端模式的處理器需要在軟體中處理端模式的轉換,因為採用小端模式的處理器在與小端外設互連時,不需要任何轉換。
而採用大端模式的處理器需要在硬體設計時處理端模式的轉換。大端模式處理器需要在寄存器,指令集,資料匯流排及資料匯流排與小端外設的串連等等多個方面進行處理,以解決與小端外設串連時的端模式轉換問題。
在寄存器和資料匯流排的位序定義上,基於大小端模式的處理器有所不同。
一個採用大端模式的32位處理器,如基於E500核心的MPC8541,將其寄存器的最高位msb(most significant bit)定義為0,最低位lsb(lease significant bit)定義為31;而小端模式的32位處理器,將其寄存器的最高位定義為31,低位地址定義為0。
與此向對應,採用大端模式的32位處理器資料匯流排的最高位為0,最高位為31;採用小端模式的32位處理器的資料匯流排的最高位為31,最低位為0。4.5所示。
大小端模式處理器外部匯流排的位序也遵循著同樣的規律,根據所採用的資料匯流排是32位,16位和8位,大小端處理器外部匯流排的位序有所不同。
¨ 大端模式下32位元據匯流排的msb是第0位,MSB是資料匯流排的第0~7的欄位;而lsb是第31位,LSB是第24~31欄位。小端模式下32位匯流排的msb是第31位,MSB是資料匯流排的第31~24位,lsb是第0位,LSB是7~0欄位。
¨ 大端模式下16位元據匯流排的msb是第0位,MSB是資料匯流排的第0~7的欄位;而lsb是第15位,LSB是第8~15欄位。小端模式下16位匯流排的msb是第15位,MSB是資料匯流排的第15~7位,lsb是第0位,LSB是7~0欄位。
¨ 大端模式下8位元據匯流排的msb是第0位,MSB是資料匯流排的第0~7的欄位;而lsb是第7位,LSB是第0~7欄位。小端模式下8位匯流排的msb是第7位,MSB是資料匯流排的第7~0位,lsb是第0位,LSB是7~0欄位。
由上分析,我們可以得知對於8位,16位和32位寬度的資料匯流排,採用大端模式時資料匯流排的msb和MSB的位置都不會發生變化,而採用小端模式時資料匯流排的lsb和LSB位置也不會發生變化。
為此,大端模式的處理器對8位,16位和32位的記憶體訪問(包括外設的訪問)一般都包含第0~7欄位,即MSB。小端模式的處理器對8位,16位和32位的記憶體訪問都包含第7~0位,小端方式的第7~0欄位,即LSB。
由於大小端處理器的資料匯流排其8位,16位和32位寬度的資料匯流排的定義不同,因此需要分別進行討論在系統層級上如何處理端模式轉換。
在一個大端處理器系統中,需要處理大端處理器對小端外設的訪問。
1.1.2.1 大端處理器對32位小端外設進行訪問
大端處理器採用32位匯流排與小端外設進行訪問時,大端處理器的32位元據匯流排的第0~7位用來處理OP0,第8~15位用來處理OP1,第16~23位用來處理OP2,第24~31位用來處理OP3。而32位的小端裝置使用資料匯流排的第31~24位用來處理OP0,第23~16位用來處理OP1,第15~8位用來處理OP2,第7~0位用來處理OP3。
大端處理器,如MPC8541,使用stw,sth,stb和lwz,lhz,lbz指令對32位的外部裝置進行訪問。在這些指令結束後,存放在外部裝置的資料將被讀入MPC8541的通用寄存器中。為保證軟體的一致性,當訪問結束後,存放在通用寄存器的位元組序,即OP0,OP1,OP2和OP3必須要和存放在小端外設的位元組序一致。此時在使用大端處理器的資料匯流排串連小端外設時必須要進行一定的處理,按照某種拓撲結構串連以保證軟體的一致性。大端處理器資料匯流排與小端外設進行串連的拓撲結構4.6所示。
4.6所示,採用大端處理器訪問小端裝置時,將各自的OP0~OP3欄位直接相連。在大端處理器的32位元據匯流排的最高位為0,最低位為31;而小端裝置的最高位為31,最低位為0。因此硬體工程師在進行訊號串連時需要將採用大端處理器的0~31位分別與小端裝置的31~0位一一對應,進行互連。
1.1.2.2 大端處理器對8,16位小端外設進行訪問
大端處理器使用8位,16位元據匯流排對8位,16位的小端外設進行串連。對於32位處理器,用來串連外設的匯流排一般是32位。因此體繫結構工程師在進行大端處理器匯流排設計時有兩種選擇,是採用32位匯流排的高端部分(第0~15欄位)還是低端部分(第16~31欄位)串連小端裝置。PowerPC處理器使用32位匯流排的高端部分,即資料匯流排的第0~15位串連16位的小端裝置,使用0~7位串連8位的小端裝置。
PowerPC處理器採用16位匯流排與16位的小端外設進行訪問時,PowerPC處理器的16位元據匯流排的第0~7位用來處理OP0,第8~15位用來處理OP1。而16位的小端裝置使用資料匯流排的第15~8位用來處理OP0,第7~0位用來處理OP1。
PowerPC處理器採用8位匯流排與8位的小端外設進行訪問時,PowerPC處理器的8位元據匯流排的第0~7欄位用來處理OP0。而8位的小端裝置使用資料匯流排的第7~0位用來處理OP1。大端處理器與小端外設的串連關係4.7所示。
與32位匯流排介面類似,PowerPC處理器可以使用stw,sth,stb和lwz,lhz,lbz指令對32位的外部裝置進行訪問,並將資料存放在相應的通用寄存器中。當訪問結束後,存放在通用寄存器的位元組序,即OP0,OP1必須要和存放在小端外設的位元組序一致。
PowerPC處理器對8位的小端外設進行訪問時,一個匯流排周期只能訪問8位元據,如果處理器使用stw或者lwz指令訪問8位的小端裝置內的32位元據時,在資料匯流排上將OP0,OP1,OP2和OP3依次傳遞到PowerPC的通用寄存器中。
PowerPC處理器對16位的小端外設進行訪問時,一個匯流排周期只能訪問16位元據,如果處理器使用stw或者lwz指令訪問16位的小端裝置內的32位元據時,在資料匯流排上將OP0~1和OP2~3依次傳遞到PowerPC的通用寄存器中。
PowerPC處理器使用sth或者lhz指令訪問16位的小端裝置時,16位的小端裝置將資料的第15~0位,傳遞到PowerPC處理器的匯流排的第0~15位,然後再將資料最終傳遞給相應的通用寄存器。這裡有許多讀者會感到困惑,因為為了保證軟體的一致性,PowerPC處理器使用lhz指令訪問16位的小端裝置的16位寄存器時,需要將結果儲存在通用寄存器的第16~31位,而不是0~15位。究竟PowerPC處理器是如何將系統匯流排中0~15位的資料搬移到寄存器的第16~31位中的呢?為此我們需要對lhz指令進行分析。
lhz rD,d(rA) if rA = 0 then b ← 0 else b ← (rA) EA ← b + EXTS(d) rD ← (24)0 || MEM(EA, 1) |
由lhz指令的以上描述得知lhz指令將來自資料匯流排上的OP0與OP1直接存入寄存器的第16~31位,而將第0~15位直接清零。
PowerPC處理器使用stb或者lbz指令訪問8位的小端裝置時,8位的小端裝置將資料的第7~0位,傳遞到PowerPC處理器的匯流排的第0~7位,然後再將資料最終傳遞給相應的通用寄存器,lbz指令的描述如下所示。
lbz rD,d(rA) if rA = 0 then b ← 0 else b ← (rA) EA ← b + EXTS(d) rD ← (24)0 || MEM(EA, 1) |
由lhz指令的以上描述得知lhz指令將來自資料匯流排上的OP0直接存入寄存器的第24~31位,而將第0~23位清零。
本節分別描述了大端處理器的32位,16位及8位元據匯流排與32位,16位和8位的小端裝置進行串連。如果大端處理器的資料匯流排需要同時支援小端裝置的32位,16位及8位的資料傳送方式,端模式的處理將會更加複雜。IC的設計人員在設計PCI匯流排橋片的時候將會遇到這一類問題,此時設計人員將使用多路匯流排開關來解決這一問題。端模式問題的解決需要軟硬體協調處理,並在指令集上加以支援。對於小端處理器而言,需要使用軟體轉換的方法實現大小端模式的匹配;對於大端處理器而言,在外部資料匯流排與小端外設的串連時必須要考慮資料匯流排串連的拓撲結構。
以上
來自順子複製“http://hi.baidu.com/boshenshen/blog/item/8c9d1e647e8e2ef4f6365452.html”