一. 8086的寻址方式
-
CPU访问内存单元是,要给出内存单元的地址,所有的内存单元都有唯一的地址,叫做物理地址 -
8086有20条地址总线,可以传送20位的地址,1M的寻址能力 -
但它又是
16位结构的CPU,它内部能够一次性处理、传输、暂时存储的地址为16位。如果将地址从内部简单地发出,那么它只能送出16位地址,表现出来的寻址能力只有64KB。
8086采用一种在内部用2个16位地址合成的方法来生成1个20位的物理地址
8086物理地址合成方式.png
地址加法器采用物理地址 = 段地址 * 16 + 偏移地址的方法用段地址和偏移地址合成物理地址。例如,8086CPU要访问地址为123C8H的内存单元,此时,地址加法器的工作过程如下:
地址加法器工作过程.png
同时观察下面地址:
image.png
结论: CPU可以用不同的段地址和偏移地址形成同一个物理地址
比如CPU要访问21F60H单元,则它给出的段地址SA和偏移地址EA来满足SA*16+EA = 21F60H即可。
二. 内存分段管理
-
8086是用基础地址(段地址*16) + 偏移地址 = 物理地址的方式给出物理地址。 -
为了方便开发,我们可以采取分段的方法来管理内存,比如:
image.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指向的指令作为下一条需要取出执行的指令。
image.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
五.指令执行过程
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.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指令 --- 练习
第一题:
image.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重复 该流程
第二题:
image.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的倍数的内存单元中,我们可以认为,这段内存是用来存放代码的,从而定义了一个代码段。比如,将:
image.png
这段长度为10个字节的指令,存放在123B0H ~ 123B9H的一组内存单元中,我们就可以认为,123B0H~123B9H这段内存是用来存放代码的,是一个代码段,它的段地址为123BH,长度为10个字节。
如何使得代码段中的指令被执行呢?将一段内存当做代码段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就自动将我们定义的代码段中的指令当做指令来执行。CPU只认被CS:IP指向的内存单元中的内容为指令。所以要让CPU执行我们放在代码段中的指令,必须要将CS:IP指向所定义的代码段钟的第一条指令的首地址。对于上面的例子,我们将一段代码存放在123B0H ~ 123B9H 内存单元中,将其定义为代码段,如果要让这段代码得到执行,可设CS = 123BH,IP=0000H。














网友评论