一. 8086
的寻址方式
-
CPU
访问内存单元是,要给出内存单元的地址,所有的内存单元都有唯一的地址,叫做物理地址
-
8086
有20
条地址总线,可以传送20
位的地址,1M
的寻址能力 -
但它又是
16位
结构的CPU,它内部能够一次性处理、传输、暂时存储的地址为16位
。如果将地址从内部简单地发出,那么它只能送出16位
地址,表现出来的寻址能力只有64KB
。
8086
采用一种在内部用2
个16位
地址合成的方法来生成1
个20位
的物理地址
![](https://img.haomeiwen.com/i2252551/6adba4bc18bb7c1a.png)
地址加法器
采用物理地址 = 段地址 * 16 + 偏移地址
的方法用段地址
和偏移地址
合成物理地址
。例如,8086CPU
要访问地址为123C8H
的内存单元,此时,地址加法器的工作过程如下:
![](https://img.haomeiwen.com/i2252551/02717ec94900b91d.png)
同时观察下面地址:
![](https://img.haomeiwen.com/i2252551/830dd1298cd16564.png)
结论: CPU
可以用不同的段地址和偏移地址形成同一个物理地址
比如CPU
要访问21F60H
单元,则它给出的段地址SA
和偏移地址EA
来满足SA*16+EA = 21F60H
即可。
二. 内存分段管理
-
8086
是用基础地址(段地址*16) + 偏移地址 = 物理地址
的方式给出物理地址
。 -
为了方便开发,我们可以采取分段的方法来管理内存,比如:
![](https://img.haomeiwen.com/i2252551/b5567367a55f57aa.png)
-
地址
10000H~100FFH
的内存单元组成一个段,该段的起始地址(基础地址)为10000H
,段地址为1000H
,大小为100H
. -
地址
10000H ~ 1007FH
、10080H ~ 100FFH
的内存单元组成2
个字段,他们的起始地址(基础地址)为:10000H和10080H
,段地址为1000H
和1008H
,大小都为80H
. -
在编程时可以根据需要,将若干连续地址的内存单元看做一个段,用
段地址*16
定为段的起始地址(基础地址)
,用偏移地址
定位段中的内存单元。 -
段地址*16
必然是16的倍数,所以一个段的起始地址(基础地址)也一定是16
的倍数。 -
偏移地址为
16
位,16
位地址的寻址能力为64KB
,所以一个段的长度最大为64KB
练习:
1. 在8086
中如果给定一个段地址,仅通过变换偏移地址来进行寻址,最多可定位多少个内存单元?
解答:
偏移地址为16
位,变化范围是0x0000~0xFFFFH
,仅用偏移地址来寻址最多可寻64KB
个内存单元。比如给定段地址1000H
,用偏移地址寻址,CPU
的寻址范围为:10000H ~ 1FFFFH
.
2. 在8086PC
机中,存储单元的地址用两个元素来描述,即段地址和偏移地址。
“数据在21F60H内存单元中”,这句话对于8086PC
机一般不这样将,取而代之的是两种类似的说法:
- 数据存在内存
2000:1F60
单元中, - 数据存在内存的
2000H
段中的1F60H
单元中。这两种描述都表示"数据在内存21F60H
单元中"。
三. 段寄存器
-
8086
在访问内存是要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。 -
是什么部件提供段地址?段地址在
8086
的段寄存器中存放。 -
8086
有4
个段寄存器:CS、DS、SS、ES、
当CPU需要访问内存时由这4
个段寄存器提供内存单元的段地址 -
CS (Code Segment)
: 代码段寄存器 -
DS (Data Segment)
: 数据段寄存器 -
SS (Stack Segment)
: 堆栈段寄存器 -
ES (Extra Segment)
: 附加段寄存器
四. CS和IP
-
CS
为代码段寄存器
,IP
为指令指针寄存器
,它们指示了CPU
当前要读取指令的地址。 - 任意时刻,
8086CPU
都会将CS:IP
指向的指令作为下一条需要取出执行的指令。
![](https://img.haomeiwen.com/i2252551/9f2cec2a41cd9f04.png)
(1) 8086CPU
当前状态: CS
中的内容为2000H
,IP
中的内容为0000H
;
(2) 内存20000H ~ 20009H
单元存放着可执行的机器码;
(3) 内存20000H ~ 20009H
单元中存放的机器码对应的汇编指令如下。
地址: 20000H ~ 20002H
,内容: B8 23 01
, 长度: 3Byte
, 对应汇编指令: mov ax, 0123H
;
地址: 20003H ~ 20005H
, 内容:BB 03 00
, 长度: 3Byte
, 对应汇编指令: mov bx, 0003H
;
地址: 20006H ~ 20007H
, 内容: 89 D8
, 长度: 2Byte
, 对应汇编指令: mov ax, bx
;
地址: 20008H ~ 20009H
, 内容: 01 D8
, 长度: 2Byte
, 对应汇编指令: add ax, bx
五.指令执行过程
![](https://img.haomeiwen.com/i2252551/e9ffd7f3ccf81c00.png)
![](https://img.haomeiwen.com/i2252551/872c996f125d31e8.png)
![](https://img.haomeiwen.com/i2252551/4159d78299e6169c.png)
![](https://img.haomeiwen.com/i2252551/19bd3fb573827eb7.png)
![](https://img.haomeiwen.com/i2252551/6fe989a48dc07a64.png)
![](https://img.haomeiwen.com/i2252551/997a3c7257597d29.png)
![](https://img.haomeiwen.com/i2252551/bcfea75a146ac070.png)
![](https://img.haomeiwen.com/i2252551/32407b80d437d3e7.png)
![](https://img.haomeiwen.com/i2252551/f12496884e225d32.png)
![](https://img.haomeiwen.com/i2252551/ce997404cd74d76e.png)
![](https://img.haomeiwen.com/i2252551/23c4eff49f4707ad.png)
![](https://img.haomeiwen.com/i2252551/d1806828ed95e7c3.png)
![](https://img.haomeiwen.com/i2252551/9a825de77d16c415.png)
![](https://img.haomeiwen.com/i2252551/78d5db0f39d68e36.png)
通过上面的过程展示,8086CPU
的工作过程可以简要描述如下:
- 从
CS:IP
指向的内存单元读取指令,读取的指令进入指令缓冲器
2.IP = IP + 所读指令的长度
,从而指向下一条指令。
- 执行指令。转到步骤
1
,重复该过程。
在8086CPU
加电启动或复位后(即CPU
刚开始工作时)CS
和IP
被设置为CS = FFFFH
,IP = 0000H
,即在8086PC
机刚启动时,CPU
从内存FFFF0H
单元读取指令执行,FFFF0H
单元中的指令是8086PC
机开机后执行的第一条指令。
六.指令和数据
-
在内存或者磁盘上,指令和数据没有任何区别,都是二进制信息。
-
CPU
在工作的时候把有的信息看做指令,有的信息看做数据,为同样的信息赋予了不同的意义。
举个🌰 :
例如,内存中的二进制信息 1000 1001 1101 1000
,计算机可以把它看做大小为89D8H的数据来处理,也可以看做指令mov ax, bx
来执行
1000 1001 1101 1000 -> 89D8H(数据)
1000 1001 1101 1000 -> mov ax, bx (程序)
-
CPU
根据什么将内存中的信息看做指令: -
CPU
将CS:IP
指向的内存单元的内容看做指令 - 如果内存中的某段内容曾被
CPU
执行过,那么它所在的内存单元必然被CS:IP
指向过。
七. jmp指令
-
CPU
从何处执行指定是由CS、IP
中的内容决定的,我们可以通过改变CS、IP
的内容来控制CPU
执行目标指令。 -
8086
提供了一个mov指令(传送指令)
,可以用来修改大部分寄存器的值,比如mov ax, 10; mov bx, 20; mov cx, 30; mov dx, 40
-
但是,
mov
指令不能用于设置CS、IP
的值,这些指令统称为转移指令、最简单的是jmp
指令。
举个🌰 :
若想同时修改CS、IP
的内容,可用形如"jmp 段地址: 偏移地址"
的指令来完成。如:jmp 2AE3 : 3,执行后: CS = 2AE3H, IP = 0003H, CPU将从2AE33H处读取指令 jmp 3:0B16, 执行后: CS = 0003H, IP = 0B16H, CPU将从 00B46H处读取指令。
** “jmp 段地址: 偏移地址”
指令的功能为: 用指令中给出的段地址修改CS, 偏移地址修改IP**。
若想仅修改IP的内容,可用形如"jum 某一合法寄存器" 的指令完成,如:
jmp ax, 指令执行前: ax = 1000H, CS = 2000H, IP = 0003H
指令执行后: ax = 1000H, CS = 2000H, IP = 1000H
jmp bx, 指令执行前:bx = 0B16H, CS = 2000H, IP = 0003H
指令执行后: bx = 0B16H, CS = 2000H, IP = 0B16H
"jmp 某一合法寄存器" 指令的功能为: 用寄存器中的值修改IP
jum ax, 在含义上好似: mov IP, ax
八.jmp指令 --- 练习
第一题:
![](https://img.haomeiwen.com/i2252551/dfd8c5f4369c31c4.png)
答案:
- mov ax, 6622H
- jmp 1000 : 3
- mov ax, 0000
- mov bx, ax
- jmp bx
- mov ax, 0123H
- 转到第3步执行
分析:
-
CPU
初始状态:CS = 2000H, IP = 0000H
,所以一开始寻址地址从2000H
开始。执行mov ax, 6622H
- 然后执行:
jmp 1000:3
,此时寻址地址是从10003H
开始 - 在
10003H
执行mov ax, 0000
,这时候ax寄存器的值为0000
- 然后执行
mov bx, ax
,将ax的值赋值给bx
,bx
寄存器的值为0000
, - 然后执行
jmp bx
,这时候寻址地址从10000H
开始 - 在
10000H
执行mov ax, 0123H
- 然后转到
10003H
重复 该流程
第二题:
![](https://img.haomeiwen.com/i2252551/a285f62bd1ef09b3.png)
答案:
CPU
4次修改IP
,
分别在:
mov ax, bx
执行了一次
sub ax, ax
执行了一次
jmp ax
执行了两次,
最后IP
中的值是0
.
分析:
-
mov ax, bx
->将bx的值移到ax寄存器 -
sub ax, ax
, -> 将ax寄存器中的值减去本身,所以ax
寄存器中的值为0
-
jmp ax -> jmp 0
,在这里修改了IP
的值,IP
的值为0
.
九. 代码段
前面讲过,对于8086PC
机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将长度为N
(N
小于等于64KB
)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,我们可以认为,这段内存是用来存放代码的,从而定义了一个代码段。比如,将:
![](https://img.haomeiwen.com/i2252551/07ad45801b5e1468.png)
这段长度为10
个字节的指令,存放在123B0H ~ 123B9H
的一组内存单元中,我们就可以认为,123B0H~123B9H
这段内存是用来存放代码的,是一个代码段,它的段地址为123BH
,长度为10
个字节。
如何使得代码段中的指令被执行呢?将一段内存当做代码段,仅仅是我们在编程时的一种安排,CPU
并不会由于这种安排,就自动将我们定义的代码段中的指令当做指令来执行。CPU
只认被CS:IP
指向的内存单元中的内容为指令。所以要让CPU
执行我们放在代码段中的指令,必须要将CS:IP
指向所定义的代码段钟的第一条指令的首地址。对于上面的例子,我们将一段代码存放在123B0H ~ 123B9H
内存单元中,将其定义为代码段,如果要让这段代码得到执行,可设CS = 123BH,IP=0000H
。
网友评论