x86 Assembly Code


;------------------------------------------------------------------------------
; Program 4 CS308 Fall 2006
; Karen ---
;
; (With some code segments from fp32demo.asm as written by Joe Toone
; and found at: )
;
;------------------------------------------------------------------------------
; This program demonstrates the use of FPU instructions in x86 Assembly.
; It accepts characters from the keyboard and converts them to IEEE real form.
; Values for the area and volume of selected shapes are found. The results
; are then converted back to ASCII and printed on the screen. The file
; "io32.inc" must be included for the string operations to work. "MAXSTR" is
; required by "io32.inc" and ESI and EDI must be initialized to the correct
; values before calling the procedures in "io32.inc" (see headers in io32.inc
; for the proper useage).
;------------------------------------------------------------------------------
TITLE PROG4.asm

CR equ 0dh ;ASCII 13 for carriage return
LF equ 0ah ;ASCII 10 for line feed
NEWLINE equ CR,LF ;A complete newline
BEEP equ 7 ;Beep the computer speaker
MAXSTR equ 80d ;Accept up to 80 characters strings
FALSE equ 0 ;Flags
TRUE equ 1 ;
C3 equ 0100000000000000b ;Condition codes which are checked
C2 equ 0000010000000000b ; in the FPU Status register
C0 equ 0000000100000000b ;

.586 ;Allow Pentium instructions
.MODEL FLAT ;FLAT memory model
INCLUDE io32.inc ;Include the external I/O procedures

.STACK 4096h ;4K hex bytes for stack
.DATA
Intro BYTE NEWLINE,LF, ' ****************************************************'
BYTE NEWLINE,LF, ' This program will calculate the area and volume'
BYTE NEWLINE, ' of a selected shape using real numbers'
BYTE NEWLINE,LF, ' ****************************************************',0
Menu BYTE NEWLINE,LF,'What would you like to calculate?'
BYTE NEWLINE, ' 1) Surface Area and Volume of a Cube'
BYTE NEWLINE, ' 2) Surface Area and Volume of a Rectangular Prism'
BYTE NEWLINE, ' 3) Surface Area and Volume of a Sphere'
BYTE NEWLINE, ' 4) Surface Area and Volume of a Cylinder'
BYTE NEWLINE, ' 5) Surface Area and Volume of a Cone'
BYTE NEWLINE, ' 6) Exit Program'
BYTE NEWLINE,LF,'*****Enter a Number to Select --> ',0
Choice BYTE ? ;Menu Choice character
Invalid BYTE NEWLINE,'That was not a valid menu choice, try again.',NEWLINE,BEEP,0
NextLine BYTE NEWLINE,0
SizeP BYTE NEWLINE,'Enter the SIZE as a Floating Point Number --> ',0
RadiusP BYTE NEWLINE,'Enter the RADIUS as a Floating Point Number --> ',0
LengthP BYTE NEWLINE,'Enter the LENGTH as a Floating Point Number --> ',0
WidthP BYTE NEWLINE,'Enter the WIDTH as a Floating Point Number --> ',0
HeightP BYTE NEWLINE,'Enter the HEIGHT as a Floating Point Number --> ',0
AreaEq BYTE NEWLINE,' The AREA = ',0 ;
VolumeEq BYTE NEWLINE,' The VOLUME = ',0
AsciiArea BYTE MAXSTR dup(0) ;Used to store input string of digits
AsciiVolume BYTE MAXSTR dup(0) ;Used to store input string of digits
AsciiNum BYTE MAXSTR dup(0) ;Used to store input string of digits
SizeN REAL4 ? ;Storage for real number
RadiusN REAL4 ? ;Storage for real number
LengthN REAL4 ? ;Storage for real number
HeightN REAL4 ? ;Storage for real number
WidthN REAL4 ? ;Storage for real number
AreaN REAL4 ? ;Storage for real number
VolumeN REAL4 ? ;Storage for real number
Six REAL4 6.0 ;Storage for 6
Three REAL4 3.0 ;Storage for 3
Four REAL4 4.0 ;Storage for 4
Two REAL4 2.0 ;Storage for 2

;************ The following data items are required by fp2a and a2fp ********
one REAL4 1.0 ;Used in fp2a
ten REAL4 10.0 ;Used in a2fp and fp2a
round REAL4 0.000005 ;Used for rounding control in fp2a
byteTen BYTE 10 ;Used in fp2a
point BYTE ? ;Flag for a2fp
minus BYTE ? ;Flag for a2fp
digit WORD ? ;Used in a2fp and fp2a
exponent WORD ? ;Used in fp2a
controlWd WORD ? ;Used in fp2a


;************************** MACRO Definitions ********************************
PrintStr MACRO StringToPrint
IFB
.ERR
EXITM
ENDIF
lea esi,StringToPrint ;Pointer to string to be printed
call PrintString ; go print the string
ENDM

ReadStr MACRO StringToGet
IFB
.ERR
EXITM
ENDIF
lea esi,StringToGet ;Pointer to string storage
call GetString ; go get the string
ENDM

CharIn MACRO CharToGet
IFB
.ERR
EXITM
ENDIF
lea esi,CharToGet ;Pointer to character storage
call GetChar ; go get the character
ENDM

CharOut MACRO CharToPut
IFB
.ERR
EXITM
ENDIF
lea esi,CharToPut ;Pointer to character to be printed
call PutChar ; go print the character
ENDM

Ascii2Float MACRO Ascii2Convert, FloatNum
IFB
.ERR
EXITM
ENDIF
IFB
.ERR
EXITM
ENDIF
lea esi,Ascii2Convert ;Pointer to ASCII number to convert
call a2fp ;Convert an ASCII sequence to a FP number
fstp FloatNum ;Pop ST into Data Segment variable
ENDM

Float2Ascii MACRO FloatNum,AsciiOut
IFB
.ERR
EXITM
IFB
.ERR
EXITM
ENDIF
ENDIF
lea esi,FloatNum ;Pointer to floating point number
lea edi,AsciiOut ;Pointer to output string destination
call fp2a ;Convert IEEE FP to ASCII
ENDM

;-------- Main Body -----------------------------------------------------------
; Given :Nothing
; Process :Main Body - contains inline code and procedure calls to convert
; ASCII numbers to IEEE Floating Point values, calculates volume
; and area of selected shapes, and then converts IEEE Floating Point
; values to ASCII numbers so that the results may be printed.
; Return :Nothing
;------------------------------------------------------------------------------
.CODE
_main:
DoIntro:PrintStr Intro ;Display the intro
PrintStr NEXTLINE ;NewLine
DoMenu: PrintStr Menu ;Display the menu
CharIn Choice ;Get menu selection
PrintStr NEXTLINE ;NewLine
.if Choice == '1' ;Did user choose 1
call Cube ; yes, then calculate Cube
.elseif Choice == '2' ;Did user choose 2
call Rectangle ; yes, then calculate Rectangle
.elseif Choice == '3' ;Did user choose 3
call Sphere ; yes, then calculate sphere
.elseif Choice == '4' ;Did user choose 4
call Cylinder ; yes, then calculate cylinder
.elseif Choice == '5' ;Did user choose 5
call Cone ; yes, then calculate cone
.elseif Choice != '6' ;Did user not choose 6?
PrintStr Invalid ; no, then print error message
.else
jmp quit
.endif ;End of IF structure
jmp DoMenu ;Print Menu again
quit: INVOKE ExitProcess, 0 ; exit with return code 0

;******************************************************************************
;*******************Calculate Area & Volume of a Cube**************************
; Given : Nothing
; Process : Ask for size and return Area and Volume in Real Numbers
; Return : Nothing
;------------------------------------------------------------------------------
Cube PROC NEAR32

pushad ;Save the contents of all registers
pushfd ;
PrintStr SizeP ;Prompt the user for a the size
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,SizeN ;Convert String and store as Real
; ---Find Area
fld SizeN ;Load size to FPU
fmul SizeN ;Size*Size in ST
fmul Six ;S*S*6 in ST
fstp AreaN ;Area=ST
; ---Find Volume
fld SizeN ;Load size to FPU
fmul SizeN ;ST = S*S
fmul SizeN ;S*S*S in ST
fstp VolumeN ;Volume=ST
; ---Print Results
Float2Ascii AreaN, AsciiArea ;Convert Real and store as String
Float2Ascii VolumeN, AsciiVolume ;Convert Real and store as String
PrintStr AreaEq ;Area =
PrintStr AsciiArea
PrintStr NextLine ; and move to next line
PrintStr VolumeEq
PrintStr AsciiVolume
PrintStr NextLine ; and move to next line
popfd ;Restore the registers
popad ;
ret ;Return to Calling procedure
Cube ENDP

;******************************************************************************
;*******************Calculate Area & Volume of a Rectangle*********************
; Given : Nothing
; Process : Ask for length, width, and height and return Area
; and Volume in Real Numbers
; Return : Nothing
;------------------------------------------------------------------------------
Rectangle PROC NEAR32

pushad ;Save the contents of all registers
pushfd ;
PrintStr LengthP ;Prompt the user for a the length
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,LengthN ;Convert String and store as Real
PrintStr HeightP ;Prompt the user for a the height
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,HeightN ;Convert String and store as Real
PrintStr WidthP ;Prompt the user for a the width
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,WidthN ;Convert String and store as Real
; ---Find Area
fld LengthN ;Load length to FPU
fld WidthN ;Load width to FPU
fmul ;L*W in ST
fld LengthN ;push L
fld HeightN ;push h
fmul ;L*H in ST
fld HeightN ;push H
fld WidthN ;push W
fmul ;H*W in ST
fadd ;H*W + L*H in ST
fadd ;H*W + L*H + L*W in ST
fmul Two ;ST= 2(LH+LW+HW)
fstp AreaN ;Area=ST
; ---Find Volume
fld LengthN ;push L
fmul WidthN ;ST = L*W
fmul HeightN ;ST = L*W*H
fstp VolumeN ;Volume=ST
; ---Print Results
Float2Ascii AreaN, AsciiArea ;Convert Real and store as String
Float2Ascii VolumeN, AsciiVolume ;Convert Real and store as String
PrintStr AreaEq ;Area =
PrintStr AsciiArea
PrintStr NextLine ; and move to next line
PrintStr VolumeEq
PrintStr AsciiVolume
PrintStr NextLine ; and move to next line
popfd ;Restore the registers
popad ;
ret ;Return to Calling procedure
Rectangle ENDP

;******************************************************************************
;*******************Calculate Area & Volume of a Sphere************************
; Given : Nothing
; Process : Ask for radius and return Area and Volume in Real Numbers
; Return : Nothing
;------------------------------------------------------------------------------
Sphere PROC NEAR32

pushad ;Save the contents of all registers
pushfd ;
PrintStr RadiusP ;Prompt the user for a the size
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,RadiusN ;Convert String and store as Real
; ---Find Area
fld RadiusN ;push R
fmul RadiusN ;ST= r*r
fldpi ;push (pi)
fmul ;(pi)*r*r
fmul Four ;ST = 4*(pi)*r*r
fstp AreaN ;Area=ST
; ---Find Volume
fld RadiusN ;push R
fmul RadiusN ;ST= r*r
fmul RadiusN ;ST= r*r*r
fldpi ;push (pi)
fmul ;(pi)*r*r*r
fmul Three ;ST = 3*(pi)*r*r*r
fld Four ;push 4
fdiv st, st(1) ;ST= 4 / (3*(pi)*r*r*r)
fstp VolumeN ;Volumn=ST
; ---Print Results
Float2Ascii AreaN, AsciiArea ;Convert Real and store as String
Float2Ascii VolumeN, AsciiVolume ;Convert Real and store as String
PrintStr AreaEq ;Area =
PrintStr AsciiArea
PrintStr NextLine ; and move to next line
PrintStr VolumeEq
PrintStr AsciiVolume
PrintStr NextLine ; and move to next line
popfd ;Restore the registers
popad ;
ret ;Return to Calling procedure

Sphere ENDP

;******************************************************************************
;*******************Calculate Area & Volume of a Cylinder**********************
; Given : Nothing
; Process : Ask for radius & height and return Area and Volume in Real Numbers
; Return : Nothing
;------------------------------------------------------------------------------
Cylinder PROC NEAR32
pushad ;Save the contents of all registers
pushfd ;
PrintStr RadiusP ;Prompt the user for a the radius
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,RadiusN ;Convert String and store as Real
PrintStr HeightP ;Prompt the user for a the height
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,HeightN ;Convert String and store as Real
; ---Find Area
fldpi ;push pi
fmul RadiusN ;ST= pi*r
fmul HeightN ;ST= pi*r*h
fldpi ;push pi
fmul RadiusN ;ST= pi*r
fmul RadiusN ;ST= pi*r*r
fadd ;ST= pi*r*h + pi*r*r
fmul Two ;ST= 2(pi*r*h + pi*r*r)
fstp AreaN ;Area=ST
; ---Find Volume
fldpi ;push pi
fmul RadiusN ;ST= pi*r
fmul RadiusN ;ST= pi*r*r
fmul HeightN ;ST= pi*r*r*h
fstp VolumeN ;Volume=ST
; ---Print Results
Float2Ascii AreaN, AsciiArea ;Convert Real and store as String
Float2Ascii VolumeN, AsciiVolume ;Convert Real and store as String
PrintStr AreaEq ;Area =
PrintStr AsciiArea
PrintStr NextLine ; and move to next line
PrintStr VolumeEq
PrintStr AsciiVolume
PrintStr NextLine ; and move to next line
popfd ;Restore the registers
popad ;
ret ;Return to Calling procedure
Cylinder ENDP

;******************************************************************************
;*******************Calculate Area & Volume of a Cone**************************
; Given : Nothing
; Process : Ask for radius & height and return Area and Volume in Real Numbers
; Return : Nothing
;------------------------------------------------------------------------------
Cone PROC NEAR32

pushad ;Save the contents of all registers
pushfd ;
PrintStr RadiusP ;Prompt the user for a the radius
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,RadiusN ;Convert String and store as Real
PrintStr HeightP ;Prompt the user for a the height
ReadStr AsciiNum ;Read an ASCII number into data segment
Ascii2Float AsciiNum,HeightN ;Convert String and store as Real
; ---Find Area
fld RadiusN ;push r
fmul RadiusN ;ST = r*r
fld HeightN ;push h
fmul HeightN ;ST = h*h
fadd ;ST = h*h + r*r
fsqrt ;St = Sqrt(ST)
fmul RadiusN ;ST = r*sqrt(hh+rr)
fldpi ;push pi
fmul ;ST = pi*r*sqrt(rr+hh)
fldpi ;push pi
fmul RadiusN ;ST = pi*r
fmul RadiusN ;ST = pi*r*r
fadd ;ST = pi*r*r + pi*r*sqrt(rr+hh)
fst AreaN ;area = st
; ---Find Volume
fldpi ;push pi
fmul RadiusN ;ST= pi*r
fmul RadiusN ;ST= pi*r*r
fmul HeightN ;ST= pi*r*r*h
fdiv Three ;ST= ST/3
fstp VolumeN ;Volume=ST
; ---Print Results
Float2Ascii AreaN, AsciiArea ;Convert Real and store as String
Float2Ascii VolumeN, AsciiVolume ;Convert Real and store as String
PrintStr AreaEq ;Area =
PrintStr AsciiArea
PrintStr NextLine ; and move to next line
PrintStr VolumeEq
PrintStr AsciiVolume
PrintStr NextLine ; and move to next line
popfd ;Restore the registers
popad ;
ret ;Return to Calling procedure

Cone ENDP


;--------- Convert ASCII String to Floating Point Number ----------------------
; Source :fp32demo.asm as written by Joe Toone
; :
; Given :ESI register pointing to the ASCII number to convert
; Process :After an optional leading minus sign, only digits 0-9 and a decimal
; point are accepted -- the scan terminates with any other character.
; This procedure produces an IEEE floating point number. No registers
; are changed and the flags are not affected.
; Return :The floating point value is returned in ST.
;------------------------------------------------------------------------------
a2fp PROC NEAR32
pushad ;Save the contents of all registers
pushfd ;
finit ;Initialize the Floating Point Stack
fld1 ; divisor := 1.0
fldz ; value := 0.0
mov point, false ; no decimal point found yet
mov minus, false ; no minus sign found yet
lodsb ; load first character into AL register
cmp al,'-' ; check for minus sign
jne NotMinus ; skip if not
mov minus, true ; minus sign found
lodsb ; load next character into AL register
NotMinus: ; was not negative number
WhileMore:cmp al, '.' ; decimal point?
jne NotPoint ; skip if not
mov point, true ; found decimal point
jmp nextChar
NotPoint: cmp al, '0' ; character a digit?
jl EndWhile ; exit if lower than '0'
cmp al, '9'
jg EndWhile ; exit if higher than '9'
and ax, 000fh ; convert ASCII to integer value
mov digit, ax ; put integer in memory
fmul ten ; value := value * 10
fiadd digit ; value := value + digit
cmp point, true ; already found a decimal point?
jne endifDec ; skip if not
fxch ; put divisor in ST and value in ST(1)
fmul ten ; divisor := divisor * 10
fxch ; value back to ST; divisor back to ST(1)
endifDec:
nextChar: lodsb ; load next character into AL registe
jmp WhileMore ; go process the character
EndWhile: fdivr ; value := value / divisor
cmp minus, true ; was there a minus sign?
jne IsPositive ; no, it is a positive number
fchs ; yes, value := -value
IsPositive:
popfd ;Restore the registers
popad ;
ret ;Return to calling procedure
a2fp ENDP

;--------- Convert Floating Point Number to ASCII String ----------------------
; Source :fp32demo.asm as written by Joe Toone
; :
; Given :ESI pointing to FP value to convert and EDI pointing to the output
; string destination.
; Process :Build ASCII string with format [blank/-]d.dddddE[+/-]dd and store
; the string in the data segment. (Output is always 12 characters.)
; No registers are changed and the flags are not affected.
; Return :Nothing
;------------------------------------------------------------------------------
fp2a PROC NEAR32
pushad ;Save the contents of all registers
pushfd ;
finit ; initialize the Floating Point Stack
fstcw controlWd ; get control word
push controlWd ; save control word
or controlWd, 0000110000000000b
fldcw controlWd ; set control to chop
fld REAL4 PTR [esi] ; load ST with the FP value
mov exponent, 0 ; exponent := 0
ftst ; value >= 0?
fstsw ax ; status word to AX
and ax, C0 ; check C0
jnz elseNeg ; skip if set (value negative)
mov al,' ' ; blank for positive
stosb ; write the blank to the string
jmp NotNeg ; jump over negative sign
elseNeg: mov al,'-' ; minus for negative
stosb ; write the minus to the string
fchs ; convert number to positive
NotNeg:
mov exponent, 0 ; exponent := 0
ftst ; value = 0?
fstsw ax ; status word to AX
and ax, C3 ; check C3
jne endifZero ; skip if zero
fcom ten ; value > 10?
fstsw ax ; status word to AX
and ax, C3 or C2 or C0 ; check for all C3=C2=C0=0
jnz elseLess ; skip if value not > 10
untilLess:
inc exponent ; add 1 to exponent
fdiv ten ; value := value/10
fcom ten ; value < 10
fstsw ax ; status word to AX
and ax, C0 ; check C0
jz untilLess ; continue until value < 10
jmp endifBigger ; exit if
elseLess:
whileLess:
fcom one ; value < 1
fstsw ax ; status word to AX
and ax, C0 ; check C0
jz endwhileLess ; exit if not less
fmul ten ; value := 10*value
dec exponent ; subtract 1 from exponent
jmp whileLess ; continue while value < 1
endwhileLess:
endifBigger:
endifZero:
fadd round ; add rounding value
fcom ten ; value > 10?
fstsw ax ; status word to AX
and ax, C3 or C2 or C0 ; C3=C2=C0=0? (value > 10?)
jnz endifOver ; skip if not
fdiv ten ; value := value/10
inc exponent ; add 1 to exponent
endifOver:
; at this point 1.0 <= value < 10.0
fist digit ; store integer part
mov bx, digit ; copy integer to BX
or bx, 30h ; convert digit to character
mov al,bl ; copy character to AL for writing
stosb ; write the character to the string
mov al,'.' ; load AL with decimal point
stosb ; write decimal point to string

mov ecx,5 ; count of remaining digits
forDigit: fisub digit ; subtract integer part
fmul ten ; multiply by 10
fist digit ; store integer part
mov bx, digit ; copy integer to BX
or bx, 30h ; convert digit to character
mov al,bl ; copy character to write
stosb ; write the character to the string
loop forDigit ; repeat 5 times
mov al,'E' ; exponent indicator
stosb ; write the character to the string
mov ax, exponent ; get exponent
push ax ; save the exponenet
cmp ax, 0 ; exponent >= 0 ?
jnge NegExp
mov al,'+' ; non-negative exponent
stosb ; write the character to the string
pop ax ; restore the exponent if not negative
jmp endifNegExp
NegExp: mov al,'-' ; negative exponent
stosb ; write the character to the string
pop ax ; restore the exponent if negative
neg ax ; change exponent to positive
endifNegExp:
div byteTen ; convert exponent to 2 digits
or ax, 3030h ; convert both digits to ASCII
stosb ; write AL character to the string
mov al,ah ; copy low order character to DL
stosb ; write the character to the string
xor al,al ; zero the AL register
stosb ; write NULL to terminate string
pop controlWd ; restore control word
fldcw controlWd ; load the control word back to FPU
popfd ;Restore the registers
popad ;
ret ;Return to calling procedure
fp2a ENDP

Public _main ;declare _main as a public procedure
END ;end of code segment





Powered by Blogger


eXTReMe Tracker