0x19:[bx+idata] 处理数组
[bx+idata]表示一个内存单元, 例如:mov ax, [bx+200]
它表示将 ds:(bx)+200 内存单元的内容送入 ax 寄存器。
该指令也可以写成如下格式:
1 2 3
| mov ax, [200+bx] mov ax, 200[bx] mov ax, [bx].200
|
利用数组改进大小写转换程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| assume cs:codesg,ds:datasg
datasg segment db 'BaSiC';转为大写 db 'MinIx';转为小写 datasg ends
codesg segment start: mov ax,datasg mov ds,ax
mov cx,5 mov bx,0 s: mov al,0[bx] and al,11011111b ;'BaSiC';转为大写 mov 0[bx],al
mov al,5[bx] or al,00100000b ;'MinIx';转为小写 mov 5[bx],al inc bx loop s
mov ax,4c00h int 21h
codesg ends
end start
|

0x20:SI 和 DI 寄存器
si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| assume cs: codesg, ds: datasg
datasg segment db 'welcome to masm!';用si和di实现将字符串‘welcome to masm!"复制到它后面的数据区中。 db '................' datasg ends
codesg segment start: mov ax, datasg mov ds, ax mov si, 0 mov cx, 8 ;只需要复制8次,si是16位寄存器,一次复制2字节 s: mov ax, 0[si] ;[0 + si] mov 16[si], ax ;[16 + si] 使用[bx +idata]方式代替di,使程序更简洁 add si, 2 ; si只能作为16位寄存器 loop s mov ax, 4c00h int 21h codesg ends end start
|
[bx + si] 和 [bx + di]
[bx+si]和[bx+di]的含义相似
[bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)
指令mov ax, [bx + si]
的含义:将一个内存单元字数据的内容送入ax,段地址在ds中
该指令也可以写成如下格式:mov ax, [bx][si]
[bx+si+idata]和[bx+di+idata]
[bx+si+idata]表示一个内存单元,它的偏移地址为(bx)+(si)+idata
指令mov ax,[bx+si+idata]
的含义:将一个内存单元字数据的内容送入ax,段地址在ds中
0x21:不同的寻址方式的灵活应用
[idata]
用一个常量来表示地址,可用于直接定位一个内存单元;
[bx]
用一个变量来表示内存地址,可用于间接定位一个内存单元;
[bx+idata]
用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
[bx+si]
用两个变量表示地址;
[bx+si+idata]
用两个变量和一个常量表示地址。

由于每个单词都是 16 个字节,所以利用二重循环来处理。

实际上,这个程序是有问题的。
因为我们进行二重循环时,只有 cx 一个1循环计数器,当进行内层循环时,会覆盖外层循环次数。
第一次改进:

我们利用 dx 寄存器来暂存外层循环时 cx 的值,当内层循环结束时,再从 dx 中恢复 cx 的值。
但是寄存器的数量有限,当程序复杂时,寄存器数量将不够用。
第二次改进:利用栈来暂存数据!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| ;将datasg段中每个单词改为大写字母 assume cs:codesg,ds:datasg,ss:stacksg
datasg segment db 'ibm ' ;16 db 'dec ' db 'dos ' db 'vax ' ;看成二维数组 datasg ends
stacksg segment ;定义一个段,用来做栈段,容量为16个字节 dw 0, 0, 0, 0, 0, 0, 0, 0 stacksg ends
codesg segment start: mov ax, stacksg mov ss, ax mov sp, 16 mov ax, datasg mov ds, ax mov bx, 0 ;初始ds:bx ;cx为默认循环计数器,二重循环只有一个计数器,所以外层循环先保存cx值,再恢复,我们采用栈保存 mov cx, 4 s0: push cx ;将外层循环的cx值入栈 mov si, 0 mov cx, 3 ;cx设置为内层循环的次数 s: mov al, [bx+si] and al, 11011111b ;每个字符转为大写字母 mov [bx+si], al inc si loop s add bx, 16 ;下一行 pop cx ;恢复cx值 loop s0 ;外层循环的loop指令将cx中的计数值减1 mov ax,4c00H int 21H codesg ends end start
|
0x22:寄存器小结

bx、si、di和bp
在8086CPU中,只有这4个寄存器可以用在“[…]”中来进行内存单元的寻址。
在[ ]中,这4个寄存器可以单个出现,或只能以4种组合出现:bx和si、bx和di
、bp和si、bp和di
。
只要在[……]中使用寄存器bp,而指令中没有显性地给出段地址, 段地址就默认在ss中。
同样地,使用寄存器bx,没有显式给出段地址,段地址默认为ds。