1、内存访问
CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086CPU中,内存地址由段地址和偏移地址组成。8086中有一个DS寄存器,通常用来存放要访问数据的段地址。例如我们要读取10000H单元的内容,可以用如下的程序段进行。
mov bx,1000H mov ds,bx mov al,[0]
[...]表示一个内存单元,其中的0表示内存单元的偏移地址。段地址从ds中获取。
8086CPU不支持将数据直接送入段寄存器的操作,所以使用寄存器bx作个中转。
2、几个指令
mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 寄存器,段寄存器
mov 段寄存器,寄存器
mov 段寄存器,内存单元
mov 内存单元,段寄存器
mov 内存单元,寄存器
add 寄存器,数据
add 寄存器,寄存器
add 寄存器,内存单元
add 内存单元,寄存器
sub 寄存器,数据
sub 寄存器,寄存器
sub 寄存器,内存单元
sub 内存单元,寄存器
注意:add ds,ax是错误的指令。
3、数据段
对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。我们可以将一组长度为N(N<=64KB)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。
将一段内存当作数据段,是我们在编程时的一种安排,可以在具体操作的时候,用ds存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。
4、栈
栈是一种具有特殊的访问方式的存储空间。栈有两个基本操作:入栈和出栈。入栈是将一个新的元素放到栈顶,出栈是从栈顶取出一个元素。栈的操作规则是LIFO(Last In First Out,后进先出)。
8086CPU提供相关的指令来以栈的方式访问内存空间,也就是在基于8086CPU编程时,可以将一段内存当作栈来使用。一个栈段容量最大为64KB。
8086CPU提供PUSH(入栈)和POP(出栈)指令。
8086CPU中有两个寄存器,段寄存器SS和寄存器SP,任意时刻,SS:SP指向栈顶元素。
push ax的执行,由以下两步完成。
1) SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
2)将ax中的内容送入SS:SP指向的内存单元中,SS:SP此时指向新栈顶。
入栈时,栈顶从高地址向低地址方向增长。
注意:
如果将10000H~1000FH这段空间当作栈,初始状态栈是空的,此时,SS=1000H,SP=0010H。
如果将10000H~1FFFFH这段空间当作栈,初始状态栈是空的,此时,SS=1000H,SP=0。
pop ax的执行过程和push ax正好相反,
1)将SS:SP指向的内存单元处的数据送入ax中;
2)SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。
注意:8086CPU不保证我们对栈的操作不会越界,我们在编程的时候需要自己操心栈顶越界的问题,要根据可能用到的最大栈空间,来安排栈的大小。
push和pop指令的格式可以如下:
push 寄存器
pop 寄存器
push 段寄存器
pop 段寄存器
push 内存单元
pop 内存单元
5、段的总结
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元,这完全是我们自己的安排。
我们可以用一个段存放数据,将它定义为"数据段";
我们可以用一个段存放代码,将它定义为"代码段";
我们可以用一个段当作栈,将它定义为"栈段"。
我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:
对于数据段,将它的段地址放在DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问。
对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令。
对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如push、pop指令等,就将我们定义的栈段当作栈空间来用。