1、BX
BX――基址寄存器(Base Register),常存放存储器地址。我们前文提到了这个寄存器:2021-7-24 8086CPU 内 14 个寄存器功能一览 。
我们知道,要完整地描述一个内存单元,需要两种信息:①内存单元的地址;②内存单元的长度 ,也就是类型。
mov ax,[0]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个 字,偏移地址为0,段地址在ds中。
mov al,[0]
将一个内存单元的内容送入al,这个内存单元的长度为1字节(字节单元),存放一个 字节,偏移地址为0,段地址在ds中。
以上两条指令都通过目标内存单元的类型自动规定了送入信息的长度。(记得数据段的段地址在 ds 内)
[bx]同样也表示一个内存单元,它的偏移地址在bx中,比如下面的指令:
mov ax,[bx]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中。
mov al,[bx]
将一个内存单元的内容送入al,这个内存单元的长度为1字节(字节单元),存放一个字节,偏移地址在bx中,段地址在ds中。
关于段的内容总结,参见2021-7-26 汇编语言 高屋建瓴:栈,段的理解(炉边小坐)。
关于一些符号的约定:
1、描述性的符号:"()”
为了描述上的简洁,在以后的课程中,我们将使用一个描述性的符号“()”来表示一 个寄存器或一个内存单元中的内容。
注意,“()”中元素可以有三种类型,其余为非法:①寄存器名;②段寄存器名;③内存单元的物理地址(一个20位数据)。比如:(ax)、(ds)、(al)、(ex)、(20000H)、((ds)*16+(bx))等是正确的用法;(2000:0)、((ds): 1000H)等是不正确的用法。
2、约定符号idata表示常量
我们在Debug中写过类似的指令:mov ax,[0],表示将ds:O处的数据送入ax中。指 令中,在里用一个常量0表示内存单元的偏移地址。以后,我们用idata表示常 量。比如:
mov ax,[idata]就代表 movax,[l]、mov ax,[2]> mov ax,[3]等。 注意[ ]不能丢
下面讲[BX]的功能;
下面先来看一看下面指令的功能。
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)。
看一段程序: 内存情况如图
mov ax,2000H
mov ds,ax
mov bx,1000H//为了让 ds=2000H,bx=1000H
mov ax,[bx]//将 2000:1000 的字型数据存入 ax
inc bx//这条指令的含义是 bx 内的内容+1
inc bx//这条指令的含义是 bx 内的内容+1 (bx=1002H)
mov [bx],ax//将 ax 中的数据传入 2000:1002H 处(bx 为 1002H)
inc bx //这条指令的含义是 bx 内的内容+1
inc bx//这条指令的含义是 bx 内的内容+1
mov [bx],ax//将 ax 中的数据传入 2000:1004H 处(bx 为 1004H)
inc bx//这条指令的含义是 bx 内的内容+1
mov [bx], al//将 ax 的低字节存入 2000:1005H 处
inc bx//这条指令的含义是 bx 内的内容+1
mov [bx],al//将 ax 的低字节存入 2000:1006H 处
最后看一下内存图
2、loop 指令
loop指令的格式是:loop标号,CPU执行loop指令的时候,要进行两步操作, ①(cx)=(cx)-1;②判断CX中的值,不为零则转至标号处执行程序,如果为零则向下执行。可以看到,CX中的值影响着loop指令的执行结果。通常我们用loop指令来实现循环功能,CX中存放循环次数!!。
我们用一个程序说明用法,还是之前的题目:写一个程序,实现 2^2,结果存于 ax 中。
我们轻松知道怎么做,对吧:
assume cs:wtf
wtf segment
mov ax,2
add ax,ax
mov ax 4c00h
int 21h
wtf ends
end
如何?忘记的同学请翻看:2021-7-27 汇编语言 程序:驱动万物的伟力
好,我们来改编一下程序:写一个程序,实现运算2^13
你也许说,这不是一样吗? 把 add ax,ax重复 12 次就好了,那如果是2^1000呢?难道要 command+c、+v 一千次吗?这时候就要 loop 出场了!
assume cs:wtf
wtf segment
mov ax,2 //基础预备
mov cx,12//输入循环次数
s: add ax,ax //循环结构
loop s //循环结构
mov ax 4c00h//结束模块
int 21h
wtf 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)。
怎么说?感觉比 C 里边的 for 循环还简洁(笑)学过 C、C++的同学应该瞬间理解了!
我假设各位都是 C 的好手,这里就不具体分析 loop s 指令的内部过程了。(赶着看奥运国乒女单决赛,中国又包揽金银,没办法就是强)
那么总结出来CX和loop指令相配合实现循环功能的3个要点:
1、在CX中存放循环次数;
2、loop指令中的标号所标识地址要在前面;
3、要循环执行的程序段,要写在标号和loop指令的中间。
题目:编程,用加法计算123*236,结果存在ax中。思考后看分析。
assume cs:gpnb
gpnb segment
mov ax,123
mov cx,235
s: mov ax,123
loop s
mov ax 4c00h//结束模块
int 21h
gpnb ends
end
优化算法:
上面的方法做了 236次加法,我们可以将236加123次。可先设(ax)=0,然后循环做 123次(ax)=(ax)+236,这样可以用123次加法实现相同的功能。
assume cs:gpnb
gpnb segment
mov ax,236
mov cx,122
s: mov ax,236
loop s
mov ax 4c00h//结束模块
int 21h
gpnb ends
end