本节提供几个利用协处理器进行编程的例子,从这些例子可看出使用协处理器指令编程的方法和技巧。
解:
.MODEL SMALL
.386
.387
.DATA
L DD 4.0
F DD 1000.0 ;为了便于循环控制,F“从大到小”来计算
TEN DD 10.0
Y DD 100 DUP(?)
.CODE
.STARTUP
FLDPI ;装入π
FADD ST, ST(0) ;自身相加,得到2π
FMUL L ;计算出不变的结果2πL
MOV ECX, 100
MOV EDI, OFFSET Y-4
again:
FLD F
FMUL ST, ST(1) ;得到一个计算结果2πLF
FSTP dword ptr [EDI+4*ECX] ;保存当前得到结果(从后向前)
FLD F
FSUB TEN
FSTP F ;F的值变小10.0
LOOP again
FCOMP ;先前计算出结果2πL出栈,使之为空
.EXIT 0
END
解:
.MODEL SMALL
.386
.387
.DATA
DATA DD -1234.75
STATUS DW ?
WHOLE DD ?
FRACT DD ?
.CODE
DISPS PROC NEAR ;子程序:显示AL中的字符
MOV AH, 6
MOV DL, AL
INT 21H
RET
DISPS ENDP
.STARTUP
FSTCW STATUS ;以小数形式显示浮点数DATA
OR STATUS,0C00H ;设定截取舍入方式
FLDCW STATUS
FLD DATA
FTST
FSTSW AX
AND AX, 4500H
CMP AX, 0100H
JNZ Positive
MOV AL, ‘-‘
CALL DISPS
FABS
Positive:
FLD ST
FRNDINT
FIST WHOLE ;保存整数部分
FSUBR
FABS
FSTP FRACT ;保存小数部分
MOV EAX, WHOLE
MOV EBX, 10
MOV CX, 0
PUSH BX
Again1:
MOV EDX, 0
DIV EBX
ADD DL, 30H
PUSH DX
INC CX
CMP EAX, 0
JNZ Again1
Disp1:
POP AX
CALL DISPS ;显示整数部分
LOOP Disp1
MOV AL, ‘.’
CALL DISPS ;显示小数点
MOV EAX, FRACT
FSTCW STATUS
XOR STATUS, 0C00H
FLDCW STATUS
FLD FRACT
FXTRACT
FSTP FRACT
FABS
FISTP WHOLE
MOV ECX, WHOLE
MOV EAX, FRACT
SHL EAX, 9
RCR EAX, CL
Again2:
MUL EBX
PUSH EAX
XCHG EAX, EDX
ADD AL, 30H
CALL DISPS
POP EAX
CMP EAX, 0
JNZ Again2
.EXIT 0
END
解:
.MODEL SMALL
.386
.387
.DATA
DATA DD 0
TEN DD 10.0
TEMP DW ?
SIGN DB ?
.CODE
GETCH MACRO ;宏GETCH的功能是从键盘读入一个字符
MOV AH, 1
INT 21H
ENDM
.STARTUP
FLDZ ;ST=0
GETCH
.IF AL == ‘+’ ;判定是否输入正号‘+’
MOV SIGN, 0
GETCH
.ENDIF
.IF AL == ‘-‘
MOV SIGN, 1 ;判定是否输入负号‘-’
GETCH
.ENDIF
.REPEAT
FMUL TEN
MOV AH,0
SUB AL, 30H
MOV TEMP, AX
FIADD TEMP ;部分数×10.0+(字符-‘0’)
GETCH
.UNTIL AL<’0’ || AL>’9’ ;完成整数部分的处理
CMP AL, ‘.’
JNE exit
FLD1 ;开始处理小数部分
.WHILE1
FDIV TEN
GETCH
.BREAK .IF AL<’0’ || AL>’9’
MOV AH, 0
SUB AL, 30H
MOV TEMP, AX
FILD TEMP
FMUL ST, ST(1)
FADD ST(2), ST
FCOMP
.ENDW
FCOMP
exit:
.IF SIGN == 1 ;如果是负数,那么需要改变符号
FCHS
.ENDIF
FSTP DATA ;保存最终转换的结果
.EXIT 0
END
解:
;调用参数:方程的系数a、b和c,R1和R2是指向存放根的指针;
;返回参数:返回值存于AX中,其含义:0—有二个根,1—有一个根R1,2—无实根。
Quadratic PROC USES DS DI SI, AA:DWORD, BB:DWORD, CC:DWORD, R1:PDWORD, R2:PDWORD
LES DI, R1 ;(ES:DI) → 1st Root-R1
LDS SI, R2 ;(DS:SI) → 2nd Root-R2
SUB BX, BX ;用BX来标识方程有根的情况
FLD1 ;栈顶寄存器置1
FADD ST, ST ;栈顶寄存器自加,变成2
FLD ST ;把数值2复制一份到新的栈顶
FMUL AA ;ST = 2A
FTST ;测试ST是否为0,即,考虑A=0的情况
FSTSW AX ;把当前状态寄存器存入AX中
FWAIT ;等待协处理器完成上面操作
SAHF ;AH装入到标志寄存器中
JNZ Notzero ;考虑A = 0的情况
FLD CC ;常数项C进栈
FCHS ;改变栈顶的符号,得到-C
FLD BB ;参数B进栈
FTST ;测试当前栈顶是否为0
FSTSW AX
SAHF
JZ EXIT2 ;考虑B = 0的情况
FDIV ;计算出-C/B
FSTP dword ptr ES:[DI] ;得到一个根,并弹出栈顶
FSTP ST ;弹出多余的堆栈数据
JMP EXIT1 ;返回,并标识有1个根
Notzero:
FMUL ST(1), ST ;ST(1) = 4A
FXCH ;ST和ST(1)交换
FMUL CC ;ST = 4AC
FTST
FSTSW AX
SAHF
JP EXIT2 ;如果状态位C2=1,则4AC是无穷大
FLD BB ;装入参数B
FMUL ST, ST ;ST = B2
FSUBR ;ST = B2 - 4AC
FTST
FSTSW AX
SAHF
JC EXIT2 ;如果C0=1,则B2 < 4AC
JNZ Tworoot ;如果C3=1,则B2 = 4AC
INC BX ;标志有1个根
Tworoot:
FSQRT ;求出B2 - 4AC的平方根
FLD BB
FCHS ;得到-B
FXCH ;ST 和ST(1)交换
FLD ST ;栈顶再复制一份
FADD ST, ST(2) ;ST = -B + SQRT(B2 - 4AC)
FXCH ;ST 和ST(1)交换
FSUBP ST(2), ST ;ST = -B - SQRT(B2 - 4AC)
FDIV ST, ST(2) ;得到一个根ST = ST/(2A)
FSTP dword ptr ES:[DI] ;存储第一个根
FDIVR ;得到另一个根ST = ST/(2A)
FSTP dword ptr DS:[SI] ;存储第二个根
JMP EXIT
EXIT2:
INC BX ;无根时的返回出口
FSTP ST ;清除多余的堆栈数据
EXIT1:
INC BX ;有一个根时的返回出口
FSTP ST ;清除多余的堆栈数据
EXIT:
MOV AX, BX
RET
Quadratic ENDP
END