1.字单元,即存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节
- 在内存中存储时,由于内存单元是字节单元(一个字节存放一个单元),那么一个字要用两个地址连续的内存单元来存放,这个字的低位字节存放在低地址单元中,高位字节存放在高地址单元中
起始地址为N的字单元 可以简称为N地址字单元CPU中,用16位寄存器来存储一个字
- 两个连续的内存单元组成一个字型数据
如:0 20H1 4EH2 12H则,0地址单元中存放的字节型数据是20H0地址字单元存放的字型数据是4E20H1地址字单元存放的字型数据是124EH
- 任何两个地址连续的内存单元,N号单元和N+1号单元,可以是两个内存单元,也可以是N地址字单元,的高位字节单元和低位字节单元
2.mov指令
一.将数据直接送入寄存器
二.将一个寄存器中内容送入到另一个寄存器
三.将一个内存单元中的内容送入到一个寄存器中
四.将一个寄存器中的数据送入到一个内存单元中
五.将一个寄存器中的数据送入到一个段寄存器中
六.将一个段寄存器中的数据送入到一个寄存器中
(ps:可以看到三四,内存单元和寄存器的数据可以互传的,同理五六也是)
七.将N地址字单元字型数据,送入到一个段寄存器中
八.同理
{例子:
用10000H处存放的字型数据设置ds段寄存器
mov ax,1000H
mov ds,ax
mov ds,[0]
}
(如果操作[number] 对段寄存器或者寄存器操作,则会将ds:number的内存单元和下一个内存单元的字节型数据转移到 寄存器中,因为寄存器(8086)是16位的)
如:
mov bx,1000H
mov ds,bx
mov al,[0]
(上面例子即:将物理地址为1000:0的内存单元中的字节型数据,送入寄存器al中)
[***]表示一个内存单元,里面填0(数字)表示内存单元的偏移地址
mov 指令中的[]说明操作对象是一个内存单元,[]里面填0说明这个内存单元的偏移地址为0,它的段地址默认放在ds中,指令执行时,8086CPU会自动从DS中取出
上面的例子中为什么不能直接mov ds,1000H呢?
因为8086CPU不支持将数据直接送入段寄存器中,所以要用一个(一般的)寄存器来进行数据中转为何不支持直接送入?因为这是8086CPU硬件设计“特色”
从内存单元到寄存器 是mov 寄存器名,内存单元地址 那么从寄存器到内存单元,就是mov 内存单元地址,寄存器名
(这是要将寄存器数据存入到内存单元中)
3.8086CPU是16位结构,有16根数据线,所以可以一次性传送16位的数据,也就是一个字
比如 :
mov ax,1000H
mov ds,ax
mov ax,11316
mov [0],ax
将AX寄存器中的数据 11316(十进制) =>2C34H(十六进制) 放入 1000:0开始的内存单元中因为一个内存单元大小是1Byte(8bit), 所以要用两个内存单元来存储这个数据,所以就是 1000:0单元 存储低8位,也就是34H,1000:1单元存储高8位,也就是2CH
4.数据段(对于8086CPU)
在编程时,根据需要,将一组内存单元定义为一个段,将长度为N (N<=64KB),地址连续,起始地址为16的倍数的内存单元当做专门存储数据的内存空间,则这段内存空间 称为数据段
如:将 123B0H~123B9H的内存单元定义为数据段,则现在想要累加前三个单元中的数据(字节型数据)
mov ax,123BH
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]
如若要累加前三个字型数据则:
mov ax,123BH
mov ds,ax
mov ax,0
add ax,[0]
add ax,[2]
add ax,[4]
(PS:在内存和存储器之间传送字型数据时,高地址单元对应高8位存储器,低地址单元对应低8位存储器)
- 8086CPU栈机制
push ax 将寄存器ax中的数据送入到栈中
pop ax 从栈顶取出数据送入ax
(push是先将SP改变,然后再放入数据)
(pop是先将数据取出,然后再改变SP)
push和pop不仅可以操作寄存器,还可以操作段寄存器,内存单元
push的时候sp=sp-2,pop的时候sp=sp+2
8086CPU的出入栈都是以字为单位进行的
8086CPU中,有两个段寄存器,SS和SP,栈顶的段地址存放在SS中,偏移地址存放在SP中,那么任何时刻,SS:SP都是指向栈顶元素的,push和pop指令执行时,CPU都会通过SS:SP获取栈顶的地址
初始状态,栈为空时,SS:SP指向栈空间最高地址单元的下一个单元
SS用 mov ss,寄存器名 来改变,sp可以直接mov将具体数据送入
如:10000H~1000FH这段空间为栈,初始状态栈为空,SS=1000H,那么SP则为0010H(PS:出栈后的元素依然在内存单元中,但是缺不在栈中,因为栈顶地址已经改变,然后下一次push新的数据进来的时候,上一次出栈的元素所在的内存单元的数据将被新的数据覆盖)
特别地:当栈满的时候用push,或者栈空的时候用pop,都会发生栈顶越界问题,那么栈顶就指向了栈外的内存单元,这些内存单元很有可能存在其他有用的数据或者指令,这样将会导致一连串的错误
(ps:对于8086CPU来说,它不能保证我们对栈的操作不会越界,它只会考虑当前栈顶在哪里,当前要执行哪条命令)
6.清空一个寄存器,可以用sub
如:
mov ax,0 与 sub ax,ax的区别
mov ax,0机器码是3个字节,sub ax,ax机器码是2个字节
扩展:
一个栈段最大位64KB=65536个内存单元(Byte)
若将10000H~1FFFFH这段空间当做栈段,初始化栈为空,则SS=1000H,sp=0
当栈中还有一个元素时,sp=FFFEH,这个元素出站后,sp=sp+2=10000H=0(因为8086CPU最大栈段是64KB)
同理,如果栈满了,则sp也是为0,这样,如果再push,栈顶就会环绕,覆盖原来栈中的内容
段地址总结:
对于数据段,段地址存放在DS,偏移地址用[],可以用mov,add,sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当做数据来访问
对于代码段,段地址存放在CS,偏移地址存放在IP,目前用jmp操作,CPU就将执行我们定义的代码段中的指令
对于栈段,段地址存放在SS,栈顶单元的偏移地址存放在SP,这样,用push和pop时。CPU就会将我们定义的栈段当栈来用
(ps:一段内存,既可以是代码存储空间,又可以是数据存储空间,也可以是栈空间,也可以什么都不是,关键在于CPU中段寄存器CS,IP,SS,SP,DS的设置)
7.debug的T命令在执行 修改寄存器ss的指令时,下一条指令也紧接着被执行(前面不深究中断机制)