段寄存器的引用
由于8086/8088CPU有四个段寄存器,可保存四个段值,所以可同时使用四个段,但这个段有所分工。每当需要产生一个20位的物理地址时,BIU会自动引用一个段寄存器,且左移4位再与一个16位的偏移相加。
在取指令的时候,自动引用代码段寄存器CS,再加上由IP所给出的16位偏移,得到要取指令的物理地址。
当涉及到一个堆栈操作时,则自动引用堆栈段寄存器SS,再加上由SP所给出的16位偏移,得到堆栈操作所需的物理地址。当偏移涉及BP寄存器时,缺省引用的段寄存器也为堆栈段寄存器SS。
在存取一个普通存储器操作数时,则自动选择数据段寄存器DS或附加段寄存器ES,再加上16位偏移,得到存储器操作数的物理地址。此时的16位偏移,可以是包含在指令中的直接地址,也可以是某一个16位存储器指针寄存器的值,也可以是指令中的偏移再加上存储器指针寄存器中的值,这取决于指令的寻址方式。除了串操作时目的段选择附加段寄存器ES外,却省选择数据段寄存器DS。
在不改变段寄存器值的情况下,寻址的最大范围是64K字节。若某个程序使用的总的存储长度(包括代码、堆栈和数据区)不超过64K字节,则整个程序可以合用一个64K字节的段。若有一个程序,它的代码长度、堆栈长度和数据区长度均不超过64K字节,则可在程序开始时分别给DS和SS等段寄存器赋值,在程序的其他地方就可不再考虑这些段寄存器所含的段值,程序就能正常地运行。假如某个程序的数据区长度超过64K字节,那么就要在两个或多个数据段中存取数据。如果出现这种情况,只要再从存取一个数据段改变到存取另一个数据段时,改变数据段寄存器内的段值就可以了。
由于BIU能根据需要自动选择段寄存器,所以通常情况下在指令中不指明所需要的段寄存器。取指令和堆栈操作所引用的段寄存器分别规定为CS和SS,是不可变的;串操作中目的段的段寄存器规定位ES也是不可变的。但是,在存取一般存储器操作数时,段寄存器可以不一定是DS;当偏移涉及BP寄存器时,段寄存器也不是非要为SS。8086/8088允许使用段超越前缀,改变上述两种情况下所使用的段寄存器,也即用段超越前缀直接明确指定引用的段寄存器。表2.3列出了段寄存器的引用规定,其中“可选用的段寄存器”栏就列出了可作为段超越前缀改变的段寄存器,另外,有效地址EA(Effective Address)就是指段内偏移。
表2.3 段寄存器的引用规定
访问存储器涉及的方式 |
正常使用的段寄存器 |
可选用的段寄存器 |
偏移 |
取指令 |
CS |
无 |
IP |
堆栈操作 |
SS |
无 |
SP |
一般数据存取(下列情况除外) |
DS |
CS、ES、SS |
有效地址 |
源数据串 |
DS |
CS、ES、SS |
SI |
目的数据串 |
ES |
无 |
DI |
BP作为指针寄存器使用 |
SS |
CS、DS、ES |
有效地址 |
2.3 8086/8088的寻址方式
表示指令中操作数据所在的方法称为寻址方式。8086/8088有七种基本的寻址方式:立即寻址、寄存器寻址、直接寻址、寄存器间接寻址、寄存器相对寻址、基址加变址寻址和相对基址加变址寻址。
直接寻址、寄存器间接寻址、寄存器相对寻址、基址加变址寻址和相对基址加变址寻址,这五种寻址方式属于存储器寻址,用于说明操作数所在存储单元的地址。由于总线接口单元BIU能根据需要自动引用段寄存器得到段值,所以这五种方式也就是确定存放操作数的存储单元有效地址EA的方法。BIU能根据需要自动引用段寄存地址EA是一个16位的无符号数,在利用这五种方法计算有效地址时,所得的结果认为是一个无符号数。
除了这些基本的寻址方式外,还有固定寻址和I/O端口寻址等。
2.3.1 立即寻址方式
操作数就包含在指令中,它作为指令的一部分,跟在操作码后存放在代码前。这种操作数称为立即数。
立即数可以是8位,也可以是16位,那么按“高高低低”原则存放,即高位字节在高地址存储单元,低位字节在低地址存储单元。
指令“MOV AX, 1234H”的存储和执行情况如图2.7所示
这种寻址方式主要用于给寄存器或存储单元赋初值的场合。
图 2.6 立即方式示意图
2.3.2 寄存器寻址方式
操作数在CPU内部的寄存器中,指令中指定寄存器号。对于16位操作数,寄存器可以是AX、BX、CX、DX,SI、DI、SP和 BP等;对于8位操作数,寄存器可以是AL、AH、BL、BH、CL、CH、DL和DH。
例如,指令“MOV SI,AX”和指令“MOV AL,DH”中的源操作数和目的操作数均是寄存器寻址。再如,图2.7所示指令中,目的操作数采用寄存器寻址。
由于操作数在寄存器中,不需要通过访问存储器来取得操作数,所以采用这种寻址方式的指令执行速度较快。
2.3.3 直接寻址方式
操作数在存储器中,指令直接包含有操作数的有效地址。操作数一般存放在数据段,所以操作数的地址由DS加上指令中直接给出的16位偏移得到。如果采用段超越前缀,则操作数也可含在数据段外其他段中。
设数据段寄存器DS的内容是5000H字存储单元中的内容是6789H,那么在执行指令“MOV AX,[1234H]”后寄存器AX的内容是6789H。图2.8是此指令的存储和执行情况,为方便,本
章常用(reg)表示寄存器reg的内容。于是该例的假设用(DS)=5000H表示,执行结果用(AX)=6789H表示。
下面指令中目标操作数采用直接寻址,并且使用了段超越前缀:
MOV ES:5678H,BL ;用的段寄存器是ES
这种寻址方式常用于处理单个存储器变量的情况。它可实现在64k字节的段内寻找操作数。直接寻址的操作数通常是程序使用的变量。
注意立即寻址和直接寻址书写表示方法上的不同,直接寻址的地址要放在方括号中。在源程序中,往往用变量名表示。
2.3.4 寄存器间接寻址方式
操作数在存储器中,操作数有效地址在SI、DI、BX、BP这四个寄存器之一中,在一般情况(即不使用段超越前缀明确指定段寄存器)下,如果有效地址在SI、DI和BX中,则以DS段寄存器之内容为段值;如果有效地址在BP中,则以SS段寄存器值内容为段值。
例如,MOV AX,[SI]
假设,(DS)=5000H,(SI)=F1234H
那么,存取的物理存储单元地址是5124H。再设字存储单元的内容是6789H,那么,在执行该命令后,(AX)=6789H。图2.8反映该指令的存储和执行情况。
下面指令种源操作数采用寄存器间接寻址,并且使用了段超越前缀:
MOV DL, CS:[BX] ;引用的段寄存器是CS
下面指令中的操作数采用寄存器间接寻址,由于使用BP作为指针寄存器,所以缺省的段寄存器是SS:
MOV [BP],CX ;引用的段寄存器是BP
这种寻址方式可用于表格处理,在处理完表中的一项后,只要修改指针寄存器的内容就可以方便的处理表中的另一项。