2.7 “段地址×16+偏移地址=物理地址”的本质含义

在理解8086CPU段地址和偏移地址的本质含义时,不应拘泥于某一种引申出来的逻辑意义,而应清楚其本质含义。只有这样,才能更灵活地利用它来分析和解决问题。“段地址×16+偏移地址=物理地址”的本质含义是:CPU在访问内存时,用一个基础地址(段地址×16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

更一般地说,8086CPU的这种寻址功能是“基础地址+偏移地址=物理地址”寻址模式的一种具体实现方案。8086CPU中,段地址×16可看作是基础地址。

下面,用两个与CPU无关的例子做进一步的比喻说明。

比喻1:基础地址+偏移地址=物理地址

比如说,学校、体育馆、图书馆同在一条笔直的单行路上,学校位于路的起点(从路的起点到学校距离是0米)。如图2.8所示:

学校      体育馆       图书馆
0m       2000m       2826m

你要去图书馆,问我地址,我可以用两种方式告诉你:

  1. 从学校走2826m到图书馆。这2826m可以认为是图书馆的物理地址。
  2. 从学校走2000m到体育馆,从体育馆再走826m到图书馆。第一个距离2000m是相对于起点的基础地址,第二个距离826m是相对于基础地址的偏移地址。

第一种方式是直接给出物理地址2826m,而第二种方式是用基础地址和偏移地址相加来得到物理地址。

比喻2:段地址×16+偏移地址=物理地址

在上面的例子中,我们进一步限制条件:只能通过纸条来通信。显然,我必须有一张可以容纳4位数据的纸条,才能写下2826这个数据。

学校      体育馆       图书馆
0m       2000m       2826m

可不巧的是,我没有能容纳4位数据的纸条,仅有两张可以容纳3位数据的纸条。这样我只能以这种方式告诉你2826这个数据:

2 0 0
8 2 6

在第一张纸上写上200(段地址),在第二张纸上写上826(偏移地址)。假设我们事前对这种情况有过约定:你得到这两张纸后,做这样的运算:200(段地址)×10+826(偏移地址)=2826(物理地址)。

8086CPU就是这样一个只能提供两张3位数据纸条的CPU。

2.8 段的概念

“段地址”这个名称中包含着“段”的概念。这种说法可能对一些学习者产生了误导,使人误以为内存被划分成了一个一个的段,每一个段有一个段地址。其实,内存并没有分段,段的划分来自于CPU。由于8086CPU用“基础地址(段地址×16)+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。

例如,地址10000H-100FFH的内存单元可以看作一个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H。也可以认为地址10000H-1007FH和10080H-100FFH的内存单元组成两个段,它们的起始地址(基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H。

10000H        1007FH        100FFH
[---------段1---------]
[---------段2---------]

在编程时可以根据需要,将若干地址连续的内存单元看作一个段,用段地址×16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。段地址×16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的长度最大为64KB。

2.9 段寄存器

8086CPU在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。段地址在8086CPU的段寄存器中存放。8086CPU有4个段寄存器:CS、DS、SS、ES。当8086CPU要访问内存时由这4个段寄存器提供内存单元的段地址。本章中只看一下CS。

2.10 CS和IP

CS和IP是8086CPU中两个最关键的寄存器,它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器,从名称上可以看出它们和指令的关系。

在8086PC机中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存M×16+N单元开始,读取一条指令并执行。也可以这样表述:8086机中,任意时刻,CPU将CS

指向的内容当作指令执行。

指令执行过程

图2.10展示了8086CPU读取、执行指令的工作原理(图中只包括了和所要说明的问题密切相关的部件,图中数字都为十六进制)。

  1. 8086CPU当前状态:CS中的内容为2000H,IP中的内容为0000H;
  2. 内存20000H-20009H单元存放着可执行的机器码;
  3. 内存20000H-20009H单元中存放的机器码对应的汇编指令如下:
    • 地址:20000H-20002H,内容:B82301,长度:3Byte,对应汇编指令:mov ax,0123H
    • 地址:20003H-20005H,内容:BB0300,长度:3Byte,对应汇编指令:mov bx,003H
    • 地址:20006H-20007H,内容:89D8,长度:2Byte,对应汇编指令:mov ax,bx
    • 地址:20008H-20009H,内容:01D8,长度:2Byte,对应汇编指令:add ax,bx

下面的一组图(图2.11-图2.19)展示了8086CPU读取、执行一条指令的过程。

8086CPU当前状态:CS中的内容为2000H,IP中的内容为0000H。

CS,IP中的内容送入地址加法器,地址加法器完成:物理地址=段地址×16+偏移地址。

地址加法器将物理地址送入输入输出控制电路。

输入输出控制电路将物理地址20000H送上地址总线。

从内存20000H单元开始存放的机器指令B82301通过数据总线被送入CPU。

输入输出控制电路将机器指令B82301送入指令缓冲器。

IP中的值自动增加。读取一条指令后,IP中的值自动增加,使CPU可以读取下一条指令。当前读入的指令B82301长度为3个字节,所以IP中的值加3。此时,CS

指向内存单元2000:0003。

执行控制器执行指令B82301(即mov ax,0123H)。

指令B82301被执行后AX中的内容为0123H。此时,CPU将从内存单元2000:0003处读取指令。

下面的一组图(图2.20-图2.26)展示了8086CPU继续读取、执行3条指令的过程。

CS=2000H,IP=0003H,CPU将从内存2000H×16+0003H处读取指令BB 0300。

CPU从内存20003H处读取指令BB0300入指令缓冲器(IP中的值加3)。

执行指令BB 0300(mov bx,0003H)。

CPU从内存20006H处读取指令89 D8入指令缓冲器(IP中的值加2)。

执行指令89 D8(即mov ax,bx)后,AX中的内容为0003H。

CPU从内存20008H处读取指令01 D8入指令缓冲器(IP中的值加2)。

执行指令01 D8(即add ax,bx)后,AX中的内容为0006H。

通过上面的过程展示,8086CPU的工作过程可以简要描述如下:

  1. 从CS指向的内存单元读取指令,读取的指令进入指令缓冲器;
  2. IP指向下一条指令;
  3. 执行指令。转到步骤1,重复这个过程。

在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=FFFFH,IP=0000H,即在8086PC机刚启动时,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令是8086PC机开机后执行的第一条指令。

现在,我们更清楚了CS和IP的重要性,它们的内容提供了CPU要执行指令的地址。

在内存中,指令和数据没有任何区别,都是二进制信息,CPU在工作的时候把有的信息看作指令,有的信息看作数据。现在,如果提出一个问题:CPU根据什么将内存中的信息看作指令?如何回答?我们可以说,CPU将CS

指向的内存单元中的内容看作指令,因为,在任何时候,CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。如果说,内存中的一段信息曾被CPU执行过的话,那么,它所在的内存单元必然被CS指向过。

2.11 修改CS、IP的指令

在CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制。CPU从何处执行指令是由CS、IP中的内容决定的,程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令。

8086CPU必须提供相应的指令来修改CS、IP的值。大部分寄存器的值都可以用mov指令来改变,如mov ax,123将AX中的值设为123,mov bx,123mov cx,123等。但是mov指令不能用于设置CS、IP的值。8086CPU为CS、IP提供了另外的指令来改变它们的值。这些指令被统称为转移指令。现在介绍一个最简单的可以修改CS、IP的指令:jmp指令。

修改CS、IP的指令:jmp

若想同时修改CS、IP的内容,可用形如“jmp 段地址:偏移地址”的指令完成,如:

  • jmp 2AE3:003,执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H处读取指令。
  • jmp 3:0B16,执行后:CS=0003H,IP=0B16H,CPU将从00B16H处读取指令。

若想仅修改IP的内容,可用形如“jmp 寄存器”的指令完成,如:

  • 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。jmp ax,在含义上好似:mov IP,ax。

我们用已知的汇编指令的语法来描述新学的汇编指令的功能。例如,jmp 3:01B6在含义上好似mov CS,3 mov IP,01B6。

问题2.3

内存中存放的机器码和对应的汇编指令情况如图2.27所示,设CPU初始状态CS=2000H,IP=0000H,请写出指令执行序列。

地址      内存中的机器码    对应的汇编指令
10000H   B8 23 01        mov ax,0123H
10003H   B8 00 00        mov ax,0000H
10006H   8B D8           mov bx,ax
10008H   FF E3           jmp bx

20000H   B8 22 66        mov ax,6622H
20003H   EA 03 00 00 10  jmp 1000:0003
20008H   89 C1           mov cx,ax

分析:
CPU对图2.27中的指令的执行过程如下:

  1. 当前CS=2000H,IP=0000H,CPU从内存2000H×16+0=20000H处读取指令,读入的指令是:B82266(mov ax,6622H),读入后IP=IP+3=0003H;
  2. 指令执行后,CS=2000H,IP=0003H,CPU从内存2000H×16+0003H=20003H处读取指令,读入的指令是:EA 03 00 00 10(jmp 1000:0003),读入后IP=IP+5=0008H;
  3. 指令执行后,CS=1000H,IP=0003H,CPU从内存1000H×16+0003H=10003H处读取指令,读入的指令是:B80000(mov ax,0000),读入后IP=IP+3=0006H;
  4. 指令执行后,CS=1000H,IP=0006H,CPU从内存1000H×16+0006H=10006H处读取指令,读入的指令是:8B D8(mov bx,ax),读入后IP=IP+2=0008H;
  5. 指令执行后,CS=1000H,IP=0008H,CPU从内存1000H×16+0008H=10008H处读取指令,读入的指令是:FF E3(jmp bx),读入后IP=IP+2=000AH;
  6. 指令执行后,CS=1000H,IP=0000H,CPU从内存10000H处读取指令……

指令执行序列为:

  1. mov ax,6622H
  2. jmp 1000:003
  3. mov ax,0000
  4. mov bx,ax
  5. jmp bx
  6. mov ax,0123H
  7. 转到第3步执行

2.12 代码段

可以将长度为N(N≤64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,定义为一个代码段。例如,将以下指令存放在123B0H-123B9H的一组内存单元中:

mov ax,0000
add ax,0123H
mov bx,ax
jmp bx

我们可以认为,123B0H-123B9H这段内存是用来存放代码的,是一个代码段,它的段地址为123BH,长度为10个字节。

要让CPU执行我们放在代码段中的指令,必须将CS

指向所定义的代码段中的第一条指令的首地址。例如,将CS=123BH、IP=0000H。

2.9~2.12 小结

  1. 段地址在8086CPU的段寄存器中存放。当8086CPU要访问内存时,由段寄存器提供内存单元的段地址。8086CPU有4个段寄存器,其中CS用来存放指令的段地址。
  2. CS存放指令的段地址,IP存放指令的偏移地址。8086机中,任意时刻,CPU将CS指向的内容当作指令执行。
  3. 8086CPU的工作过程:
    1. 从CS指向的内存单元读取指令,读取的指令进入指令缓冲器;
    2. IP指向下一条指令;
    3. 执行指令。转到步骤1,重复这个过程。
  4. 8086CPU提供转移指令修改CS、IP的内容。

检测点2.3

下面的3条指令执行后,CPU几次修改IP?都是在什么时候?最后IP中的值是多少?

mov ax, bx
jmp bx
jmp ax

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐