购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.3 微处理器的寻址机制

3.3.1 存储器分段技术

实模式下80x86/Pentium可直接寻址的地址空间为2 20 =1M字节单元。这就是说,CPU需输出20位地址信息才能实现对1M字节单元存储空间的寻址。但实模式下CPU中所使用的寄存器均是16位的,内部ALU也只能进行16位运算,其寻址范围局限在2 16 =65536(64K)字节单元。为了实现对1M字节单元的寻址,80x86系统采用了存储器分段技术。具体做法是,将1M字节的存储空间分成许多逻辑段,每段最长64K字节单元,可以用16位地址码进行寻址。每个逻辑段在实际存储空间中的位置是可以浮动的,其起始地址可由段寄存器的内容来确定。实际上,段寄存器中存放的是段起始地址的高16位,称之为“段基值”(segment base value)。

80x86/Pentium系列微处理器中设置了4个或6个16位的段寄存器。它们分别是代码段寄存器CS、数据段寄存器DS、附加段寄存器ES、堆栈段寄存器SS以及在80386及更高型号微处理器中使用的段寄存器FS和GS。

以8086~80286微处理器为例,由于设置有4个段寄存器,因此任何时候CPU可以定位当前可寻址的4个逻辑段,分别称为当前代码段、当前数据段、当前附加段和当前堆栈段。当前代码段的段基值(即段基地址的高16位)存放在CS寄存器中,该段存放程序的可执行指令;当前数据段的段基值存放在DS寄存器中,当前附加段的段基值存放在ES寄存器中,这两个段的存储空间存放程序中参加运算的操作数和运算结果;当前堆栈段的段基值存放在SS寄存器中,该段的存储空间用作程序执行时的存储器堆栈。

需要说明的是,各个逻辑段在实际的存储空间中可以完全分开,也可以部分重叠,甚至完全重叠。这种灵活的分段方式如图3.4所示。另外,段的起始地址的计算和分配通常是由系统完成的,并不需要普通用户参与。

图3.4 逻辑段在物理存储器中的位置

其实,还有其他方法也可以将1M字节单元的物理存储空间分成可用16位地址码寻址的逻辑段。例如将20位物理地址分成两部分:高4位为段号,可用机器内设置的4位长的“段号寄存器”来保存;低16位为段内地址,也称“偏移地址”,如图3.5所示。

图3.5 另一种分段方法

但是,这种分段方法有其不足之处。一是4位长的“段号寄存器”与其他寄存器不兼容,操作上会增添麻烦;二是这样划分的段每个逻辑段大小固定为64K字节单元,当程序中所需的存储空间不是64K字节单元的倍数时,就会浪费存储空间。反观前一种分段机制,则要灵活、方便得多,所以80x86/Pentium系统中采用了前一种分段机制。

3.3.2 实模式下的存储器寻址

1.物理地址与逻辑地址

在有地址变换机构的计算机系统中,每个存储单元可以看成具有两种地址:物理地址和逻辑地址。物理地址是信息在存储器中实际存放的地址,它是CPU访问存储器时实际输出的地址。例如,实模式下的80x86/Pentium系统的物理地址是20位,存储空间为2 20 =1M字节单元,地址范围从00000H到FFFFFH。CPU和存储器交换数据时所使用的就是这样的物理地址。

逻辑地址是编程时所使用的地址。或者说程序设计时所涉及的地址是逻辑地址而不是物理地址。编程时不需要知道产生的代码或数据在存储器中的具体物理位置。这样可以简化存储资源的动态管理。在实模式下的软件结构中,逻辑地址由“段基值”和“偏移量”两部分构成。前面已提及,“段基值”是段的起始地址的高16位。“偏移量”(offset)也称偏移地址,它是所访问的存储单元距段的起始地址之间的字节距离。给定段基值和偏移量,就可以在存储器中寻址所访问的存储单元。

在实模式下,“段基值”和“偏移量”均是16位的。“段基值”由段寄存器CS、DS、SS、ES、FS和GS提供;“偏移量”由BX、BP、SP、SI、DI、IP或以这些寄存器的组合形式来提供。

2.实模式下物理地址的产生

实模式下CPU访问存储器时的20位物理地址可由逻辑地址转换而来。具体方法是,将段寄存器中的16位“段基值”左移4位(低位补0),再与16位的“偏移量”相加,即可得到所访问存储单元的物理地址,如图3.6所示。

上述由逻辑地址转换为物理地址的过程也可以表示成如下计算公式:

物理地址=段基值×16+偏移量

图3.6 实模式下物理地址的产生

上式中的“段基值×16”在微处理器中是通过将段寄存器的内容左移4位(低位补0)来实现的,与偏移量相加的操作则由地址加法器来完成。

例3.2 】 设代码段寄存器CS的内容为4232H,指令指针寄存器IP的内容为0066H,即CS=4232H,IP=0066H,则访问代码段存储单元的物理地址计算如下:

例3.3 】 设数据段寄存器DS的内容为1234H,基址寄存器BX的内容为0022H,即DS=1234H,BX=0022H,则访问数据段存储单元的物理地址计算如下:

例3.4 】 若段寄存器内容是002AH,产生的物理地址是002C3H,则偏移量是多少?

将段寄存器内容左移4位,低位补0得:002A0H。

从物理地址中减去上列值得偏移量为:002C3H-002A0H=0023H。

需注意的是,每个存储单元有唯一的物理地址,但它可以由不同的“段基值”和“偏移量”转换而来,这只要把段基值和偏移量改变为相应的值即可。也就是说,同一个物理地址与多个逻辑地址相对应。例如,段基值为0020H,偏移量为0013H,构成的物理地址为00213H;然而,若段基值改变为0021H,配以新的偏移量0003H,其物理地址仍然是00213H,如图3.7所示。

图3.7 一个物理地址对应多个逻辑地址

3.“段加偏移”寻址

上述由段基值(段寄存器的内容)和偏移量相结合的存储器寻址机制也称为“段加偏移”寻址机制,所访问的存储单元的地址常被表示成“段基值:偏移量”的形式。例如,若段基值为2000H,偏移量为3000H,则所访问的存储单元的地址为2000H:3000H。

图3.8进一步说明了这种“段加偏移”的寻址机制如何选择所访问的存储单元的情形。这里段寄存器的内容为1000H,偏移地址为2000H。图中显示了一个64KB长的存储器段,该段起始于10000H,结束于1FFFFH。图中也表示了如何通过段基值(段寄存器的内容)和偏移量找到存储器中被选单元的情形。偏移量也称偏移地址,如图中所示,它是自段的起始位置到所选存储单元之间的字节距离。

图3.8中段的起始地址10000H是由段寄存器内容1000H左移4位低位补0(或在1000H后边添加0H)而得到的。段的结束地址1FFFFH是由段起始地址10000H与段长度FFFFH(64K)相加的结果。

还需指出的是,在这种“段加偏移”的寻址机制中,由于是将段寄存器的内容左移4位(相当于乘以十进制数16)来作为段的起始地址的,所以实模下各个逻辑段只能起始于存储器中16字节整数倍的边界。这样可以简化实模式下CPU生成物理地址的操作。通常称这16字节的小存储区域为“分段”或“节”(paragraph)。

图3.8 实模式下存储器寻址机制——“段加偏移”

4.默认的段和偏移寄存器

在“段加偏移”的寻址机制中,微处理器有一套用于定义各种寻址方式中段寄存器和偏移地址寄存器的组合规则。例如,代码段寄存器总是和指令指针寄存器组合用于寻址程序的一条指令。这种组合是CS:IP还是CS:EIP取决于微处理器的操作模式。代码段寄存器定义代码段的起点,指令指针寄存器指示代码段内指令的位置。这种组合(CS:IP或CS:EIP)定位微处理器执行的下一条指令。例如,若CS=2000H,IP=3000H,则微处理器从存储器的2000H:3000H单元,即23000H单元取下一条指令。

8086~80286微处理器各种默认的16位“段加偏移”寻址组合方法如表3.1所示。表3.2表示80386及更高型号的微处理器使用32位“段加偏移”寻址组合的默认情况。80386及更高型号的微处理器的“段加偏移”寻址组合比8086~80286微处理器的选择范围更大。

表3.1 默认的16位“段加偏移”寻址组合

表3.2 默认的32位“段加偏移”寻址组合

5.“段加偏移”寻址机制允许程序重定位

“段加偏移”寻址机制给系统带来的一个突出优点就是允许程序或数据在存储器中重定位。重定位是程序或数据的一种重要特性,它是指一个完整的程序或数据块可以在有效的存储空间中任意地浮动并重新定位到一个新的地址区域。

这是由于在现代计算机的寻址机制中引入了分段的概念之后,用于存放段地址的段寄存器的内容可以由程序重新设置,所以在偏移地址不变的情况下,就可以将整个程序或数据块移动到存储器任何新的可寻址区域去。例如,一条指令位于距段首(段起始地址)6个字节的位置,它的偏移地址是6。当整个程序移到新的区域时,这个偏移地址6仍然指向距新的段首6个字节的位置,只是段寄存器的内容必须重新设置为程序所在的新存储区的地址。如果没有这种重定位特性,一个程序在移动之前必须大范围地重写或改写,这要花费大量时间,且容易出现差错。

“段加偏移”寻址机制所带来的这种可重定位特性,使编写与具体位置无关的程序(动态浮动码)成为可能。

3.3.3 堆栈

堆栈是存储器中的一个特定的存储区,它的一端(栈底)是固定的,另一端(栈顶)是浮动的,信息的存入和取出都只能在浮动的一端进行,并且遵循后进先出(Last-In First-Out)的原则。堆栈主要用来暂时保存程序运行时的一些地址或数据信息。例如,当CPU执行调用(Call)指令时,用堆栈保存程序的返回地址(亦称断点地址);在中断响应及中断处理时,通过堆栈“保存现场”和“恢复现场”;有时也利用堆栈为子程序传递参数。

堆栈是在存储器中实现的,并由堆栈段寄存器SS和堆栈指针寄存器SP来定位。SS寄存器中存放的是堆栈段的段基值,它确定了堆栈段的起始位置。SP寄存器中存放的是堆栈操作单元的偏移量,SP总是指向栈顶。图3.9给出了堆栈的基本结构及操作示意图。值得注意的是,这种结构的堆栈是所谓“向下生长的”,即栈底在堆栈的高地址端,当堆栈为空时SP就指向栈底。因此,堆栈段的段基址(由SS寄存器确定)并不是栈底。

实模式下的堆栈为16位宽(字宽),堆栈操作指令(PUSH指令或POP指令)对堆栈的操作总是以字为单位进行。即要压栈(执行PUSH指令)时,先将SP的值减2,然后将16位的信息压入新的栈顶;要弹栈(执行POP指令)时,先从当前栈顶取出16位的信息,然后将SP的值加2。可概括为:“压栈时,先修改栈指针后压入”,“弹栈时,先弹出后修改栈指针”。

图3.9 堆栈的结构与操作

由图3.9可以看出,堆栈的操作既不对堆栈中的项进行移动,也不清除它们。压栈时在新栈顶写入信息,弹栈时则只是简单地改变SP的值指向新的栈顶。 Rg8GcthUbPn42++JI+BVfZDPXj6bl/YM0S/Z10H0KMaodD9e+00yGoYo11DCxL41

点击中间区域
呼出菜单
上一章
目录
下一章
×