_ASSEMBLY LANGUAGE PROGRAMMING FOR THE 80X87_ by Nicholas Wilt [LISTING ONE] ; pow.asm: integer power function callable from Borland C++. ; Copyright (C) 1991 by Nicholas Wilt. All rights reserved. .MODEL LARGE,C .CODE ; double intpow(double x, unsigned int y); ; Returns x^y. PUBLIC intpow intpow PROC X:QWORD,Y:WORD fld1 ; Load 1 into the 80x87 mov cx,Y ; Get y fld X ; Load x into the 80x87 jcxz Return ; If y already zero, return TestY: test cx,1 ; Is the LSB of y set? jz NextIteration ; Jump if no fmul st(1),st ; ret *= x NextIteration: fmul st,st(0) ; Square x shr cx,1 ; y >>= 1 jnz TestY ; Continue if nonzero Return: fstp st ; Pop stack. Return value is ; now in ST(0). ret intpow ENDP END [LISTING TWO] ; sumarray(), a Borland C++-callable function to sum the values ; in an array of floats. ; Copyright (C) 1991 by Nicholas Wilt. All rights reserved. .MODEL LARGE,C .CODE ; double sumarray(float *arr, int n); ; Returns sum of the n elements in arr. PUBLIC sumarray sumarray PROC ARR:DWORD,N:WORD les bx,ARR ; ES:BX <- pointer to arr mov cx,N ; Get number of elements fldz ; Load zero jcxz LeaveSum ; Leave if count is 0. DoSum: fadd dword ptr es:[bx] ; Add value in array to ST(0). add bx,4 ; Point to next value in array. loop DoSum ; Loop until done. LeaveSum: ; Return value in ST(0). ret sumarray ENDP END [LISTING THREE] ; quad.asm: integer power function callable from Borland C++. ; Copyright (C) 1991 by Nicholas Wilt. All rights reserved. .MODEL LARGE,C .CODE ; int solve_quadratic(double a, double b, double c, double *x1, double *x2); ; solve_quadratic takes the coefficients of a quadratic polynomial ; and finds the roots of that polynomial. If there are two real ; roots, it writes them back to x1 and x2 and returns 1. If the ; discriminant b^2-4*a*c is less than 0, the roots are not real ; and solve_quadratic returns 0. ; The quadratic formula is as follows: ; (-b +/- sqrt(b*b-4*a*c)) / 2*a PUBLIC solve_quadratic solve_quadratic PROC A:QWORD,B:QWORD,C:QWORD,X1:DWORD,X2:DWORD ; Comments show stack contents ; separated by | signs ; Stack top is at left fld A ; a Here, ST(0) contains a. fld B ; b | a Now ST(1) has a. Etc. ; Negate b -- squaring it is sign-independent, and we need b ; negated in all the other instances in the formula. fchs fld C ; c | b | a fld st(1) ; b | c | b | a fmul st,st(0) ; b*b | c | b | a ; Just plain fxch has an implicit operand of ST(1). fxch ; c | b*b | b | a fadd st,st(0) ; 2*c | b*b | b | a fadd st,st(0) ; 4*c | b*b | b | a fmul st,st(3) ; 4*a*c | b*b | b | a fsubp st(1), st ; b*b-4*a*c | b | a ftst ; Compare against 0 ; We've computed b*b-4*a*c. If negative, we return 0. ; To do the comparison, we have to store the 80x87 status ; word and use sahf to store it into the flags. Once it's ; in the flags, we can jump on above or equal (jae) to jump if the ; number tested is greater than 0 after the FTST instruction above. sub sp,2 ; Quick, allocate a local mov bx,sp ; Point BX at it fstsw ss:[bx] ; Store the 80x87's status word there mov ax,ss:[bx] ; AX <- status word add sp,2 ; Deallocate the local sahf ; Get SW into flags jae ComputeResults ; Jump if positive fstp st ; This instruction clears the stack fstp st ; we've got three values on the stack fstp st ; to clear xor ax,ax ; Return 0 - no roots found. jmp short LeaveQuadratic ComputeResults: fsqrt ; Find square root of discriminant fxch st(2) ; a | b | sqrt(b*b-4*a*c) fadd st,st(0) ; 2*a | b | sqrt(b*b-4*a*c) fld st(1) ; b | 2*a | b | sqrt(b*b-4*a*c) fadd st,st(3) ; b+sqrt(b*b-4*a*c) | 2*a | b | sq.. fdiv st,st(1) ; x1 | 2*a | b | sqrt(b*b-4*a*c) les bx,X1 ; fstp qword ptr es:[bx] ; 2*a | b | sqrt(b*b-4*a*c) fxch ; b | 2*a | sqrt(b*b-4*a*c) fsubrp st(2),st ; 2*a | -b - sqrt(b*b-4*a*c) fdiv ; x2 les bx,X2 ; Store x2 fstp qword ptr es:[bx] mov ax,1 ; Return 1 LeaveQuadratic: ret ; Return solve_quadratic ENDP END