第11章-數(shù)學(xué)協(xié)處理器_第1頁
第11章-數(shù)學(xué)協(xié)處理器_第2頁
第11章-數(shù)學(xué)協(xié)處理器_第3頁
已閱讀5頁,還剩20頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第11章數(shù)學(xué)協(xié)處理器內(nèi)核目錄kernel/math目錄中包含數(shù)學(xué)協(xié)處理器仿真處理代碼文件,共包含9個(gè)C語言程序,見表11-1。本章內(nèi)容與具體硬件結(jié)構(gòu)關(guān)系非常密切,因此需要讀者具備較深的有關(guān)In tel CPU和協(xié)處理器指令代碼結(jié)構(gòu)的知識(shí)。但好在這些內(nèi)容與內(nèi)核實(shí)現(xiàn)關(guān)系不大,因此跳過本章內(nèi)容并 不會(huì)阻礙讀者對內(nèi)核實(shí)現(xiàn)方法的完整理解。不過假設(shè)能理解本章內(nèi)容,那么對于實(shí)現(xiàn)系統(tǒng)級應(yīng) 用程序例如匯編和反匯編等程序和編制協(xié)處理器浮點(diǎn)處理程序?qū)⒂泻艽髱椭?。?11-1 linux/kernel/math 目錄名稱大小/B最后修改時(shí)間名稱大小/B最后修改時(shí)間|_三 1 Makefile33771991-12-3

2、1 12:26:48閤 ea.c18071991-12-31 11:57:05add.c19991992-01-01 16:42:02error.c2341991-12-28 12:42:091 三 1 compare.c9041992-01-01 17:15:341= 1 get_put.c51451992-01-01 01:38:13三 1 convert.c43481992-01-01 19:07:43寧math_emulate.c115401992-01-07 21:12:05=j div.c20991992-01-01 01:41:43 ="l mul.c15171992-

3、01-01 01:42:3311.1總體功能描述在電腦上執(zhí)行計(jì)算量較大的運(yùn)算通常可以使用三種方法來完成。一種是直接使用CPU普通指令執(zhí)行計(jì)算。由于CPU指令是一類通用指令,因此使用這些指令進(jìn)行復(fù)雜和大量的運(yùn)算工作 需要編制復(fù)雜的計(jì)算子程序,并且一般只有通曉數(shù)學(xué)和電腦的專業(yè)人員才能編制出這些子程序。 另一種方法是為CPU配置一個(gè)數(shù)學(xué)協(xié)處理器芯片。使用協(xié)處理器芯片可以極大地簡化數(shù)學(xué)處理 編程難度,并且運(yùn)算速度和效率也會(huì)成倍提高,但需要另外增加硬件投入。還有一種方法是在 系統(tǒng)內(nèi)核級使用仿真程序來模擬協(xié)處理器的運(yùn)算功能。這種方法可能是運(yùn)算速度和效率最低的 一種,但與使用了協(xié)處理器一樣可以方便程序員編制

4、計(jì)算程序,并且能夠在對程序不加任何改 動(dòng)的情況下把所編程序運(yùn)行在具有協(xié)處理器的機(jī)器上。在甚至內(nèi)核開發(fā)初期,數(shù)學(xué)協(xié)處理器芯片80387或其兼容芯片價(jià)格不菲,并且一直是普通PC中的奢侈品。因此除非在科學(xué)計(jì)算量很大的場合或特別需要之處,一般PC中不會(huì)安裝80387芯片。雖然現(xiàn)在的Intel處理器中都內(nèi)置了數(shù)學(xué)協(xié)處理器功能部件,從而現(xiàn)在的操作系統(tǒng)中已經(jīng)無須包含協(xié)處理器仿真程序代碼,但是因?yàn)?0387仿真程序完全建立在模擬80387芯片處理結(jié)構(gòu)和分析指令代碼結(jié)構(gòu)根底上,因此學(xué)習(xí)本章內(nèi)容后讀者不僅能夠了解80387協(xié)處理器編程方法,而且對編寫匯編和反匯編處理程序也有很大幫助。如果80386 PC中沒有包括

5、80387數(shù)學(xué)協(xié)處理器芯片,那么當(dāng) CPU執(zhí)行到一條協(xié)處理器指 令時(shí)就會(huì)引發(fā)“設(shè)備不存在異常中斷 7。該異常過程的處理代碼在第 158行開始處。如果操 作系統(tǒng)在初始化時(shí)已經(jīng)設(shè)置了 CPU控制存放器 CR0的EM位,那么此時(shí)就會(huì)調(diào)用程序中的math_emulate()函數(shù)來用軟件"解釋執(zhí)行每一條協(xié)處理器指令。內(nèi)核中的數(shù)學(xué)協(xié)處理器仿真程序完全模擬了80387芯片執(zhí)行協(xié)處理器指令的方式。在處理一條協(xié)處理器指令之前,該程序會(huì)首先使用數(shù)據(jù)結(jié)構(gòu)等類型在內(nèi)存中建立起一個(gè)“軟80387環(huán)境,包括模仿所有 80387內(nèi)部棧式累加器組 ST、控制字存放器 CWD、狀態(tài)字存放器 SWD 和特征字TWD T

6、AG word存放器,然后分析引起異常的當(dāng)前協(xié)處理器指令操作碼,并根據(jù) 具體操作碼執(zhí)行相應(yīng)的數(shù)學(xué)模擬運(yùn)算。因此在描述程序的處理過程之前,有必要先介紹一下 80387的內(nèi)部結(jié)構(gòu)和根本工作原理。11.1.1 浮點(diǎn)數(shù)據(jù)類型本節(jié)主要介紹協(xié)處理器使用的浮點(diǎn)數(shù)據(jù)類型。首先簡單回憶一下整型數(shù)的幾種表示方式, 然后說明浮點(diǎn)數(shù)的幾種標(biāo)準(zhǔn)表示方式以及在80387中運(yùn)算時(shí)使用的臨時(shí)實(shí)數(shù)表示方法。1 整型數(shù)據(jù)類型對于In tel 32位CPU來講,有三種根本無符號(hào)數(shù)據(jù)類型:字節(jié)byte、字word和雙字double word,分別有8、16和32位。無符號(hào)數(shù)的表示方式很簡單,字節(jié)中的每個(gè)位都代表 一個(gè)二進(jìn)制數(shù),并且根

7、據(jù)其所處位置具有不同的權(quán)值。例如一個(gè)無符號(hào)二進(jìn)制數(shù)0b10001011可表示為:U = 0b10001011 = 1 X 27 + 0X 26 + 0X 25 + 0 X 24 + 1 X 23 + 0 X 22 + 1 X 21 + 1 X 20 = 139它對應(yīng)十進(jìn)制數(shù)139。其中權(quán)值最小的一位20通常被稱為最低有效位LSB , LeastSignificant Bit而權(quán)值最大的位27被稱為最高有效位MSB , Most Significant Bit。而電腦中具有負(fù)數(shù)值的整型數(shù)據(jù)表示方法通常也有三種:2的補(bǔ)碼Two' scomplement、符號(hào)數(shù)Sign magnitude丨

8、和偏置數(shù)biased number表示方式。表 11- 2給出了這三種形式表 示的一些數(shù)值。表11-2 整型數(shù)的幾種表示形式十進(jìn)制數(shù)2的補(bǔ)碼表示法偏置表示法127符號(hào)數(shù)表示法128無法表示0b11111111無法表示1270b011111110b111111100b011111111260b011111100b111111010b0111111020b000000100b100000010b0000001010b000000010b100000000b0000000100b000000000b011111110b000000000無法表示無法表示0b1000000010b111111110b0

9、11111100b1000000120b111111100b011111010b100000101260b100000100b000000010b111111101270b100000010b000000000b111111111280b10000000無法表示無法表示2的補(bǔ)碼二進(jìn)制補(bǔ)碼表示法是目前大多數(shù)電腦CPU使用的整數(shù)表示方法,因?yàn)?CPU的無符號(hào)數(shù)的簡單加法也適用于這種格式的數(shù)據(jù)運(yùn)算。使用這種表示法,一個(gè)數(shù)的負(fù)數(shù)就是該 數(shù)每位取反后再加1。MSB位就是該數(shù)的符號(hào)位。 MSB= 0表示一個(gè)正數(shù);MSB = 1表示負(fù)數(shù)。80386 CPU具有8位1字節(jié)、16位1字和32位雙字2的補(bǔ)碼數(shù)據(jù)類

10、型,分別可以表 示的數(shù)據(jù)范圍是:128127、 32768 32767、 21474836482146473647。另外,在 80387仿真程序中使用了一種稱為臨時(shí)整數(shù)類型的格式,如圖11-1所示。它的長度為10字節(jié),可表示64位整型數(shù)據(jù)類型。其中低 8字節(jié)最大可表示63位無符號(hào)數(shù),而最高 2字節(jié)僅使用了最高 有效位來表示數(shù)值的正負(fù)。對于32位整型值那么使用低 4字節(jié)來表示,16位整型值那么使用低 2字節(jié)表示。數(shù)的偏置表示法通常用于表示浮點(diǎn)數(shù)格式中的指數(shù)字段值。把一個(gè)數(shù)加上指定的偏置值就是該數(shù)的偏置數(shù)表示的值。 從表11-1可以看出,這種表示方法的數(shù)值具有無符號(hào)數(shù)的大小順序。因此這種表示方法易

11、于比擬數(shù)值大小。即大數(shù)值的偏置表示值總是無符號(hào)值的一個(gè)大數(shù),而其 他兩種表示方式卻并非如此。符號(hào)數(shù)表示法有一個(gè)位專門用于表示符號(hào)0表示正數(shù),1表示負(fù)數(shù),而其他位那么與無符號(hào)整數(shù)表示的數(shù)值相同。浮點(diǎn)數(shù)的有效數(shù)尾數(shù)局部使用的就是這種表示方法,而符號(hào)位代 表整個(gè)浮點(diǎn)數(shù)的正負(fù)符號(hào)。2 . BCD碼數(shù)據(jù)類型BCD Binary Coded Decimal碼數(shù)值是二進(jìn)制編碼的十進(jìn)制數(shù)值,對于壓縮的BCD編碼,每個(gè)字節(jié)可表示兩位十進(jìn)制數(shù),其中每4位表示一位09的數(shù)。例如,十進(jìn)制數(shù) 59的壓縮BCD碼表示是0x01011001。對于非壓縮的BCD碼,每個(gè)字節(jié)只使用低 4位表示1位十進(jìn)制數(shù)。80387協(xié)處理器支

12、持10字節(jié)壓縮BCD碼的表示和運(yùn)算,可表示18位十進(jìn)制數(shù),如圖11-2 所示。與臨時(shí)整數(shù)格式類似,其中最高字節(jié)僅使用了符號(hào)位最高有效位來表示數(shù)值的正負(fù),其余位均不用。假設(shè) BCD碼數(shù)據(jù)是負(fù)數(shù),那么會(huì)使用最高地址處1字節(jié)的最高有效位置 1來表示負(fù)值。否那么最高字節(jié)所有位均是0。不用dt7 J16d)5 dMdi5 JI2 dH dIO(17 J6d4曲l12dl dO符號(hào)位I宇節(jié)圖11-280387支持的BCD碼數(shù)據(jù)類型3 浮點(diǎn)數(shù)據(jù)類型具有整數(shù)局部和小數(shù)尾數(shù)局部的數(shù)稱為實(shí)數(shù)或浮點(diǎn)數(shù)。實(shí)際上整型數(shù)是小數(shù)局部為0的實(shí)數(shù),是實(shí)數(shù)集的一個(gè)子集。由于電腦使用固定長度位來表示一個(gè)數(shù),因此并不能精確地表 示所

13、有實(shí)數(shù)。由于電腦表示實(shí)數(shù)時(shí)為了在固定長度位內(nèi)能表示盡量精確的實(shí)數(shù)值,分配給表示 小數(shù)局部的位個(gè)數(shù)并不是固定的,即小數(shù)點(diǎn)是可以“浮動(dòng)的,因此電腦表示的實(shí)數(shù)數(shù)據(jù)類型 也稱為浮點(diǎn)數(shù)。為了便于程序移植,目前電腦中都使用IEEE標(biāo)準(zhǔn)754指定的浮點(diǎn)數(shù)表示方式來表示實(shí)數(shù)。這種實(shí)數(shù)表示方式的一般格式如圖11-3所示。它由有效數(shù) Significant丨局部、指數(shù)Exponent局部和符號(hào)位Sign組成。80387協(xié)處理器支持三種實(shí)數(shù)類型,它們每個(gè)局部使 用的位數(shù)如圖11-4所示。5jpfSi (ExpMKnt)帥 ificnnd)'苻號(hào)憧譽(yù)余她-(-1戶有斂數(shù)圖11-3浮點(diǎn)數(shù)一般格式圖11-4 80

14、387協(xié)處理器使用的實(shí)數(shù)格式其中S是一個(gè)位的符號(hào)位。S=1表示是負(fù)實(shí)數(shù);S=0表示是正實(shí)數(shù)。有效數(shù)Significant丨給出 了實(shí)數(shù)數(shù)值的有效位數(shù)或尾數(shù)。當(dāng)使用指數(shù)時(shí),一個(gè)實(shí)數(shù)可以表示成多種形式。例如十進(jìn)制數(shù) 字可以表示成x 102、x 100、x 101或x 102等。為了使計(jì)算能夠得到最大精度值,我們總是對 實(shí)數(shù)進(jìn)行規(guī)格化Normalize丨處理,即調(diào)整實(shí)數(shù)的指數(shù)值,使得二進(jìn)制最高有效數(shù)值總是1,并且小數(shù)點(diǎn)就位于其右側(cè)。因此,上述例子正確的規(guī)格化處理結(jié)果就是x101。對于二進(jìn)制數(shù)來說就是x 2n其中X是1或0。如果我們總是使用這種形式來表示一個(gè)實(shí)數(shù),那么小數(shù)點(diǎn)左邊肯定是1。所以在8038

15、7的短實(shí)數(shù)單精度和長實(shí)數(shù)雙精度格式中,這個(gè)“1就沒有必要明確地表示出來。因此在短實(shí)數(shù)或長實(shí)數(shù)的二進(jìn)制有效數(shù)中,0X0111.010實(shí)際上就是0X1.0111.010。格式中的指數(shù)字段含有把一個(gè)數(shù)表示成規(guī)格化形式時(shí)所需要的2的幕次值。正如前面提到的,為了便于數(shù)字大小的比擬,80387使用偏置數(shù)形式來存儲(chǔ)指數(shù)值。短實(shí)數(shù)、長實(shí)數(shù)和臨時(shí)實(shí)數(shù)的偏置基量分別是127、1023和16383。因此一個(gè)短實(shí)數(shù)指數(shù)值0b10000000實(shí)際表示210b01111111 + 0b00000001。另外,臨時(shí)實(shí)數(shù)是 80387內(nèi)部運(yùn)算時(shí)表示數(shù)的格式。它的最高有效數(shù)1被明確地放置在位63處,并且無論你給出的數(shù)是什么數(shù)據(jù)

16、類型的例如,整型數(shù)、短實(shí)數(shù)或BCD碼數(shù)等,80387都會(huì)把它轉(zhuǎn)換成臨時(shí)實(shí)數(shù)格式。80387這樣做的目的是為了使得精度最大化并且盡量減少運(yùn)算過程中的溢出異常。顯式地把1表示出來是因?yàn)?80387在運(yùn)算過程中確實(shí)需要該位用于表示極小的數(shù)值。當(dāng)輸入到80387中的短型或長型實(shí)數(shù)被轉(zhuǎn)換成臨時(shí)實(shí)數(shù)格式時(shí),就會(huì)明確地在位63處放置一個(gè)1。4 .特殊實(shí)數(shù)與上面表中格式某些值無法表示的情況類似,使用實(shí)數(shù)格式表示的某些值也有其特殊含義。對于80位長度格式的臨時(shí)實(shí)數(shù),80387并沒有使用其可表示的所有范圍數(shù)值。表11-3是80387使用中的臨時(shí)實(shí)數(shù)所能表示的所有可能的數(shù)值,其中有效數(shù)一欄虛線左側(cè)1位表示臨時(shí)實(shí)數(shù)位

17、63,即明確表示數(shù)值1的位。短實(shí)數(shù)和長實(shí)數(shù)沒有此位,因此也沒有表中的偽非規(guī)格化類別。 下面說明其中的一些特殊值:零值、無窮值、非規(guī)格化值、偽非規(guī)格化值以及信號(hào)NaNNot aNumber 和安靜 NaN。表11-380387臨時(shí)實(shí)數(shù)所能表示的數(shù)值類型和范圍負(fù)號(hào)偏置型指數(shù)有效數(shù)類別0/111.11111.11安靜 NaNs - QNaNs Quiet NaNs0/111.1110/111.11110.00不確定值Indefinite 0/111.11101.110/111.111信號(hào) NaNs -SNaNs Signalling NaNs0/111.11100.010/111.11100.00無

18、窮數(shù)Infinite0/111.10111.110/11規(guī)格化數(shù)正常數(shù)Normals0/100.01100.000/10000111.110/100001偽非規(guī)格化數(shù)Pseudo-Denormals0/10000100.000/100.00011.110/100.000非規(guī)格化數(shù)Denormals0/100.00000.010/100.00000.00零Zero零是指數(shù)和有效數(shù)均為 0的值,其余指數(shù)為 0的值作保存,即指數(shù)是 0的值不能表示一個(gè) 正常實(shí)數(shù)值。無窮值是指數(shù)值為全 1、有效數(shù)值為全零的值,而且指數(shù)值為0x1111的所有其余值也作保存使用。非規(guī)格化數(shù)Denormals是一種用于表示非

19、常小數(shù)值的特殊類值。它可以表示漸進(jìn)下溢或漸進(jìn)精度喪失情況。通常要求數(shù)值表示成規(guī)格化數(shù)左移直到有效數(shù)的最高有效位是位1。然而非規(guī)格化數(shù)的有效數(shù)最高有效位不是1。此時(shí)偏置型指數(shù) 0x0000分別是值為2 126、2 1022、2 16382的短實(shí)數(shù)、長實(shí)數(shù)和臨時(shí)實(shí)數(shù)指數(shù)值的特殊表示方式。這種表示比擬特殊,因?yàn)槠眯椭笖?shù)0x0001對三種實(shí)數(shù)類型也分別表示相同的指數(shù)值2 126、2 1022、2 16382。偽非規(guī)格化類數(shù)值Pseudo-denormals是有效數(shù)最高有效位為1的值,而非規(guī)格化類數(shù)值的該位是0。偽非規(guī)格化數(shù)很少見,它們可以用規(guī)格化類數(shù)來表示卻沒有這么做。因?yàn)樯厦嬉?經(jīng)說明特殊的偏置指

20、數(shù)0X00.00與規(guī)格化數(shù)的指數(shù) 0X00.01具有相同的值。因此偽非規(guī)格化類數(shù)可以表示成規(guī)格化類數(shù)值。另一種特殊情況是 NaN。 NaN是指"不是一個(gè)數(shù)Not a Number。NaN有兩種形式:會(huì)產(chǎn)生信號(hào)Signaling丨的和不會(huì)產(chǎn)生信號(hào)的或稱為安靜的Quiet。當(dāng)一個(gè)產(chǎn)生信號(hào)的NaNSNaN丨被用于操作時(shí)就會(huì)引發(fā)一個(gè)無效操作異常,而一個(gè)安靜的NaN QNaN丨那么不會(huì)。SnaN是一類會(huì)引發(fā)無效操作異常的數(shù)值。使用的方法就是程序先把變量都初始化為SNaN值,在實(shí)際使用這個(gè)變量時(shí)還需要對其進(jìn)行真正的賦值。這樣假設(shè)操作過程中使用了一個(gè)未被初始化的值就會(huì)引發(fā)異常。當(dāng)然,NaN類數(shù)值也

21、可以用來存儲(chǔ)其他信息。80387自身不會(huì)產(chǎn)生 SNaN類的值,但會(huì)產(chǎn)生QNaN類的值。當(dāng)發(fā)生無效操作異常時(shí)80387就會(huì)產(chǎn)生一個(gè) QNaN類值,并且操作的結(jié)果將是不確定值Indefinite。不確定值是一種特殊的QNaN類值。每種數(shù)據(jù)類型都有一個(gè)表示不確定值的數(shù)。對于整型數(shù)那么是用其最大負(fù)數(shù)來表示 其不確定值。另外還有一些 80387不支持的臨時(shí)實(shí)數(shù)值,即那些沒有在上表中列出的數(shù)值范圍。假設(shè) 80387遇到這些數(shù)值,就會(huì)引發(fā)無效操作異常。11.1.2 數(shù)學(xué)協(xié)處理器功能和結(jié)構(gòu)80386雖然是一個(gè)通用微處理器,但其指令并不是非常適用于數(shù)學(xué)計(jì)算。因此假設(shè)使用80386來執(zhí)行數(shù)學(xué)計(jì)算,那么就需要編制非

22、常復(fù)雜的程序,而且執(zhí)行效率也相對較低。80387作為80386的輔助處理芯片,極大地?cái)U(kuò)展了程序員的編程范圍。以前程序員不太可能做到的事,使用協(xié)處理器后就可以很容易地,并且快速而精確地完成。80387具有一組特別的存放器。這組存放器可以讓80387直接操作比80386所能處理的大或小幾個(gè)數(shù)量級的數(shù)值。80386使用2進(jìn)制補(bǔ)數(shù)方式表示一個(gè)數(shù)。這種方法不適合用來表示小數(shù)。而80387并不使用2的補(bǔ)數(shù)方法來表示數(shù)值,它使用了IEEE標(biāo)準(zhǔn)754規(guī)定的80位10個(gè)字節(jié)格式。這種格式不僅具有廣泛的兼容性,而且能夠使用二進(jìn)制表示極大或極小的 數(shù)值。例如,它能表示大到X104932數(shù)值,也能處理小到x 10 4

23、932的數(shù)。80387并不保持固定小數(shù)點(diǎn)的位置,如果數(shù)值小的話就多使用一些小數(shù)位,如果數(shù)值大的話就少用幾位小數(shù)位。因此 小數(shù)點(diǎn)的位置是可以“浮動(dòng)的。這也是術(shù)語“浮點(diǎn)數(shù)的由來。為支持浮點(diǎn)運(yùn)算,80387中包含三組存放器,如圖 11-5所示。8個(gè)80位長的數(shù)據(jù)存放 器累加器,可用于臨時(shí)存放 8個(gè)浮點(diǎn)操作數(shù),并且這些累加器可以執(zhí)行棧式操作;3個(gè)16位狀態(tài)和控制存放器: 一個(gè)狀態(tài)字存放器 SWD、一個(gè)控制字存放器 CWD和一個(gè)特征TAG 存放器; 4個(gè)32位出錯(cuò)指針存放器FIP、FCS、FOO和FOS用于確定導(dǎo)致80387內(nèi)部異 常的指令和內(nèi)存操作數(shù)。敎(卜.xpnnciiu也紅數(shù) iSiniik&#

24、39;arid.l§古s$sM 竹0ME02ST( I7150Stdins WurdWordrip00000 Opcodk?FCSFOOaKKMMMKJIXMJOOO圖11-580387的存放器1 棧式浮點(diǎn)累加器在浮點(diǎn)指令執(zhí)行過程中,8個(gè)80位長度的物理存放器組被作為棧式累加器使用。雖然每個(gè)80位存放器有固定的物理順序位置即左邊的07,但當(dāng)前棧頂那么由ST即ST(O)來指明。ST之下的其余累加器使用名稱ST(i)來指明i = 17。至于哪個(gè)80位物理存放器是當(dāng)前棧頂ST,那么由具體操作過程指定。在狀態(tài)字存放器中名稱為TOP的3位字段含有當(dāng)前棧頂 ST對應(yīng)的80位物理存放器的絕對位置。

25、一個(gè)入棧Push操作將會(huì)把 TOP字段值遞減1,并把新值存儲(chǔ)于新的ST中。在入棧操作之后,原來的 ST變成了 ST(1),而原來的ST(7)變成了現(xiàn)在的 ST。即所有累加器的名稱都從原來的ST(i)變成了 ST(i+1)&0x7)。一個(gè)出棧Pop操作將會(huì)讀出當(dāng)前ST對應(yīng)的80位存放器的值,并且把 TOP字段值遞增1。因此在出棧操作之后,原來的 ST即ST(0)變成了 ST(7),原來的ST(1)成為新的ST。即所有累加器的名稱都從原來的ST(i)變成 ST(i 1)& 0x7) oST的作用如同一個(gè)累加器是因?yàn)樗蛔鳛樗懈↑c(diǎn)指令的一個(gè)隱含操作數(shù)。假設(shè)有另一個(gè)操作數(shù),那么該第2

26、個(gè)操作數(shù)可以是任何其余累加器之一ST(i),或者是一個(gè)內(nèi)存操作數(shù)。棧中的每個(gè)累加器為一個(gè)實(shí)數(shù)提供了使用臨時(shí)實(shí)數(shù)格式存儲(chǔ)的80位空間,其最高位s是符號(hào)位,位7864是15位的指數(shù)字段,位 630是64位的有效數(shù)字段。浮點(diǎn)指令被設(shè)計(jì)成能充分利用這個(gè)累加器棧模式。浮點(diǎn)加載指令FLD等會(huì)從內(nèi)存中讀取一個(gè)操作數(shù)并壓入棧中,而浮點(diǎn)存儲(chǔ)指令那么會(huì)從當(dāng)前棧頂取得一個(gè)值并寫到內(nèi)存中。假設(shè)棧 中該值不再需要時(shí)還可以同時(shí)執(zhí)行出棧操作。加和乘之類的操作會(huì)把當(dāng)前ST存放器內(nèi)容作為一個(gè)操作數(shù),而另一個(gè)取自其他存放器或內(nèi)存中,并且在計(jì)算完后即把結(jié)果保存在ST中。還有一類“操作并彈出操作形式用于在ST和ST(1)兩者之間進(jìn)行

27、運(yùn)算。這種操作形式會(huì)執(zhí)行一次彈出操作,然后把結(jié)果放入新的ST中。2 .狀態(tài)與控制存放器三個(gè)16位的存放器TAG字、控制字和狀態(tài)字控制著浮點(diǎn)指令的操作并且為其提供狀 態(tài)信息。它們的具體格式如圖11-6所示。下面逐一對它們進(jìn)行說明。1控制字控制字Control Word丨可用于程序設(shè)置各種處理選項(xiàng)來控制80387的操作。其中可分為三個(gè)局部。位1110的RC Rounding Control是舍入控制字段,用于對計(jì)算結(jié)果進(jìn)行舍入操作。 位98的PC Precision Control丨是精度控制字段,用于在保存到指定存儲(chǔ)單元之前對計(jì)算結(jié) 果進(jìn)行精度調(diào)整。所有其他操作使用臨時(shí)實(shí)數(shù)格式精度,或者使用指令

28、指定的精度。位50是異常屏蔽位,用于控制協(xié)處理器異常處理。這6位對應(yīng)80387可能發(fā)生的6種異常情況。其中每一種異常都可以單獨(dú)屏蔽掉。如果發(fā)生某個(gè)特定異常并且其對應(yīng)屏蔽位沒有置位,那么 80387就會(huì)向CPU通報(bào)這個(gè)異常,并且會(huì)讓CPU產(chǎn)生異常中斷int 16。然而如果設(shè)置了對應(yīng)屏蔽位,那么80387就會(huì)自己處理并糾正發(fā)生的異常問題而不會(huì)通知CPU。這個(gè)存放器隨時(shí)可以讀寫,其中各位的具體含義參見圖11-6o2狀態(tài)字在運(yùn)行期間,80387會(huì)設(shè)置狀態(tài)字Status Word中的位,用于程序檢測特定的條件。當(dāng)發(fā)生異常時(shí),它可讓 CPU確定發(fā)生異常的原因。因?yàn)樗?個(gè)協(xié)處理器異常都會(huì)讓CPU產(chǎn)生異常中

29、斷int16。3特征字特征字Tag Word丨存放器含有8個(gè)2位的Tag字段,分別對應(yīng)8個(gè)物理浮點(diǎn)數(shù)據(jù)存放器。這些特征字段分別指明相應(yīng)的物理存放器含有有效、零、特殊浮點(diǎn)數(shù)值,或者是空的。特殊數(shù) 值是指那些無限值、非數(shù)值、非規(guī)格化或不支持格式的數(shù)值。特征字段Tag可用于檢測累加器堆棧上下溢出情況。如果入棧Push操作遞減TOP指向了一個(gè)非空存放器,就會(huì)發(fā)生棧上溢 出。如果出棧Pop操作企圖去讀取或彈出空存放器,就會(huì)造成棧下溢出Underflow。棧的上下溢出都將引發(fā)無效操作異常。會(huì)人方式0C會(huì)人妣近戒偶戟01ropPC狀志晞価00TEIM無效提作01t廉SBL)LDM10/F-7Ma 7OEOM

30、上湛出CO IBsf peue oe ze|deir4時(shí)抑I00RCPC 01pm|uMZMIA1B-1T15S7T睥4T咄Taf2持征宇會(huì)人方式Fk.UF. Ok.Zt DE.IE這些優(yōu) UH抬不件執(zhí)h課點(diǎn)戰(zhàn)令時(shí)發(fā)生曲 岸常豈釧由程中枇更便。SF傀冊帽標(biāo)屯.苦無散掾作rh于弟勿器溢出鍛慮異 常!m葉液標(biāo)也.丑那么門勸甩試.H.IK如黑僮$心川任何屈財(cái)異常發(fā)生*那么這2饒 帔及SL西JH均曲。C3hC2, 1,CO這些是梟耳冉比持氐 燦1于叫的卜m臥 用于浮直1匕按梧令.TOP用干措明十詢那牛80悄存放器悄干棧頂, 卻購卜竹理寄在器對應(yīng)就加器莎圖11-6控制和狀態(tài)存放器格式T鑼00對應(yīng)峑加器&

31、#163;過01累10特殊W.非麹值 罪規(guī)格化11卑加器帝3 出錯(cuò)指針存放器出錯(cuò)指針存放器Error-Pointer Register是4個(gè)32位的80387存放器,其中含有 80387 最后執(zhí)行指令和所用數(shù)據(jù)的指針,參見圖11-6。前兩個(gè)存放器FIP和FCS中是最后執(zhí)行指令中2個(gè)操作碼的指針忽略前綴碼。FCS是段選擇符和操作碼,F(xiàn)IP是段內(nèi)偏移值。后兩個(gè)存放器FOO和FOS是最后執(zhí)行指令內(nèi)存操作數(shù)的指針。FOS中是段選擇符,F(xiàn)OO中是段內(nèi)偏移值。如果最后執(zhí)行的協(xié)處理器指令不含內(nèi)存操作數(shù),那么后兩個(gè)存放器值無用。指令FLDENV、FSTENV、FNSTENV、FRSTOR、FSAVE和FNSA

32、VE用于加載和保存這 4個(gè)存放器的內(nèi)容。前3條指令共加載或保存 28字節(jié)內(nèi)容:控制字、狀態(tài)字和特征字以及 4個(gè)出錯(cuò)指針存放器。 控 制字、狀態(tài)字和特征字都以32位操作,高16位為0。后3條指令用于加載或保存協(xié)處理器所有108字節(jié)的存放器內(nèi)容。4 浮點(diǎn)指令格式對協(xié)處理器進(jìn)行仿真就是解析具體的浮點(diǎn)指令操作碼和操作數(shù),根據(jù)每一條指令的結(jié)構(gòu)使用80386的普通指令來執(zhí)行相應(yīng)的仿真操作。數(shù)學(xué)協(xié)處理器80387共有七十多條指令,共分 5類,見表11-4。每條指令的操作碼都有2個(gè)字節(jié),其中第一個(gè)字節(jié)高5位都是二進(jìn)制11011。這5位的數(shù)值0x1b或十進(jìn)制27丨正好是字符 ESC轉(zhuǎn)義的ASCII代碼值,因此所

33、有數(shù)學(xué) 協(xié)處理器指令都被形象地稱為ESC轉(zhuǎn)義指令。在仿真浮點(diǎn)指令時(shí)可忽略相同的ESC位,只要判斷低11位的值即可。表11-4浮點(diǎn)指令類型第1字節(jié)第2字節(jié)可選字段11 1 0 1 1OPA1MOD1OPBR/MSIBDISP21 1 0 1 1MFOPAMODOPBR/MSIBDISP31 1 0 1 1dPOPA11OPBST(i)41 1 0 1 1001111OP51 1 0 1 1011111OP15 11109876543210表中各個(gè)字段的含義如下有關(guān)這些字段的具體含義和詳細(xì)說明請參考80x86處理器手冊:1OPOperation opcode是指令操作碼,在有些指令中它被分成了OP

34、A和OPB兩局部。2MF Memory Format是內(nèi)存格式。 00: 32位實(shí)數(shù);01: 32位整數(shù);10: 64位實(shí)數(shù); 11 : 64位整數(shù)。3P Pop指明在操作后是否要執(zhí)行一次出棧處理。0 :不需要;1:操作后彈出棧。4d destination丨指明保存操作結(jié)果的累加器。0: ST(0) ; 1: ST(i)。5MOD Mode和R/M Register/Memory是操作方式字段和操作數(shù)位置字段。6SIB Scale Index Base和 DISP Displacement是具有 MOD 和 R/M 字段指令的可選 后續(xù)字段。另外,所有浮點(diǎn)指令的匯編語言助記符都以字母F開頭,

35、例如:FADD、FLD等。還有如下一些標(biāo)準(zhǔn)表示方法:1FI所有操作整型數(shù)據(jù)的指令都以FI開頭,例如FIADD、FILD等。2FB所有操作BCD類型數(shù)據(jù)的指令都以 FB開頭,例如FBLD、FBST等。3FxxP所有會(huì)執(zhí)行一次出棧操作的指令均以字母P結(jié)尾,例如FSTP、FADDP等。4FxxPP所有會(huì)執(zhí)行二次出棧操作的指令均以字母PP結(jié)尾,例如 FCOMPP、FUCOMPP 等。5FNxx 除了以FN開頭的指令,所有指令在執(zhí)行前都會(huì)先檢測未屏蔽的運(yùn)算異常。 而以FN開頭的指令不檢測運(yùn)算異常情況,例如FNINIT、FNSAVE等。程序11.2.1 功能描述程序中的所有函數(shù)可分為3局部:第一類是設(shè)備不

36、存在異常處理程序接口函數(shù) math_emulate(),只有這一個(gè)函數(shù); 第二類是浮點(diǎn)指令仿真處理主函數(shù)do_emu(),也只有一個(gè)函數(shù);另外所有函數(shù)都是仿真運(yùn)算輔助類函數(shù),包括其余幾個(gè)C語言程序中的函數(shù)。在一臺(tái)不包含80387協(xié)處理器芯片的 PC中,如果內(nèi)核初始化時(shí)在 CR0中設(shè)置了仿真標(biāo)志 EM = 1,那么當(dāng)CPU遇到一條浮點(diǎn)指令時(shí)就會(huì)引起 CPU產(chǎn)生異常中斷int 7,并且在該中斷處 理過程中調(diào)用本程序中第 476行處的math_emulate(long false)函數(shù)。在math_emulate()函數(shù)中,假設(shè)判斷出當(dāng)前進(jìn)程還沒有使用過仿真的協(xié)處理運(yùn)算時(shí)就會(huì)對 仿真的80387控制

37、字、狀態(tài)字和特征字Tag Word丨進(jìn)行初始化操作,設(shè)置控制字中所有6種協(xié)處理器異常屏蔽位并復(fù)位狀態(tài)字和特征字。然后調(diào)用仿真處理主函數(shù)do_emu()。使用的參數(shù)是作為如下info結(jié)構(gòu)的中斷處理過程中調(diào)用math_emulate()函數(shù)的返回地址指針。info結(jié)構(gòu)實(shí)際上就是棧中自從 CPU產(chǎn)生中斷int7后逐漸入棧的一些數(shù)據(jù)構(gòu)成的一個(gè)結(jié)構(gòu),因此它與系統(tǒng)調(diào)用時(shí)內(nèi)核棧中數(shù)據(jù)的分布情況根本相同。參見文件第11行和開始局部。11 struct info 12longmath ret;/ math_emulate()調(diào)用者int7丨返回地址。13longorig eip;/臨時(shí)保存原EIP的地方。14l

38、ongedi;/異常中斷int7處理過程入棧的存放器。15longesi;16longebp;17longsys call ret;/中斷7返回時(shí)將去執(zhí)行系統(tǒng)調(diào)用的返回處理代碼。18longeax;/以下局部18-30 行與系統(tǒng)調(diào)用時(shí)棧中結(jié)構(gòu)相同19longebx;20longecx;21longedx;22longorig eax;/如不是系統(tǒng)調(diào)用而是其他中斷時(shí),該值為-1。23longfs;24longes;25longds;26longeip;/ 26 - 30行 由CPU自動(dòng)入棧。27longcs;28longeflags;29longesp;30longss;31 ;do_emu()

39、函數(shù)第52行首先根據(jù)狀態(tài)字來判斷有沒有發(fā)生仿真的協(xié)處理器內(nèi)部異常。假設(shè)有那么設(shè)置狀態(tài)字的忙位B位15,否那么就復(fù)位忙位 B。然后從上述info結(jié)構(gòu)中EIP字段處取得產(chǎn)生協(xié)處理器異常的二字節(jié)浮點(diǎn)指令代碼code,并在屏蔽掉每條浮點(diǎn)指令碼中都相同的ESC碼二進(jìn)制11011位局部后,根據(jù)此時(shí)的code值對具體的浮點(diǎn)指令進(jìn)行軟件仿真運(yùn)算處理。為便于處理,該函數(shù)按5種類型浮點(diǎn)指令碼分別使用了五個(gè)switch語句進(jìn)行處理。例如,第一個(gè)switch語句第75行用于處理那些不涉及尋址內(nèi)存操作數(shù)的浮點(diǎn)指令。而最后兩個(gè) switch語句第419、432行那么專門用來處理操作數(shù)與內(nèi)存相關(guān)的指令。對于后一種類型的指

40、令,其處理過程的根本流程是首先根據(jù)指令代碼中的尋址模式字節(jié)取得內(nèi)存操作數(shù)的有效地址, 然后從該有效地址處讀取相應(yīng)的數(shù)據(jù)整型數(shù)、實(shí)數(shù)或 BCD碼數(shù)值。接著把讀取的值轉(zhuǎn)換成 80387內(nèi)部處理使用的臨時(shí)實(shí)數(shù)格式。在計(jì)算完畢后,再把臨時(shí)實(shí)數(shù)格式的數(shù)值轉(zhuǎn)換為原數(shù)據(jù) 類型,最后保存到用戶數(shù)據(jù)區(qū)中。另外,在具體仿真一條浮點(diǎn)指令時(shí),假設(shè)發(fā)現(xiàn)浮點(diǎn)指令無效,那么程序會(huì)立刻調(diào)用放棄執(zhí)行 函數(shù)_math_abort()。該函數(shù)會(huì)向當(dāng)前執(zhí)行進(jìn)程發(fā)送指定的信號(hào),同時(shí)修改棧指針esp指向中斷過程中調(diào)用 math_emulate()函數(shù)的返回地址 math_ret,并立刻返回到中斷處理過程中去。11.2.2 代碼注釋程序1

41、1-11 /*23 *4 * (C) 1991 Linus Torvalds5 */66 /*7 * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants8 * even for soft-float, unless you use bruce evans' patches. The patches9 * are great, but they have to be re-applied for every version, and the10 * library is different for soft-

42、float and 80387. So emulation is more11 * practical, even though it's slower.12 *13 * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking14 * about add/sub/mul/div. Urgel. I should find some good source, but ril15 * just fake up something.16 *17 * 30.12.91 - add/sub/mul/div/c

43、om seem to work mostly. I should really18 * test every possible combination.19 */* 仿真范圍有限的程序 91.12.27-絕大多數(shù)是一些加載/存儲(chǔ)指令。除非你使用了Bruce Evans的* 補(bǔ)丁程序,否那么即使使用軟件執(zhí)行浮點(diǎn)運(yùn)算,gcc也需要這些指令。Bruce的補(bǔ)丁程序非常好,但每* 次更換gcc版本你都得用這個(gè)補(bǔ)丁程序。而且對于軟件浮點(diǎn)實(shí)現(xiàn)和80387,所使用的庫是不同的。因* 此使用仿真是更為實(shí)際的方法,盡管仿真方法更慢。* 91.12.28-加載/存儲(chǔ)協(xié)處理器指令可以用了,即使是BCD碼的也能使用。我

44、將開始考慮實(shí)現(xiàn) add/* sub/mul/div指令。唉,我應(yīng)該找一些好的資料,不過現(xiàn)在我會(huì)先仿造一些操作。* 91.12.30 - add/sub/mul/div/com這些指令好似大多數(shù)都可以使用了。我真應(yīng)該測試每種指令* 可能的組合操作。*/2122 /*23 * This file is full of ugly macros etc: one problem was that gcc simply24 * didn't want to make the structures as they should be: it has to try to25 * align them

45、. Sickening code, but at least rve hidden the ugly things26 * in this one file: the other files don't need to know about these things.27 *28 * The other files also don't care about ST(x) etc - they just get addresses29 * to 80-bit temporary reals, and do with them as they please. I wantedto3

46、0 * hide most of the 387-specific things here.31 */* 這個(gè)程序中到處都是些別扭的宏:問題之一是gcc就是不想把結(jié)構(gòu)建立成其應(yīng)該成為的樣子: gcc企* 圖對結(jié)構(gòu)進(jìn)行對齊處理。真是討厭,不過我起碼已經(jīng)把所有蹩腳的代碼都隱藏在這么一個(gè)文件中了:* 其他程序文件不需要了解這些信息。* 其他的程序也不需要知道ST(x)等80387內(nèi)部結(jié)構(gòu)-它們只需要得到80位臨時(shí)實(shí)數(shù)的地址就可以* 隨意操作。我想盡可能在這里隱藏所有387專有信息。*/3233 #include <signal.h>34/信號(hào)頭文件。定義信號(hào)符號(hào),信號(hào)結(jié)構(gòu)及信號(hào)操作函數(shù)原

47、型。35 #define _ALIGNED_TEMP_REAL 136 #include <linux/math_emu.h>37 #include <linux/kernel.h>38 #include <asm/segment.h>39/協(xié)處理器頭文件。定義臨時(shí)實(shí)數(shù)結(jié)構(gòu)和387存放器操作宏等。/內(nèi)核頭文件。含有一些內(nèi)核常用函數(shù)的原形定義。/段操作頭文件。定義了有關(guān)段存放器操作的嵌入式匯編函數(shù)。"=a" (x):"" (short)x)/交換2字節(jié)位置。/取仿真的ST(x)累加器值。/取仿真的ST(x)累加器的指針4

48、0 #define bswapw(x) _asm_("xchgb %al,%ah"41 #define ST(x) (*_st(x)42 #define PST(x) (const temp_real *) _st(x)4343 /*44 * We don't want these inlined - it gets too messy in the machine-code.45 */*我們不想讓這些成為嵌入的語句-因?yàn)檫@會(huì)使得到的機(jī)器碼太混亂。*/以下這些是相同名稱浮點(diǎn)指令的仿真函數(shù)。46 static void fpop(void);47 static voi

49、d fpush(void);48 static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);49 static temp_real_unaligned * _st(int i);51/執(zhí)行浮點(diǎn)指令仿真。/該函數(shù)首先檢測仿真的I387結(jié)構(gòu)狀態(tài)字存放器中是否有未屏蔽的異常標(biāo)志置位。假設(shè)有那么對狀態(tài)字中/ 忙標(biāo)志B進(jìn)行設(shè)置。然后把指令指針保存起來,并取岀代碼指針EIP處的2字節(jié)浮點(diǎn)指令代碼code/接著分析代碼code,并根據(jù)其含義進(jìn)行處理。針對不同代碼類型值,Linus使用了幾個(gè)不同的/ switch程序塊進(jìn)行仿真處理。

50、/ 參數(shù)是info 結(jié)構(gòu)的指針。50 static void do_emu(struct info * info)51 52 unsigned short code;53 temp_real tmp;54 char * address;57/該函數(shù)首先檢測仿真的I387結(jié)構(gòu)狀態(tài)字存放器中是否有未屏蔽的異常標(biāo)志置位。假設(shè)有就設(shè)置狀態(tài)字/中的忙標(biāo)志 B位15,否那么復(fù)位 B標(biāo)志。然后我們把指令指針保存起來。再看看執(zhí)行本函數(shù)的代/碼是不是用戶代碼。如果不是,即調(diào)用者的代碼段選擇符不等于OxOf ,那么說明內(nèi)核中有代碼使用了/浮點(diǎn)指令。于是在顯示岀浮點(diǎn)指令岀的CS、EIP值和信息“內(nèi)核中需要數(shù)學(xué)仿真后

51、停機(jī)。58if (I387.cwd & I387.swd & 0x3f)59I387.swd |= 0x8000;/設(shè)置忙標(biāo)志Bo60else61I387.swd &= 0x7fff;/清忙標(biāo)志Bo62ORIG_EIP = EIP;/保存浮點(diǎn)指令指針。63/* 0x0007 means user code space */64if (CS != 0x000F) /不是用戶代碼那么停機(jī)。65printk("math_emulate: %04x:%08xnr",CS,EIP);66panic("Math emulation needed in

52、kernel");67/然后我們?nèi)绱a指針EIP處的2字節(jié)浮點(diǎn)指令代碼code。由于IntelCPU存儲(chǔ)數(shù)據(jù)時(shí)是“小頭/Little endian在前的,此時(shí)取岀的代碼正好與指令的第1、第2字節(jié)順序顛倒。因此我們需/要交換一下code中兩個(gè)字節(jié)的順序。然后再屏蔽掉第1個(gè)代碼字節(jié)中的ESC位二進(jìn)制11011丨。接著/把浮點(diǎn)指令指針 EIP保存到TSS段i387結(jié)構(gòu)中的fip 字段中,而CS保存到fcs字段中,同時(shí)把/略微處理過的浮點(diǎn)指令代碼 code放到fcs字段的高16位中。保存這些值是為了在出現(xiàn)仿真的處理/器異常時(shí)程序可以像使用真實(shí)的協(xié)處理器一樣進(jìn)行處理。最后讓EIP指向隨后的浮點(diǎn)指令或操作數(shù)。68code = get_fs_word(unsigned short *) EIP); /取2字節(jié)的浮點(diǎn)指令代碼。69bswapw(code);/

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論