組合語言作業四
姓名: 顏嘉志
學號: B83503019
專題報告:
Using FPU
在微處理器的計算之中,若使用
要處理浮點運算,當然需要特別的
|
FPU DATA REGISTERS |
|
TAG |
||
|
79 |
78 |
63 |
|
1 |
R1 |
sign |
exponent |
Significant |
|
|
r2 |
|
|
|
|
|
r3 |
|
|
|
|
|
r4 |
|
|
|
|
|
r5 |
|
|
|
|
|
r6 |
|
|
|
|
|
r7 |
|
|
|
|
|
r8 |
|
|
|
|
|
15 |
Control Register |
Status Register |
Instruction Pointer |
Data Pointer |
其中,最重要的是
簡單的說,
Data Type |
BITS |
Significant Digits (decimal) |
Approximate Range (decimal) |
word integer |
16 |
4 |
-32768 ~ 32768 |
Short integer |
32 |
9 |
-2*10^9~2*10^9 |
Long integer |
64 |
18 |
-9*10^18 ~ 9*10^18 |
Short real |
32 |
6-7 |
1.175*10^-38 ~ 3.403*10^38 |
Long real |
64 |
15-16 |
2.225*10^308 ~ 1.798*10^308 |
Temp real |
80 |
9 |
3.37*10^-4932 ~ 1.19*10^4932 |
Packed decimal |
80 |
18 |
-99…99 ~ 99…99 (18 digits) |
FPU
基本運作
FPU
基本上是以一個Stack和外界的memory或register溝通。就如同stack的特性一樣,只有stack的入口可以和外界做load或store的動作。而在stack內部 (即 r0 - r7 )則可以任意的交換、運算,如同一般的register一樣。先來看看一個簡單的例子:
若我想求
finit |
|
; Initialize FPU & clear all registers |
fld |
a |
; Push a onto FPU stack |
fld |
b |
; Push b |
fmulp |
st(1), st |
; st 代表stack的top,st(1) 代表stack; 的第二個element,st(2) 代表stack; 的第三個element,依此類推。Fmulp; 代表把 st和st(1) 相乘之後放入; st(1),然後再pop st,故,此時; stack只剩a*b了。 |
fld |
c |
Push c |
fdivp |
st(1), st |
St = a*b/c |
fst |
Memory |
Store to the memory |
在運算之中,
下面列出了一些基本的指令:
(A)
、加法:
fadd |
st(i), st |
|
fadd |
st, st(i) |
|
faddp |
st(i), st |
;add and pop |
fadd |
|
; 即 faddp st(1), st |
(B)
、淢法:
fsub |
st(i), st |
;st(i) – st |
fsub |
st, st(i) |
;st – st(i) |
fsubp |
st(i), st |
;sub and pop |
fsub |
|
; 即 fsubp st(1), st |
(C)
、乘法:
fmul |
st(i), st |
|
fmul |
st, st(i) |
|
fmulp |
st(i), st |
;mul and pop |
fmul |
|
; 即 fmulp st(1), st |
(D)
、除法:
fdiv |
st(i), st |
;st(i) / st |
fdiv |
st, st(i) |
;st / st(i) |
fdivp |
st(i), st |
;div and pop |
fdiv |
|
; 即 fdivp st(1), st |
(E)
、特殊運算:
fptan |
;st = tan(st) |
fsin |
;st = sin(st) |
fcos |
;st = cos(st) |
fpatan |
;st = arctan(st) |
f2xm1 |
;st = 2^st –1, |st| < 0.5 |
fyl2x |
;st(1) = st(1)*log2(st) and pop |
fyl2xp1 |
;st(1) = st(1)*log2(st+1) and pop |
fsqrt |
;st = sprt(st) |
fscale |
;st(1) = st*2^st(1) |
fabs |
;st = |st| |
fchs |
;st = -st |
(F)
、Push 常數:
fldz |
;push 0.0 |
fld1 |
;push 1.0 |
fldpi |
;push pi |
fldl2t |
;push log2(10) |
fldl2e |
;push log2(e) |
fldlg2 |
;push log10(2) |
fldln2 |
;push log(2) |
(G)
、操作指令:
fld |
st(i) |
;load |
fst |
st(i) |
;store |
fxch |
st(i) |
;exchange st and st(i) |
finit |
|
;initialize |
fwait |
|
; 令CPU等候FPU運算 |
問題:
在一
Vc = E*(1-exp(-t/T))
其中
T = R*C為time constant,E為直流電壓。若
E = 100V,t = 0.002s,T = 0.001s,求Vc應該為多少?
答:
我們可以寫一個
#include <stdio.h>
#include <conio.h>
const double value = 0.5;
double t = -0.002;
double T = 0.001;
double E = 100.0;
double Vc;
void Calculate_exp_step1(void);
void Calculate_exp_step2(double temp);
void Calculate_Vc(void);
void main(void)
{
//----------------------------------------------------------------------------------------------------------//
// 第一步,先算出 Vc = (t/T)*log2(e)
//----------------------------------------------------------------------------------------------------------//
Calculate_exp_step1();
//----------------------------------------------------------------------------------------------------------//
// 第二步,讓 Vc = Vc / k,使得 Vc 在 0 ~ 0.5 之間 (為了要用 f2xm1 這
// 個指令)。而 k = 2^m,故迴圈要跑 m 次
//-----------------------------------------------------------------------------------------------------------//
Vc = -Vc;
int key = 0;
while( Vc > value )
{
Vc = Vc/2;
key++;
}
Vc = -Vc;
int number = 1;
//--------------------------------------------------------------------------------------------------------//
// number 就是前面所說的 k,key 就是前面所說的 m; number = 2^key
//--------------------------------------------------------------------------------------------------------//
number = number<<key;
double temp = Vc;
Vc = 1;
//------------------------------------------------------------------------------------------------------//
// 第三步,用 y^x = 2^(x*log2(y)) 使得 Vc = 2^( (1/k)*(t/T)*log2(e) )
// 即 Vc = ( exp((t/T)*(1/k)) ) ^ k = exp(t/T)
//------------------------------------------------------------------------------------------------------//
for(int i=0; i<number; i++)
Calculate_exp_step2(temp);
//-----------------------------------------------------------------------------------------------------//
// 第四步,求 Vc = E*( 1 - exp(t/T) )
//-----------------------------------------------------------------------------------------------------//
Calculate_Vc();
printf("\n Vc = %lf\n", Vc);
}
void Calculate_exp_step1(void)
{
//------------------------------------------------------------------------------------------//
// begin asm: return = (t/T)*log2(e)
//------------------------------------------------------------------------------------------//
asm{
finit;
fld t;
fld T;
fdivp st(1), st;
fldl2e;
fmulp st(1), st;
fst Vc;
}
//------------------------------------------------ End of asm -------------------------------------//
}
void Calculate_exp_step2(double temp)
{
//------------------------------------------------------------------------------------------//
// begin asm: return = e^(t/T)
//------------------------------------------------------------------------------------------//
double result;
asm{
finit;
fld temp;
fld1;
fxch;
f2xm1;
fxch;
faddp st(1), st;
fst result;
}
Vc *= result;
//------------------------------------------------ End of asm -------------------------------------//
}
void Calculate_Vc(void)
{
//------------------------------------------------------------------------------------------//
// begin asm: return = E*(1-e^(t/T))
//------------------------------------------------------------------------------------------//
asm{
finit;
fld Vc;
fld1;
fxch;
fsubp st(1), st;
fld E;
fmul;
fst Vc;
}
//------------------------------------------------ End of asm -------------------------------------//
}
執行結果如下:
A:\>testfpu
Vc = 86.466472
A:\>
The Personal Computer from the inside out, Addison Wesley
i486 Reference Manual