8086匯編語言實現簡易計算器


8086匯編語言實現簡易計算器

本周看了一個很有意思的知識。

C語言的編譯器最初是怎么來的?

最初應該是由匯編語言實現一個簡化版C語言,然后使用簡化版的C語言進行多次迭代,功能更新,從而出現了如今強大的C語言。

本人找到了一個古老的課程設計,當時學匯編時候的一個小demo分享出來。

1.概述

為了更深入地理解計算機工作原理以及CPU的功能和結構,掌握匯編語言的使用。本文以簡易計算器程序的匯編語言實現為主要任務,進行對程序的一些算法和匯編語言語法的論述。計算器是最簡單的計算工具,簡單計算器具有加、減、乘、除四項運算功能。想要用匯編語言實現簡單的計算器,就必須通過對數據存儲,寄存器的使用,加減乘除相關指令以及模塊的調用等匯編語言知識進行運用,以實現一個基本功能完善,界面友好,操作簡便易行的計算器。用匯編語言實現簡單計算器還涉及到輸入輸出模塊的設計,加減乘除運算的判斷以及退出程序的判斷的設計。通過對各種指令的合理使用,設計各個功能模塊。當實現各個程序模塊后,通過程序的調用最終實現一個簡單的計算器。本文以用8086匯編語言實現簡易計算器為目標,對程序的算法以及結構進行分析和解釋。

匯編語言的語句類型有指令語句、偽指令語句和宏指令語句。

在實現簡易計算器的過程中暫不需要宏指令語句,故對此語句不進行介紹。

計算器的實現需要使用輸入輸出,DOS系統的01H,02H,09H號調用可以完成所需功能。

由於簡易計算器對結果沒有很高的范圍要求,故對四則運算只需考慮ADD,SUB,MUL,DIV等指令。在計算器中,輸入的是10進制數字,而在匯編語言中讀入字符只能一位一位的讀取,故需要使用MUL設置一個循環算法,將輸入的數字以16進制形式放入寄存器中,而輸出則是使用MOD設置一個循環算法,將16進制轉化為10進制后處理為ASCII碼進行輸出。

2.程序算法結構

簡易計算器程序的任務主要有處理輸入數據,選擇運算方式進行計算,顯示算式結果。程序中為這三個任務做了5個子程序:do_before,do_add,do_sub,do_mul,do_div,show。

簡易計算機結構

在進行簡易計算器程序的制作之前,需要設計程序的結構。從簡易計算器設計的任務要求可知,需要計算機先進行判定需要進行的運算方式,對輸入數據進行計算,最后輸出輸入的算式及計算結果。如:

系統輸出:please input the operator(from + - * /):

用戶輸入運算符選擇運算方式

系統輸出:please input the x and y:

用戶輸入兩個運算數

系統輸出:x+y=z (進行加法運算)

程序流程圖如下:(很簡陋,本科階段畫的)

算法介紹

主要需要用到的子程序主要有輸入轉化子程序do_before:DOS功能01H號調用中的輸入,是將數字一位一位地存儲在AL寄存器中的(如123,讀入寄存器的為1,2,3),而且輸入的數字是以ASCII碼存儲在寄存器中的,需要將其轉化為ASCII碼代表的數字,並將一位一位的數字合並轉化為一個具有數學意義的多位數字。四則運算子程序do_add,do_sub,do_mul,do_div:主要使用add,sub,mul,div指令,下文中只對do_add子程序進行介紹,其余三個子程序類似。輸出結果子程序show:DOS功能02H號調用中的輸出,是輸出一位數字,不能輸出整數型,所以需要對運算結果進行處理,將16進制的數據,轉化為10進制,並一位位地進行輸出。

1.輸入轉化子程序

do_before:
          mov ah,1h
          int 21h           ;調用DOS功能1H號,讀入一位數字
          mov temp,0
          sub al,'0'       ;將數字轉化為ASCII碼代表的數字
          cmp al,0       ;判斷輸入的是否是數字
          jl done1       ;不是數字的話結束輸入
          cmp al,9      ;判斷輸入的是否是數字
          jg done1      ;不是數字的話結束輸入
          xor ah,ah     ;高位清零
          mov temp,ax
          mov ax,x
          mul ten     ;ten 中存儲的是10
          add ax,temp
          mov x,ax
          jmp do_before  ; 輸入未結束,循環調用
        done1:
          ret     

該子程序流程圖如下:

2.加法子程序

do_add:
          call crlf       ;調用輸出回車子程序
          mov ax,data
          mov ds,ax
          mov ah,09h
          lea dx,message4   ;輸出’please input the x and y:’
          int 21h
          call do_before1
          call do_before2      ;輸入兩個運算數
          call crlf 
          mov ax,temp1
          mov x,ax
          call show1
          mov dl,'+'
          mov ah,2h
          int 21h
          mov ax,temp2
          mov x,ax
          call show1
          mov ax,temp1 
          mov x,ax
          mov dl,'='              ;輸出算式
          mov ah,2h
          int 21h
          mov ax,x
          add ax,y          ;進行加法
          mov x,ax  
          call show         ;輸出結果
          ret

由於該子程序是順序結構,不對其流程圖進行描述。

do_add子程序直接對輸入算式進行了輸出,對兩個運算數進行加法后調用了show子程序對結果進行了輸出,兩部分合在一起后便湊成了完整的算式。

3.輸出結果子程序

show:            ;顯示結果並結束
            mov ax,x             ;x中此時存儲的是運算結果
            mov bx,0ah           ;給bx寄存器中賦10,方便結果輸出
            mov cx,0            ;cx寄存器作計數器
     step1:  mov dx,0
            div  bx             ;執行div指令后商在ax寄存器中,余數在dx寄存器中
            cmp ax,0ah          ;判斷商是否小於10
            jl n1
            push dx             ;將余數壓入棧
            inc cx              ;計數器加1,cx代表棧中數字的數量
            jmp step1         ;若商不小於10,則一直進行壓棧、判斷的循環
     n1:    push dx           ;將最后一位余數壓入棧
            inc cx
            push ax           ;最后一位小於10的商入棧
            inc cx
            jmp step2
     step2:  pop dx          ;將棧中數字依次輸出
            add dl,'0'
            mov ah,2h
            int 21h
            loop step2 
            mov ah,4ch       ;返回DOS
            int 21h           ;系統調用
            ret

該子程序的流程圖如下:

該子程序算法是將16進制數除以10,將余數壓入棧,若商大於10,將商除以10,余數再次壓入棧,循環這個步驟直到商小於10,將商壓入棧,壓入的順序即是10進制數字由后到前的順序,依次出棧得到的結果就是10進制的運算結果。

此外,如do_add子程序中出現的show1子程序,是為了顯示兩個運算數,調用完之后不返回DOS。程序中,將第一個運算數存進了x,第二個運算數存進了y。由於程序中不需要考慮負數作為運算數,故寄存器中存儲的都是無符號數,需要考慮減法和除法中,x小於y的情況。在do_sub中,當判斷x小於y后,將x和y內的數據調換,調換過程中需要借用一個寄存器,在源代碼中借用的ax寄存器,調換之后按正常情況計算,在運算結果前添加負號即得到正確結果。在do_div中,判斷x小於y后,可直接在等號后輸出x。

3.實現效果

4.源碼

 data segment
       x dw 0            ;第一個數
       y dw 0            ;第二個數
       z dw 0
       temp1 dw 0
       temp2 dw 0
       temp dw 0
       ten  dw 0ah
       op db 0             ;操作符
       message db 'please choose the operator : (from + - * /)',0ah,0dh,'$'
       message2 db 'input error',0ah,0dh,'$'
       message3 db '......','$'
       message4 db 'please input the x and y:',0ah,0dh,'$'
       data ends  

     assume cs:code,ds:data
     
     code segment
        start:
          mov ax,data
          mov ds,ax
          mov ah,09h
          lea dx,message
          int 21h  
          call input
          
        input:
          mov ah,1h
          int 21h
          cmp al,'+'
          jz nx_1 
          cmp al,'-'
          jz nx_2
          cmp al,'*'
          jz nx_3
          cmp al,'/'
          jz nx_4 
          jnz er_1
              
                     
        er_1: 
          call crlf
          call show_error 
          call done           
          
        nx_1:
          call do_add
          
        nx_2:
          call do_sub
        
        nx_3:
          call do_mul
          
        nx_4:
          call do_div
          
        show_error:
          mov ax,data
          mov ds,ax
          mov ah,09h
          lea dx,message2
          int 21h
          
        do_before1:
          mov ah,1h
          int 21h  
          mov temp,0
          sub al,'0'
          cmp al,0
          jl done1
          cmp al,9
          jg done1
          xor ah,ah     ;高位清零
          mov temp,ax
          mov ax,x
          mul ten  
          add ax,temp
          mov x,ax 
          mov temp1,ax
          jmp do_before1
        done1:
          ;add x,'0'
          ret            
        
        do_before2:
          mov ah,1h
          int 21h
          mov temp,0
          sub al,'0'
          cmp al,0
          jl done1
          cmp al,9
          jg done1
          xor ah,ah     ;高位清零
          mov temp,ax
          mov ax,y
          mul ten  
          add ax,temp
          mov y,ax   
          mov temp2,ax
          jmp do_before2 
          
       done:
          mov ax,4c00h
          int 21h

                  
        do_add:
          call crlf
          mov ax,data
          mov ds,ax
          mov ah,09h
          lea dx,message4
          int 21h
          call do_before1
          call do_before2
          call crlf 
          mov ax,temp1
          mov x,ax
          call show1
          mov dl,'+'
          mov ah,2h
          int 21h
          mov ax,temp2
          mov x,ax
          call show1
          mov ax,temp1 
          mov x,ax
          mov dl,'='
          mov ah,2h
          int 21h
          mov ax,x
          add ax,y
          mov x,ax
          call show 
          ret 
          
          
        do_sub:
          call crlf
          mov ax,data
          mov ds,ax
          mov ah,09h
          lea dx,message4
          int 21h
          call do_before1
          call do_before2 
          call crlf
          call show1
          mov dl,'-'
          mov ah,2h
          int 21h
          mov ax,temp2
          mov x,ax
          call show1
          mov ax,temp1
          mov x,ax
          mov dl,'='
          mov ah,2h
          int 21h
          mov ax,x
          cmp ax,y   
          jl exchange
          mov ax,x
          sub ax,y 
          mov x,ax
          call show
          ret
          
          
        exchange:
                          ;小x減大y
            mov dl,'-'
            mov ah,2h
            int 21h 
            mov ax,y
            mov bx,x
            sub ax,bx
            mov x,ax
            call show
         
                      
        do_mul:
            call crlf 
            mov ax,data
            mov ds,ax
            mov ah,09h
            lea dx,message4
            int 21h
            call do_before1
            call do_before2 
            call crlf
            call show1
            mov dl,'*'
            mov ah,2h
            int 21h
            mov ax,temp2
            mov x,ax
            call show1
            mov ax,temp1
            mov x,ax
            mov dl,'='
            mov ah,2h
            int 21h
            mov ax,x
            mov bx,y
            mul bx
            mov x,ax
            call show 
            
        do_div:
            call crlf
            mov ax,data
            mov ds,ax
            mov ah,09h
            lea dx,message4
            int 21h
            call do_before1
            call do_before2 
            call crlf
            mov ax,temp1
            mov x,ax
            call show1
            mov dl,'/'
            mov ah,2h
            int 21h
            mov ax,temp2
            mov x,ax
            call show1
            mov ax,temp1
            mov x,ax
            mov dl,'='
            mov ah,2h
            int 21h
            mov ax,x
            mov bx,y
            cmp ax,bx
            jl do_div2
            mov dx,0
            div bx 
            mov x,ax
            mov temp,dx
            cmp dx,0
            jz div_0
            call show1
            mov ax,data      ;求余
            mov ds,ax
            lea dx,message3
            mov ah,9h
            int 21h
            mov ax,temp
            mov x,ax
            call show1
            mov ah,4ch
            int 21h
            ret            
            
        div_0: 
            call show
            
            
        do_div2:                 ;x比y小
            mov dl,'0'
            mov ah,2h
            int 21h
            mov ax,data      ;求余
            mov ds,ax
            lea dx,message3
            mov ah,9h
            int 21h
            mov ax,x
            call show
        
        
        crlf:      ;回車換行
            mov ah,2
            mov dl,0DH
            int 21H
            mov dl,0AH
            int 21H
            ret    
            
        show:            ;顯示結果並結束
            mov ax,x 
            mov bx,0ah
            mov cx,0
     step1: mov dx,0
            div  bx
            cmp ax,0ah
            jl n1
            push dx 
            inc cx
            jmp step1
     n1:    push dx
            inc cx
            push ax
            inc cx
            jmp step2
     step2: pop dx
            add dl,'0'
            mov ah,2h
            int 21h
            loop step2 
            mov ah,4ch
            int 21h
            ret
            
       show1:            ;顯示結果不結束
            mov ax,x 
            mov bx,0ah
            mov cx,0
     step_1: mov dx,0
            div  bx
            cmp ax,0ah
            jl n_1
            push dx 
            inc cx
            jmp step_1
     n_1:    push dx
            inc cx
            push ax
            inc cx
            jmp step_2
     step_2: pop dx
            add dl,'0'
            mov ah,2h
            int 21h
            loop step_2 
            ret
        code ends
end  start 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM