首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 汇编语言 >

fistp改成fist后对程序的影响,该如何处理

2012-03-30 
fistp改成fist后对程序的影响下面是书上的一个画时钟程序我把计算X坐标过程_CalcX和计算Y坐标过程_CalcY中

fistp改成fist后对程序的影响
下面是书上的一个画时钟程序我把计算X坐标过程_CalcX和计算Y坐标过程_CalcY中的fistp改成了fist,结果时钟不能正确画出来,按理来说应该没什么两样!

改前

改后


源程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 3rd Edition>
; by 罗云彬, http://www.win32asm.com.cn
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Clock.asm
; 时钟例子:使用 GDI 函数绘画指针
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Clock.asm
; rc Clock.rc
; Link /subsystem:windows Clock.obj Clock.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
includewindows.inc
includeuser32.inc
includelibuser32.lib
includekernel32.inc
includelibkernel32.lib
includeGdi32.inc
includelibGdi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAINequ1000h
ID_TIMERequ1
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?

hInstancedd?
hWinMaindd?
dwCenterXdd?;圆心X
dwCenterYdd?;圆心Y
dwRadiusdd?;半径

.const
szClassNamedb'Clock',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟的位置、大小等参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcClockParamproc
local@stRect:RECT

invokeGetClientRect,hWinMain,addr @stRect
moveax,@stRect.right
subeax,@stRect.left;eax = 宽度
movecx,@stRect.bottom
subecx,@stRect.top;ecx = 高度
;********************************************************************
; 比较客户区宽度和高度,以小的值作为时钟的直径
;********************************************************************
.ifecx > eax
movedx,eax;高度 > 宽度
subecx,eax
shrecx,1
movdwCenterX,0
movdwCenterY,ecx
.else
movedx,ecx
subeax,ecx
shreax,1
movdwCenterX,eax
movdwCenterY,0
.endif
shredx,1
movdwRadius,edx
adddwCenterX,edx
adddwCenterY,edx
ret

_CalcClockParamendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 X 坐标
; X = 圆心X + Sin(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_dwPara180dw180
_CalcXproc_dwDegree,_dwRadius
local@dwReturn

filddwCenterX
fild_dwDegree
fldpi
fmul;角度*Pi
fild_dwPara180
fdivpst(1),st;角度*Pi/180
fsin;Sin(角度*Pi/180)
fild_dwRadius
fmul;半径*Sin(角度*Pi/180)
fadd;X+半径*Sin(角度*Pi/180)
fistp@dwReturn
moveax,@dwReturn
ret

_CalcXendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算时钟圆周上某个角度对应的 Y 坐标
; Y = 圆心Y - Cos(角度) * 半径
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_CalcYproc_dwDegree,_dwRadius
local@dwReturn

filddwCenterY
fild_dwDegree
fldpi
fmul
fild_dwPara180
fdivpst(1),st
fcos
fild_dwRadius
fmul
fsubpst(1),st
fistp@dwReturn
moveax,@dwReturn
ret

_CalcYendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 按照 _dwDegreeInc 的步进角度,画 _dwRadius 为半径的小圆点
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawDotproc_hDC,_dwDegreeInc,_dwRadius
local@dwNowDegree,@dwR


local@dwX,@dwY

mov@dwNowDegree,0
moveax,dwRadius
subeax,10
mov@dwR,eax
.while@dwNowDegree <=360
finit
;********************************************************************
; 计算小圆点的圆心坐标
;********************************************************************
invoke_CalcX,@dwNowDegree,@dwR
mov@dwX,eax
invoke_CalcY,@dwNowDegree,@dwR
mov@dwY,eax

moveax,@dwX;画点
movebx,eax
movecx,@dwY
movedx,ecx
subeax,_dwRadius
addebx,_dwRadius
subecx,_dwRadius
addedx,_dwRadius
invokeEllipse,_hDC,eax,ecx,ebx,edx

moveax,_dwDegreeInc
add@dwNowDegree,eax
.endw
ret

_DrawDotendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 画 _dwDegree 角度的线条,半径=时钟半径-参数_dwRadiusAdjust
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DrawLineproc_hDC,_dwDegree,_dwRadiusAdjust
local@dwR
local@dwX1,@dwY1,@dwX2,@dwY2

moveax,dwRadius
subeax,_dwRadiusAdjust
mov@dwR,eax
;********************************************************************
; 计算线条两端的坐标
;********************************************************************
invoke_CalcX,_dwDegree,@dwR
mov@dwX1,eax
invoke_CalcY,_dwDegree,@dwR
mov@dwY1,eax
add_dwDegree,180
invoke_CalcX,_dwDegree,10
mov@dwX2,eax
invoke_CalcY,_dwDegree,10
mov@dwY2,eax
invokeMoveToEx,_hDC,@dwX1,@dwY1,NULL
invokeLineTo,_hDC,@dwX2,@dwY2

ret

_DrawLineendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ShowTimeproc_hWnd,_hDC
local@stTime:SYSTEMTIME

pushad
invokeGetLocalTime,addr @stTime
invoke_CalcClockParam
;********************************************************************
; 画时钟圆周上的点
;********************************************************************
invokeGetStockObject,BLACK_BRUSH
invokeSelectObject,_hDC,eax
invoke_DrawDot,_hDC,360/12,3;画12个大圆点
invoke_DrawDot,_hDC,360/60,1;画60个小圆点
;********************************************************************
; 画时钟指针
;********************************************************************
invokeCreatePen,PS_SOLID,1,0
invokeSelectObject,_hDC,eax
invokeDeleteObject,eax
movzxeax,@stTime.wSecond
movecx,360/60
mulecx;秒针度数 = 秒 * 360/60
invoke_DrawLine,_hDC,eax,15
;********************************************************************
invokeCreatePen,PS_SOLID,2,0
invokeSelectObject,_hDC,eax
invokeDeleteObject,eax
movzxeax,@stTime.wMinute
movecx,360/60
mulecx;分针度数 = 分 * 360/60
invoke_DrawLine,_hDC,eax,20
;********************************************************************
invokeCreatePen,PS_SOLID,3,0
invokeSelectObject,_hDC,eax
invokeDeleteObject,eax
movzxeax,@stTime.wHour
.ifeax >=12
subeax,12
.endif
movecx,360/12
mulecx
movzxecx,@stTime.wMinute
shrecx,1
addeax,ecx
invoke_DrawLine,_hDC,eax,30
;********************************************************************


invokeGetStockObject,NULL_PEN
invokeSelectObject,_hDC,eax
invokeDeleteObject,eax
popad
ret

_ShowTimeendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMainprocuses ebx edi esi hWnd,uMsg,wParam,lParam
local@stPS:PAINTSTRUCT

moveax,uMsg
.ifeax ==WM_TIMER
invokeInvalidateRect,hWnd,NULL,TRUE
.elseifeax ==WM_PAINT
invokeBeginPaint,hWnd,addr @stPS
invoke_ShowTime,hWnd,eax
invokeEndPaint,hWnd,addr @stPS
.elseifeax ==WM_CREATE
invokeSetTimer,hWnd,ID_TIMER,1000,NULL
;********************************************************************
.elseifeax ==WM_CLOSE
invokeKillTimer,hWnd,ID_TIMER
invokeDestroyWindow,hWinMain
invokePostQuitMessage,NULL
;********************************************************************
.else
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
xoreax,eax
ret

_ProcWinMainendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMainproc
local@stWndClass:WNDCLASSEX
local@stMsg:MSG

invokeGetModuleHandle,NULL
movhInstance,eax
;********************************************************************
; 注册窗口类
;********************************************************************
invokeRtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invokeLoadIcon,hInstance,ICO_MAIN
mov@stWndClass.hIcon,eax
mov@stWndClass.hIconSm,eax
invokeLoadCursor,0,IDC_ARROW
mov@stWndClass.hCursor,eax
pushhInstance
pop@stWndClass.hInstance
mov@stWndClass.cbSize,sizeof WNDCLASSEX
mov@stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov@stWndClass.lpfnWndProc,offset _ProcWinMain
mov@stWndClass.hbrBackground,COLOR_WINDOW + 1
mov@stWndClass.lpszClassName,offset szClassName
invokeRegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
invokeCreateWindowEx,WS_EX_CLIENTEDGE,\
offset szClassName,offset szClassName,\
WS_OVERLAPPEDWINDOW,\
100,100,250,270,\
NULL,NULL,hInstance,NULL
movhWinMain,eax
invokeShowWindow,hWinMain,SW_SHOWNORMAL
invokeUpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
.whileTRUE
invokeGetMessage,addr @stMsg,NULL,0,0
.break.if eax== 0
invokeTranslateMessage,addr @stMsg
invokeDispatchMessage,addr @stMsg
.endw
ret

_WinMainendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call_WinMain
invokeExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
endstart





[解决办法]
FPU寄存器若不及时“弹栈”清理,则寄存器满后再载入数据,载入的数据为随机值。
[解决办法]
假如像1楼说的那样,当st栈满的话,在入栈就会出错的话,这个问题就可以解释了。
每次做完这两个函数_CalcX,_Calcy之后,堆栈中就会有两个st被使用;
1.在计算小圆点的圆心坐标的时候,是一个循环,但是循环之后就会做finit,将ST内容清掉,所以在计算小圆点的圆心坐标做完之后,只会有2个st被使用到。
2. 画时钟指针
会调用 _DrawLine三次,每次都会使用到_CalcX,_Calcy,也就是每次都会消耗st 2个,并没有finit动作,所以在最后调用_DrawLine的时候,已经使用了6个st,st已经不够用了,就出现错误,出现你上面描述的现象(只会有一条线有问题)。

要证明我上面的是否是正确,你在_DrawLine 函数的最后加上finit,看看是否不会再有问题
[解决办法]
当st栈满的话,在入栈就会出错


就是这样的,为了避免计算堆栈放置出现这样的问题,我也很喜欢使用finit


[解决办法]
楼主尝试一下:在你修改的那两个函数前加上finit。
_dwPara180 dw 180 
_CalcX proc _dwDegree,_dwRadius 
local @dwReturn 

finit
fild dwCenterX 
fild _dwDegree 
fldpi 
fmul ;角度*Pi 
fild _dwPara180 
.....


_CalcY proc _dwDegree,_dwRadius 
local @dwReturn 

finit
fild dwCenterY 
fild _dwDegree 
fldpi 
fmul 
fild _dwPara180 
fdivp st(1),st 
fcos 



热点排行