diff --git a/apb.asm b/apb.asm new file mode 100644 index 0000000..c3ab007 --- /dev/null +++ b/apb.asm @@ -0,0 +1,192 @@ +;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 \ No newline at end of file