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 
posted @ 2021-04-14 18:21  GaoYuan206  阅读(36)  评论(0编辑  收藏  举报