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