[BX]和loop指令

5.1 [bx]

[bx]

assume cs:kk

kk segment

nn: mov ax,2000H
mov ds,ax
mov al,[0]//等于mov al,0
mov bl,[1]//等于mov bl,1
mov cl,[3]
mov dl,[4]

mov ax,4c00H
int 21H

kk ends
end nn
用编辑器和debug写的命令不同
[bx]表示一个内存单元,它的偏移地址在bx中,比如
不能
mov ax,[0]
只能
mov bx,0
mov ax,[bx]
mov al,[bx]

loop 循环

描述性符号”()”
(ax)=0010H
2000:1000处的内容为0010H
(21000H)=0010H
对于mov ax,[2]的功能
(ax)=((ds)*16+2)
对于mov [3],ax的功能
((ds)*16+2)=(ax)
对于add ax,2的功能
(ax)=(ax)+2
对于add ax,bx的功能
(ax)=(ax)+(bx)
对于push ax的功能
(sp)=(sp)-2
((ss)*16+(sp))=(ax)
对于pop ax的功能
(ax)=((ss)16+(sp))
(sp)=(sp)+2
约定符号idata(我的数据//常量)
mov ax,[idata]就代表mov ax,[1]、mov ax,[2]、mov ax,[3]等
mov bx,idata就代表mov bx,1、mov bx,2、mov bx,3等
mov ds,idata就代表mov ds,1.。。。但是这是错误的,非法的
mov ax,[bx]
功能: bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA处的数据送入ax中。
(ax)=(ds
16+(bx))
mov| bx ,ax
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的数据送入内存SA:EA处。
(ds *16 +(bx)) = (ax)

inc bx的含义是nx中的内容加1

mov bx,1
inc bx
bx=2

5.2 loop指令

指令的格式是:loop标号,CPU执行loop指令
(cx)=(cx)-1
判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。
cx的值影响着loop指令的执行结果
Cx中存放循环次数
2^2

assume cs:code
code segment
mov ax,2
add ax,ax

mov ax,4c00H
int 21H
code ends

end


2^3

assume cs:code

code segment
mov ax,2
add ax,ax
add ax,ax

mov ax,4c00H
int 21H
code ends

end


2^12
Assume cs:code
code segment
mov ax,2
mov cx,11
s: add ax,ax
loop s//s为标号

mov ax,4c00H
int 21H
code ends
end
(1)标号
在汇编语言中,标号代表一个地址,此程序中有一个标号s。它实际上标识了一个地址,这个地址处有一条指令: add ax,ax。
(2)loop s
CPU执行loop s的时候,要进行两步操作:
①(cx)=(cx)-1 ;
②判断cx中的值,不为0则转至标号s所标识的地址处执行(这里的指令是“add ax,ax),如果为零则执行下一条指令(下一条指令是mov ax,4c00h)。
(3)以下三条指令
mov cx,1 1
s: add ax,ax
loop s
执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前转至s处执行add ax,ax。所以,我们可以利用cx来控制add ax,ax的执行次数
loop指令
(1)在cx中存放循环次数;
(2)loop指令中的标号所标识地址要在前面;
(3)要循环执行的程序段,要写在标号和loop指令的中间。
mov cx,循环次数
s:
循玎执行的程序段
loop s//(cx=cx-1 判断cx是否为0)

5.3在Debug中跟踪用loop指令实现的循环程序

我们说的是“赋值”,就是说,让ax中的数据的值(数据的大小)和ffff:0006单元中的数据的值(数据的大小)相等。
8位数据01H和16位数据0001H的数据长度不一样,但它们的值是相等的。

不能直接mov ax,[bx],要mov al,[bx]–mov ah,0,否则会将ds:[bx]和ds:[bx+1]的值赋给ax

注意程序中的第一条指令mov ax,0ffffh。
我们知道大于9FFFH的十六进制数据A000H、A001H、…..、COOOH、COO1H、、FFFEH、FFFFH等,在书写的时候都是以字母开头的。

而在3汇编源程序中,数据不能以字母开头,所以要在前面加0。

调试多次用G命令也可以用P命令
-g XXXX
XXXX偏移地址
-p直接循环完

5.4debug和汇编编译器MASM对指令的不同处理

debug中数字默认16进制masm中默认10进制
#5.5 loop和[bx]的联合应用
在做加法的时候,我们有两种方法:
(dx)=(dx)+内存中的8位数据:
(dl)=(dl)+内存中的8位数据;
第一种方法中的问题是两个运算对象的类型不匹配,第二种方法中的问题是结果有可能超界。
目前的方法(后面还有别的方法)就是得用一个16位寄存器来做中介。
mov ax,0ffffH
mov ds,ax ;设置(ds)=0ffffh
mov dx,0 ;初始化素累加寄存器,(dx)=0
mov al,ds: [0]
mov ah,0 ;(ax)=((ds)*16+0)= (0ffff0h)
add dx,ax ;向dx中加.上offffh:0单元的数值

loop改进后
mov ax,0ffffH
mov ds,ax
mov dx,0
mov bx,0
mov cx,000bH
s: mov al,[bx]
mov ah,0
add dx,ax
inc bx
loop s
5.6 段前缀
指令“mov ax,[bx]”中 ,内存单元的偏移地址由bx给出,而段地址默认在ds中。//ds就称之为段前缀
我们可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。
这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的”ds:”、”cs:”、”ss:”或”es:”,在汇编语言中称为段前缀
mov ax,cs:[0]
mov bx,es:[0]

5.7一段安全的空间

在8086模式中,随意向一段内存空间写入内容是很危险的,因为这段空间中可能存放着重要的系统数据或代码。
在一般的PC机中,DOS方式下,DOS和其他合法的程序一般都不会使用0:2000:2FF( 0:200h~0:2FFh) 的256个字节的空间。所以,我们使用这段空间是安全的。

5.8段前缀的使用

将内存ffff:0~ ffff:b单元中的数据拷贝到0:2000:20b单元中。
(1) 0:200
0:20b单元等同于0020:0 -0020:b单元,它们描述的是同一段内存空间:
(2)拷贝的过程应用循环实现,简要描述如下:
初始化: X=0
循环12次:
将fff:X单元中的数据送入0020:X(需要用一个寄存器中转)
X=X+1
(3)在循环中,源单f元ff:X和目标单元的0020:X的偏移地址X是变量。我们用bx来存放。
(4)我们用将0:2000:20b用0020:00020:b描述,就是为了使目标单元的偏移地址和源始单元的偏移地址从同一数值0开始。


assume cs:code
code segment
mov bx, 0; (bx)=0,偏移地址从o开始
mov cx,12; (cx)=12, 循环12次
s: mov ax,offffh
mov ds ,ax; (ds)=Offffh
mov dl, [bx] ; (dl)=((ds)*16+(bx)),将ffff :bx中的数据送入dl
mov ax,0020h
mov ds,ax ; (ds)=0020h
mov [bx],dl ; ((ds)*16+ (bx))=(dl),将dl的数据送入0020:bx
inc bx ; (bx)=(bx) +1
loop s
mov ax,4c00h
int 21h
code ends
end


改进
assume cs:code
code segment
mov ax,0ffffH
mov ax,0020h
mov es,ax
mov bx,0
mov cx,12
s: mov dl,[bx]
mov es:[bx],dl
inc bx
loop s

mov ax,4c00h
int 21h
code ends
end