1. 处理的数据在什么地方?
  2. 要处理的数据长度是多少?

bx、si、di 和 bp

只有这个 4 个寄存器可以用来在 [...] 中进行内存单元寻址。

1
2
3
4
5
6
mov ax, [bx]
mov ax, [bx+si]
mov ax, [bx+di]
mov ax, [bp]
mov ax, [bp+si]
mov ax, [bp+di]

错误用法:

1
mov ax, [cx]

[...] 中,这 4 个寄存器可以单个出现或者以 4 种组合出现:bx 和 si、bx 和 di、bp 和 si、bp 和 di。

以下都是正确的指令:

1
2
3
4
5
6
7
8
9
10
11
12
mov ax, [bx]
mov ax, [si]
mov ax, [di]
mov ax, [bp]
mov ax, [bx+si]
mov ax, [bx+di]
mov ax, [bp+si]
mov ax, [bp+di]
mov ax, [bx+si+idata]
mov ax, [bx+di+idata]
mov ax, [bp+si+idata]
mov ax, [bp+di+idata]

[...] 中使用寄存器 bp,段地址默认从 ss 读取。

数据位置的表达

  1. 立即数:指令要处理的直接包含在机器指令中的数据(执行前在 CPU 的指令缓冲器中)
  2. 寄存器:指令要处理的数据在寄存器
  3. 段地址(SA)和偏移地址(EA):指令要处理的数据在内存中

寻址方式

当数据存放在内存中时,我们可以使用多种方式给定这个内存单元的偏移地址。8086CPU 寻址方式总结:

寻址方式 含义 名称 常用格式举例
[idata] EA=idata;SA=(ds) 直接寻址 [idata]
[bx] EA=(bx);SA=(ds) 寄存器间接寻址 [idata]
[si] EA=(si);SA=(ds) 寄存器间接寻址 [idata]
[di] EA=(di);SA=(ds) 寄存器间接寻址 [idata]
[bp] EA=(bp);SA=(ss) 寄存器间接寻址 [idata]
[bx+idata] EA=(bx);SA=(ds) 寄存器相对寻址 [idata]
[si+idata] EA=(si);SA=(ds) 寄存器相对寻址 [idata]
[di+idata] EA=(di);SA=(ds) 寄存器相对寻址 [idata]
[bp+idata] EA=(bp);SA=(ss) 寄存器相对寻址 [idata]
[bx+si] EA=(bx)+(si);SA=(ds) 基址变址寻址 [idata]
[bx+di] EA=(bx)+(di);SA=(ds) 基址变址寻址 [idata]
[bp+si] EA=(bp)+(si);SA=(ss) 基址变址寻址 [idata]
[bp+di] EA=(bp)+(di);SA=(ss) 基址变址寻址 [idata]
[bx+si+idata] EA=(bx)+(si)+idata;SA=(ds) 相对基址变址寻址 [idata]
[bx+di+idata] EA=(bx)+(di)+idata;SA=(ds) 相对基址变址寻址 [idata]
[bp+si+idata] EA=(bp)+(si)+idata;SA=(ss) 相对基址变址寻址 [idata]
[bp+di+idata] EA=(bp)+(di)+idata;SA=(ss) 相对基址变址寻址 [idata]

bx、bp 存基址,si、di 存变址,有了 idata 叫相对。

指令要处理的数据有多长

8086CPU 可以处理 byte 和 word 两种尺寸的数据。在机器指令中要指明指令进行的是字操作还是字节操作

  1. 通过寄存器名指明要处理的数据的尺寸。寄存器是 ax 就是字,al、ah 就是字节操作。
  2. 通过操作符 X ptr 指明内存单元长度,X 可以为 word 或 byte。
1
2
mov word ptr ds:[0], 1  ;操作一个字单元
mov byte ptr ds:[0], 1 ;操作一个字节单元
  1. 其他方法,有些指令默认访问单元是字单元还是字节单元,push [1000H],push 指令只执行字操作。

bx 定位整个结构体,idata 定位结构体中的某个数据项,si 定位数组项中的每个元素。[bx].idata[si]

1
2
3
4
5
6
7
8
9
10
11
12
13
mov ax, seg
mov ds, ax
mov bx, 60h

mov word ptr [bx+0ch], 38
add word ptr [bx+0eh], 70

mov si, 0
mov byte ptr [bx+10h+si], 'V'
inc si
mov byte ptr [bx+10h+si], 'A'
inc si
mov byte ptr [bx+10h+si], 'X'

div 指令

div 是除法指令

  1. 除数:8 位、16 位两种,在一个寄存器或内存单元。
  2. 被除数:如果除数为 8 位,被除数为 16 位,默认放在 ax;如果除数为 16 位,被除数为 32 位,dx 存放高 16 位,ax 存放低 16 位。
  3. 结果:除数为 8 位,al 存商,ah 存余数;除数为 16 位,ax 存商,dx 存余数。

先把被除数放好(ax 或 dx:ax),然后指定除数

1
2
3
div 除数
div ax
div 内存单元(除数)
1
div byte ptr ds:[0]

含义:

(al)=(ax)/((dx)*16+0) 的商
(ah)=(ax)/((dx)*16+0) 的余数

1
div word ptr es:[0]

含义:

(ax)=((dx)*10000h+(ax))/((es)*16+0) 的商
(dx)=((dx)*10000h+(ax))/((es)*16+0) 的余数

伪指令 dd

dd 用于定义 dword(double word,双字)型数据。

1
2
3
4
5
data segment
db 1
dw 1
dd 1
data ends

在 data 段定义了 3 个数据:

  1. 01h 占 1 个字节;
  2. 0001h 占 1 个字;
  3. 00000001h 占 2 个字

dup

由编译器识别处理的符号,伪指令,配合 db、dw、dd 等数据定义伪指令使用,用来进行数据的重复。

1
db 3 dup (0)

定义 3 个字节,值为 0。

1
db 3 dup (0,1,2)

定义 9 个字节,他们是 0、1、2、0、1、2、0、1、2。

dup 的使用格式如下:

1
2
3
db 重复次数 dup (重复的字节型数据)
dw 重复次数 dup (重复的字型数据)
dd 重复次数 dup (重复的双字型数据)

定义一个 200 个字节的栈段:

1
2
3
stack segemnt
db 200 dup (0)
stack ends

实验 7 寻址方式在结构化数据访问中的应用

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
assume cs:codesg

data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
;表示21年的21个字符串

dd 16,22,382,1356,2390,8000,16000,24486,50056,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
;表示21年公司总收入的21个dword型数据

dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
;表示21年公司雇员人数的21个word型数据
data ends

table segment
db 21 dup('year summ ne ?? ')
table ends

codesg segment
start: mov ax,data
mov ds,ax ;ds 数据段
mov ax,table
mov es,ax ;es 数据段
mov cx,21
mov bx,0
mov bp,0
s: mov ax,ds:[bp]
mov es:[bx],ax
mov ax,ds:[bp+2]
mov es:[bx+2],ax
add bp,4
add bx,16
loop s
mov bx,5 ;开始填写收入
mov cx,21
s2: mov ax,ds:[bp]
mov es:[bx],ax
mov ax,ds:[bp+2]
mov es:[bx+2],ax
add bp,4
add bx,16
loop s2
mov bx,10 ;开始填写雇员数
mov cx,21
s3: mov ax,ds:[bp]
mov es:[bx],ax
add bp,2
add bx,16
loop s3
;开始计算人均收入
mov cx,21
mov bx,13
mov si,0
s4: mov dx,es:[7+si]
mov ax,es:[5+si]
div word ptr es:[10+si]
mov es:[13+si],ax
add si,16
loop s4
mov ax,4c00h
int 21h
codesg ends
end start