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
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
2进制转十进制在线计算器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
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 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

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。