第三节 :寄存器(内存访问)
1. 内存中字的存储:
16位寄存器来存储一个字。高8位存放高位字节,低8位存放低位字节
字单元:存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节。
将起始地址为N的字单元简称为N地址字单元。
2. DS和[address]:
DS寄存器:通常用来存放要访问数据的段地址。
[address]表示一个偏移地址为address的内存单元。
Eg:读取10000H单元的内容:
Mov bx,1000H
Mov ds,bx
Mov a1,[0]
[]说明操作对象是一个内存单元,段地址默认放在ds中,指令执行时,8086CPU会自动从ds中取出。
注意:mov ds,1000H 指令非法。只能用一个寄存器进行中转。
Eg:将a1中的数据送到内存单元10000H:
Mov bx,1000H
Mov ds,bx
Mov [0],a1
3. 字的传送:
Eg:指令执行后寄存器ax 10000H存放23,10001H存放11
Mov bx,1000H
Mov ds,bx
Mov a1,[0] ----->ax=1123H
指令执行时,字型数据的高8位送入ah,低8位送到al。区分字单元
4.mov,add,sub指令:
Mov类似于赋值,add 相加,sub相减
推测:有mov 段寄存器,寄存器 是否有 mov 寄存器,段寄存器
Mov 内存单元,段寄存器?
Mov 段寄存器,内存单元?
Mov,add,sub具有两个操作对象的指令。Jmp是具有一个操作对象的指令。
5. 数据段:
可以将一组长度为N(N<=64kb),地址连续,起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。、
Eg:累加这个数据段中的前3个单元中的数据
Mov ax,123BH
Mov ds,ax
Mov a1,0 用a1存放累加结果
Add a1,[0] 将数据段第一个单元(偏移地址为0)中的数值加到a1中;
Add a1,[1]
Add a1,[2]
累加数据段中的前3个字型数据
Mov ax,123BH
Mov ds,ax
Mov ax,0 用a1存放累加结果
Add ax,[0] 将数据段第一个单元(偏移地址为0)加到ax中;
Add ax,[2] 将数据段第二个单元(偏移地址为2)加到ax中;
Add ax,[4]
6. 栈:LIFO(last in first out,后进后出):
7. CPU提供的栈机制:
8086CPU提供入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)
出入栈的操作都是以字为单位的。
Eg:栈操作
Mov ax,0123H
Push ax
Pop ax
注意:字型数据用两个单元存放,高地址单元存放8位,低地址单元存放低8位。
Cpu如何知道栈顶的位置?
8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。
任意时刻,SS:SP指向栈顶元素。
PUSH ax的执行,由以下两步完成。//POP ax相反
1. SP=SP-2,SS:SP指向当前栈顶前面单元,以当前栈顶前面的单元为新的栈顶;
2. 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。
入栈时,栈顶从高地址向低地址方向增长。
**:如果将10000H~1000FH这段空间当作栈,初始状态栈是空的,此时SS=1000H,SP=?
SP应该等于0010H
栈空时SS:SP指向栈空间最高地址单元的下一个单元,每次执行,SP-=2。栈中没有元素,也就不存在栈顶元素,所以SS:SP只能指向栈的最底部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2.
Eg:栈最底部字单元的地址为1000:000E,所以栈空时,SP=0010H
8. 栈顶超界的问题:
如何保证在入栈,出栈时,栈顶不会超出栈空间?
8086CPU中并没有寄存器来检测栈顶上下限,但是栈顶超界很危险。
8086工作的机理,只考虑当前的状况,只考虑当前的情况:当前栈顶在何处,当前要执行的指令是哪一条。
在编程的过程自己操心栈顶超界问题:要根据可能用到的最大栈空间,来安排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候,防止栈空的时候继续出栈而导致的超界
9.PUSH,POP指令:
栈空间是内存空间的一部分,只是一段可以以一种特殊的方式进行访问的内存空间。
PUSH/POP 寄存器 将一个寄存器中的数据入栈/出栈,用一个寄存器接收出栈的数据
PUSH/POP 段寄存器 同上;
PUSH 内存单元 将一个内存字单元处的字入栈(注意:栈操作都是以字为单位)
POP 内存单元 出栈,用一个内存字单元接收出栈的数据
Eg:将10000H~1000FH这段空间当作栈,初始状态栈是空的,将AX,BX,DS数据入栈
Mov ax,1000H
Mov ss,ax //设置栈的段地址,ss=1000H,不能直接向段寄存器SS送入数据
Mov sp,0010H //设置栈顶的偏移地址,因栈为空,所以SP=0010H
Push ax
Push bx
Push ds
清空AX,BX
Sub ax,ax (2个字节)
Sub bx,bx
将ax清零,也可以用mov ax,0(3个字节)
交换AX和BX中的数据
Push ax ;push bx ;pop ax ;pop bx
执行push时,CPU的两步操作:先改变SP,后向SS:SP处传送
执行POP时,CPU的两步操作:先读取SS:SP处的数据,后改变SP
10. 栈段:
可以根据需要,将一组内存单元定义为一个段。将长度为N(N<=64KB)的一组地址连续,起始地址为16的倍数的内存单元,当作栈空间来用,定义一个栈段。
可以用一个段存放数据,将定义为“数据段”
---->段地址放在DS中,用MOV,ADD,SUB等访问内存单元的指令。
可以用一个段存放代码,将定义为“代码段”
---->段地址放在CS中,将段中第一条指令的偏移地址放在IP中。
可以用一个段当作栈,将定义为“栈段”
---->段地址放在SS中,将栈顶单元的偏移地址放在SP中,执行POP,PUSH将栈段当做栈空间来用。
Debug的T命令在执行修改寄存器ss的指令时,下一条指令也紧接着被执行。