寄存器 \color{blue}{\huge{寄存器}} 寄存器
一个 16 16 16位的寄存器存储一个 16 16 16位的数据。
将输入的数据转化为二进制的数据之后存放到 A X AX AX中。
8086 8086 8086上一代 C P U CPU CPU中的寄存器都是 8 8 8位的,那么在上一代编写的程序,如何才能保证对于下一代 C P U CPU CPU的兼容?
解决:
将多位数的通用寄存器进行分位操作,分成两个独立的 8 8 8位寄存器进行使用。高八位分成 A H AH AH,低八位分成 A L AL AL。分别进行存储即可。
8086 8086 8086是 16 16 16位的 C P U CPU CPU。
那么 8086 8086 8086的字长就是 16 16 16位。
一个字可以存储在一个 16 16 16位寄存器中,这个字的高位存储在高 8 8 8位寄存器,低位存储在低 8 8 8位寄存器。
示例:
所有的内存单元构成的存储空间是一个一维的线性空间,不过对于线性空间的划分使得不同的存储空间存储不同的数据。
如果 C P U CPU CPU想要访问内存单元的时候要给出对应内存单元的地址。每一个内存单元在这个线性的存储空间里面都有一个唯一的地址,这个唯一的地址就是物理地址。
8086 8086 8086有 20 20 20位地址总线,所以它的寻址能力是 1 M 1M 1M。但是 8086 8086 8086本身是 16 16 16位结构的 C P U CPU CPU,里面的运算器一次只能处理 16 16 16位的数据,也就是说内部处理的数据对应的寻址能力只有 64 K B 64KB 64KB,内外寻址能力不同,如何弥补这个差距?
物理地址 = 段地址 ( 基地址 ) ∗ 16 + 偏移地址 物理地址 \space = \space 段地址(基地址) * 16 \space + \space 偏移地址 物理地址 = 段地址(基地址)∗16 + 偏移地址
可以使用坐标进行理解,选定好基坐标之后,添加偏移量就可以访问到物理地址,当然选定不同的基坐标,访问同一物理地址对应的偏移量也不同。
这个合成地址的位置在 C P U CPU CPU中的地址加法器中进行操作,待合成的地址一起送入到地址加法器中,然后地址加法器输出合成后的地址。
∗ 16 *16 ∗16的意义就是将原本 16 16 16位的基地址,左移 4 4 4位,这样就变成了 20 20 20位的数据,之后加上偏移量,就使用了两个 16 16 16位的地址来确定了 20 20 20位的地址。
物理地址 = 段地址 ( 基地址 ) ∗ 16 + 偏移地址 物理地址 \space = \space 段地址(基地址) * 16 \space + \space 偏移地址 物理地址 = 段地址(基地址)∗16 + 偏移地址
这是 8086 8086 8086进行物理寻址的方法,但是实际上内存并没有进行分段,就只是一块连续的存储地址,每个段落的划分(段地址的起始点选择)是由 C P U CPU CPU进行确定的。
C S CS CS:代码段寄存器(存储基地址)
I P IP IP:指令指针寄存器(存储偏移量)
C S : I P CS:IP CS:IP: C P U CPU CPU将内存中的 C S : I P CS:IP CS:IP指向的内容当作指令进行执行。
C S : I P = 基地址 : 偏移量 CS:IP \space = \space 基地址:偏移量 CS:IP = 基地址:偏移量
C S : I P CS:IP CS:IP可以确定一条指令的位置,但是除了执行完一条指令 C P U CPU CPU会自动跳转到下一条指令之外,还有没有其他的方法来修改 C S : I P CS:IP CS:IP呢?
❗❗❗ M o v Mov Mov指令不能够对 C S : I P CS:IP CS:IP进行修改, M o v c s 2000 H × Mov \space cs \space 2000H \space × Mov cs 2000H × 这是错误的! C P U CPU CPU不允许将立即数作为更改 C S : I P CS:IP CS:IP的数据,即使将立即数放置到其他的寄存器再进行转移也不可以。
8086 C P U 8086CPU 8086CPU, 16 16 16位作为一个字,高 8 8 8位放高位字节,低 8 8 8位放低位字节,并且在物理存储中低位字节放在低地址单元,高位字节放在高地址单元。
字单元就是存放在其中的数据单位类型是字,由两个地址连续的内存单元组成,存放一个字型的数据( 16 16 16位)
字节单元内存放的就是一个字节,子单元内存放的就是一个字。但是在物理存储中一个地址对应一个字节,但是一个字要看由多少个字节构成进而确定一个字的地址。
C P U CPU CPU读取内存单元的时候,必须先给出这个内存单元的地址。
读取数据: D S DS DS和 [ a d d r e s s ] [address] [address]集合
mov bx, 1000H
mov ds, bx
mov al, [0]
//bx通用寄存器将自己存储的值赋值给了ds寄存器,ds寄存其中存储就是现在的段地址(1000H),后面的[0]就是在ds段地址的基础之上的偏移地址
mov bx, 1000H
mov ds, bx
mov [0], al
//将al中的数据写入到(1000:0)中
//将段地址送入DS中的两种方式
(1) mov ds, 1000H ❌
(2) mov bx, 1000H ✔️
mov ds, bx
8086 C P U 8086CPU 8086CPU不支持将数据直接送入到段寄存器中,只能从 数据 → 通用寄存器 → 段寄存器 \color{red}{数据→通用寄存器→段寄存器} 数据→通用寄存器→段寄存器这条路径。
8086 C P U 8086CPU 8086CPU也可以一次性传送一个字( 16 16 16位的数据)
mov bx, 1000H
mov ds, bx
mov ax, [0] //(1000:0)处的字型数据送入到ax中
mov [0], cx //cs中的16位数据送到(1000:0)处
❗❗❗传递字型数据的时候读取的使用一定从高位向低位读两个字节(是10001H → 10000H)
8086 C P U 8086CPU 8086CPU访问内存中的数据的时候需要使用:
物理地址 = 段地址 ∗ 16 + 偏移地址 物理地址 = 段地址 * 16 + 偏移地址 物理地址=段地址∗16+偏移地址
于是 地址段 \color{red}{地址段} 地址段:就是一组长度为 N N N、地址连续、起始地址为 16 16 16倍数的内存单元当作专门存放存储数据的内存空间。
D S : ( [ a d d r e s s ] ) DS : ([address]) DS:([address])
D S DS DS:存放数据段的段地址。
a d d r e s s address address:指令访问数据段中具体单元的时候访问的内存地址。
❗❗❗❗事实证明除了不能够将数据 M o v Mov Mov到 段寄存器中 \color{red}{段寄存器}中 段寄存器中,其他的 M o v Mov Mov使用方法都是正确的。
add 段寄存器, 存储器 ❌
//add操作会将后面的值加入到前面,但是段存储器不允许值随便改变
add 内存单元, 内存单元 ❌
//add两个参数不能都是内存单元
C P U CPU CPU中包含有栈机制,并且直接提供相关的栈操作,支持使用栈的方式直接访问内存空间。 8086 C P U 8086CPU 8086CPU中可以直接将一段内存当作栈来使用。
//ax:通用寄存器等..
//操作的时候以字为单位
push ax //将ax中的数据压入栈中
pop ax //从栈顶取出数据存放到ax中
举例:
上图是执行到了mov cx 1122H
后内存中栈空间的情况,之后向下操作,每次弹出一个字,最后的结果就是:ax = 1122H, bx = 2266H,cx = 0123H
。
与栈相关的寄存器:
①. 定义好初始的栈内存空间
mov ax,1000H
mov ss,ax
mov sp,0010H
②. 向 a x ax ax和 b x bx bx中存放要交换的两个数据
mov ax,001AH
mov bx,0018H
push ax
push bx
④. 逆顺序出栈, a x ax ax先接收 p o p pop pop出来的值,然后才是 b x bx bx。
pop ax
pop bx
❗❗❗❗出栈之后栈顶指针会发生改变,改变指向的位置但是原有的数据弹出之后还是会保存到内存中,但是因为栈顶指针已经不在指向那些空间了,所以那些数字也就没有意义了。
栈空还要 p o p pop pop操作可能会发生栈顶越界(高地址方向),栈满还要进行 p u s h push push操作可能发生栈顶越界(低地址方向)。但是 8086 C P U 8086CPU 8086CPU并没有相关的栈情况检查操作,不知道程序安排的栈空间有多大,只能够自己仔细小心操作。
p o p pop pop与 p u s h push push操作的本质就是寄存器与内存进行的数据交换,但是这个交换地址的确定不是直接附加的,需要通过 S S : S P SS:SP SS:SP来进行确定。
mov bx, 1000H
mov dx, bx //设置代码段地址ds
mov bx, 1001H
mov ss, bx //设定栈段
mov sp, 10H //设定栈顶位置sp
//取出两个数并利用栈进行交换,之后放回内存中
mov ax, [0]
mov bx, [2]
push ax
push bx
pop ax
pop bx
mov [0], ax
mov [0], bx