大端和小端格式(2010-08-06 22:00:02)
端模式(Endian)的這個(gè)詞出自Jonathan Swift書(shū)寫(xiě)的《格列佛游記》。這本書(shū)根據(jù)將雞蛋敲開(kāi)的方法不同將所有的人分為兩類,從圓頭開(kāi)始將雞蛋敲開(kāi)的人被歸為Big Endian,從尖頭開(kāi)始將雞蛋敲開(kāi)的人被歸為L(zhǎng)ittile Endian。小人國(guó)的內(nèi)戰(zhàn)就源于吃雞蛋時(shí)是究竟從大頭(Big-Endian)敲開(kāi)還是從小頭(Little-Endian)敲開(kāi)。在計(jì)算機(jī)業(yè)Big Endian和Little Endian也幾乎引起一場(chǎng)戰(zhàn)爭(zhēng)。在計(jì)算機(jī)業(yè)界,Endian表示數(shù)據(jù)在存儲(chǔ)器中的存放順序。下文舉例說(shuō)明在計(jì)算機(jī)中大小端模式的區(qū)別。
如果將一個(gè)32位的整數(shù)0x12345678存放到一個(gè)整型變量(int)中,這個(gè)整型變量采用大端或者小端模式在內(nèi)存中的存儲(chǔ)由下表所示。為簡(jiǎn)單起見(jiàn),本書(shū)使用OP0表示一個(gè)32位數(shù)據(jù)的最高字節(jié)MSB(Most Significant Byte),使用OP3表示一個(gè)32位數(shù)據(jù)最低字節(jié)LSB(Least Significant Byte)。
如果將一個(gè)16位的整數(shù)0x1234存放到一個(gè)短整型變量(short)中。這個(gè)短整型變量在內(nèi)存中的存儲(chǔ)在大小端模式由下表所示。
由上表所知,采用大小模式對(duì)數(shù)據(jù)進(jìn)行存放的主要區(qū)別在于在存放的字節(jié)順序,大端方式將高位存放在低地址,小端方式將低位存放在高地址。采用大端方式進(jìn)行數(shù)據(jù)存放符合人類的正常思維,而采用小端方式進(jìn)行數(shù)據(jù)存放利于計(jì)算機(jī)處理。到目前為止,采用大端或者小端進(jìn)行數(shù)據(jù)存放,其孰優(yōu)孰劣也沒(méi)有定論。 有的處理器系統(tǒng)采用了小端方式進(jìn)行數(shù)據(jù)存放,如Intel的奔騰。有的處理器系統(tǒng)采用了大端方式進(jìn)行數(shù)據(jù)存放,如IBM半導(dǎo)體和Freescale的PowerPC處理器。不僅對(duì)于處理器,一些外設(shè)的設(shè)計(jì)中也存在著使用大端或者小端進(jìn)行數(shù)據(jù)存放的選擇。 因此在一個(gè)處理器系統(tǒng)中,有可能存在大端和小端模式同時(shí)存在的現(xiàn)象。這一現(xiàn)象為系統(tǒng)的軟硬件設(shè)計(jì)帶來(lái)了不小的麻煩,這要求系統(tǒng)設(shè)計(jì)工程師,必須深入理解大端和小端模式的差別。大端與小端模式的差別體現(xiàn)在一個(gè)處理器的寄存器,指令集,系統(tǒng)總線等各個(gè)層次中。 1.1.1
從軟件的角度上,不同端模式的處理器進(jìn)行數(shù)據(jù)傳遞時(shí)必須要考慮端模式的不同。如進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳遞時(shí),必須要考慮端模式的轉(zhuǎn)換。有過(guò)Socket接口編程經(jīng)驗(yàn)的程序員一定使用過(guò)以下幾個(gè)函數(shù)用于大小端字節(jié)序的轉(zhuǎn)換。 ¨ ¨ ¨ ¨ 其中互聯(lián)網(wǎng)使用的網(wǎng)絡(luò)字節(jié)順序采用大端模式進(jìn)行編址,而主機(jī)字節(jié)順序根據(jù)處理器的不同而不同,如PowerPC處理器使用大端模式,而Pentuim處理器使用小端模式。 大端模式處理器的字節(jié)序到網(wǎng)絡(luò)字節(jié)序不需要轉(zhuǎn)換,此時(shí)ntohs(n)=n,ntohl = n;而小端模式處理器的字節(jié)序到網(wǎng)絡(luò)字節(jié)必須要進(jìn)行轉(zhuǎn)換,此時(shí)ntohs(n) = __swab16(n),ntohl = __swab32(n)。__swab16與__swab32函數(shù)定義如下所示。
PowerPC處理器提供了lwbrx,lhbrx,stwbrx,sthbrx四條指令用于處理字節(jié)序的轉(zhuǎn)換以優(yōu)化__swab16和__swap32這類函數(shù)。此外PowerPC處理器中的rlwimi指令也可以用來(lái)實(shí)現(xiàn)__swab16和__swap32這類函數(shù)。在Linux PowerPC中,定義了一系列有關(guān)字節(jié)序轉(zhuǎn)換的函數(shù),其詳細(xì)定義在./include/asm-powerpc/byteorder.h文件中。 程序員在對(duì)普通文件進(jìn)行處理也需要考慮端模式問(wèn)題。在大端模式的處理器下對(duì)文件的32,16位讀寫(xiě)操作所得到的結(jié)果與小端模式的處理器不同。讀者單純從軟件的角度理解上遠(yuǎn)遠(yuǎn)不能真正理解大小端模式的區(qū)別。事實(shí)上,真正的理解大小端模式的區(qū)別,必須要從系統(tǒng)的角度,從指令集,寄存器和數(shù)據(jù)總線上深入理解,大小端模式的區(qū)別。 1.1.2
除了4.2.1節(jié)中,軟件上對(duì)不同端模式編程上的差異,處理器在硬件上也由于端模式問(wèn)題在設(shè)計(jì)中有所不同。從系統(tǒng)的角度上看,端模式問(wèn)題對(duì)軟件和硬件的設(shè)計(jì)帶來(lái)了不同的影響,當(dāng)一個(gè)處理器系統(tǒng)中大小端模式同時(shí)存在時(shí),必須要對(duì)這些不同端模式的訪問(wèn)進(jìn)行特殊的處理。 PowerPC處理器主導(dǎo)網(wǎng)絡(luò)市場(chǎng),可以說(shuō)絕大多數(shù)的通信設(shè)備都使用PowerPC處理器進(jìn)行協(xié)議處理和其他控制信息的處理,這也可能也是在網(wǎng)絡(luò)上的絕大多數(shù)協(xié)議都采用大端編址方式的原因。因此在有關(guān)網(wǎng)絡(luò)協(xié)議的軟件設(shè)計(jì)中,使用小端方式的處理器需要在軟件中處理端模式的轉(zhuǎn)變。而Pentium主導(dǎo)個(gè)人機(jī)市場(chǎng),因此多數(shù)用于個(gè)人機(jī)的外設(shè)都采用小端模式,包括一些在網(wǎng)絡(luò)設(shè)備中使用的PCI總線,F(xiàn)lash等設(shè)備,這也要求硬件工程師在硬件設(shè)計(jì)中注意端模式的轉(zhuǎn)換。 本書(shū)中的小端外設(shè)是指這種外設(shè)中的寄存器以小端方式進(jìn)行存儲(chǔ),如PCI設(shè)備的配置空間,NOR FLASH中的寄存器等等。 對(duì)于有些設(shè)備,如DDR顆粒,沒(méi)有以小端方式存儲(chǔ)的寄存器,因此從邏輯上講并不需要對(duì)端模式進(jìn)行轉(zhuǎn)換。在設(shè)計(jì)中,只需要將雙方數(shù)據(jù)總線進(jìn)行一一對(duì)應(yīng)的互連,而不需要進(jìn)行數(shù)據(jù)總線的轉(zhuǎn)換。 如果從實(shí)際應(yīng)用的角度說(shuō),采用小端模式的處理器需要在軟件中處理端模式的轉(zhuǎn)換,因?yàn)椴捎眯《四J降奶幚砥髟谂c小端外設(shè)互連時(shí),不需要任何轉(zhuǎn)換。 而采用大端模式的處理器需要在硬件設(shè)計(jì)時(shí)處理端模式的轉(zhuǎn)換。大端模式處理器需要在寄存器,指令集,數(shù)據(jù)總線及數(shù)據(jù)總線與小端外設(shè)的連接等等多個(gè)方面進(jìn)行處理,以解決與小端外設(shè)連接時(shí)的端模式轉(zhuǎn)換問(wèn)題。 在寄存器和數(shù)據(jù)總線的位序定義上,基于大小端模式的處理器有所不同。 一個(gè)采用大端模式的32位處理器,如基于E500內(nèi)核的MPC8541,將其寄存器的最高位msb(most significant bit)定義為0,最低位lsb(lease significant bit)定義為31;而小端模式的32位處理器,將其寄存器的最高位定義為31,低位地址定義為0。 與此向?qū)?yīng),采用大端模式的32位處理器數(shù)據(jù)總線的最高位為0,最高位為31;采用小端模式的32位處理器的數(shù)據(jù)總線的最高位為31,最低位為0。如圖4.5所示。
大小端模式處理器外部總線的位序也遵循著同樣的規(guī)律,根據(jù)所采用的數(shù)據(jù)總線是32位,16位和8位,大小端處理器外部總線的位序有所不同。 ¨ ¨ ¨ 由上分析,我們可以得知對(duì)于8位,16位和32位寬度的數(shù)據(jù)總線,采用大端模式時(shí)數(shù)據(jù)總線的msb和MSB的位置都不會(huì)發(fā)生變化,而采用小端模式時(shí)數(shù)據(jù)總線的lsb和LSB位置也不會(huì)發(fā)生變化。 為此,大端模式的處理器對(duì)8位,16位和32位的內(nèi)存訪問(wèn)(包括外設(shè)的訪問(wèn))一般都包含第0~7字段,即MSB。小端模式的處理器對(duì)8位,16位和32位的內(nèi)存訪問(wèn)都包含第7~0位,小端方式的第7~0字段,即LSB。 由于大小端處理器的數(shù)據(jù)總線其8位,16位和32位寬度的數(shù)據(jù)總線的定義不同,因此需要分別進(jìn)行討論在系統(tǒng)級(jí)別上如何處理端模式轉(zhuǎn)換。 在一個(gè)大端處理器系統(tǒng)中,需要處理大端處理器對(duì)小端外設(shè)的訪問(wèn)。 1.1.2.1
大端處理器采用32位總線與小端外設(shè)進(jìn)行訪問(wèn)時(shí),大端處理器的32位數(shù)據(jù)總線的第0~7位用來(lái)處理OP0,第8~15位用來(lái)處理OP1,第16~23位用來(lái)處理OP2,第24~31位用來(lái)處理OP3。而32位的小端設(shè)備使用數(shù)據(jù)總線的第31~24位用來(lái)處理OP0,第23~16位用來(lái)處理OP1,第15~8位用來(lái)處理OP2,第7~0位用來(lái)處理OP3。 大端處理器,如MPC8541,使用stw,sth,stb和lwz,lhz,lbz指令對(duì)32位的外部設(shè)備進(jìn)行訪問(wèn)。在這些指令結(jié)束后,存放在外部設(shè)備的數(shù)據(jù)將被讀入MPC8541的通用寄存器中。為保證軟件的一致性,當(dāng)訪問(wèn)結(jié)束后,存放在通用寄存器的字節(jié)序,即OP0,OP1,OP2和OP3必須要和存放在小端外設(shè)的字節(jié)序一致。此時(shí)在使用大端處理器的數(shù)據(jù)總線連接小端外設(shè)時(shí)必須要進(jìn)行一定的處理,按照某種拓?fù)浣Y(jié)構(gòu)連接以保證軟件的一致性。大端處理器數(shù)據(jù)總線與小端外設(shè)進(jìn)行連接的拓?fù)浣Y(jié)構(gòu)如圖4.6所示。
如圖4.6所示,采用大端處理器訪問(wèn)小端設(shè)備時(shí),將各自的OP0~OP3字段直接相連。在大端處理器的32位數(shù)據(jù)總線的最高位為0,最低位為31;而小端設(shè)備的最高位為31,最低位為0。因此硬件工程師在進(jìn)行信號(hào)連接時(shí)需要將采用大端處理器的0~31位分別與小端設(shè)備的31~0位一一對(duì)應(yīng),進(jìn)行互連。 1.1.2.2
大端處理器使用8位,16位數(shù)據(jù)總線對(duì)8位,16位的小端外設(shè)進(jìn)行連接。對(duì)于32位處理器,用來(lái)連接外設(shè)的總線一般是32位。因此體系結(jié)構(gòu)工程師在進(jìn)行大端處理器總線設(shè)計(jì)時(shí)有兩種選擇,是采用32位總線的高端部分(第0~15字段)還是低端部分(第16~31字段)連接小端設(shè)備。PowerPC處理器使用32位總線的高端部分,即數(shù)據(jù)總線的第0~15位連接16位的小端設(shè)備,使用0~7位連接8位的小端設(shè)備。 PowerPC處理器采用16位總線與16位的小端外設(shè)進(jìn)行訪問(wèn)時(shí),PowerPC處理器的16位數(shù)據(jù)總線的第0~7位用來(lái)處理OP0,第8~15位用來(lái)處理OP1。而16位的小端設(shè)備使用數(shù)據(jù)總線的第15~8位用來(lái)處理OP0,第7~0位用來(lái)處理OP1。 PowerPC處理器采用8位總線與8位的小端外設(shè)進(jìn)行訪問(wèn)時(shí),PowerPC處理器的8位數(shù)據(jù)總線的第0~7字段用來(lái)處理OP0。而8位的小端設(shè)備使用數(shù)據(jù)總線的第7~0位用來(lái)處理OP1。大端處理器與小端外設(shè)的連接關(guān)系如圖4.7所示。
與32位總線接口類似,PowerPC處理器可以使用stw,sth,stb和lwz,lhz,lbz指令對(duì)32位的外部設(shè)備進(jìn)行訪問(wèn),并將數(shù)據(jù)存放在相應(yīng)的通用寄存器中。當(dāng)訪問(wèn)結(jié)束后,存放在通用寄存器的字節(jié)序,即OP0,OP1必須要和存放在小端外設(shè)的字節(jié)序一致。 PowerPC處理器對(duì)8位的小端外設(shè)進(jìn)行訪問(wèn)時(shí),一個(gè)總線周期只能訪問(wèn)8位數(shù)據(jù),如果處理器使用stw或者lwz指令訪問(wèn)8位的小端設(shè)備內(nèi)的32位數(shù)據(jù)時(shí),在數(shù)據(jù)總線上將OP0,OP1,OP2和OP3依次傳遞到PowerPC的通用寄存器中。 PowerPC處理器對(duì)16位的小端外設(shè)進(jìn)行訪問(wèn)時(shí),一個(gè)總線周期只能訪問(wèn)16位數(shù)據(jù),如果處理器使用stw或者lwz指令訪問(wèn)16位的小端設(shè)備內(nèi)的32位數(shù)據(jù)時(shí),在數(shù)據(jù)總線上將OP0~1和OP2~3依次傳遞到PowerPC的通用寄存器中。 PowerPC處理器使用sth或者lhz指令訪問(wèn)16位的小端設(shè)備時(shí),16位的小端設(shè)備將數(shù)據(jù)的第15~0位,傳遞到PowerPC處理器的總線的第0~15位,然后再將數(shù)據(jù)最終傳遞給相應(yīng)的通用寄存器。這里有許多讀者會(huì)感到困惑,因?yàn)闉榱吮WC軟件的一致性,PowerPC處理器使用lhz指令訪問(wèn)16位的小端設(shè)備的16位寄存器時(shí),需要將結(jié)果保存在通用寄存器的第16~31位,而不是0~15位。究竟PowerPC處理器是如何將系統(tǒng)總線中0~15位的數(shù)據(jù)搬移到寄存器的第16~31位中的呢?為此我們需要對(duì)lhz指令進(jìn)行分析。
由lhz指令的以上描述得知lhz指令將來(lái)自數(shù)據(jù)總線上的OP0與OP1直接存入寄存器的第16~31位,而將第0~15位直接清零。 PowerPC處理器使用stb或者lbz指令訪問(wèn)8位的小端設(shè)備時(shí),8位的小端設(shè)備將數(shù)據(jù)的第7~0位,傳遞到PowerPC處理器的總線的第0~7位,然后再將數(shù)據(jù)最終傳遞給相應(yīng)的通用寄存器,lbz指令的描述如下所示。
由lhz指令的以上描述得知lhz指令將來(lái)自數(shù)據(jù)總線上的OP0直接存入寄存器的第24~31位,而將第0~23位清零。 本節(jié)分別描述了大端處理器的32位,16位及8位數(shù)據(jù)總線與32位,16位和8位的小端設(shè)備進(jìn)行連接。如果大端處理器的數(shù)據(jù)總線需要同時(shí)支持小端設(shè)備的32位,16位及8位的數(shù)據(jù)傳送方式,端模式的處理將會(huì)更加復(fù)雜。IC的設(shè)計(jì)人員在設(shè)計(jì)PCI總線橋片的時(shí)候?qū)?huì)遇到這一類問(wèn)題,此時(shí)設(shè)計(jì)人員將使用多路總線開(kāi)關(guān)來(lái)解決這一問(wèn)題。端模式問(wèn)題的解決需要軟硬件協(xié)調(diào)處理,并在指令集上加以支持。對(duì)于小端處理器而言,需要使用軟件轉(zhuǎn)換的方法實(shí)現(xiàn)大小端模式的匹配;對(duì)于大端處理器而言,在外部數(shù)據(jù)總線與小端外設(shè)的連接時(shí)必須要考慮數(shù)據(jù)總線連接的拓?fù)浣Y(jié)構(gòu)。 |
|
來(lái)自: Upandi > 《我的圖書(shū)館》