Tiger6117

Calculator Source Code- Assembly x86

Aug 17th, 2016
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. name "calc2"
  3.  
  4. ; command prompt based simple calculator (+,-,*,/) for 8086.
  5. ; example of calculation:
  6. ; input 1 <- number:   10
  7. ; input 2 <- operator: -
  8. ; input 3 <- number:   5
  9. ; -------------------
  10. ;     10 - 5 = 5
  11. ; output  -> number:   5
  12.  
  13.  
  14.  
  15.  
  16.  
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18. ;;; this maro is copied from emu8086.inc ;;;
  19. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  20. ; this macro prints a char in AL and advances
  21. ; the current cursor position:
  22. PUTC    MACRO   char
  23.         PUSH    AX
  24.         MOV     AL, char
  25.         MOV     AH, 0Eh
  26.         INT     10h    
  27.         POP     AX
  28. ENDM
  29. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  30.  
  31.  
  32.  
  33.  
  34.  
  35. org 100h
  36.  
  37. jmp start
  38.  
  39.  
  40. ; define variables:
  41.  
  42. msg0 db "note: calculator works with integer values only.",0Dh,0Ah
  43.      db "to learn how to output the result of a float division see float.asm in examples",0Dh,0Ah,'$'
  44. msg1 db 0Dh,0Ah, 0Dh,0Ah, 'enter first number: $'
  45. msg2 db "enter the operator:    +  -  *  /     : $"
  46. msg3 db "enter second number: $"
  47. msg4 db  0dh,0ah , 'the approximate result of my calculations is : $'
  48. msg5 db  0dh,0ah ,'thank you for using the calculator! press any key... ', 0Dh,0Ah, '$'
  49. err1 db  "wrong operator!", 0Dh,0Ah , '$'
  50. smth db  " and something.... $"
  51.  
  52. ; operator can be: '+','-','*','/' or 'q' to exit in the middle.
  53. opr db '?'
  54.  
  55. ; first and second number:
  56. num1 dw ?
  57. num2 dw ?
  58.  
  59.  
  60. start:
  61. mov dx, offset msg0
  62. mov ah, 9
  63. int 21h
  64.  
  65.  
  66. lea dx, msg1
  67. mov ah, 09h    ; output string at ds:dx
  68. int 21h  
  69.  
  70.  
  71. ; get the multi-digit signed number
  72. ; from the keyboard, and store
  73. ; the result in cx register:
  74.  
  75. call scan_num
  76.  
  77. ; store first number:
  78. mov num1, cx
  79.  
  80.  
  81.  
  82. ; new line:
  83. putc 0Dh
  84. putc 0Ah
  85.  
  86.  
  87.  
  88.  
  89. lea dx, msg2
  90. mov ah, 09h     ; output string at ds:dx
  91. int 21h  
  92.  
  93.  
  94. ; get operator:
  95. mov ah, 1   ; single char input to AL.
  96. int 21h
  97. mov opr, al
  98.  
  99.  
  100.  
  101. ; new line:
  102. putc 0Dh
  103. putc 0Ah
  104.  
  105.  
  106. cmp opr, 'q'      ; q - exit in the middle.
  107. je exit
  108.  
  109. cmp opr, '*'
  110. jb wrong_opr
  111. cmp opr, '/'
  112. ja wrong_opr
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119. ; output of a string at ds:dx
  120. lea dx, msg3
  121. mov ah, 09h
  122. int 21h  
  123.  
  124.  
  125. ; get the multi-digit signed number
  126. ; from the keyboard, and store
  127. ; the result in cx register:
  128.  
  129. call scan_num
  130.  
  131.  
  132. ; store second number:
  133. mov num2, cx
  134.  
  135.  
  136.  
  137.  
  138. lea dx, msg4
  139. mov ah, 09h      ; output string at ds:dx
  140. int 21h  
  141.  
  142.  
  143.  
  144.  
  145. ; calculate:
  146.  
  147.  
  148.  
  149.  
  150.  
  151. cmp opr, '+'
  152. je do_plus
  153.  
  154. cmp opr, '-'
  155. je do_minus
  156.  
  157. cmp opr, '*'
  158. je do_mult
  159.  
  160. cmp opr, '/'
  161. je do_div
  162.  
  163.  
  164. ; none of the above....
  165. wrong_opr:
  166. lea dx, err1
  167. mov ah, 09h     ; output string at ds:dx
  168. int 21h  
  169.  
  170.  
  171. exit:
  172. ; output of a string at ds:dx
  173. lea dx, msg5
  174. mov ah, 09h
  175. int 21h  
  176.  
  177.  
  178. ; wait for any key...
  179. mov ah, 0
  180. int 16h
  181.  
  182.  
  183. ret  ; return back to os.
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195. do_plus:
  196.  
  197.  
  198. mov ax, num1
  199. add ax, num2
  200. call print_num    ; print ax value.
  201.  
  202. jmp exit
  203.  
  204.  
  205.  
  206. do_minus:
  207.  
  208. mov ax, num1
  209. sub ax, num2
  210. call print_num    ; print ax value.
  211.  
  212. jmp exit
  213.  
  214.  
  215.  
  216.  
  217. do_mult:
  218.  
  219. mov ax, num1
  220. imul num2 ; (dx ax) = ax * num2.
  221. call print_num    ; print ax value.
  222. ; dx is ignored (calc works with tiny numbers only).
  223.  
  224. jmp exit
  225.  
  226.  
  227.  
  228.  
  229. do_div:
  230. ; dx is ignored (calc works with tiny integer numbers only).
  231. mov dx, 0
  232. mov ax, num1
  233. idiv num2  ; ax = (dx ax) / num2.
  234. cmp dx, 0
  235. jnz approx
  236. call print_num    ; print ax value.
  237. jmp exit
  238. approx:
  239. call print_num    ; print ax value.
  240. lea dx, smth
  241. mov ah, 09h    ; output string at ds:dx
  242. int 21h  
  243. jmp exit
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  254. ;;; these functions are copied from emu8086.inc ;;;
  255. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  256.  
  257.  
  258. ; gets the multi-digit SIGNED number from the keyboard,
  259. ; and stores the result in CX register:
  260. SCAN_NUM        PROC    NEAR
  261.         PUSH    DX
  262.         PUSH    AX
  263.         PUSH    SI
  264.        
  265.         MOV     CX, 0
  266.  
  267.         ; reset flag:
  268.         MOV     CS:make_minus, 0
  269.  
  270. next_digit:
  271.  
  272.         ; get char from keyboard
  273.         ; into AL:
  274.         MOV     AH, 00h
  275.         INT     16h
  276.         ; and print it:
  277.         MOV     AH, 0Eh
  278.         INT     10h
  279.  
  280.         ; check for MINUS:
  281.         CMP     AL, '-'
  282.         JE      set_minus
  283.  
  284.         ; check for ENTER key:
  285.         CMP     AL, 0Dh  ; carriage return?
  286.         JNE     not_cr
  287.         JMP     stop_input
  288. not_cr:
  289.  
  290.  
  291.         CMP     AL, 8                   ; 'BACKSPACE' pressed?
  292.         JNE     backspace_checked
  293.         MOV     DX, 0                   ; remove last digit by
  294.         MOV     AX, CX                  ; division:
  295.         DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
  296.         MOV     CX, AX
  297.         PUTC    ' '                     ; clear position.
  298.         PUTC    8                       ; backspace again.
  299.         JMP     next_digit
  300. backspace_checked:
  301.  
  302.  
  303.         ; allow only digits:
  304.         CMP     AL, '0'
  305.         JAE     ok_AE_0
  306.         JMP     remove_not_digit
  307. ok_AE_0:        
  308.         CMP     AL, '9'
  309.         JBE     ok_digit
  310. remove_not_digit:      
  311.         PUTC    8       ; backspace.
  312.         PUTC    ' '     ; clear last entered not digit.
  313.         PUTC    8       ; backspace again.        
  314.         JMP     next_digit ; wait for next input.      
  315. ok_digit:
  316.  
  317.  
  318.         ; multiply CX by 10 (first time the result is zero)
  319.         PUSH    AX
  320.         MOV     AX, CX
  321.         MUL     CS:ten                  ; DX:AX = AX*10
  322.         MOV     CX, AX
  323.         POP     AX
  324.  
  325.         ; check if the number is too big
  326.         ; (result should be 16 bits)
  327.         CMP     DX, 0
  328.         JNE     too_big
  329.  
  330.         ; convert from ASCII code:
  331.         SUB     AL, 30h
  332.  
  333.         ; add AL to CX:
  334.         MOV     AH, 0
  335.         MOV     DX, CX      ; backup, in case the result will be too big.
  336.         ADD     CX, AX
  337.         JC      too_big2    ; jump if the number is too big.
  338.  
  339.         JMP     next_digit
  340.  
  341. set_minus:
  342.         MOV     CS:make_minus, 1
  343.         JMP     next_digit
  344.  
  345. too_big2:
  346.         MOV     CX, DX      ; restore the backuped value before add.
  347.         MOV     DX, 0       ; DX was zero before backup!
  348. too_big:
  349.         MOV     AX, CX
  350.         DIV     CS:ten  ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
  351.         MOV     CX, AX
  352.         PUTC    8       ; backspace.
  353.         PUTC    ' '     ; clear last entered digit.
  354.         PUTC    8       ; backspace again.        
  355.         JMP     next_digit ; wait for Enter/Backspace.
  356.        
  357.        
  358. stop_input:
  359.         ; check flag:
  360.         CMP     CS:make_minus, 0
  361.         JE      not_minus
  362.         NEG     CX
  363. not_minus:
  364.  
  365.         POP     SI
  366.         POP     AX
  367.         POP     DX
  368.         RET
  369. make_minus      DB      ?       ; used as a flag.
  370. SCAN_NUM        ENDP
  371.  
  372.  
  373.  
  374.  
  375.  
  376. ; this procedure prints number in AX,
  377. ; used with PRINT_NUM_UNS to print signed numbers:
  378. PRINT_NUM       PROC    NEAR
  379.         PUSH    DX
  380.         PUSH    AX
  381.  
  382.         CMP     AX, 0
  383.         JNZ     not_zero
  384.  
  385.         PUTC    '0'
  386.         JMP     printed
  387.  
  388. not_zero:
  389.         ; the check SIGN of AX,
  390.         ; make absolute if it's negative:
  391.         CMP     AX, 0
  392.         JNS     positive
  393.         NEG     AX
  394.  
  395.         PUTC    '-'
  396.  
  397. positive:
  398.         CALL    PRINT_NUM_UNS
  399. printed:
  400.         POP     AX
  401.         POP     DX
  402.         RET
  403. PRINT_NUM       ENDP
  404.  
  405.  
  406.  
  407. ; this procedure prints out an unsigned
  408. ; number in AX (not just a single digit)
  409. ; allowed values are from 0 to 65535 (FFFF)
  410. PRINT_NUM_UNS   PROC    NEAR
  411.         PUSH    AX
  412.         PUSH    BX
  413.         PUSH    CX
  414.         PUSH    DX
  415.  
  416.         ; flag to prevent printing zeros before number:
  417.         MOV     CX, 1
  418.  
  419.         ; (result of "/ 10000" is always less or equal to 9).
  420.         MOV     BX, 10000       ; 2710h - divider.
  421.  
  422.         ; AX is zero?
  423.         CMP     AX, 0
  424.         JZ      print_zero
  425.  
  426. begin_print:
  427.  
  428.         ; check divider (if zero go to end_print):
  429.         CMP     BX,0
  430.         JZ      end_print
  431.  
  432.         ; avoid printing zeros before number:
  433.         CMP     CX, 0
  434.         JE      calc
  435.         ; if AX<BX then result of DIV will be zero:
  436.         CMP     AX, BX
  437.         JB      skip
  438. calc:
  439.         MOV     CX, 0   ; set flag.
  440.  
  441.         MOV     DX, 0
  442.         DIV     BX      ; AX = DX:AX / BX   (DX=remainder).
  443.  
  444.         ; print last digit
  445.         ; AH is always ZERO, so it's ignored
  446.         ADD     AL, 30h    ; convert to ASCII code.
  447.         PUTC    AL
  448.  
  449.  
  450.         MOV     AX, DX  ; get remainder from last div.
  451.  
  452. skip:
  453.         ; calculate BX=BX/10
  454.         PUSH    AX
  455.         MOV     DX, 0
  456.         MOV     AX, BX
  457.         DIV     CS:ten  ; AX = DX:AX / 10   (DX=remainder).
  458.         MOV     BX, AX
  459.         POP     AX
  460.  
  461.         JMP     begin_print
  462.        
  463. print_zero:
  464.         PUTC    '0'
  465.        
  466. end_print:
  467.  
  468.         POP     DX
  469.         POP     CX
  470.         POP     BX
  471.         POP     AX
  472.         RET
  473. PRINT_NUM_UNS   ENDP
  474.  
  475.  
  476.  
  477. ten             DW      10      ; used as multiplier/divider by SCAN_NUM & PRINT_NUM_UNS.
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485. GET_STRING      PROC    NEAR
  486. PUSH    AX
  487. PUSH    CX
  488. PUSH    DI
  489. PUSH    DX
  490.  
  491. MOV     CX, 0                   ; char counter.
  492.  
  493. CMP     DX, 1                   ; buffer too small?
  494. JBE     empty_buffer            ;
  495.  
  496. DEC     DX                      ; reserve space for last zero.
  497.  
  498.  
  499. ;============================
  500. ; Eternal loop to get
  501. ; and processes key presses:
  502.  
  503. wait_for_key:
  504.  
  505. MOV     AH, 0                   ; get pressed key.
  506. INT     16h
  507.  
  508. CMP     AL, 0Dh                  ; 'RETURN' pressed?
  509. JZ      exit_GET_STRING
  510.  
  511.  
  512. CMP     AL, 8                   ; 'BACKSPACE' pressed?
  513. JNE     add_to_buffer
  514. JCXZ    wait_for_key            ; nothing to remove!
  515. DEC     CX
  516. DEC     DI
  517. PUTC    8                       ; backspace.
  518. PUTC    ' '                     ; clear position.
  519. PUTC    8                       ; backspace again.
  520. JMP     wait_for_key
  521.  
  522. add_to_buffer:
  523.  
  524.         CMP     CX, DX          ; buffer is full?
  525.         JAE     wait_for_key    ; if so wait for 'BACKSPACE' or 'RETURN'...
  526.  
  527.         MOV     [DI], AL
  528.         INC     DI
  529.         INC     CX
  530.        
  531.         ; print the key:
  532.         MOV     AH, 0Eh
  533.         INT     10h
  534.  
  535. JMP     wait_for_key
  536. ;============================
  537.  
  538. exit_GET_STRING:
  539.  
  540. ; terminate by null:
  541. MOV     [DI], 0
  542.  
  543. empty_buffer:
  544.  
  545. POP     DX
  546. POP     DI
  547. POP     CX
  548. POP     AX
  549. RET
  550. GET_STRING      ENDP
Add Comment
Please, Sign In to add comment