匯編,浮點運算符,fldpi,fmul等指令說明.
協處理器指令系統
協處理器共有68條不同的指令,匯編程序在遇到協處理器指令助記符時,都會將其轉換成機器語言的ESC指令,ESC指令代表了協處理器的操作碼。
協處理器指令在執行過程中,需要訪問內存單元時,CPU會為其形成內存地址。協處理器在指令執行期間內利用數據總線來傳遞數據。80287協處理器利用I/O地址00FAH~00FFH來實現其與CPU之間的數據交換,而80387~Pentium系列芯片,則是利用I/O地址800000FAH~800000FFH來實現這兩者之間的數據交換。
一.指令操作符的命名規則
協處理器指令的操作符(或助憶符)在命名設計時,遵循了下列規則:
1、在操作符後面加上字母P:表示該指令執行完後,還進行一次堆棧彈出操作,彈出棧頂數據以後要對其它的寄存器進行相應的調整。如:FADDP/FSUBP/FSUBRP /FMULP/FDIVP /FDIVRP等;
2、在操作符後面加上字母R:表示將兩個操作數的源/目的位置交換再進行運算,它僅限於減法、除法指令,因為加法和乘法不受源/目的操作數的位置影響結果。如:FSUBR和FDIVR等;
不加R時 —— 目的操作數=目的操作數 op 源操作數
加R模式 —— 目的操作數=源操作數 op 目的操作數
假設:棧頂數據st(0)為10,內存變量data的值為1,分別執行下列指令將有不同的結果。
FSUB data ; ST(0)=ST(0)-data
FSUBR data ;ST(0)=data-ST(0)
FSUB ST(3), ST(0) ;指令執行後,ST(3)=ST(3)-ST(0)
FSUBR ST(3), ST(0) ;指令執行後,ST(3)=ST(0)-ST(3)
3、操作符的第2個字母是I:表示內存操作數是整數(註意:不能是BYTE類型)。它對加、減、乘、除指令以及堆棧操作指令都有效。
FIADD data —— 整數加法,它表示內存單元data是一個整數,把該整數加到棧頂的浮點數上(ST(0)=ST(0)+data)。
4、操作符的第二個字母是B:表示用於操作壓縮的BCD碼格式的內存操作數(用TWORD聲明,10個字節),如FBLD和FBSTP等。
5、操作符的第2個字母是N:表示在指令執行之前檢查非屏蔽數值性錯誤。如:FSAVE和FNSAVE等,前者稱為等待形式(wait version),後者稱為非等待形式(no-wait version)。
在使用.8087偽指令情況下,匯編程序會在等待形式的指令前面加上指令WAIT,而在非等待形式的指令前面加上空操作指令NOP。
理解了上述操作符命名規則,就能很容易地區分同類指令之間的差異。
二.數據傳送指令
為了滿足協處理器和CPU之間進行數據交流的需求,就需要實現內存單元和協處理器之間進行數據傳送的指令。協處理器的指令系統中有三大類數據傳送指令:BCD傳送指令、數傳送指令和浮點數傳送指令。
(一)、BCD傳送指令
1、FBLD
指令格式:FBLD MemBCD
指令功能:將操作數中的BCD數據壓入協處理器的堆棧中(ST(0)=MemBCD);MemBCD是TWORD類型的內存變量。
2、FBSTP
指令格式:FBSTP MemBCD
指令功能:將協處理器中的BCD數據存入內存(MemBCD=ST(0)),並進行堆棧的彈出操作。
例如:
.387 data1 DT 123, -543 data2 DT 2.5 …… FBLD data1 FBSTP data |
;把data1壓進棧(ST(0)=data1) ;把當前堆頂數據彈出,並傳送給data (data=ST(0)) |
(二)、整數傳送指令
1、FILD
指令格式:FILD MemInt ;ST(0)=MemInt
其中:MemInt是定義為整型數據類型的內存單元,但不能是用BYTE定義的存儲單元。下同,不再敘述。
2、FIST/FISTP
|
指令格式:
其中:
指令功能: |
FIST MemInt Mem是定義整型數據類型的內存單元,(用WORD,DWORD和QWORD定義)。 將協處理器堆棧棧頂的數據傳送到目標存儲單元中。在進行數據傳送時,系統自動根據控制寄存器中舍入控制位的設置把棧頂浮點數舍入成整型數據。 |
而FIST與FISTP的區別在以前就講過,在執令後加P的表示帶有出棧操作。那麽FIST的功能是MemInt=ST(0),但ST(0)不出棧,但FISTP則在進行傳送之後再進行對棧頂進行出棧。
(三)、浮點數傳送指令
1、FLD
指令格式:
FLD STReg/MemReal
指令功能:
將浮點數據壓入協處理器的堆棧中。當進行內存單元內容壓棧時,系統會自動決定傳送數據的精度。比如:用DD或REAL4定義的內存單元數值是單精度數等。
STReg是處理器堆棧寄存器ST(0)~ST(7)。
例如:
|
.387 data1 DWORD 123, -543 data2 REAL8 -321.5 data3 REAL10 2.5 …… FLD data1 ;壓一個單精度數據進棧 FLD data2 ;壓一個雙精度數據進棧 FLD ST(0) ;把堆棧寄存器ST(0)的值再壓進棧 FLD data3 ;壓一個擴展精度數據進棧 |
2、FST
|
指令格式: 指令功能: |
FST STReg/MemReal 將協處理器堆棧棧頂的數據傳送到目標操作數中。在進行數據傳送時,系統自動根據控制寄存器中舍入控制位的設置把棧頂浮點數舍入成相應精度的數據。 |
3、FSTP
|
指令格式: |
FSTP STReg/MemReal |
指令功能: |
與FST相類似,所不同的是:指令FST執行完後,不進行堆棧的彈出操作,即:堆棧不發生變化,而指令FSTP執行完後,則需要進行堆棧的彈出操作,堆棧將發生變化。 |
從上面的浮點傳送指令中可以看出,不僅可以對內存變量進行傳送,也可以進行寄存器之間的傳送,這一點是整型數據以及BCD型數據傳送指令所不具有的。
4、FXCH
|
指令格式: 指令功能: |
FXCH [STReg] 將指定的寄存器中的浮點數與堆頂浮點數進行交換。如果不指定操作數,那麽,默認ST(0)和ST(1)二者之間交換數據。 |
例如:FXCH ST(2) —— ST(0)與堆棧寄存器ST(2)進行數據交換。
由於FXCH指令隱含ST(0)作為其中的一個操作數,所以其後只需指定一個操作數,但該操作數必須是寄存器,而且不能為ST(0),但是該指令後的寄存器是可選的,如果沒有指定寄存器操作數,那麽隱含是對ST(1)和ST(0)進行交換。
對數據傳送指令的一點總結:它包括三種數據的傳送指令,整型,壓縮的BCD型以及實型,三種數據的傳送有各自的指令集。
壓縮的BCD傳送指令僅有壓棧以及彈棧兩條:FBLD以及FBSTP,它們都僅有一個操作數,而且操作數必須是內存操作數的TWORD類型。
整型數據傳送指令有三條:FILD、FIST和FISTP,其中後兩條是出棧,唯一的區別在於出棧後是否改變(彈出)棧頂數據。它們都僅有一個操作數,而且操作數必須是內存操作數的WORD、DWORD以及QWORD類型,不能為BYTE類型。
相對來講,實數傳送指令比較多,它一共有四條:FLD、FST、FSTP和FXCH。前三條指令的用法與整型類似,只不過用於傳送實型數據,而且三條指令不僅支持內存操作數(為REAL4、REAL8和REAL10類型),而且支持寄存器之間的傳送。三條指令同樣需要一個操作數。而對於FXCH指令,它可以有一個或者沒有操作數,但如果有操作數,那麽這個參數必須為寄存器。
三.算術運算指令
在協處理器的指令系統中,有關數學運算指令有:加法指令、減法指令、乘法指令、除法指令和求平方根指令等。涉及數學運算的指令有比例運算、舍入運算、求絕對值運算和改變數值符號運算等指令。
(一)、整型算術運算指令
指令格式:
FIADD MemInt ;加法指令
FISUB MemInt ;減法指令
FISUBR MemInt ;減法指令
FIMUL MemInt ;乘法指令
FIDIV MemInt ;除法指令
FIDIVR MemInt ;除法指令
指令說明:
由於整型算術運算指令都僅有一個操作數,那麽另一個操作數就被隱含成ST(0),而運算結果也被保存在ST(0)中。
加和乘都僅有一條指令,它們的運算規則為:
ST(0)=ST(0)+MemInt
ST(0)=ST(0)*MemInt
但減法和除法都分別有兩條指令,後面帶R的指令是在運算之前先交換源/目的操作數的位置再進行運算。由於在加法和乘法運算中交換兩個操作數的位置的運算結果是一樣的,所以不存在加R的情況。
減法和除法的運算規則為:
ST(0)=ST(0)-MemInt ;相對於FISUB指令。
ST(0)=MemInt-ST(0) ;相對於FISUBR指令。
ST(0)=ST(0)/MemInt ;相對於FIDIV指令。
ST(0)=MemInt/ST(0) ;相對於FIDIVR指令。
綜上所述,在進行整型算術運算中,僅須指定一個內存操作數就可以了,另一個操作數則默認為是ST(0),並且結果也存放在ST(0)中。
(二)、實型算術運算指令
1.不帶彈出操作的算術運算指令。
指令格式:
FADD [STReg1, STReg2] ;加法指令。
FADD MemReal ;加法指令。
FSUB [STReg1, STReg2] ;減法指令
FSUB MemReal ;減法指令
FSUBR [STReg1, STReg2] ;減法指令
FSUBR MemReal ;減法指令
FMUL [STReg1, STReg2] ;乘法指令
FMUL MemReal ;乘法指令
FDIV [STReg1, STReg2] ;除法指令
FDIV MemReal ;除法指令
FDIVR [STReg1, STReg2] ;除法指令
FDIVR MemReal ;除法指令
上面的指令可以分為帶R和不帶R,區別在以前就講過。從上面的格式可以看出,它們都有三種使用格式:
(1) 不帶任何操作數。
如果不帶操作數,那麽FPU就默認為ST(1)作為目的操作數,而ST(0)作為源操作數。但這種情況下有一個彈出的動作,如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ST(1)=3.14
FSUB ;ST(1)=ST(1)-ST(0)=3.14-4.13=-0.99,再彈出ST(0)
也就是說執行過程是ST(1)=ST(1) op ST(0),再將ST(0)彈出,那麽ST(1)就變成ST(0),而原來的ST(0)就被彈出了。這一點是初學者最容易忘記的地方,在不帶有P的算術運算指令進行實數運算,並且不指定任何操作數的時候,指令默認有一個彈出操作。但這個規則僅用於實型算術運算,因為整型算術運算有一個操作數。
(2) 帶有一個操作數。
從上面的指令格式可以看出,如果帶有一個操作數,那麽這個操作數必須是內存操作數,在這種情況下,將ST(0)與該操作數進行運算,不管源/目的操作數位置如何,結果都存入ST(0)中(註意:這種情況沒有彈出動作)。例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FSUB Val2 ;ST(0)=ST(0)-Val2=3.14-4.13=-0.99
而在上面的FSUB帶一個R的話,即
FSUBR Val2
那麽就進行ST(0)=Val2-ST(0)的運算。
(3) 帶兩個操作數。
如果帶有兩個操作數,那麽兩個操作數必須都為寄存器,而且其中一個寄存器必須為ST(0)。結果存入目的寄存器中,同樣這種情況不帶彈出動作。例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ,ST(1)=3.14
FSUB ST(0),ST(1)
那麽,ST(0)=ST(0)-ST(1)=4.13-3.14=0.99,但ST(1)的值不變,還是為3.14。如果寫成:
FSUB ST(1),ST(0)
那麽,ST(1)=ST(1)-ST(0)=3.14-4.13=-0.99,而ST(0)值不變。
2.帶彈出操作的算術運算指令
指令格式:
FADDP STReg, ST ;加法指令
FSUBP STReg, ST ;減法指令
FSUBRP STReg,ST ;減法指令
FMULP STReg, ST ;乘法指令
FDIVP STReg, ST ;除法指令
FDIVRP STReg, ST ;除法指令
由於所有的指令都帶P,那麽都有彈出動作,從指令格式中可以看出,它們都有兩個操作數,而且倆操作數都是寄存器,源操作數都是ST(0)寄存器,而目的操作數是ST(1)~ST(7)中的任何一個,但不能是ST(0)。在進行運算時,運算結果存入目的寄存器中(ST(1)~ST(7)),然後對ST(0)進行彈出,彈出後下面的所有寄存器都要作相應的調整,例如:
.DATA
Val1 REAL8 3.14
Val2 REAL8 4.13
.CODE
FLD Val1 ;ST(0)=3.14
FLD Val2 ;ST(0)=4.13 ST(1)=3.14
FSUBRP ST(1),ST(0)
那麽,結果是這樣計算的:ST(1)=ST(0)-ST(1)=4.13-3.14=0.99並且將ST(0)彈出,然後存放結果的ST(1)以及後續的寄存器就進行調整,那麽此時ST(1)就變成ST(0)了,那麽最後的結果存入ST(0)中,而原來的ST(0)值4.13則被移出。
(三)、其它數學運算指令
在協處理器中,除了完成具體的數學運算指令外,還設置了若幹個與數學運算有關的運算指令。
改變符號:FCHS
這個指令會改變 ST(0)的正負值,如果原先 ST(0)為正值,執行後變為負值;原先為負值,執行後為正值。可以用這個指令計算相反數。
絕對值:FABS
把 ST(0)之值取出,取其絕對值後再存回去。
平方根:FSQRT
將 ST(0)之值取出,開根號後再存回去。
FSCALE 指令
這個指令是計算ST(0)*2ST(1)之值,再把結果存入 ST(0) 裏而 ST(1) 之值不變。ST(1) 必須是在 -32768 到 32768 (-215 到 215 )之間的整數,如果超過這個範圍計算結果無法確定,如果不是整數 ST(1) 會先向零舍入成整數再計算。所以為安全起見,最好是由整數載入到 ST(1) 裏。
FRNDINT 指令
這個指令是把 ST(0) 的數值舍入成整數,FPU 提供四種舍入方式,由 FPU 的控制字組(control word)中的 RC 兩個位決定,如下表:
RC |
舍入控制 |
說明 |
例子 |
00 |
四舍五入 |
向最近的整數 |
4.8 → 5.0 -4.8 →-5.0 |
01 |
取小於源數的最大整數 |
正值舍去小數部分 |
4.8 → 4.0 -4.8 →-5.0 |
10 |
取大於源數的最小整數 |
正值舍去小數部分後再加一 |
4.8 → 5.0 -4.8 →-4.0 |
11 |
向零對齊 |
不論正負值均舍去小數部分 |
4.8 → 4.0 -4.8 →-4.0 |
FPREM 指令
這個指令是求余數,較簡略的說法是將 ST(0) 除以 ST(1) 後的余數存回 ST,ST(1) 則不變(ST(0)=ST(0)%ST(1))。這個指令實際運作時,是以連續減法的方式求出余數。
FXTRACT 指令
這個指令稱為抽取指數與有效數,是把 ST(0) 內的數值改成 X*2Y,然後把 Y 存回 ST(0)裏,再把 X 壓入堆棧,所以最後 ST(0)為有效數,ST(1) 為以 2 為底的指數。FXTRACT 與 FSCALE 恰好成相反運算。
四.比較運算指令
使用比較指令是將棧頂中的數(ST(0))與其它操作數進行比較,實現條件跳轉。所謂條件跳轉就是比較兩數的大小,如果某數較大,就執行一段程序,若較小則執行另一段程序。在 FPU 的指令集並沒有能使 FPU 跳轉的指令,事實上 FPU 也無法改變 CPU 寄存器之值 (還記得要改變程序執行地址必須改變 CS:IP 之值),所以要產生 FPU 條件跳轉必須用間接方法。其步驟有四個:
先用 FPU 的比較指令改變 FPU 的狀態寄存器寄存器。
再用 FPU 的指令 FSTSW 把狀態寄存器存入一個內存變量裏。
將此內存變量存入 AH 寄存器,再用 CPU 指令 SAHF 指令存入 CPU 的標誌寄存器裏。此步驟使標誌寄存器之值等於FPU狀態寄存器。
再用 CPU 指令 JL/JG/JE/JA/JB 來跳轉至正確處執行。
狀態寄存器
FPU 有五類寄存器,前章已介紹過最常用的堆棧寄存器,這裏將介紹狀態寄存器(status register)。狀態寄存器是一個 16 位的寄存器,表示 FPU 的狀態,所謂狀態是指 FPU 是不是在忙碌中、是否除以零、是否無效運算、現在堆棧頂端是那一個堆棧寄存器等等,在此處我們要註意的是四個狀態碼位,C0、C1、C2、C3。這些位分布如下圖:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
B |
C3 |
TOP |
C2 |
C1 |
C0 |
ES |
SF |
PE |
UE |
OE |
ZE |
DE |
IE |
比較指令:FCOM、FCOMP、FCOMPP、FICOM、FICOMP
標題所見的這些比較指令都是以堆棧頂(ST(0))為目的操作數,而源操作數可以是內存變量或是其它的堆棧寄存器,例如:
FCOM ST(0),ST(1)
FCOM ST(0),x
上述第一例是比較 ST(0)和ST(1) 之數值,第二例是比較 ST(0)和內存變量 x 之數值,而這內存變量的形態可以是短實數和長實數。因為 FCOM 等指令均以 ST(0)為目的操作數,所以 ST(0)是可以省略不寫的,例如上述兩例,可以寫成下面的樣子,
FCOM ST(1)
FCOM x
結果是一樣的。假如 ST(0)的比較對象是 ST(1) 的話(源操作數是ST(1)),連 ST(1) 也可以省略。至於 FCOMP 和 FCOMPP 分別是比較後彈出一次和彈出兩次,這裏彈出的數會丟失而不會存入內存中,這點和 FSTP 不同。而 FICOM 和 FICOMP 是用來比較整數的,而源操作數可以是字和雙字整數,但不能是寄存器,至於目的操作數默認為是ST(0)。
FPU 的比較指令會改變狀態寄存器的 C3 和 C0 位,比較後跟據ST(0)和源操作數的大小,設置C3 和 C0標誌位如下表所示:
比較結果 |
C3 |
C0 |
ST(0)>源操作數 |
0 |
0 |
ST(0)<源操作數 |
0 |
1 |
ST(0)=源操作數 |
1 |
0 |
ST(0)不可比較 |
1 |
1 |
FSTSW 指令
FSTSW (store status register) 這個指令的功能是把狀態寄存器取出並存入內存變量裏,而這個內存變量必須是 16 位的內存變量。其語法是:
FSTSW mem16
SAHF 指令
SAHF 是 8088 指令集中的一個指令,並非 FPU 指令。這個指令是把 AH 寄存器中的值移到標誌寄存器的較低的 8 個位,這 8 個位只有第七、六、四、二、零位有用,第五、三、一位沒有使用。如下圖所示:
所以假如 AH 為 0100 0000B,則執行 SAHF 指令後,零標誌會被設為一。所以,跳轉指令其實是僅僅看標誌寄存器的設定值決定如何跳轉,至於標誌寄存器如何設定(人為還是機器指令運行結果),在跳轉指令執行時是不會理會的。
FPU 的狀態寄存器裏的 C3 和 C0 位,經 FSTSW 指令傳到 16 位內存變量,再傳到 AX 寄存器裏,AH 的第 6和0 位(ZF和CF)就是表示 C3 和 C0 位,再由 SAHF 指令移到標誌寄存器,其對應的位是零標誌與進位標誌,所以只要檢查這兩個標誌就可以比較 ST(0)與源操作數的大小,而決定跳轉方向。
FTST和FXAM指令
FTST 棧頂數據ST(0)與0進行比較。
FXAM 檢測棧頂數據ST(0)是正數、負數,還是規格化數。
兩條指令都是無操作數指令,它們的的比較結果參考C3和C0值的那個表。
五.常數操作指令
FPU 裏有 7 個指令是用來把常用的常數壓入堆棧頂稱為常數指令。這些常數都是內建在 FPU 裏的數值,都屬於暫時實數,其有效位數達 19 位數,當程序需要用到時可以很快的加載,節省時間與內存。這 7 個常數指令介紹如下:
FLD1 載入 1.0。( 把 1.0 壓入堆棧頂 )
FLDZ 載入零。( 把 0.0 壓入堆棧頂 )
FLDPI 載入圓周率,3.141592653589793239。( 把 π 壓入堆棧頂 )
FLDL2T 載入Log210。(把 Log210壓入堆棧頂)
FLDL2E 載入Log2e,e 是自然對數的底數。( 把Log2e壓入堆棧頂 )
FLDLG2 載入Log102。( 把Log102壓入堆棧頂 )
FLDLN2 載入Loge2,事實上Loge2等於 Ln 2。( 把Loge2壓入堆棧頂 )
六.超越函數運算指令
所謂超越函數運算指令是指復雜的函數運算的指令。8087 有五個超越指令,一個用於指數,兩個用於自然對數,另外兩個用於三角函數的計算。對於 8087 的超越指令所輸入的自變量和數學上的自變量不完全相同,例如求 2 的 X 次方,在數學上 X 可以是任意值,但用 8087 計算時 X 卻只能在 0 到 0.5 之間,如果要求 2 的任意數次方得用程序來計算。假如在 8087 程序中的自變量超過這個範圍,會引起錯誤但是 8087 卻沒有檢查機制,所以要小心使用。
F2XM1 指令
這個指令是用來計算2ST-1然後將結果存回 ST 裏。F2XM1 裏的 X 表示 ST 寄存器,M 表示減法之意,它的語法就是:
F2XM1
不含任何操作數。這個指令運算之前還有一個限制,那就是 X 必須是在 0 到 0.5 之間的實數才行,可以等於 0 或 0.5;在 Pentium 等級及其以上,X 可以擴充到在 0 到 1 之間。這個指令之所以要減一的目的是如果 X 很小,則2X會很接近一,減去一可增加有效數。
FYL2X 指令
這個指令是用來計算ST(1)*Log2 ST,這個指令會先彈出 ST 然後以計算的結果取代 ST 寄存器。這個指令的限制是 ST 必須為正數。
FYL2XP1 指令
這個指令是計算ST*Log2( ST(1)+1 ),這個指令會先彈出 ST 然後以計算的結果取代 ST 寄存器,ST(1) 必須是大於零且小於二分之根號二的數。這個指令在 Log 後的數很接近一時,比 FYL2X 有較好的準確度。
FPTAN 指令
這個指令用來計算 tan(ST) 之結果,而計算結果是以分數 Y/X 的形式存入堆棧,計算後先把 tan(ST)之值壓入堆棧(當作 Y 值),再把 1 (當作 X 值)壓入堆棧,換句話說最後的結果是ST(1)為tan(ST),ST為1。在8087等級的FPU運算時,計算前ST必須是0~π/4;如果在 Pentium 等級及其以上的 CPU,除了計算前ST須以弧度表示外,似乎沒有範圍限制。
FPATAN 指令
這個指令是用來計算 arctan ( ST(1)/ST ) 的,然後把計算結果以弧度表示存入ST。整個計算過程是先彈出堆棧頂當做分母(X),再彈出新的堆棧頂(也就是原來的ST(1) )當做分子,計算Y/X之反正切函數,再把計算結果存回堆棧頂。如果是在 8087 FPU 上運算,計算前 ST 與 ST(1) 必須為正值,而在 Pentium 及其以上的 CPU 則無此限制。
在 80387 等級及其以上的 FPU 還提供的更多的超越函數:
FSIN 指令
這是用來計算堆棧頂的正弦函數 (sin),再把結果壓入堆棧頂,計算前堆棧頂沒有範圍的限制,但要使用弧度,80387 等級及其以上的 FPU 才提供這個指令。
FCOS 指令
這是用來計算堆棧頂的余弦函數 (cos),再把結果壓入堆棧頂,計算前堆棧頂沒有範圍的限制,但要使用弧度,80387 等級及其以上的 FPU 才提供這個指令。
FSINCOS 指令
這個指令只有在 80387 等級及其以上的 FPU 才提供,它會彈出堆棧頂然後計算 sin ST 與 cos ST 之值,然後把 sin ST 之結果壓入堆棧寄存器,再把 con ST 之結果壓入堆棧寄存器,所以堆棧頂為余弦值, ST(1) 為正弦值。
七.協處理器控制指令
協處理器控制指令是用來控制協處理器狀態而設置的,它包括協處理器的初始化、狀態寄存器內容的存取、異常處理和任務切換等操作。
FINIT/FNINIT
初始化協處理器,初始化後協處理器的狀態如下表所示:
協處理器初始化的狀態
控制項 |
值 |
狀態含義 |
控制位IC |
0 |
投影 |
控制位PC |
10 |
擴展精度 |
控制位RC |
00 |
最近舍入或偶數 |
錯誤屏蔽 |
11111 |
錯誤位關閉 |
忙標誌 |
0 |
不忙 |
C3~C0 |
???? |
未定 |
TOP |
000 |
堆棧棧頂設定為寄存器0 |
ES |
0 |
無錯誤 |
錯誤位 |
00000 |
無錯誤 |
全部標記 |
11 |
空 |
寄存器 |
-- |
不改變 |
FLDCW Mem16
將由操作數指定的字存儲單元內容存儲到控制寄存器中。
FSTCW/ FNSTCW Mem16
把控制寄存器的內容存儲到由操作數指定的字存儲單元。與指令“FLDCW”相對應。
FSTSW Mem16
FSTSW AX
FNSTSW Mem16
FNSTSW AX
將控制寄存器的內容傳送到寄存器AX中。在8087協處理器中無此指令。
FCLEX/FNCLEX
清除狀態寄存器中的“錯誤”和“忙”標誌。
FSAVE Mem
FNSAVE Mem
將全部機器狀態存儲到內存中。
FRSTOR Mem
從內存復原機器狀態,它可恢復由指令“FSAVE/FNSAVE”保存的信息。
FSTENV Mem
FNSTENVMem
存儲協處理器環境。
FLDENV Mem
重新裝入由指令FSTENV/FNSTENV存儲的協處理器環境。
FINCST
堆棧指針加1。
FDECSTP
堆棧指針減1。
FFREE ST(i)
釋放堆棧寄存器,即使其標記為空,但其內容並沒有改變。
FNOP
協處理器的空操作
FWAIT
使處理器處於等待狀態,以便協處理器完成其操作。該指令主要用於在CPU訪問被協處理器影響的內存數據之前。
匯編,浮點運算符,fldpi,fmul等指令說明.