内存中字的存储
两个字节 = 一个字
在0地址处开始存放20000(4E20H),如下图所示,高位对应高地址位,低位对应低地址位。
由此需要注意的问题是:
- 0地址单元存放的字节型数据是20
- 0地址单元存放的字型数据数是4E20
- 2地址单元中存放的字节型数据是12
- 2地址单元中存放的字型数据是0012
- 1地址单元中存放的字型数据是124E
小结
任何两个地址连续的内存单元,N号单元和N+1号单元,可以将他们看成两个内存单元,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。
DS和[address]
- CPU要读取一个内存单元时,必须先给出这个内存单元的地址
- 在8086PC中,内存地址由段地址和偏移地址组成。
- 8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。
- 执行指令的时候,8086CPU自动取DS中的数据为内存单元中的段地址。
如何把1000H送入ds
- 传送指令 MOV ax 1
- 8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器(硬件设计的问题)
- mov ds 1000H是非法的
- 遵循的原理:数据->通用寄存器->段寄存器
将aI中的数据 存入内存单元10000H
问题的本质:将寄存器中的数据送入内存单元
- mov al 1000H
上述指令的意思是将内存单元的数送入到寄存器当中。
正确结论:
mov bx,1000H
mov ds,bx
mov [0],al
必须通过段寄存器作为媒介才能完成将寄存器的数存入内存中。
字的传送
因为8086CPU是16位的结构,有16根的数据线,所以,可以一次性传送16位的数据,也就是一次性传送一个字
- 比如
mov bx,1000H
mov ds,bx
mov ax,[0];1000:0处的字型数据存放至ax中
mov [0],cx;cx中的数据送到内存1000:0处
mov、add、sub指令
- mov 寄存器,数据
- mov 寄存器,寄存器
- mov 寄存器,内存单元
- mov 内存单元,寄存器
- mov 段寄存器,寄存器
- mov 寄存器,段寄存器(也是正确的)
数据段
对于8086CPU机,我们可以根据需要将一组内存单元定义为一个段(可以是代码段,也可以是数据段)
我们可以将一组长度为N(N <= 64K)、地址连续、起始地址为16的倍数的内存单元当作是专门存储数据的内存空间,从而定义了一个数据段。
小结
- 字在内存中存储时,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放在高地址中。
- 用mov指令要访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中
- [address]表示一个偏移地址为address的内存单元。
- 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器对应,低地址单元和低8位寄存器相对应,
- mov,add,sub是具有两个操作对象的指令,jmp是具有一个操作对象的指令。
CPU提供的栈机制
8086CPU提供入栈和出栈指令,最基本的两个是:
- PUSH(入栈):push ax表示将寄存器ax中的数据送入栈中
- POP(出栈):pop ax表示从栈顶取出数据送入ax。
- 8086CPU的入栈和出栈操作都是以字节为单位进行的。
- 8086CPU中,入栈时,栈顶从高地址向低地址方向增长。
- 栈空,SS:SP指向栈空间最高地址单元的下一个单元。
栈顶越界问题
在使用push和pop时,都会发生栈顶越界的问题,下图是关于栈顶越出的两个例子:
- push操作导致栈顶越界
- pop操作导致栈顶越界
push和pop指令
push和pop指令可以是在寄存器和内存之间传送数据的。当然也有别的形式,可以是如下的形式:
- push 寄存器:将一个寄存器中的数值入栈
- pop 寄存器:出栈,用一个寄存器接收出栈的数据
当然也可以是如下的形式: - push 段寄存器;将一个段寄存器中的数据入栈
- pop 段寄存器:出栈,用一个段寄存器接收出栈的数据
也可以在内存单元与内存单元之间传送数据: - push 内存单元:将一个内存字单元处的字入栈
- pop 内存单元:出栈,用一个内存单元接收出栈的数据
- 比如:
mov ax,1000H
mov ds,ax;内存单元的段地址放在ds中
push [0];将1000:0处的字压入栈中
pop [2];出栈,出栈的数据送入1000:2处
需要注意的是:
执行push时,CPU要进行两部操作;
- 比如:
- 第一步操作是:先改变SP
- 第二步操作是:向SS:SP处传送
执行pop时,也需要两步操作: - 第一步操作是:先读取SS:SP处的数据
- 第二步操作是:再改变SP的值
段的综述
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。
- 可以用一个段存放数据,将它定义为“数据段”
- 对于数据段,将它的段地址放在DS中,用mov,add,sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当做数据来进行访问。
- 可以用一个段存放代码,将它定义为“代码段”
- 对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码中的指令。
- 可以用一个段当做栈,将它定义为“栈段”
- 将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行PUSH、pop指令时,就将我们定义的栈段当做栈空间来进行使用。
检测点3.2
补全下面的两段代码,使其可以将10000H~1000FH中的8个字,逆序复制到20000H-2000FH中。逆序复制得含义如图所示:
代码段1:
mov ax,1000H
mov ds,ax
mov ax,2000H
mov ss,ax
mov sp,01H
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
代码段2:
mov ax,2000H
mov ds,ax
mov ax,1000H
mov ss,ax
mov sp,00H
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]