assembly language

[X86 어셈블리] FPU 프로그래밍 / 구의 부피 계산하기 / fmul, fmulp, fdiv, fdivp

leo_roh 2023. 8. 4. 17:38

구의 부피 공식

반지름이 r일 때 구의 부피 V

V = (4/3) × π × r³  

위의 간단한 공식을 8087 FPU 프로그래밍으로 구현해보자.

 

코드

ax 레지스터에 반지름 값을 넣고 스택에 push한다. 이 값을 인자로 하여 get_sphere_volume 프로시져가 구의 부피를 계산한다.

TITLE Sphere Volume

.DOSSEG
.8086
.8087
.MODEL TINY

.DATA
volume DD ?
int_four DW 4
int_three DW 3

.CODE
.STARTUP

    mov ax, 3 ;r
    push ax
    call get_sphere_volume
    add sp, 2
    
    mov ah, 4Ch
    xor al, al
    int 21h

get_sphere_volume PROC
    push bp
    mov bp, sp

    finit
    fild WORD PTR [bp+4]
    fild WORD PTR [bp+4]

    fmul st, st
    fmul ;fmulp st(1), st(0)
    

    fild WORD PTR int_four
    fmul 

    fild WORD PTR int_three
    fdiv

    fldpi
    fmul

    fstp volume
    fwait

    mov sp, bp
    pop bp
    ret
get_sphere_volume ENDP

END

 

get_sphere_volume 프로시져에서는 부동 소수 연산을 위해 8087을 사용한다. 8087 레지스터의 상태는 다음과 같이 바뀐다.

8087 st 레지스터 상태 변화

 

FMUL과 FMULP

FMUL은 두 레지스터를 피연산자로 명시한 경우에는 pop 동작을 수행하지 않지만 피연산자를 명시하지 않을 경우 pop 동작을 수행한다. 

즉, FMULFMULP st(1), st(0)으로 작동된다. 실제로 어셈블 후 확인해보면 FMULP st(1), st(0)로 어셈블된 것을 확인할 수 있다. 한편 두개의 레지스터를 피연산자로 명시하는 경우 첫번째 피연산자 레지스터에 곱한 결과가 저장되고 pop 동작은 없다. 어셈블 후 실제로 이진파일에 들어간 명령어도 FMUL이다. 아래의 그림에서 두번째 붉은 사각형에서 FMUL을 어셈블러가 FMULP st(1), st로 어셈블 한 것을 확인할 수 있다. 곱하기 외에 덧셈, 뺄셈, 나눗셈 또한 같은 방식으로 작동한다. 

CodeView로 확인한 어셈블 결과