飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 3449|回复: 5

[转贴] VB中的常见函数

[复制链接]

该用户从未签到

发表于 2008-8-19 16:23:54 | 显示全部楼层 |阅读模式
标 题: [转贴]VB函数的列表(newlaos翻译整理)
发帖人:linhanshi
时 间: 2004-09-06 22:33
原文链接:http://bbs.pediy.com/showthread.php?threadid=4632
详细信息:


1) 数据类型转换:
a) __vbaI2Str    将一个字符串转为8 位(1个字节)的数值形式(范围在 0 至 255 之间) 或2 个字节的数值形式(范围在 -32,768 到 32,767 之间)。
b)__vbaI4Str   将一个字符串转为长整型(4个字节)的数值形式(范围从-2,147,483,648到2,147,483,647)
c)__vbar4Str  将一个字符串转为单精度单精度浮点型(4个字节)的数值形式
d)__vbar8Str   将一个字符串转为双精度单精度浮点型(8个字节)的数值形式
e) VarCyFromStr    (仅VB6库. 要调试,则在WINICE.DAT里必须有 OLEAUT32.DLL)字符串到变比型数据类型
f) VarBstrFromI2  (仅VB6库. 要调试,则在WINICE.DAT里必须有 OLEAUT32.DLL)整型数据到字符串:

2) 数据移动:
a) __vbaStrCopy      将一个字符串拷贝到内存,类似于 Windows API HMEMCPY
b) __vbaVarCopy     将一个变量值串拷贝到内存
c) __vbaVarMove    变量在内存中移动,或将一个变量值串拷贝到内存

3) 数**算:
a)  __vbavaradd      两个变量值相加
b) __vbavarsub      第一个变量减去第二个变量
c) __vbavarmul     两个变量值相乘
d) __vbavaridiv     第一个变量除以第二个变量,得到一个整数商
e) __vbavarxor       两个变量值做异或运算

4) 程序设计杂项:
a) __vbavarfornext  这是VB程序里的循环结构, For... Next...  (Loop)
b) __vbafreestr    释放出字符串所占的内存,也就是把内存某个位置的字符串给抹掉
c) __vbafreeobj   释放出VB一个对象(一个窗口,一个对话框)所占的内存,也就是把内存某个位置的一个窗口,一个对话框抹掉
d) __vbastrvarval  从字符串特点位置上获取其值
e) multibytetowidechar  将数据转换为宽字符格式,VB在处理数据之都要这样做,在TRW2000显示为7.8.7.8.7.8.7.8
f) rtcMsgBox   调用一个消息框,类似于WINDOWS里的messagebox/a/exa,此之前一定有个PUSH命令将要在消息框中显示的数据压入椎栈
g) __vbavarcat    将两个变量值相连,如果是两个字符串,就连在一起
h) __vbafreevar  释放出变量所占的内存,也就是把内存某个位置的变量给抹掉
i) __vbaobjset
j)  __vbaLenBstr   获得一个字符串的长度,注:VB中一个汉字的长度也为1
k) rtcInputBox    显示一个VB标准的输入窗口,类似window's API getwindowtext/a, GetDlgItemtext/a
l) __vbaNew      调用显示一个对话框,类似 Windows' API Dialogbox
m) __vbaNew2    调用显示一个对话框,类似 Windows' API Dialogboxparam/a
n) rtcTrimBstr   将字串左右两边的空格去掉

5) 比较函数
a)  __vbastrcomp   比较两个字符串,类似于 Window's API lstrcmp
b)  __vbastrcmp   比较两个字符串,类似于 Window's API lstrcmp
c) __vbavartsteq  比较两个变量值是否相等
d)__vbaFpCmpCy                  - Compares Floating point to currency. sp;            Compares Floating point to currency

6) 在动态跟踪,分析算法时,尤其要注意的函数:
rtcMidCharVar  从字符串中取相应字符,VB中的MID函数,用法MID("字符串","开始的位置","取几个字符")
rtcLeftCharVar 从字符串左边取相应字符,VB中的用法:left("字符串","从左边开始取几个字符")
rtcRightCharVar 从字符串右边取相应字符,VB中的用法:Right("字符串","从右边开始取几个字符")
__vbaStrCat  用字符串的操作,就是将两个字符串合起来,在VB中只有一个&或+
__vbaStrCmp  字符串比较,在VB中只有一个=或<>
ASC()函数    取一个字符的ASC值,在反汇编时,还是有的movsx 操作数

7) 在函数中的缩写:
bool 布尔型数据(TRUE 或  FALSE)
str  字符串型数据 STRING
i2   字节型数据或双字节整型数据  BYTE or Integer
ui2  无符号双字节整型数据  
i4   长整型数据(4字节)  Long
r4   单精度浮点型数据(4字节)  Single
r8   双精度浮点型数据(8字节)  Double
cy  (8 个字节)整型的数值形式 Currency
var  变量     Variant
fp  浮点数据类型  Float Point
cmp  比较   compare
comp 比较   compare

===================================================
刚才查一个函数 顺便放一个CM让大家练手:

00402953    FF15 64104000   CALL DWORD PTR DS:[<&MSVBVM60.__vbaR8Str>; MSVBVM60.__vbaR8Str
00402959    DD5D DC         FSTP QWORD PTR SS:[EBP-24]               ; 将KEY保存到四字的内存空间
0040295C    8D4D D8         LEA ECX,DWORD PTR SS:[EBP-28]
0040295F    FF15 9C104000   CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeS>; MSVBVM60.__vbaFreeStr
00402965    8D4D D4         LEA ECX,DWORD PTR SS:[EBP-2C]
00402968    FF15 98104000   CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeO>; MSVBVM60.__vbaFreeObj
0040296E    817D DC 00E45F9>CMP DWORD PTR SS:[EBP-24],9C5FE400       ; 内存中保存的浮点数
00402975    0F85 81000000   JNZ CM2.004029FC
0040297B    817D E0 E774A64>CMP DWORD PTR SS:[EBP-20],42A674E7       ; 内存中保存的浮点数
00402982    75 78           JNZ SHORT CM2.004029FC

CM2.rar

3.89 KB, 下载次数: 4, 下载积分: 飘云币 -2 枚

PYG19周年生日快乐!

该用户从未签到

 楼主| 发表于 2008-8-19 16:41:16 | 显示全部楼层
Ch 22 FPU (1) 簡介

link:http://home.educities.edu.tw/wanker742126/asm/ch22.html

FPU 簡介
FPU 是什麼
FPU 稱為浮點運算器是 floating-point processor unit 的縮寫它是一個處理數學運算的晶片。早在 1979 年英特爾就為了搭配 8086/8088 開發出一個名為 8087 的 FPU,IBM/PC/XT 個人電腦中的主機板上面,在 CPU 插槽附近有一個空著的插槽,就是給 FPU 用的。假如您去買 FPU,可以把 FPU 插在上面,再調整組態開關,就可使用 FPU 了。到了 80286、80386 時代也有與之配合的 FPU,分別稱為 80287、80387。到了 80486 時代,Intel 更把 FPU 整合到 80486 裡面變成單一晶片 ( 那時也有不含 FPU 的 80486,稱之為 SX,而含有 FPU 的稱為 DX)。到了 Pentuim 的時代,FPU 已經完全整合到 CPU 中,使用者完全感覺不到它的存在了。

講了這麼多,到底這個浮點運算器是幹什麼用的呢?小木偶想我們花了很多時間在講各種問題的處理上,這些都會牽涉到數的計算,直到目前為止,都停留在整數的計算,而帶有小數、很大或很小的數,或者我們想計算三角函數、指數、對數時,一般的 CPU 是不能用一條指令就計算出來,常用的方法是以軟體模擬計算,這種模擬常要花很多時間同時也增加程式碼。所以 Intel 就特別設計了一個處理器,專門做這些數值的計算,有別於整數所以稱之為浮點運算器,因為是輔助 CPU 運算的所以也有人稱為輔助運算器、共同處理器 (coprocessor) 或是數值資料處理器 (NDP,numberic data processor) 等等。FPU 是採用硬體來計算浮點數、對數、三角函數等複雜運算,所以速度比用 CPU 以軟體模擬還快且精確許多,而且程式碼也小很多。

我想,由上面的說明,您應當瞭解 CPU 和 FPU 所處理的事不一樣,FPU 和 CPU 各有各的指令集,彼此不互相干擾。當 CPU 由記憶體提取指令時,如果發現這個指令是屬於 FPU 的指令,就將該指令所需要的位址計算好,交由 FPU 去處理,而 CPU 就接著去處理下一道指令,所以 CPU 和 FPU 能夠同步運算。但是這裡出現兩個問題,第一,如果下一道指令恰好要用到上一道 FPU 所計算的結果,這時就會產生錯誤;第二,在 FPU 運算結束之前,不能再執行下一道 FPU 指令。程式設計師有責任要注意到第一種錯誤是否可能發生,為保證同步運算,在兩個相連的 FPU 和 CPU 指令且同時存取相同的記憶體位址時,得在 FPU 指令前加上 WAIT 指令,而第二種錯誤的避免責任由組譯器負責,MASM 會在每一條 FPU 指令前自動加上 WAIT 這個指令,以保證與 CPU 能同步。

WAIT/FWAIT 指令
WAIT 指令就是使 CPU 等候 FPU 執行完成的指令,也可以寫成 FWAIT。組譯器會自動在每條 FPU 指令前加上 FWAIT 指令。

FPU 暫存器
FPU 的暫存器可分為五類,堆疊暫存器 (register stack)、狀態字組 (status word)、控制字組 (control word)、標籤字組 (tag word)、例外指標 (exception pointer)。雖然看起來很複雜,但是最重要且最常用的是堆疊暫存器。

FPU 共有八個堆疊暫存器,分別是 ST、ST(1)、ST(2)、ST(3)……ST(7),這八個暫存器每一個都是 80 位元,用來存放運算時所需要的資料,這和以前我們所說的堆疊所存的資料不太相同,但是操作方式卻是一樣的。FPU 許多運算都是先把數值推入堆疊頂端的 ST 暫存器,再對 ST 暫存器作運算。

這 8 個堆疊暫存器運作方式如同自助餐廳堆在起一堆的餐盤,當服務生堆上一個新餐盤,原來露在最上面的餐盤就變成第二個,第一個變成新餐盤,並且露在最上面;當取出最上面的餐盤,其餘就都往上移一位置,原來第二個餐盤就露出來了。以術語來說,資料存放在堆疊稱為推入 (push),移出頂端的資料稱為彈出 (pop),但是在 FPU 實際運用上並不是真的把數值移到上或下一個堆疊暫存器,而是以一個指標來表示那一個堆疊暫存器在頂端,同時 FPU 也允許存取底下的堆疊,不像餐盤只能拿取最上面的餐盤。

以下圖說明,一開始堆疊是空的,首先把 987654 推入堆疊頂,所以 ST 為 987654,其餘仍是空的;第二步把 123456 推入堆疊,於是 ST 變為 123456,原先的 987654 被移到 ST(1),其餘仍是空的;第三步取出堆疊頂的資料,123456 被移到其他地方(記憶體某處),987654 被移到 ST,而 ST(7) 會移進一個空的資料。

01.GIF


--------------------------------------------------------------------------------

第一個 FPU 組合語言程式
原始程式
好了,小木偶想先簡單寫一個程式來介紹如何操作 FPU 的堆疊暫存器。底下小木偶介紹一個簡單的程式可以直接計算 32 位元的整數加法程式,但是為了將注意力集中在 FPU 的堆疊暫存器上,所以執行結果必須用 DEBUG.EXE 來觀察。

;***************************************
code    segment
        assume  cs:code,ds:code
        org     100h
;---------------------------------------
start:  jmp     short begin
n1      dd      987654  ;07 被加數
n2      dd      123456  ;08 加數
sum     dt      ?       ;09 聚集的 BCD 數
begin:  finit           ;  st   ; st(1) ; st(2) ;10
        fild    n1      ; 987654;       ;       ;11
        fild    n2      ; 123456; 987654;       ;12
        fadd            ;1111110;       ;       ;13
        fbstp   sum     ;       ;       ;       ;14
        int     20h
;---------------------------------------
code    ends
;***************************************
        end     start
短整數與聚集 BCD 數
FPU 可以接受七種型態的數值,在此程式裏只用兩種:短整數 (或短式整數,short integer)與聚集的 BCD 數。短整數是由雙字組 (您也可以說 32 個位元) 組成,它是以 2 的補數方式表示整數,其範圍為 -2x109 到 +2x109,它相當於 BASIC 的單精確度資料型態,在組合語言原始碼裏用『DD』定義,程式的第 7﹑8 行就定義了兩個短整數,n1 與 n2。

聚集的 BCD 數是由十個位元組組成,可以表示 18 位的整數,最高位址的那一個位元組的第 07 個位元表示此數的正負值,如果該位元為一表負值,零表正值,第 0 到 6 位元則未使用,在組合語言原始碼裏用『DT』來定義,DT 的意思是 define ten bytes,程式第 9 行就定義了一個聚集的 BCD 數。

現在來看看這個程式中所用到的幾個 FPU 指令,您可以看到四個新的指令,它們都是以『F』開頭的,事實上,凡是 FPU 的指令都是以『F』開頭。

FINIT 指令
FINIT 的功能就是把 FPU 重設,會把清除堆疊暫存器,所有的忙碌中斷,例外中斷旗標,一般要使用 FPU 時通常都會先用 FINIT 來重設。

FILD 指令
這個指令是用來把整數推入堆疊暫存器內 (載入整數到堆疊暫存器),至於要推入的整數則寫在 FILD 的後面,您可以將它看成 integer load 的意思,而要推入的整數型態則是由『DW』﹑『DD』﹑『DQ』定義,這三個定義分別定義字組整數、短整數、長整數。其語法是

FILD    來源運算元
FADD 指令
這是把目的運算元 (直接接在指令後的變數或堆疊暫存器) 與來源運算元 (接在目的運算元後的變數或堆疊暫存器) 相加,並將結果存入目的運算元,它有三種格式:

指定兩個運算元,則其中一個一定要是 ST 暫存器,另一個也要是堆疊暫存器,FADD 會把來源運算元與目的運算元相加,並將結果存入目的運算元。例如:
FADD    ST,ST(2)
這個例子是把 ST 加上 ST(2) 後再存回 ST 中,所以 ST 值會改變而 ST(2) 之值不變。
指定一個運算元,則此運算元表示來源運算元,而且必須是短實數或長實數其中之一的變數,FADD 會把來源運算元加上 ST,並存入 ST。例如:
FADD    mem
這個例子事實上和 FADD ST,mem 一樣。


不指定運算元,就如同本程式,則 FADD 會把 ST(1) 加上 ST 並將和存入 ST(1),再彈出 ST 暫存器,所以最後的結果是 ST 等於原 ST 加上原 ST(1),並且還有彈出動作,這是初學者常犯的錯誤。(參考 FADDP 指令)
FBSTP 指令
這是把堆疊頂以聚集的 BCD 數彈出到接在後面的目的運算元,這個目的運算元必須是用『DT』定義的聚集 BCD 數。這個指令您可以記成 BCD store and pop,很明顯的 FBSTP 中的『ST』是 store 之意,P 是 pop 之意,其語法是:

FBSTP   目的運算元
以 DEBUG 觀察
小木偶將此程式命名為 FPU1.ASM,並將它變成 FPU1.COM 執行檔,用 DEBUG 看看:

H:\HomePage\SOURCE>debug fpu1.com [Enter]
-d 100 L20 [Enter]
1F90:0100  EB 12 06 12 0F 00 40 E2-01 00 00 00 00 00 00 00   ......@.........
1F90:0110  00 00 00 00 9B DB E3 9B-DB 06 02 01 9B DB 06 06   ................
-r [Enter]
AX=0000  BX=0000  CX=002B  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=1F90  ES=1F90  SS=1F90  CS=1F90  IP=0100   NV UP EI PL NZ NA PO NC
1F90:0100 EB12          JMP     0114
-t [Enter]

AX=0000  BX=0000  CX=002B  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=1F90  ES=1F90  SS=1F90  CS=1F90  IP=0114   NV UP EI PL NZ NA PO NC
1F90:0114 9B            WAIT
-u 114 129 [Enter]
1F90:0114 9B            WAIT
1F90:0115 DBE3                  FINIT
1F90:0117 9B            WAIT
1F90:0118 DB060201              FILD    DWORD PTR [0102]
1F90:011C 9B            WAIT
1F90:011D DB060601              FILD    DWORD PTR [0106]
1F90:0121 9B            WAIT
1F90:0122 DEC1                  FADDP   ST(1),ST
1F90:0124 9B            WAIT
1F90:0125 DF360A01              FBSTP   TBYTE PTR [010A]
1F90:0129 CD20          INT     20
您可以看到,在原始程式裏小木偶並沒有使用 WAIT 指令,但是 MASM 會自動在每一行 FPU 指令前加上去,而您可能發現 FADD 指令被 MASM 換成 FADDP ST(1),ST 了,怎麼會這樣呢?我想當我解釋完 FADDP 指令您就會釋疑了。

FADDP 指令
這個指令是使目的運算元加上 ST 暫存器,並彈出 ST 暫存器,而目的運算元必須是堆疊暫存器的其中之一,最後不管目的運算元為何,經彈出一次後,目的運算元會變成上一個堆疊暫存器了。其語法為:

FADDP   ST(?),ST
所以 FADDP ST(1),ST 結果和 FADD 指令省略所有運算元時是一樣的。

在上面用白色字表示的數值為 0F1206,這個數當然是十六進位整數,也就是程式中定義的 n1,您可以以筆算看看,是不是就是 987654?如果您已經不記得怎麼計算,請參考附錄一。

用 DEBUG 來追蹤這個程式並無意義,因為 DEBUG 無法觀察 FPU 的暫存器,所以小木偶直接執行到程式尾端,觀察經過 FBSTP 運算後的 sum 變數:

-g 129 [Enter]

AX=0000  BX=0000  CX=002B  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=1F90  ES=1F90  SS=1F90  CS=1F90  IP=0129   NV UP EI PL NZ NA PO NC
1F90:0129 CD20          INT     20
-d 100 L20 [Enter]
1F90:0100  EB 12 06 12 0F 00 40 E2-01 00 10 11 11 01 00 00   ......@.........
1F90:0110  00 00 00 00 9B DB E3 9B-DB 06 02 01 9B DB 06 06   ................
上面紅色的數值就是其結果,是不是和我們運算的一樣呢?


--------------------------------------------------------------------------------

小數的加法
以 FPU 來計算整數,實在是大材小用,底下我們來看看 FPU 怎樣計算帶有小數的加法。

;***************************************
code    segment
        assume  cs:code,ds:code
        org     100h
;---------------------------------------
start:  jmp     short begin
n1      dd      10.25   ;07 被加數
n2      dd      2.33    ;08 加數
sum     dd      ?       ;09 和
begin:  finit           ;  st   ; st(1) ; st(2) ;10
        fld     n1      ; 10.25 ;       ;       ;11
        fld     n2      ;  2.33 ; 10.25 ;       ;12
        fadd            ; 12.58 ;       ;       ;13
        fstp    sum     ;       ;       ;       ;14
        int     20h
;---------------------------------------
code    ends
;***************************************
        end     start
這個程式小木偶命名為 FPU2.ASM,它和 FPU1.ASM 不同之處,僅在於載入與彈出的部分,載入小數或是很大很小的數 (帶有小數的數或以十的冪方表示的數稱為浮點數) 用 FLD 載入,不可用 FILD 否則 FPU 會自動將小數點後的數捨入。

FLD 指令
載入浮點數到 ST 暫存器。而要載入的數可以用『DD』、『DQ』﹑『DT』來定義。

FSTP 指令
這個指令是用來把 ST 的數以浮點數的方式彈出至後面接的變數裏,而這個變數必須是用『DD』、『DQ』、『DT』其中之一定義的。其語法是:

FSTP    變數名
我想初學者要注意的是載入整數要用 FILD,載入浮點數要用 FLD(註一),這點很重要,也是常犯的錯誤。好吧,現在用 DEBUG 載入觀察看看。

H:\HomePage\SOURCE>debug fpu2.com [Enter]
-r [Enter]
AX=0000  BX=0000  CX=0025  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=128B  ES=128B  SS=128B  CS=128B  IP=0100   NV UP EI PL NZ NA PO NC
128B:0100 EB0C          JMP     010E
先看看 n1、n2 組譯後變成什麼樣子?

-d 102 Lc [Enter]
128B:0100        00 00 24 41 B8 1E-15 40 00 00 00 00           ..$A...@....
Short Real 短實數
上面白色部分的就是 n1 組譯後的情形,變成 41 24 00 00 了,n2 則變成 40 15 1E B8,sum 是 00 00 00 00,怎麼會變成這樣呢?原來組譯器看到帶有小數點的數值 (浮點數) 會翻譯成 IEEE 格式,而不用十六進位來處理。用 『DD』定義的浮點數稱為『短實數』,短實數佔有 4 個位元組,共 32 個位元。這 32 位元的最高位元 (第 31 位元) 表示正負值 (sign),若為零表示此數為正數,為一表示此數是負數。第 23 到 30 位元這 8 個位元表示指數部分 (exponent),指數部分是以 2 為底數,但在做乘冪之前,指數還得減去基準數 (bias),短實數的基準數是 127。第 0 位元到第 22 位元是有效數部份 (significand),有效數部份是以 1 開始,依次減半的等比數列 1/2、1/4、1/8、1/16、1/32……的方式排列相加,因為 1 固定所以不表示,而從 1/2 開始。而最後短實數的數值是:

短實數 = (-1)sign×significand×2exponent
以 10.25 為例,組譯器翻譯成 IEEE 格式是 41 24 00 00 先變成二進位 0100 0001 0010 0100 0000 0000 0000 0000,第 31 位元(天藍色)為零表示正數,接下來的 8 個位元(白色)換成十進位是 130,減去基底數 127 等於 3,所以指數部分就是 23。而最後面的部分是有效數,小木偶將它排成直列來說明:

1 ==>              1 (固定值,不在IEEE格式表示出來)
0 ==>表示 1/2*0  = 0
1 ==>表示 1/4*0  = 0.25
0 ==>表示 1/8*0  = 0
0 ==>表示 1/16*0 = 0
1 ==>表示 1/32*1 = 0.03125
以下皆為零
最後 1+0.25+0.03125 為 1.28125,再乘以指數部份 23 即可得 10.25。

這種方法看起來很複雜,不過我們不需要知道如此瑣碎的事情,我們對浮點數只需要知道三件事,佔用位元組幾個,準確度多少,能表示的範圍多大,這些請看註三。

-u 10e 123 [Enter]
128B:010E 9B            WAIT
128B:010F DBE3                  FINIT
128B:0111 9B            WAIT
128B:0112 D9060201              FLD     DWORD PTR [0102]
128B:0116 9B            WAIT
128B:0117 D9060601              FLD     DWORD PTR [0106]
128B:011B 9B            WAIT
128B:011C DEC1                  FADDP   ST(1),ST
128B:011E 9B            WAIT
128B:011F D91E0A01              FSTP    DWORD PTR [010A]
128B:0123 CD20          INT     20
-g [Enter]

Program terminated normally
-d 102 Lc [Enter]
128B:0100        00 00 24 41 B8 1E-15 40 AE 47 49 41           ..$A...@.GIA
同樣的,計算完後仍以浮點數方式表示,見白色部份,為了方便,小木偶建議使用 SYMDEB.EXE 來除錯,雖然它無法觀看堆疊暫存器的數值,但是可以把短實數﹑長實數和暫時實數三種模式變成十進位的『科學記號』(有點和真正的科學記號出入) 顯示於螢光幕。底下用 SYMDEB 來看看:

H:\HomePage\SOURCE>symdeb fpu2.com [Enter]
Microsoft (R) Symbolic Debug Utility  Version 4.00
Copyright (C) Microsoft Corp 1984, 1985.  All rights reserved.

Processor is [80286]
-ds 102 L3 [Enter]
21FE:0102  00 00 24 41  +0.1025E+2
21FE:0106  B8 1E 15 40  +0.2329999923706055E+1
21FE:010A  00 00 00 00  +0.0E+0
-g [Enter]

Program terminated normally (0)
-ds 102 L3 [Enter]
21FE:0102  00 00 24 41  +0.1025E+2
21FE:0106  B8 1E 15 40  +0.2329999923706055E+1
21FE:010A  AE 47 49 41  +0.1257999992370605E+2
SYMDEB 加強了 dump 指令,ds 就是用短實數方式顯示,dl (英文字母的L,不是阿拉伯數字的 1) 是以常實數方式顯示,可以參考附錄六。您可以看到在 010A 處就是 FPU 的計算結果,您或許會說,怎麼不是 12.58?這是因為當把浮點數變成 IEEE 格式推入 FPU 堆疊暫存器時,會產生誤差,這是無可避免的,在 FPU 的堆疊暫存器裏僅有 80 位元,當然不能表示所有的數,所以會必定做一些捨入動作。

設計師所能做的是增加精確度而已,所以此處您應該注意兩件事。第一,您所寫的程式所需精確度為何?如果是不須太準確就用短實數,如果要求很高就用暫時實數。第二,儘量不要把堆疊暫存器的數推入彈出,只有必要時再做,因為這樣不但會降低精確度也浪費時間。

算數指令
在簡單介紹過 FPU 堆疊操作後,小木偶簡單介紹有關 80X87 四則運算指令。

加法指令:FADD﹑FADDP﹑FIADD
FPU 提供了三種加法指令,前兩種,FADD﹑FADDP 前面已敘述過,不再重複,此處僅介紹 FIADD 指令。顧名思義,『I』是指整數 (integer) 之意,FIADD 是把 ST 加上來源運算元,然後再存入 ST 暫存器,來源運算元必須是字組整數或短整數形態的變數。其語法是

FIADD   mem
mem 是字組整數或短整數形態的變數。

減法指令:FSUB﹑FSUBP﹑FSUBR﹑FSUBRP﹑FISUB﹑FISUBR
FPU 所提供的減法指令有六種:FSUB﹑FSUBP﹑FSUBR﹑FSUBRP﹑FISUB﹑FISUBR。第一個指令,FSUB 指令,它的用法和 FADD 相同,也有三種格式,分成指定兩個運算元﹑指定一個運算元和不指定運算元三種。第二個指令,FSUBP,它的用法和 FADDP 相同,所以這兩個指令就不再說明。

第三個指令,FSUBR 指令,它和 FSUB 只有一點不同,就是減數與被減數互換,這個『R』字是 reversed 的意思。它也有三種格式:

指定兩個運算元,語法如下:
FSUBR   x,y
x,y 其中之一必須是 ST 暫存器,另外一個必須是其他的堆疊暫存器,FSUBR 會把以 y-x 所得之差存入 x 內。例如:
FSUBR   ST(2),ST
是把 ST-ST(2) 之值存入 ST(2) 裏。


指定一個運算元,語法如下:
FSUBR   mem
此運算元一定要是記憶體變數,而且必須是短實數或長實數之一的實數形態,FSUBR 會把此變數之值減去 ST 暫存器再存到 ST 暫存器裏。


不指定運算元,則表示把 ST 之值減去 ST(1),並把差存回 ST(1),再做一次彈出動作,所以最後 ST 之值為原來的 ST 減 ST(1)。


第四個指令,FSUBPR,它的用法和 FSUBP 相同,只有一點不同,就是減數與被減數互換。例如

FSUBPR  ST(1),ST
這個例子會把 ST-ST(1) 之差存入 ST(1),然後再做一次彈出動作,使得最後 ST 變成原來的 ST-ST(1)。

第五個指令,FISUB,它是整數減法指令,把 ST 減去來源運算元的差,再存入 ST 內,來源運算元必須是字組整數或短整數變數。

第六個指令是,FISUBR,它也是整數減法指令,它和 FISUB 指令相同,差別只在減數與被減數交換。

乘法指令:FMUL﹑FMULP﹑FIMUL
這三個指令和 FADD﹑FADDP﹑FIADD 相同,只是加法改成乘法而已。

除法指令:FDIV﹑FDIVP﹑FDIVR﹑FDIVRP﹑FIDIV﹑FIDIVR
這六個除法指令和減法指令 FSUB﹑FSUBP﹑FSUBR﹑FSUBRP﹑FISUB﹑FISUBR 相同,只是減法改成除法。

改變符號:FCHS
這個指令會改變 ST 的正負值,如果原先 ST 為正值,執行後變為負值;原先為負值,執行後為正值。

絕對值:FABS
把 ST 之值取出,取其絕對值後再存回去。

平方根:FSQRT
將 ST 之值取出,開根號後再存回去。

FSCALE 指令
這個指令是計算 ST*2ST(1)之值,再把結果存入 ST 裏而 ST(1) 之值不變。ST(1) 必須是在 -32768 到 32768 (-215 到 215 )之間的整數,如果超過這個範圍計算結果無法確定,如果不是整數 ST(1) 會先向零捨入成整數再計算。所以為安全起見,最好是由字組整數載入到 ST(1) 裏。

FRNDINT 指令
這個指令是把 ST 的數值捨入成整數,FPU 提供四種捨入方式,由 FPU 的控制字組(control word)中的 RC 兩個位元決定,如下表:

02.GIF

FPREM 指令
這個指令是求部份餘數(partial remaimder),較簡略的說法是將 ST 除以 ST(1) 後的餘數存回 ST,ST(1) 則不變。這個指令實際運作時,是以連續減法的方式求出餘數,詳細情形在三角函數時說明。

FXTRACT 指令
這個指令稱為抽取指數與有效數(extract exponent and significand),是把 ST 內的數值改成 X*2Y,然後把 Y 存回 ST 裏,再把 X 推入堆疊,所以最後 ST 為有效數,ST(1) 為以 2 為底的指數。FXTRACT 與 FSCALE 恰好成相反運算。

整理
講了這麼多的算數指令,在此做個整理。8087 共有 68 個指令,分為 6 大類:資料傳輸(data transfer)指令、算術指令、超越函數(transcendental)指令、常數(constant)指令、比較(comparison)指令、處理機控制(processor control)指令。

針對算術指令,8087 提供了 18 個有關四則運算的指令以及三個較常用的指令。這 18 個四則運算的指令基本格式都是像下面這樣

指令    目的運算元, 來源運算元
其操作過程都是把目的運算元和來源運算元做加、減、乘、除後再存回目的運算元,其中加法與乘法目的運算元和來源運算元互換並不影響結果,但減法與除法則結果會不同,所以又分為兩種,標準減法是目的運算元減去來源運算元後再存回目的運算元,而『反』減法則是來源運算元減去目的運算元後再存回目的運算元,除法也和減法相同,不再贅述。

這些四則運算指令依目的運算元及來源運算元的格式又可分為三種,:

實數(如FADD、FSUB、FSUBR、FMUL、FDIV、FDIVR):可依後面的指定方式再分為指定兩個運算元、僅指定來源運算元和不指定運算元三種格式,請參考FADD及FSUBR之說明。


實數且彈出(如FADDP、FSUBP、FSUBRP、FMULP、FDIVP、FDIVRP):這類格式只能使用堆疊暫存器為運算元,而且 ST 固定為來源運算元,所以 ST 可省略不寫出來。


整數(如FIADD、FISUB、FISUBR、FIMUL、FIDIV、FIDIVR):此類運算的來源運算元只能為字組整數或短整數的變數,不能是堆疊暫存器。目的運算元固定是 ST 暫存器,也可以省略不寫出來。



--------------------------------------------------------------------------------

註一:事實上載入整數有兩種方法:用 FILD 和 FLD,它們的使用方法不同。假如用 FILD 載入,則必須用 DW、DD、DQ 三種方式宣告,並且其後的資料必須是沒有小數點或 E。(E 表示 10 的幾次方,這幾次方寫在 E 的後面)。假如用 FLD 載入,則用 DD、DQ 方式宣告,而其後的資料必須包含小數點或是 E。例如:

num1    dd      123456
num2    dd      123456.0
        fild    num1
        fld     num2
雖然 num1、num2 都是十二萬三千四百五十六的整數,但是經由 MASM 編碼後之結果不同,num1 被看成是十六進位整數,編碼成 01E240,num2 被看成是 IEEE 浮點格式,編碼成 00 20 F1 47,因此載入方法不同。

註二:事實上,浮點數的編碼方式有兩種,一種是 IEEE 格式,另一種是微軟自訂的『Microsoft 二進位格式』。在 MASM 第 5.0 版及其以後版本的浮點數,MASM 會自動編碼成 IEEE 格式;而在 MASM 4.0 及其以前的版本會自動使用『Microsoft 二進位格式』。要使用那一種編碼方式,可以在原始程式的第一行或第一個區段定義前面加上『.8087』或『.MSFLOAT』指示元,前者表示使用 IEEE 編碼,後者使用微軟二進位格式編碼。

換句話說,如果您是使用 MASM 5.0 及其以後的版本,不加『.8087』和加入『.8087』都會被編碼成 IEEE 格式,如果要使用『微軟二進位格式』的話必須加上『.MSFLOAT』指示元。反之,在 MASM 4.0 及其前版的組譯程式要使用 IEEE 格式編碼時必須加上『.8087』指示元,否則會使用微軟二進位格式。

另外還有『.80287』指示元是用來使用 80287 新增加的指令。

註三:80X87 所能接受的資料形態共有七種,分別是四種整數:字組整數﹑短整數﹑長整數﹑聚集 BCD 數;以及三種浮點數:短實數﹑長實數﹑暫時實數。

除了聚集 BCD 數外,整數均以十六進位來表示,只是長度不同而已,字組整數長 16 位元( 2 個位元組),用『DW』定義。短整數長 32 位元 ( 4 個位元組 ),用『DD』定義 (定義雙字組之意,define di-word)。長整數長 64 位元 ( 8 個位元組 ),用『DQ』定義 (定義四字組之意,define quart-word)。

短實數的說明,已經在前文說明,請按下閱讀,長實數與暫時實數的編排方式和短實數類似,只是指數部份和有效數部份不同而已。長實數以『DQ』定義,正負值在第 63 位元,指數部份在第 52 到 62 位元,其餘為有效數部份,基準值為 1023。暫時實數以『DT』定義,正負值在第 79 位元,指數部份在第 78 到 64 位元,其餘為有效數部份,基準值為 16383,在 FPU 堆疊暫存器裏儲存的數都是暫時實數,即使用整數載入 FPU 也會將他轉換成暫時實數。底下是它們的說明圖:

03.GIF


底下是它們的列表整理:

04.GIF
PYG19周年生日快乐!
  • TA的每日心情
    开心
    2017-6-4 17:21
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2008-8-19 16:48:44 | 显示全部楼层
    来好好学习一下/:good
    PYG19周年生日快乐!

    该用户从未签到

     楼主| 发表于 2008-8-19 16:54:27 | 显示全部楼层
    浮点型数据在内存中是如何保存的 哪位大哥知道了 能否告诉一下

    1.
    0012F4E4   00 00 00 00 00 00 F0 3F                          ......?.
    2.
    0012F4E4   00 00 00 00 00 00 00 40                          .......@
    3.
    0012F4E4   00 00 00 00 00 00 08 40                          ......@
    4.
    0012F4E4   00 00 00 00 00 00 10 40                          ......@
    5.
    0012F4E4   00 00 00 00 00 00 14 40                          ......@
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2008-8-20 17:08:06 | 显示全部楼层
    这东西不错 谢谢LZ分享:loveliness: :loveliness:
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2 小时前
  • 签到天数: 916 天

    [LV.10]以坛为家III

    发表于 2008-8-26 17:23:22 | 显示全部楼层
    这东西不错 谢谢LZ分享/:013 /:013 /:013 /:013
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表