Assembly-8086-Learn/apb.asm

192 lines
6.5 KiB
NASM
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;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;保护bxbx存有目标缓冲区的地址
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;将其传入ctodctod返回的二进制数存储在ax中
mov bx,ax;将其移入bx
lea dx,tip2
mov ah,09h
int 21h;向屏幕上输出第二条提示信息
lea dx,buf2;计算buf2的地址存入dx
call ctod;将其传入ctodctod返回的二进制数存储在ax中
add ax,bx;两数相加
push ax
mov ah,09h
lea dx,tip3
int 21h;向屏幕上输出第三条提示信息
pop ax
lea dx,tmp;计算tmp的地址存入dxtmp被用作中转缓冲区
lea bx,buf3;计算buf3的地址存入bxbuf3被用作目标缓冲区
call dtoc;调用dtoc以将ax中存储的二进制数转化为字符串
lea dx,buf3
mov ah,09h
int 21h;将转化后的字符串输出到屏幕上
mov ax,4c00h
int 21h;结束程序
code ends;代码段结束
end start;指明程序进入点为start