home *** CD-ROM | disk | FTP | other *** search
-
- Title 'Wolfware Assembler Sample Program', 'Factorial Calculator'
-
- ;=============================================================================
- ; Factorial Calculator
- ;
- ; This a program to display the factorial of numbers. Once assembled, to
- ; run, just type:
- ;
- ; FACTOR
- ;
- ; Incidentally, the factorial of a number is the product of all integers
- ; between the number and zero. For instance, the factorial of 6 (usually
- ; specified as 6!) is equal to 6 x 5 x 4 x 3 x 2 x 1 = 720. If the result
- ; is too large, an error message will be displayed.
- ;
- ; Requires CONVERT1.INC and CONVERT2.INC on the default drive/path for
- ; assembly.
-
- MaxChr Equ 40 ;input characters
-
- Fninit
-
- Mov Dx, Offset Mess1 ;opening display
- Mov Ah, 9
- Int 21h ;display string
-
- Main1
- Mov Dx, Offset Mess2 ;prompt for number
- Call Input_Integer ;get an integer
- Jc Main3 ;jump if done
-
- Call Factorial ;calculate factorial
- Jc Main2 ;jump if error
- Call Save_Binary ;store number, return exponent in AX
- Push Ax
- Mov Ah, 9
- Mov Dx, Offset Mess3 ;result message
- Int 21h ;display string
- Pop Ax
- Call Display_Binary ;display
- Jmps Main1
-
- ;--- error in calculation
-
- Main2
- Mov Ah, 9
- Mov Dx, Offset Mess4 ;result message
- Int 21h ;display string
- Jmps Main1
-
- ;--- finished
-
- Main3
- Mov Ax, 4c00h
- Int 21h
-
- ;--- messages
-
- Mess1 Db 13,10,'Factorial Calculator, Version 1.00',13,10,'$'
- Mess2 Db 13,10,'Enter number for factorial calculation: $'
- Mess3 Db 13,10,'The factorial is $'
- Mess4 Db 13,10,'The factorial cannot be calculated',13,10,'$'
-
- ;========================================
- ; Calculate the factorial of the number
- ; in ST. If error, the carry is set and
- ; the 8087 stack is cleared.
-
- Factorial Proc Near
- Push Bp
- Sub Sp, 2 ;local data
- Mov Bp, Sp
-
- Fld1 ;load one, initial total
- Fxch ;total in second stack element
-
- ;--- loop while number is not zero
-
- Factor1
- Ftst ;check if top element zero
- Fstsw Word [Bp] ;store the status word
- Fwait
- Mov Al, [Bp+1] ;get the high byte
- And Al, 45h ;mask condition codes C3 C2 and C0
- Cmp Al, 40h ;check if zero
- Je Factor2
- Fmul St(1), St(0) ;multiply
- Fstsw Word [Bp] ;store the status word
- Fwait
- Test Byte [Bp], 1fh ;check if any exceptions
- Jnz Factor3
-
- Fld1 ;load one
- Fsub ;subtract and pop
- Jmps Factor1
-
- ;--- finished
-
- Factor2
- Fstp St(0) ;pop stack
- Add Sp, 2
- Pop Bp
- Clc
- Ret
-
- ;--- exception occured
-
- Factor3
- Fstp St(0)
- Fstp St(0) ;clear stack
- Fclex ;clear exceptions
- Add Sp, 2
- Pop Bp
- Stc
- Ret
- Endp ;Factorial
-
- ;========================================
- ; Display the $ terminated string at DX
- ; and then input an integer and return it
- ; in ST. Carry set if no input. All
- ; non-numeric characters are ignored.
-
- Input_Integer Proc Near
- Pushf
- Push Bp
- Sub Sp, MaxChr+3 ;local data, room for input
- Mov Bp, Sp
-
- Inpint1
- Mov Ah, 9
- Int 21h ;display string
-
- Push Dx
- Mov Byte [Bp], MaxChr+1 ;possible number of characters (plus CR)
- Lea Dx, [Bp] ;get the location
- Mov Ah, 0ah
- Int 21h ;input string
- Call New_Line ;start a new line
- Pop Dx
-
- Mov Al, [Bp+1] ;get the input length
- Or Al, Al
- Jz Inpint6 ;jump if none
-
- Push Dx
-
- ;--- store digits
-
- Std ;set direction
- Lea Si, [Bp+1] ;get start of input minus one
- Sub Ah, Ah
- Add Si, Ax ;point to last (low) digit
- Sub Bx, Bx ;counts digits
- Mov Cx, Ax ;character count
- Call Init_Binary ;initialize BCD number
-
- Inpint2
- Lodsb ;get digit
- Sub Al, '0' ;convert to binary
- Jb Inpint3 ;jump if too low
- Cmp Al, 9 ;check if too high
- Ja Inpint3 ;jump if so
- Inc Bx
- Call Store_Binary ;store BCD digit
- Inpint3 Loop Inpint2
-
- ;--- store zeros
-
- Mov Cx, 18 ;max digits
- Sub Cx, Bx ;get difference
- Jbe Inpint5 ;jump if full (no padding)
-
- Inpint4
- Sub Al, Al ;zero digit
- Call Store_Binary ;store pad digit
- Loop Inpint4 ;loop for count
-
- ;--- number stored
-
- Inpint5
- Call Load_Binary ;put number in ST
- Pop Dx
- Jc Inpint7
-
- Add Sp, MaxChr+3
- Pop Bp
- Popf
- Clc
- Ret
-
- ;--- no input
-
- Inpint6
- Add Sp, MaxChr+3
- Pop Bp
- Popf
- Stc
- Ret
-
- ;--- illegal number, should never happen if only valid digits are read
-
- Inpint7
- Push Dx
- Mov Dx, Offset Inperr ;error message
- Mov Ah, 9
- Int 21h ;display string
- Pop Dx
- Jmp Inpint1
-
- Inperr Db 13,10,'Error in number',13,10,'$'
- Endp ;Input_Integer
-
- ;========================================
- ; Global BCD data.
-
- BCD_Flag Db ?
- BCD_Store Db ?
- BCD_Count Dw ?
- BCD_Number Label Tbyte
- Ds 10
-
- ;========================================
- ; Initialize the global BCD number.
-
- Init_Binary Proc Near
- Mov BCD_Flag, 0 ;clear flag
- Mov BCD_Count, 0 ;clear byte count
- Mov Byte BCD_Number+9, 0 ;clear sign (always positive)
- Ret
- Endp ;Init_Binary
-
- ;========================================
- ; Store the digit in AL to the BCD
- ; number.
-
- Store_Binary Proc Near
- Push Bx
- Test BCD_Flag, 1 ;check if second digit
- Jnz Stobin1
-
- ;--- wait for second digit
-
- Mov BCD_Store, Al ;save digit
- Jmps Stobin2
-
- ;--- store digit pair
-
- Stobin1
- Mov Bx, BCD_Count ;get digit count
- Cmp Bx, 9 ;check if count exceeded
- Jae Stobin3
-
- Shl Al
- Shl Al
- Shl Al
- Shl Al
- Or Al, BCD_Store ;combine other digit
- Add Bx, Offset BCD_Number ;get location
- Mov [Bx], Al ;save digit
-
- Inc BCD_Count ;increment digit count
-
- ;--- finished
-
- Stobin2
- Xor BCD_Flag, 1 ;flip flag
-
- Stobin3
- Pop Bx
- Ret
- Endp ;Store_Binary
-
- ;========================================
- ; Load the BCD number to ST. Carry is
- ; set if illegal number. Since the
- ; number reading routine skips non-digit
- ; characters, ALL input numbers should
- ; be valid (i.e. legal).
-
- Load_Binary Proc Near
- Push Bp
- Sub Sp, 2 ;local data
- Mov Bp, Sp
-
- Fbld BCD_Number ;load number
- Fxam ;examine
- Fstsw Word [Bp] ;store the status word
- Fwait
- Mov Al, [Bp+1] ;get the high byte
- And Al, 47h ;mask all condition codes
-
- Cmp Al, 04h ;check if +Normal
- Je Lodbin1
- Cmp Al, 40h ;check if +0
- Je Lodbin1
- Add Sp, 2
- Pop Bp
- Stc
- Ret
-
- Lodbin1
- Add Sp, 2
- Pop Bp
- Clc
- Ret
- Endp ;Load_Binary
-
- ;========================================
- ; Store the number in ST to the BCD
- ; number. The base ten exponent is
- ; returned in AX
-
- Save_Binary Proc Near
- Mov Ax, 40 ;significant binary digits
- Call Flt2dec ;convert floating point to integer
- Fbstp BCD_Number ;store the integer
- Ret
- Endp ;Save_Binary
-
- ;========================================
- ; Display the BCD number with an exponent
- ; in AX. Assume positive number.
-
- Display_Binary Proc Near
- Push Bp
- Sub Sp, 6
- Mov Bp, Sp
-
- ;--- display digits
-
- Pushf
- Mov Cx, 18 ;maximum digit count
- Cmp Ax, 0 ;check if negative exponent
- Jge Disbin1 ;jump if not
- Add Cx, Ax ;get real digit count
- Sub Ax, Ax ;no exponent any more
- Disbin1
- Push Ax
- Std ;reverse direction, last byte to first
- Mov Dh, Cl ;set digit count
- Sub Dl, Dl ;preceding zero flag
- Mov Cx, 9 ;byte count
- Mov Si, Offset BCD_Number + 8 ;last digit location
-
- Disbin2
- Lodsb ;load byte
- Push Ax
- Shr Al
- Shr Al
- Shr Al
- Shr Al
- Call Display_Dig ;display digit
- Pop Ax
- And Al, 0fh ;mask bits
- Call Display_Dig ;display digit
- Loop Disbin2
-
- ;--- show exponent (assume positive value)
-
- Pop Ax
- Popf
- Or Ax, Ax ;check if none
- Jz Disbin4
-
- Mov Cx, 10 ;number base
- Sub Dx, Dx ;high word of exponent
- Lea Di, [Bp] ;place to put number string
- Call Convert_Num ;convert number
-
- Mov Ah, 9 ;function
- Mov Dx, Offset Expmes ;exponent message
- Int 21h ;display
-
- Mov Dx, 0ff00h ;set digit count and preceding zero flag
- Mov Si, Di ;location of number
-
- Disbin3
- Lodsb ;load digit
- Or Al, Al ;check if finished
- Jz Disbin4
- Sub Al, '0' ;make binary digit
- Call Display_Dig ;display digit
- Jmps Disbin3
-
- Disbin4
- Call New_Line ;new display line
- Add Sp, 6
- Pop Bp
- Ret
-
- Expmes Db ' x 10^$'
- Endp ;Display_Binary
-
- ;========================================
- ; Display the digit in AL. DH= count of
- ; digits to left of decimal point (if
- ; DH=0, no display). DL= preceding
- ; zero flag (if DL = 0, zero will be
- ; skipped).
-
- Display_Dig Proc Near
- Or Dh, Dh ;check digit count
- Jz Disdig2
- Dec Dh ;reduce count
- Or Al, Al ;check if zero
- Jnz Disdig1
- Or Dl, Dl ;check zero flag
- Jz Disdig2
-
- Disdig1
- Push Dx
- Add Al, '0' ;make ASCII digit
- Call Display_Char ;display
- Pop Dx
- Mov Dl, 1 ;set flag, non-zero digit
-
- Disdig2 Ret
- Endp ;Display_Dig
-
- ;========================================
- ; Start a new display line.
-
- New_Line Proc Near
- Mov Al, 13
- Call Display_Char ;display digit
- Mov Al, 10
- Call Display_Char ;display digit
- Ret
- Endp
-
- ;========================================
- ; Display the character in AL.
-
- Display_Char Proc Near
- Mov Dl, Al ;load character
- Mov Ah, 2 ;function number
- Int 21h ;display
- Ret
- Endp
-
- ;========================================
- ; External source files.
-
- Include 'Convert1.Inc'
- Include 'Convert2.Inc'
-