成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux內核完全剖析---數學協處理器

系統 Linux
在計算機上執行計算量較大的運算通常可以使用三種方法來完成。一種是直接使用CPU普通指令執行計算。由于CPU指令是一類通用指令,因此使用這些指令進行復雜和大量的運算工作需要編制復雜的計算子程序

內核目錄kernel/math目錄中包含數學協處理器仿真處理代碼文件,共包含9個C語言程序,見表11-1。本章內容與具體硬件結構關系非常密切,因此需要讀者具備較深的有關Intel CPU和協處理器指令代碼結構的知識。但好在這些內容與內核實現關系不大,因此跳過本章內容并不會妨礙讀者對內核實現方法的完整理解。不過若能理解本章內容,那么對于實現系統級應用程序(例如匯編和反匯編等程序)和編制協處理器浮點處理程序將有很大幫助。  

Linux內核完全剖析---數學協處理器(1)

11.1 總體功能描述

在計算機上執行計算量較大的運算通常可以使用三種方法來完成。一種是直接使用CPU普通指令執行計算。由于CPU指令是一類通用指令,因此使用這些指令進行復雜和大量的運算工作需要編制復雜的計算子程序,并且一般只有通曉數學和計算機的專業人員才能編制出這些子程序。另一種方法是為CPU配置一個數學協處理器芯片。使用協處理器芯片可以極大地簡化數學處理編程難度,并且運算速度和效率也會成倍提高,但需要另外增加硬件投入。還有一種方法是在系統內核級使用仿真程序來模擬協處理器的運算功能。這種方法可能是運算速度和效率最低的一種,但與使用了協處理器一樣可以方便程序員編制計算程序,并且能夠在對程序不加任何改動的情況下把所編程序運行在具有協處理器的機器上。

在Linux 0.1x甚至Linux 0.9x內核開發初期,數學協處理器芯片80387(或其兼容芯片)價格不菲,并且一直是普通PC中的奢侈品。因此除非在科學計算量很大的場合或特別需要之處,一般PC中不會安裝80387芯片。雖然現在的Intel 處理器中都內置了數學協處理器功能部件,從而現在的操作系統中已經無須包含協處理器仿真程序代碼,但是因為80387仿真程序完全建立在模擬80387芯片處理結構和分析指令代碼結構基礎上,因此學習本章內容后讀者不僅能夠了解80387協處理器編程方法,而且對編寫匯編和反匯編處理程序也有很大幫助。

如果80386 PC中沒有包括80387數學協處理器芯片,那么當CPU執行到一條協處理器指令時就會引發“設備不存在”異常中斷7。該異常過程的處理代碼在sys_call.s第158行開始處。如果操作系統在初始化時已經設置了CPU控制寄存器CR0的EM位,那么此時就會調用math_emulate.c程序中的math_emulate()函數來用軟件“解釋”執行每一條協處理器指令。

Linux 0.12內核中的數學協處理器仿真程序math_emulate.c完全模擬了80387芯片執行協處理器指令的方式。在處理一條協處理器指令之前,該程序會首先使用數據結構等類型在內存中建立起一個“軟”80387環境,包括模仿所有80387內部棧式累加器組ST[]、控制字寄存器CWD、狀態字寄存器SWD和特征字TWD(TAG word)寄存器,然后分析引起異常的當前協處理器指令操作碼,并根據具體操作碼執行相應的數學模擬運算。因此在描述math_emulate.c程序的處理過程之前,有必要先介紹一下80387的內部結構和基本工作原理。

11.1.1 浮點數據類型

本節主要介紹協處理器使用的浮點數據類型。首先簡單回顧一下整型數的幾種表示方式,然后說明浮點數的幾種標準表示方式以及在80387中運算時使用的臨時實數表示方法。

1.整型數據類型

對于Intel 32位CPU來講,有三種基本無符號數據類型:字節(byte)、字(word)和雙字(double word),分別有8、16和32位。無符號數的表示方式很簡單,字節中的每個位都代表一個二進制數,并且根據其所處位置具有不同的權值。例如一個無符號二進制數0b10001011可表示為:

U = 0b10001011 = 1×27 + 0×26 + 0×25 + 0×24 + 1×23 + 0×22 + 1×21 + 1×20 = 139

它對應十進制數139。其中權值最小的一位(20)通常被稱為最低有效位(LSB,Least Significant Bit),而權值最大的位(27)被稱為最高有效位(MSB,Most Significant Bit)。

#p#而計算機中具有負數值的整型數據表示方法通常也有三種:2的補碼(Two’s complement)、符號數(Sign magnitude)和偏置數(biased number)表示方式。表11-2給出了這三種形式表示的一些數值。

  

Linux內核完全剖析---數學協處理器(1)

2的補碼(二進制補碼)表示法是目前大多數計算機CPU使用的整數表示方法,因為CPU的無符號數的簡單加法也適用于這種格式的數據運算。使用這種表示法,一個數的負數就是該數每位取反后再加1。MSB位就是該數的符號位。MSB= 0表示一個正數;MSB = 1表示負數。80386 CPU具有8位(1字節)、16位(1字)和32位(雙字)2的補碼數據類型,分別可以表示的數據范圍是:-128~127、-32768~32767、-2147483648~2146473647。另外,在80387仿真程序中使用了一種稱為臨時整數類型的格式,如圖11-1所示。它的長度為10字節,可表示64位整型數據類型。其中低8字節最大可表示63位無符號數,而最高2字節僅使用了最高有效位來表示數值的正負。對于32位整型值則使用低4字節來表示,16位整型值則使用低2字節表示。

數的偏置表示法通常用于表示浮點數格式中的指數字段值。把一個數加上指定的偏置值就是該數的偏置數表示的值。從表11-1可以看出,這種表示方法的數值具有無符號數的大小順序。因此這種表示方法易于比較數值大小。即大數值的偏置表示值總是無符號值的一個大數,而其他兩種表示方式卻并非如此。

符號數表示法有一個位專門用于表示符號(0表示正數,1表示負數),而其他位則與無符號整數表示的數值相同。浮點數的有效數(尾數)部分使用的就是這種表示方法,而符號位代表整個浮點數的正負符號。


Linux內核完全剖析---數學協處理器(1)

2.BCD碼數據類型

BCD(Binary Coded Decimal)碼數值是二進制編碼的十進制數值,對于壓縮的BCD編碼,每個字節可表示兩位十進制數,其中每4位表示一位0~9的數。例如,十進制數59的壓縮BCD碼表示是0x01011001。對于非壓縮的BCD碼,每個字節只使用低4位表示1位十進制數。

80387協處理器支持10字節壓縮BCD碼的表示和運算,可表示18位十進制數,如圖11-2所示。與臨時整數格式類似,其中最高字節僅使用了符號位(最高有效位)來表示數值的正負,其余位均不用。若BCD碼數據是負數,則會使用最高地址處1字節的最高有效位置1來表示負值。否則最高字節所有位均是0。

  

Linux內核完全剖析---數學協處理器(1)



#p#3.浮點數據類型

具有整數部分和小數(尾數)部分的數稱為實數或浮點數。實際上整型數是小數部分為0的實數,是實數集的一個子集。由于計算機使用固定長度位來表示一個數,因此并不能精確地表示所有實數。由于計算機表示實數時為了在固定長度位內能表示盡量精確的實數值,分配給表示小數部分的位個數并不是固定的,即小數點是可以“浮動”的,因此計算機表示的實數數據類型也稱為浮點數。為了便于程序移植,目前計算機中都使用IEEE標準754指定的浮點數表示方式來表示實數。

這種實數表示方式的一般格式如圖 11-3 所示。它由有效數(Significant)部分、指數(Exponent)部分和符號位(Sign)組成。80387協處理器支持三種實數類型,它們每個部分使用的位數如圖11-4所示。

  

Linux內核完全剖析---數學協處理器(1)

  

Linux內核完全剖析---數學協處理器(1)

其中S是一個位的符號位。S=1表示是負實數;S=0表示是正實數。有效數(Significant)給出了實數數值的有效位數或尾數。當使用指數時,一個實數可以表示成多種形式。例如十進制數字10.34可以表示成1034.0×10-2、10.34×100、1.034×101或0.1034×102等。為了使計算能夠得到最大精度值,我們總是對實數進行規格化(Normalize)處理,即調整實數的指數值,使得二進制最高有效數值總是1,并且小數點就位于其右側。因此,上述例子正確的規格化處理結果就是1.034×101。對于二進制數來說就是1.XXXXX×2N(其中X是1或0)。如果我們總是使用這種形式來表示一個實數,那么小數點左邊肯定是1。所以在80387的短實數(單精度)和長實數(雙精度)格式中,這個“1”就沒有必要明確地表示出來。因此在短實數或長實數的二進制有效數中,0x0111...010實際上就是0x1.0111...010。

格式中的指數字段含有把一個數表示成規格化形式時所需要的2的冪次值。正如前面提到的,為了便于數字大小的比較,80387使用偏置數形式來存儲指數值。短實數、長實數和臨時實數的偏置基量分別是127、1023和16383。因此一個短實數指數值0b10000000實際表示21(0b01111111 + 0b00000001)。

另外,臨時實數是80387內部運算時表示數的格式。它的最高有效數1被明確地放置在位63處,并且無論你給出的數是什么數據類型的(例如,整型數、短實數或BCD碼數等),80387都會把它轉換成臨時實數格式。80387這樣做的目的是為了使得精度最大化并且盡量減少運算過程中的溢出異常。顯式地把1表示出來是因為80387在運算過程中確實需要該位(用于表示極小的數值)。當輸入到80387中的短型或長型實數被轉換成臨時實數格式時,就會明確地在位63處放置一個1。

4.特殊實數

與上面表中格式某些值無法表示的情況類似,使用實數格式表示的某些值也有其特殊含義。對于80位長度格式的臨時實數,80387并沒有使用其可表示的所有范圍數值。表11-3是80387使用中的臨時實數所能表示的所有可能的數值,其中有效數一欄虛線左側1位表示臨時實數位63,即明確表示數值1的位。短實數和長實數沒有此位,因此也沒有表中的偽非規格化類別。下面說明其中的一些特殊值:零值、無窮值、非規格化值、偽非規格化值以及信號NaN(Not a Number)和安靜NaN。

  

Linux內核完全剖析---數學協處理器(1)

零是指數和有效數均為0的值,其余指數為0的值作保留,即指數是0的值不能表示一個正常實數值。無窮值是指數值為全1、有效數值為全零的值,而且指數值為0x11...11的所有其余值也作保留使用。

#p#非規格化數(Denormals)是一種用于表示非常小數值的特殊類值。它可以表示漸進下溢或漸進精度丟失情況。通常要求數值表示成規格化數(左移直到有效數的最高有效位是位1)。然而非規格化數的有效數最高有效位不是1。此時偏置型指數0x00...00分別是值為2-126、2-1022、2-16382的短實數、長實數和臨時實數指數值的特殊表示方式。這種表示比較特殊,因為偏置型指數0x00...01對三種實數類型也分別表示相同的指數值2-126、2-1022、2-16382。

偽非規格化類數值(Pseudo-denormals)是有效數最高有效位為1的值,而非規格化類數值的該位是0。偽非規格化數很少見,它們可以用規格化類數來表示卻沒有這么做。因為上面已經說明特殊的偏置指數0x00...00與規格化數的指數0x00...01具有相同的值。因此偽非規格化類數可以表示成規格化類數值。

另一種特殊情況是NaN。NaN是指“不是一個數”(Not a Number)。NaN有兩種形式:會產生信號(Signaling)的和不會產生信號的或稱為安靜的(Quiet)。當一個產生信號的NaN(SNaN)被用于操作時就會引發一個無效操作異常,而一個安靜的NaN(QNaN)則不會。SnaN是一類會引發無效操作異常的數值。使用的方法就是程序先把變量都初始化為SNaN值,在實際使用這個變量時還需要對其進行真正的賦值。這樣若操作過程中使用了一個未被初始化的值就會引發異常。當然,NaN類數值也可以用來存儲其他信息。

80387自身不會產生SNaN類的值,但會產生QNaN類的值。當發生無效操作異常時80387就會產生一個QNaN類值,并且操作的結果將是不確定值(Indefinite)。不確定值是一種特殊的QNaN類值。每種數據類型都有一個表示不確定值的數。對于整型數則是用其最大負數來表示其不確定值。

另外還有一些80387不支持的臨時實數值,即那些沒有在上表中列出的數值范圍。若80387遇到這些數值,就會引發無效操作異常。

11.1.2 數學協處理器功能和結構

80386雖然是一個通用微處理器,但其指令并不是非常適用于數學計算。因此若使用80386來執行數學計算,那么就需要編制非常復雜的程序,而且執行效率也相對較低。80387作為80386的輔助處理芯片,極大地擴展了程序員的編程范圍。以前程序員不太可能做到的事,使用協處理器后就可以很容易地,并且快速而精確地完成。

80387具有一組特別的寄存器。這組寄存器可以讓80387直接操作比80386所能處理的大或小幾個數量級的數值。80386使用2進制補數方式表示一個數。這種方法不適合用來表示小數。而80387并不使用2的補數方法來表示數值,它使用了IEEE標準754規定的80位(10個字節)格式。這種格式不僅具有廣泛的兼容性,而且能夠使用二進制表示極大(或極小)的數值。例如,它能表示大到1.21×104932數值,也能處理小到3.3×10-4932的數。80387并不保持固定小數點的位置,如果數值小的話就多使用一些小數位,如果數值大的話就少用幾位小數位。因此小數點的位置是可以“浮動”的。這也是術語“浮點”數的由來。

為支持浮點運算,80387中包含三組寄存器,如圖11-5所示。① 8個80位長的數據寄存器(累加器),可用于臨時存放8個浮點操作數,并且這些累加器可以執行棧式操作;② 3個16位狀態和控制寄存器:一個狀態字寄存器SWD、一個控制字寄存器CWD和一個特征(TAG)寄存器;③ 4個32位出錯指針寄存器(FIP、FCS、FOO和FOS)用于確定導致80387內部異常的指令和內存操作數。

  

Linux內核完全剖析---數學協處理器(1)



#p#

1.棧式浮點累加器

在浮點指令執行過程中,8個80位長度的物理寄存器組被作為棧式累加器使用。雖然每個80位寄存器有固定的物理順序位置(即左邊的0~7),但當前棧頂則由ST(即ST(0))來指明。ST之下的其余累加器使用名稱ST(i)來指明(i = 1~7)。至于哪個80位物理寄存器是當前棧頂ST,則由具體操作過程指定。在狀態字寄存器中名稱為TOP的3位字段含有當前棧頂ST對應的80位物理寄存器的絕對位置。一個入棧(Push)操作將會把TOP字段值遞減1,并把新值存儲于新的ST中。在入棧操作之后,原來的ST變成了ST(1),而原來的ST(7)變成了現在的ST。即所有累加器的名稱都從原來的ST(i)變成了ST((i+1)&0x7)。一個出棧(Pop)操作將會讀出當前ST對應的80位寄存器的值,并且把TOP字段值遞增1。因此在出棧操作之后,原來的ST(即ST(0))變成了ST(7),原來的ST(1)成為新的ST。即所有累加器的名稱都從原來的ST(i)變成ST((i-1)& 0x7)。

ST的作用如同一個累加器是因為它被作為所有浮點指令的一個隱含操作數。若有另一個操作數,那么該第2個操作數可以是任何其余累加器之一ST(i),或者是一個內存操作數。棧中的每個累加器為一個實數提供了使用臨時實數格式存儲的80位空間,其最高位(s)是符號位,位78~64是15位的指數字段,位63~0是64位的有效數字段。

浮點指令被設計成能充分利用這個累加器棧模式。浮點加載指令(FLD等)會從內存中讀取一個操作數并壓入棧中,而浮點存儲指令則會從當前棧頂取得一個值并寫到內存中。若棧中該值不再需要時還可以同時執行出棧操作。加和乘之類的操作會把當前ST寄存器內容作為一個操作數,而另一個取自其他寄存器或內存中,并且在計算完后即把結果保存在ST中。還有一類“操作并彈出”操作形式用于在ST和ST(1)兩者之間進行運算。這種操作形式會執行一次彈出操作,然后把結果放入新的ST中。

2.狀態與控制寄存器

三個16位的寄存器(TAG字、控制字和狀態字)控制著浮點指令的操作并且為其提供狀態信息。它們的具體格式如圖11-6所示。下面逐一對它們進行說明。

(1)控制字

控制字(Control Word)可用于程序設置各種處理選項來控制80387的操作。其中可分為三個部分。位11~10的RC(Rounding Control)是舍入控制字段,用于對計算結果進行舍入操作。位9~8的PC(Precision Control)是精度控制字段,用于在保存到指定存儲單元之前對計算結果進行精度調整。所有其他操作使用臨時實數格式精度,或者使用指令指定的精度。位5~0是異常屏蔽位,用于控制協處理器異常處理。這6位對應80387可能發生的6種異常情況。其中每一種異常都可以單獨屏蔽掉。如果發生某個特定異常并且其對應屏蔽位沒有置位,那么80387就會向CPU通報這個異常,并且會讓CPU產生異常中斷int 16。然而如果設置了對應屏蔽位,那么80387就會自己處理并糾正發生的異常問題而不會通知CPU。這個寄存器隨時可以讀寫,其中各位的具體含義參見圖11-6。

(2)狀態字

在運行期間,80387會設置狀態字(Status Word)中的位,用于程序檢測特定的條件。當發生異常時,它可讓CPU確定發生異常的原因。因為所有6個協處理器異常都會讓CPU產生異常中斷int16。

(3)特征字

特征字(Tag Word)寄存器含有8個2位的Tag字段,分別對應8個物理浮點數據寄存器。這些特征字段分別指明相應的物理寄存器含有有效、零、特殊浮點數值,或者是空的。特殊數值是指那些無限值、非數值、非規格化或不支持格式的數值。特征字段Tag可用于檢測累加器堆棧上下溢出情況。如果入棧(Push)操作遞減TOP指向了一個非空寄存器,就會發生棧上溢出。如果出棧(Pop)操作企圖去讀取或彈出空寄存器,就會造成棧下溢出(Underflow)。棧的上下溢出都將引發無效操作異常。

  

Linux內核完全剖析---數學協處理器(1)



#p#3.出錯指針寄存器

出錯指針寄存器(Error-Pointer Register)是4個32位的80387寄存器,其中含有80387最后執行指令和所用數據的指針,參見圖11-6。前兩個寄存器FIP和FCS中是最后執行指令中2個操作碼的指針(忽略前綴碼)。FCS是段選擇符和操作碼,FIP是段內偏移值。后兩個寄存器FOO和FOS是最后執行指令內存操作數的指針。FOS中是段選擇符,FOO中是段內偏移值。如果最后執行的協處理器指令不含內存操作數,則后兩個寄存器值無用。指令FLDENV、FSTENV、FNSTENV、FRSTOR、FSAVE和FNSAVE用于加載和保存這4個寄存器的內容。前3條指令共加載或保存28字節內容:控制字、狀態字和特征字以及4個出錯指針寄存器。控制字、狀態字和特征字都以32位操作,高16位為0。后3條指令用于加載或保存協處理器所有108字節的寄存器內容。

4.浮點指令格式

對協處理器進行仿真就是解析具體的浮點指令操作碼和操作數,根據每一條指令的結構使用80386的普通指令來執行相應的仿真操作。數學協處理器80387共有七十多條指令,共分5類,見表11-4。每條指令的操作碼都有2個字節,其中第一個字節高5位都是二進制11011。這5位的數值(0x1b或十進制27)正好是字符ESC(轉義)的ASCII代碼值,因此所有數學協處理器指令都被形象地稱為ESC轉義指令。在仿真浮點指令時可忽略相同的ESC位,只要判斷低11位的值即可。

  

Linux內核完全剖析---數學協處理器(1)

表中各個字段的含義如下(有關這些字段的具體含義和詳細說明請參考80x86處理器手冊):

1)OP(Operation opcode)是指令操作碼,在有些指令中它被分成了OPA和OPB兩部分。

2)MF(Memory Format)是內存格式。00:32位實數;01:32位整數;10:64位實數;11:64位整數。

3)P(Pop)指明在操作后是否要執行一次出棧處理。0:不需要;1:操作后彈出棧。

4)d(destination)指明保存操作結果的累加器。0:ST(0);1:ST(i)。

5)MOD(Mode)和R/M(Register/Memory)是操作方式字段和操作數位置字段。

6)SIB(Scale Index Base)和DISP(Displacement)是具有MOD和R/M字段指令的可選后續字段。

另外,所有浮點指令的匯編語言助記符都以字母F開頭,例如:FADD、FLD等。還有如下一些標準表示方法:

1)FI 所有操作整型數據的指令都以FI開頭,例如FIADD、FILD等。

2)FB 所有操作BCD類型數據的指令都以FB開頭,例如FBLD、FBST等。

3)FxxP 所有會執行一次出棧操作的指令均以字母P結尾,例如FSTP、FADDP等。

4)FxxPP 所有會執行二次出棧操作的指令均以字母PP結尾,例如FCOMPP、FUCOMPP等。

5)FNxx 除了以FN開頭的指令,所有指令在執行前都會先檢測未屏蔽的運算異常。而以FN開頭的指令不檢測運算異常情況,例如FNINIT、FNSAVE等。

責任編輯:趙寧寧 來源: IT專家網
相關推薦

2009-06-17 17:00:03

2009-06-17 11:58:19

Linux

2011-12-01 09:11:58

IntelMIC架構協處理器

2009-09-25 10:36:13

32nm Sandy

2013-05-13 09:47:39

Xeon Phi協處理器Intel

2010-03-22 09:18:24

Windows內核

2018-11-29 09:30:04

ARMMIPS處理器

2013-07-10 10:11:28

Intel處理器規格

2013-03-29 10:26:41

2013-06-19 09:42:47

Intel協處理器CPU

2012-09-29 10:06:56

英偉達測試Tesla K20

2020-10-14 07:35:43

Linux 5.10

2011-03-11 10:47:11

NVIDIA丹佛處理器

2010-06-22 09:40:20

英特爾

2012-11-13 14:15:41

HPC英特爾Xeon Phi

2010-01-07 13:44:54

Linux內核代碼

2010-04-26 16:43:24

IBM POWER4處

2022-10-27 10:12:25

linuxi486

2020-11-20 07:55:55

Linux內核映射

2013-06-18 18:24:16

英特爾協處理器超級計算機
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕欧美日韩一区 | 久久婷婷色 | 久久av网 | 九九色综合 | 欧美一区二区三区在线 | 久久久久免费 | 皇色视频在线 | 四虎影院新网址 | 久久91精品国产一区二区 | 天天射中文| 国产精品久久久久久久久免费樱桃 | 在线毛片网| 日韩欧美不卡 | 91pron在线| 精品91久久 | 国产成人免费视频网站视频社区 | 久草精品视频 | 国产在线不卡视频 | 美女黄视频网站 | 国产精品成人一区二区三区夜夜夜 | 久久久久久久久久久久91 | 亚洲视频在线观看 | 精品国产黄色片 | 成人亚洲一区 | 久久久久久国产 | 欧洲在线视频 | 国产精品99久久久久久www | 精品一区二区三区在线观看国产 | av三级在线观看 | 精品国产一区二区三区日日嗨 | 久久久久久久电影 | 亚洲国产一区二区三区 | 欧美一级黄色免费看 | 青青草av网站 | 欧美日韩在线成人 | 1级黄色大片 | 国产999精品久久久久久 | 国产精品jizz在线观看老狼 | 亚洲成人午夜电影 | 日韩视频区 | 一级毛片免费视频观看 |