home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / asm / wasm / factor.asm < prev    next >
Assembly Source File  |  1987-11-26  |  10KB  |  448 lines

  1.  
  2.  Title 'Wolfware Assembler Sample Program', 'Factorial Calculator'
  3.  
  4. ;=============================================================================
  5. ; Factorial Calculator
  6. ;
  7. ; This a program to display the factorial of numbers.  Once assembled, to
  8. ; run, just type:
  9. ;
  10. ;   FACTOR
  11. ;
  12. ; Incidentally, the factorial of a number is the product of all integers
  13. ; between the number and zero.  For instance, the factorial of 6 (usually
  14. ; specified as 6!) is equal to 6 x 5 x 4 x 3 x 2 x 1 = 720.  If the result
  15. ; is too large, an error message will be displayed.
  16. ;
  17. ; Requires CONVERT1.INC and CONVERT2.INC on the default drive/path for
  18. ; assembly.
  19.  
  20. MaxChr Equ 40           ;input characters
  21.  
  22.  Fninit
  23.  
  24.  Mov Dx, Offset Mess1   ;opening display
  25.  Mov Ah, 9
  26.  Int 21h                ;display string
  27.  
  28. Main1
  29.  Mov Dx, Offset Mess2   ;prompt for number
  30.  Call Input_Integer     ;get an integer
  31.  Jc Main3               ;jump if done
  32.  
  33.  Call Factorial         ;calculate factorial
  34.  Jc Main2               ;jump if error
  35.  Call Save_Binary       ;store number, return exponent in AX
  36.  Push Ax
  37.  Mov Ah, 9
  38.  Mov Dx, Offset Mess3   ;result message
  39.  Int 21h                ;display string
  40.  Pop Ax
  41.  Call Display_Binary    ;display
  42.  Jmps Main1
  43.  
  44. ;--- error in calculation
  45.  
  46. Main2
  47.  Mov Ah, 9
  48.  Mov Dx, Offset Mess4   ;result message
  49.  Int 21h                ;display string
  50.  Jmps Main1
  51.  
  52. ;--- finished
  53.  
  54. Main3
  55.  Mov Ax, 4c00h
  56.  Int 21h
  57.  
  58. ;--- messages
  59.  
  60. Mess1 Db 13,10,'Factorial Calculator, Version 1.00',13,10,'$'
  61. Mess2 Db 13,10,'Enter number for factorial calculation: $'
  62. Mess3 Db 13,10,'The factorial is $'
  63. Mess4 Db 13,10,'The factorial cannot be calculated',13,10,'$'
  64.  
  65. ;========================================
  66. ; Calculate the factorial of the number
  67. ; in ST. If error, the carry is set and
  68. ; the 8087 stack is cleared.
  69.  
  70. Factorial Proc Near
  71.  Push Bp
  72.  Sub Sp, 2              ;local data
  73.  Mov Bp, Sp
  74.  
  75.  Fld1                   ;load one, initial total
  76.  Fxch                   ;total in second stack element
  77.  
  78. ;--- loop while number is not zero
  79.  
  80. Factor1
  81.  Ftst                   ;check if top element zero
  82.  Fstsw Word [Bp]        ;store the status word
  83.  Fwait
  84.  Mov Al, [Bp+1]         ;get the high byte
  85.  And Al, 45h            ;mask condition codes C3 C2 and C0
  86.  Cmp Al, 40h            ;check if zero
  87.  Je Factor2
  88.  Fmul St(1), St(0)      ;multiply
  89.  Fstsw Word [Bp]        ;store the status word
  90.  Fwait
  91.  Test Byte [Bp], 1fh    ;check if any exceptions
  92.  Jnz Factor3
  93.  
  94.  Fld1                   ;load one
  95.  Fsub                   ;subtract and pop
  96.  Jmps Factor1
  97.  
  98. ;--- finished
  99.  
  100. Factor2
  101.  Fstp St(0)             ;pop stack
  102.  Add Sp, 2
  103.  Pop Bp
  104.  Clc
  105.  Ret
  106.  
  107. ;--- exception occured
  108.  
  109. Factor3
  110.  Fstp St(0)
  111.  Fstp St(0)             ;clear stack
  112.  Fclex                  ;clear exceptions
  113.  Add Sp, 2
  114.  Pop Bp
  115.  Stc
  116.  Ret
  117.  Endp           ;Factorial
  118.  
  119. ;========================================
  120. ; Display the $ terminated string at DX
  121. ; and then input an integer and return it
  122. ; in ST.  Carry set if no input.  All 
  123. ; non-numeric characters are ignored. 
  124.  
  125. Input_Integer Proc Near
  126.  Pushf
  127.  Push Bp
  128.  Sub Sp, MaxChr+3       ;local data, room for input
  129.  Mov Bp, Sp
  130.  
  131. Inpint1
  132.  Mov Ah, 9
  133.  Int 21h                ;display string
  134.  
  135.  Push Dx
  136.  Mov Byte [Bp], MaxChr+1        ;possible number of characters (plus CR)
  137.  Lea Dx, [Bp]                   ;get the location
  138.  Mov Ah, 0ah
  139.  Int 21h                        ;input string
  140.  Call New_Line                  ;start a new line
  141.  Pop Dx
  142.  
  143.  Mov Al, [Bp+1]         ;get the input length
  144.  Or Al, Al
  145.  Jz Inpint6             ;jump if none
  146.  
  147.  Push Dx
  148.  
  149. ;--- store digits
  150.  
  151.  Std                    ;set direction
  152.  Lea Si, [Bp+1]         ;get start of input minus one
  153.  Sub Ah, Ah
  154.  Add Si, Ax             ;point to last (low) digit
  155.  Sub Bx, Bx             ;counts digits
  156.  Mov Cx, Ax             ;character count
  157.  Call Init_Binary       ;initialize BCD number
  158.  
  159. Inpint2
  160.  Lodsb                  ;get digit
  161.  Sub Al, '0'            ;convert to binary
  162.  Jb Inpint3             ;jump if too low
  163.  Cmp Al, 9              ;check if too high
  164.  Ja Inpint3             ;jump if so
  165.  Inc Bx
  166.  Call Store_Binary      ;store BCD digit
  167. Inpint3 Loop Inpint2
  168.  
  169. ;--- store zeros
  170.  
  171.  Mov Cx, 18             ;max digits
  172.  Sub Cx, Bx             ;get difference
  173.  Jbe Inpint5            ;jump if full (no padding)
  174.  
  175. Inpint4
  176.  Sub Al, Al             ;zero digit
  177.  Call Store_Binary      ;store pad digit
  178.  Loop Inpint4           ;loop for count
  179.  
  180. ;--- number stored
  181.  
  182. Inpint5
  183.  Call Load_Binary       ;put number in ST
  184.  Pop Dx
  185.  Jc Inpint7
  186.  
  187.  Add Sp, MaxChr+3
  188.  Pop Bp
  189.  Popf
  190.  Clc
  191.  Ret
  192.  
  193. ;--- no input
  194.  
  195. Inpint6
  196.  Add Sp, MaxChr+3
  197.  Pop Bp
  198.  Popf
  199.  Stc
  200.  Ret
  201.  
  202. ;--- illegal number, should never happen if only valid digits are read
  203.  
  204. Inpint7
  205.  Push Dx
  206.  Mov Dx, Offset Inperr  ;error message
  207.  Mov Ah, 9
  208.  Int 21h                ;display string
  209.  Pop Dx
  210.  Jmp Inpint1
  211.  
  212. Inperr Db 13,10,'Error in number',13,10,'$'
  213.  Endp                   ;Input_Integer
  214.  
  215. ;========================================
  216. ; Global BCD data.
  217.  
  218. BCD_Flag  Db ?
  219. BCD_Store Db ?
  220. BCD_Count Dw ?
  221. BCD_Number Label Tbyte
  222.  Ds 10
  223.  
  224. ;========================================
  225. ; Initialize the global BCD number.
  226.  
  227. Init_Binary Proc Near
  228.  Mov BCD_Flag, 0                ;clear flag
  229.  Mov BCD_Count, 0               ;clear byte count
  230.  Mov Byte BCD_Number+9, 0       ;clear sign (always positive)
  231.  Ret
  232.  Endp           ;Init_Binary
  233.  
  234. ;========================================
  235. ; Store the digit in AL to the BCD
  236. ; number.
  237.  
  238. Store_Binary Proc Near
  239.  Push Bx
  240.  Test BCD_Flag, 1       ;check if second digit
  241.  Jnz Stobin1
  242.  
  243. ;--- wait for second digit
  244.  
  245.  Mov BCD_Store, Al      ;save digit
  246.  Jmps Stobin2
  247.  
  248. ;--- store digit pair
  249.  
  250. Stobin1
  251.  Mov Bx, BCD_Count      ;get digit count
  252.  Cmp Bx, 9              ;check if count exceeded
  253.  Jae Stobin3
  254.  
  255.  Shl Al
  256.  Shl Al
  257.  Shl Al
  258.  Shl Al
  259.  Or Al, BCD_Store               ;combine other digit
  260.  Add Bx, Offset BCD_Number      ;get location
  261.  Mov [Bx], Al                   ;save digit
  262.  
  263.  Inc BCD_Count                  ;increment digit count
  264.  
  265. ;--- finished
  266.  
  267. Stobin2
  268.  Xor BCD_Flag, 1        ;flip flag
  269.  
  270. Stobin3
  271.  Pop Bx
  272.  Ret
  273.  Endp           ;Store_Binary
  274.  
  275. ;========================================
  276. ; Load the BCD number to ST.  Carry is 
  277. ; set if illegal number.  Since the
  278. ; number reading routine skips non-digit
  279. ; characters, ALL input numbers should
  280. ; be valid (i.e. legal).
  281.  
  282. Load_Binary Proc Near
  283.  Push Bp
  284.  Sub Sp, 2              ;local data
  285.  Mov Bp, Sp
  286.  
  287.  Fbld BCD_Number        ;load number
  288.  Fxam                   ;examine
  289.  Fstsw Word [Bp]        ;store the status word
  290.  Fwait
  291.  Mov Al, [Bp+1]         ;get the high byte
  292.  And Al, 47h            ;mask all condition codes
  293.  
  294.  Cmp Al, 04h    ;check if +Normal
  295.  Je Lodbin1
  296.  Cmp Al, 40h    ;check if +0
  297.  Je Lodbin1
  298.  Add Sp, 2
  299.  Pop Bp
  300.  Stc
  301.  Ret
  302.  
  303. Lodbin1
  304.  Add Sp, 2
  305.  Pop Bp
  306.  Clc
  307.  Ret
  308.  Endp           ;Load_Binary
  309.  
  310. ;========================================
  311. ; Store the number in ST to the BCD
  312. ; number.  The base ten exponent is
  313. ; returned in AX
  314.  
  315. Save_Binary Proc Near
  316.  Mov Ax, 40             ;significant binary digits
  317.  Call Flt2dec           ;convert floating point to integer
  318.  Fbstp BCD_Number       ;store the integer
  319.  Ret
  320.  Endp           ;Save_Binary
  321.  
  322. ;========================================
  323. ; Display the BCD number with an exponent
  324. ; in AX.  Assume positive number.
  325.  
  326. Display_Binary Proc Near
  327.  Push Bp
  328.  Sub Sp, 6
  329.  Mov Bp, Sp
  330.  
  331. ;--- display digits
  332.  
  333.  Pushf
  334.  Mov Cx, 18             ;maximum digit count
  335.  Cmp Ax, 0              ;check if negative exponent
  336.  Jge Disbin1            ;jump if not
  337.  Add Cx, Ax             ;get real digit count
  338.  Sub Ax, Ax             ;no exponent any more
  339. Disbin1
  340.  Push Ax
  341.  Std                            ;reverse direction, last byte to first
  342.  Mov Dh, Cl                     ;set digit count
  343.  Sub Dl, Dl                     ;preceding zero flag
  344.  Mov Cx, 9                      ;byte count
  345.  Mov Si, Offset BCD_Number + 8  ;last digit location
  346.  
  347. Disbin2
  348.  Lodsb                  ;load byte
  349.  Push Ax
  350.  Shr Al
  351.  Shr Al
  352.  Shr Al
  353.  Shr Al
  354.  Call Display_Dig       ;display digit
  355.  Pop Ax
  356.  And Al, 0fh            ;mask bits
  357.  Call Display_Dig       ;display digit
  358.  Loop Disbin2
  359.  
  360. ;--- show exponent (assume positive value)
  361.  
  362.  Pop Ax
  363.  Popf
  364.  Or Ax, Ax              ;check if none
  365.  Jz Disbin4
  366.  
  367.  Mov Cx, 10             ;number base
  368.  Sub Dx, Dx             ;high word of exponent
  369.  Lea Di, [Bp]           ;place to put number string
  370.  Call Convert_Num       ;convert number
  371.  
  372.  Mov Ah, 9              ;function
  373.  Mov Dx, Offset Expmes  ;exponent message
  374.  Int 21h                ;display
  375.  
  376.  Mov Dx, 0ff00h         ;set digit count and preceding zero flag
  377.  Mov Si, Di             ;location of number
  378.  
  379. Disbin3
  380.  Lodsb                  ;load digit
  381.  Or Al, Al              ;check if finished
  382.  Jz Disbin4
  383.  Sub Al, '0'            ;make binary digit
  384.  Call Display_Dig       ;display digit
  385.  Jmps Disbin3
  386.  
  387. Disbin4
  388.  Call New_Line          ;new display line
  389.  Add Sp, 6
  390.  Pop Bp
  391.  Ret
  392.  
  393. Expmes Db ' x 10^$' 
  394.  Endp                   ;Display_Binary
  395.  
  396. ;========================================
  397. ; Display the digit in AL.  DH= count of
  398. ; digits to left of decimal point (if
  399. ; DH=0, no display).  DL= preceding
  400. ; zero flag (if DL = 0, zero will be
  401. ; skipped).
  402.  
  403. Display_Dig Proc Near
  404.  Or Dh, Dh      ;check digit count
  405.  Jz Disdig2
  406.  Dec Dh         ;reduce count
  407.  Or Al, Al      ;check if zero
  408.  Jnz Disdig1
  409.  Or Dl, Dl      ;check zero flag
  410.  Jz Disdig2
  411.  
  412. Disdig1
  413.  Push Dx
  414.  Add Al, '0'            ;make ASCII digit
  415.  Call Display_Char      ;display
  416.  Pop Dx
  417.  Mov Dl, 1              ;set flag, non-zero digit
  418.  
  419. Disdig2 Ret
  420.  Endp           ;Display_Dig
  421.  
  422. ;========================================
  423. ; Start a new display line.
  424.  
  425. New_Line Proc Near
  426.  Mov Al, 13
  427.  Call Display_Char      ;display digit
  428.  Mov Al, 10
  429.  Call Display_Char      ;display digit
  430.  Ret
  431.  Endp
  432.  
  433. ;========================================
  434. ; Display the character in AL.
  435.  
  436. Display_Char Proc Near
  437.  Mov Dl, Al     ;load character
  438.  Mov Ah, 2      ;function number
  439.  Int 21h        ;display
  440.  Ret
  441.  Endp
  442.  
  443. ;========================================
  444. ; External source files.
  445.  
  446.  Include 'Convert1.Inc'
  447.  Include 'Convert2.Inc'
  448.