;A simple A + B Program , using 8086 Assembler ;Copyright © 2022 Lucas & yydk77.cn ; ;Licensed under the Apache License, Version 2.0 (the "License"); ;you may not use this file except in compliance with the License. ;You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ;Unless required by applicable law or agreed to in writing, software ;distributed under the License is distributed on an "AS IS" BASIS, ;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;See the License for the specific language governing permissions and ;limitations under the License. assume cs:code,ds:data,ss:stack data segment;数据段 buf1 db 20 dup(0);用于接收用户输入的第一个加数 buf2 db 20 dup(0);用于接收用户输入的第二个加数 buf3 db 20 dup(0);用于存储最终需要输出的和的字符串形式 tmp db 20 dup(0);用于临时存储加法产生的结果,还需要对此字符串执行逆向存储 tip1 db 'Enter a value:$' tip2 db 13,10,'Enter another value:$' tip3 db 13,10,'Sum is:$' data ends;数据段结束 stack segment stack;栈段 db 128 dup(?) stack ends;栈段结束 code segment;代码段 ;子过程:mul10 ;作用:对一个0-10的数执行乘法, ;将其放大为10的cx次方,在本例中保证不会溢出 ;入口:cx=这个数位在字符串中的位置, ; 比如说cx=1这个数就是字符串的个位 ; ax=待放大的数 ;出口:ax=放大过后的数 mul10 proc near push cx;暂存cx的值 dec cx;很容易推得,实际要乘以10的次数是cx-1 jcxz ok;如果这个数在个位,那么就不用执行变换了 s0:push dx;循环开始:如果这个数不在个位,那么它需要被乘以10的(cx-1)次方 push bx;因为在循环中mul指令会破坏bx和dx,所以先暂存它们的值 mov bx,10;设置乘数为10 mul bx;mul指令隐式包含被乘数为ax,积为dx|ax,本例保证积不会溢出至dx ;因为输入不超过10000 pop bx;还原bx、dx的值 pop dx loop s0;继续循环,直至指数降为0 ok:pop cx;恢复cx的值 ret;返回,此时ax为已被放大的数 mul10 endp ;子过程:ctod ;作用:输入一个字符串,并将其转化为二进制形式存储在寄存器中 ;入口:ds:dx=缓冲区 ;出口:ax=输入数的二进制形式 ctod proc near push si push cx push bx;保护寄存器的值 mov si,dx;因为dx不能直接用来被寻址(只有bx、si和立即数)... mov byte ptr ds:[si],5;所以通过si中转一下 ;根据int 21h中断的0ah号功能的要求 ;设置(ds:dx)为期望读取到的字符串的最大长度 push ax mov ah,0ah int 21h;执行系统调用,取得字符串 pop ax inc si;si前移,此时si指向字符串的实际位数 sub cx,cx;cx清零 mov cl,[si];cx中存储有字符串的实际位数 inc si;si前移,此时si指向用户输入的内容 mov bx,0;将bx用作累加寄存器 s1: mov ah,0;置ah为0 mov al,[si];将当前si所指的字符移入al sub al,30h;al减30h,将ax转化为一个二进制数(当前si指向的数位的二进制形式) call mul10;调用mul10将其转化为与当前数位对应的二进制数 ;比如说当前si指向的是百位,且ax=2,执行mul10后ax=200 add bx,ax;将得到的值加到bi上 inc si;si后移,指向下一位 loop s1;loop指令隐含dec cx mov ax,bx;将最终转化得到的二进制数移入ax pop bx;恢复寄存器的值 pop cx pop si ret;返回,ax为读入的二进制数 ctod endp ;子过程:xchgstr ;作用:对si所指的字符串反向存储到di中 ;入口:si=待反向存储的字符串 ; di=缓冲区 ; cx=字符串长度 ;出口:di=已反向存储的字符串 xchgstr proc near push si push di push cx push ax;保护寄存器的值 s3:mov al,[si] mov [di],al;执行数据交换 dec si;si前移 inc di;di后移 loop s3;循环至cx降为0 pop ax pop cx pop di pop si;恢复寄存器的值 ret;返回,di为已反向存储好的字符串 xchgstr endp ;子过程:dtoc ;作用:将一个二进制数转化为以'$'结尾的字符串 ;入口:dx=中转缓冲区 ; bx=目标缓冲区 ; ax=待转化的二进制数 ;出口:bx=转化好的字符串 dtoc proc near push bx push dx push ax push di push cx;保护寄存器的值 sub cx,cx;置cx为0 mov si,dx;设置si、di均指向中转缓冲区 mov di,dx push bx;保护bx,bx存有目标缓冲区的地址 wk:mov dx,0;将ax除以10 mov bx,10 div bx;商在ax中,余数在dx中 add dx,30h;加30h使二进制数变成字符 mov [si],dl;将其移入中转缓冲区 inc si;si后移一位 inc cx;已处理的位数加一 cmp ax,0;如果商为0了,那么就处理完了... jne wk;但不为0的话,还需要继续处理... ;循环结束的时候,si指向字符串末尾的后一个字符 ;因为循环的逻辑是放一个字符然后si后移一位 ;所以这里调整si让它指向字符串的末尾 ;cx存储了字符串的位数,这个参数要传递给xchgstr dec si pop bx;取出目的缓冲区的地址 mov di,bx;赋给di call xchgstr;将字符串反向存储 ;注意xchgstr在返回之前已经调整了di使它指向目的缓冲区的首地址 add di,cx;让di指向字符串末尾的后一个字符 mov byte ptr [di],'$';赋予字符串结束标志,该标志被int 21h识别 pop cx pop di pop ax pop dx pop bx;恢复寄存器的值 ret;返回,此时bx指向的缓冲区存储有对应的字符串 dtoc endp ;程序的进入点 start: mov ax,data mov ds,ax mov es,ax;设置ds和es寄存器,使他们同时指向数据段 ;便于用si和di寻址 mov ax,stack mov ss,ax mov sp,127;设置ss寄存器和sp寄存器 lea dx,tip1 mov ah,09h int 21h;向屏幕上输出第一条提示信息 lea dx,buf1;计算buf1的地址存入dx call ctod;将其传入ctod,ctod返回的二进制数存储在ax中 mov bx,ax;将其移入bx lea dx,tip2 mov ah,09h int 21h;向屏幕上输出第二条提示信息 lea dx,buf2;计算buf2的地址存入dx call ctod;将其传入ctod,ctod返回的二进制数存储在ax中 add ax,bx;两数相加 push ax mov ah,09h lea dx,tip3 int 21h;向屏幕上输出第三条提示信息 pop ax lea dx,tmp;计算tmp的地址存入dx,tmp被用作中转缓冲区 lea bx,buf3;计算buf3的地址存入bx,buf3被用作目标缓冲区 call dtoc;调用dtoc以将ax中存储的二进制数转化为字符串 lea dx,buf3 mov ah,09h int 21h;将转化后的字符串输出到屏幕上 mov ax,4c00h int 21h;结束程序 code ends;代码段结束 end start;指明程序进入点为start