sqrt.asm

Program napisałem w ramach przypomnienia sobie asemblera. Zbudowany przy użyciu Netwide Assembler (32bit) i "Minimalist GNU for Windows (32bit). Wylicza pierwiastek z podanej liczby metodą Newtona.

; nasm -f win32 sqrt.asm
; ld -o sqrt.exe sqrt.obj c:\windows\system32\msvcrt.dll 
[bits 32]
extern	_scanf, _printf

;-----------------------------------------------------------------
section	.data
info:	db 10, "Program oblicza pierwiastek kwadratowy", 10, 10, 0
get_p:	db "Podaj wartosc pierwiastka: ", 0
frmt:	db "%lf", 0 ; format dla scanf/printf
;
; wyliczanie pierwiastka kwadratowego z danej liczby p
; metoda Newtona 
;
;        x1 = 0,5 * ( x0 + p / x0 )
;
c:	dq 0.5 ; stala 0,5
p:	dq 0.0 ; wartosc z ktorej obliczamy pierwiastek
x0:	dq 0.0 ; pierwsza wartosc poczatkowa rowna p 
x1:	dq 0.0
d:	dq 0.001 ; dokladnosc obliczen

;-----------------------------------------------------------------
section	.text
_WinMain@16:
	push	info
	call	_printf
	add 	esp, 4 ; sciagnij ze stosu

	push	get_p	
	call	_printf
	add 	esp, 4
	
	push	p ; adres wartosci - drugi parametr dla scanf
	push	frmt ; pierwszy parametr dla scanf
	call	_scanf
	add 	esp, 8
	
	finit ; inicjalizacja FPU
	fld 	qword[p] ; st0 = p
	fstp 	qword[x0] ; x0 = p i sciagamy wartosc z st0
loop:
	fld 	qword[p]	
	fdiv 	qword[x0] ; = p / x0
	fadd 	qword[x0] ; = x0 + p / xo
	fmul 	qword[c] ; = 0.5 * (x0 + p / x0)
	fst 	qword[x1] ; x1 = 0.5 * (x0 + p / x0)
	fsubr	qword[x0] ; x0 - x1 -> st0 = x1 
	                  ; wiec odejmujemy odwrotnie
	
	fcom 	qword[d] ; porownaj x0 - x1 z 0.001
	fstsw	ax ; przenies rejestr stanu FPU do ax

;           AH           |          AL
;15 14 13 12 11 10  9  8   7  6  5  4  3  2  1  0
;   C3          C2     C0
;
;                   C3   C2  C0
; If ST(0) > source  0   0   0
; If ST(0) < source  0   0   1
; If ST(0) = source  1   0   0
; If ST(0) ? source  1   1   1
	
	sahf ; prznies kody stanu z AH do rejestru flag
	     ; 7  6  5  4  3  2  1  0
	     ; SF:ZF:xx:AF:xx:PF:xx:CF
							;
	ja	more ; jesli st > 0.001 
		     ; jump if above (CF=0 and ZF=0)
	jbe	end ; jesli st <= 0.001 
		    ; jump if below or equal (CF=1) (ZF=1)

more:
	ffree	st0 ; zwolnij st0
	fld 	qword[x1] ; st0 = x1
	fstp 	qword[x0] ; x0 = x1
	jmp 	loop

end:
	push	dword [x1 + 4] ; printf oczekuje wartosci double
	push	dword [x1]
	push	frmt
	call	_printf
	add 	esp, 12

	xor 	eax, eax
	ret

;