《汇编语言》- 读书笔记 - 第2章-寄存器
- 2.0 8086CPU 寄存器
- 段地址:偏移地址
- 2.1 通用寄存器
- 2.2 字在寄存器中的存储
- 2.3 几条汇编指令
- 表2.1汇编指令举例
- 表2.2 程序段中指令的执行情况之一
- 问题 2.1
- 表2.3 程序段中指令的执行情况之二
- 问题 2.2
- 2.4 物理地址
- 2.5 16位结构的CPU
- 2.6 8086CPU给出物理地址的方法
- 2.7 “段地址X16+偏移地址=物理地址”的本质含义
- 2.8 段的概念
- 内存单元地址小结
- 2.9 段寄存器
- 2.10 CS和IP
- 2.11 修改 CS、IP 的指令
- 2.12 代码段
- 2.9~2.12 小结
CPU由运算器
、控制器
、寄存器
等构成,内部总线
连接这些器件,外部总线
连接主板上其他器件。
对于汇编程序员来说,寄存器
是最主要
的部件,我们能做的就是通过改变寄存器
中的内容
来控制CPU
。
不同CPU的寄存器个数和结构不同。8086CPU有14个寄存器,包括:
通用寄存器:AX、BX、CX、DX
段寄存器:CS、SS、DS、ES
偏移指针寄存器:SI、DI、SP、BP、IP
标志寄存器:PSW
2.0 8086CPU 寄存器
段地址:偏移地址
段地址:偏移地址 | 说明 |
---|---|
CS:IP | 指向下一条指令的物理地址 |
SS:SP | 指向当前堆栈顶部的物理地址 |
DS:BX | 指向数据的物理地址 |
DS:SI | 指向数据的物理地址 。例:复制中的源 |
DS:DI | 指向数据的物理地址 。例:复制中的目标 |
2.1 通用寄存器
8086CPU 的所有寄存器都是 16 位的,可以存放两个字节。
AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。
- 数据在寄存器中的存储情况
- 四个通用寄存器都可以拆分为高低位,分开使用。
2.2 字在寄存器中的存储
8bit
(位)组成一个Byte
(字节)。2字节
组成一个字
。
所以一个字包含高
和低
两个字节。共16位。
我们再看个例子:9527H
这个字的数据可以当作整体来用,表示:
9527H
= 10010101 00100111
=38183
也可以把高低位拆开分别使用,表示:
高位:95H
= 10010101B
= 149
低位:27H
= 00100111B
= 39
进制 | 寄存器值 | 高位 | 低位 |
---|---|---|---|
16 | 9527H | 95 | 27 |
2 | 1001010100100111B | 10010101 | 00100111 |
10 | 38183 | 149 | 39 |
补充:10进制数直接与高低位对应很难理解。需要转为2
或16
进制分出高低位再转成10进制。
2.3 几条汇编指令
- 写
汇编指令
或寄存器名
时,不区分
大小写。 - 下面的两个"问题"主要是介绍了寄存器执行加法后
溢出
的问题。
表2.1汇编指令举例
汇编指令 | 控制CPU完成的操作 | 用高级语言的语法描述 |
---|---|---|
mov ax,18 | 将18 送入寄存器AX | AX=18 |
mov ah,78 | 将78送入寄存器AH | AH-78 |
add ax,8 | 将寄存器AX中的数值加上8 | AX=AX+8 |
mov ax,bx | 将寄存器BX中的数据送入寄存器AX | AX-BX |
add ax,bx | 将AX和BX中的数值相加,结果存在AX中 | AX=AX+BX |
表2.2 程序段中指令的执行情况之一
(原 AX 中的值:0000H
,原 BX 中的值:0000H
)
程序段中的指令 | 指令执行后AX中的数据 | 指令执行后BX中的数据 |
---|---|---|
mov ax,4E20H | 4E20H | 0000H |
add ax,1406H | 6226H | 0000H |
mov bx,2000H | 6226H | 2000H |
add ax,bx | 8226H | 2000H |
mov bx,ax | 8226H | 8226H |
add ax,bx | ?(参见问题2.1) | 8226H |
问题 2.1
- 指令执行后AX中的数据为多少?
8226H
+ 8226H
= 1044CH
但 AX
只有16位
(对应4个16进制数)
所以溢出了,最高位的1
丢失。
最后AX
中剩下的就只有044CH
表2.3 程序段中指令的执行情况之二
程序段中的指令 | 指令执行后AX中的数据 | 指令执行后BX中的数据 |
---|---|---|
mov ax,001AH | 001AH | 0000H |
mov bx,0026H | 001AH | 0026H |
add al,bl | 0040H | 0026H |
add ah,bl | 2640H | 0026H |
add bh,al | 2640H | 4026H |
mov ah,0 | 0040H | 4026H |
add al,85H | 00C5H | 4026H |
add al,93H | ?(参见问题2.2) | 4026H |
问题 2.2
指令执行后AX中的数据为多少?
C5H
+ 93H
= 158H
但 AL
只有8位
(对应2个16进制数)
所以溢出了,最高位的1
丢失。
最后AL
中剩下的就只有58H
注意:add al,93H
进行的是 8 位运算。单独使用AL
时,它作为一个独立的8位寄存器,和AH
无关。并不会把溢出的1
放到 AH
中去。
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的,例如:
- 正确
mov ax,bx
mov bx,cx
mov ax,18H
mov al,18H
add ax,bx
add ax,20000
- 错误
mov ax,bl ; 在8位存器和16位存器之间传送数据
mov bh,ax ; 在16位寄存器和8位存器之间传送数据
mov al,20000 ; 8位存器最大可存放值为255的数据
add al,100H ; 将一个高于8位的数据加到一个8位存器中
2.4 物理地址
CPU 访问内存单元时,需要使用物理地址。
所有的内存单元构成一个线性空间,每个内存单元在其中有唯一的地址,这就是所谓的物理地址
。
不同的 CPU 可以采用不同的方式来形成物理地址。对于 8086CPU,在发送物理地址到地址总线之前,它需要先在内部生成物理地址。
2.5 16位结构的CPU
- 运算器一次最多可以处理 16 位的数据;
- 寄存器的最大宽度为 16位;
- 寄存器和运算器之间的通路为 16 位。
8086CPU是16位结构,一次性能够处理
、传输
、暂存
信息长度最大为16位
。(内存单元的地址
也是信息)
2.6 8086CPU给出物理地址的方法
8086CPU有20
位地址总线
,达到1MB寻址
能力。
也就是说地址总线
一次能收发20
辆车。
但CPU一单只能打包16
车货。
如果CPU来一单,就发车。那地址总线上就要跑4
辆空车。
为了不浪费。
CPU决定一次发两单,每单都少装点货,拼到一起刚好20
车,至于谁多谁少,程序员可以根据自己调配。
一单是段地址,一单是偏移地址。
在CPU
中有一个地址加法器
,它用来计算最终的物理地址:
物理地址
= 段地址
x 16 + 偏移地址
。
- 如图 2.6所示,当8086CPU 要读写内存时:
- CPU中的相关部件提供两个16 位的地址,一个称为段地址,另一个称为偏移地址;
- 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
- 地址加法器将两个 16 位地址合成为一个 20 位的物理地址;
- 地址加法器通过内部总线将 20 位物理地址送入输入输出控制电路;
- 输入输出控制电路将 20 位物理地址送上地址总线;
- 20 位物理地址被地址总线传送到存储器。
2.7 “段地址X16+偏移地址=物理地址”的本质含义
段地址
x16+偏移地址
=物理地址
的本质含义是:CPU 在访问内存时,用一个基础地址(段地址X16)和一个相对于基础地址的偏移地址相加,得出内存单元的物理地址。
是 基础地址
+偏移地址
=物理地址
这种寻址模式的一种实现方案。
例1:
这里如果应用 基础地址
+偏移地址
=物理地址
的寻址模式。2000可视作基址,826可视作偏移地址。
2.8 段的概念
内存中没有段
的概念。是8086CPU使用 基础地址
+偏移地址
=物理地址
方式寻址,来分段管理内存。
段地址
是x16得来的。段起始地址一定是16的倍数。- 偏移地址有16位,范围
0000h~FFFFh
。所以一个段最大为64KB
。 - 可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段。
内存单元地址小结
- CPU可以用不同的
段地址
和偏移地址
组成同一个物理地址
,也就是说同一个物理地址
可以有很多种组合方式获得。 - 数据在
21F60H
内存单元中。对于8086PC机一般表达为:
2.1. 数据存在内存2000:1F60
单元中;
2.2. 数据存在内存的2000H
段中的1F60H
单元中。
2.9 段寄存器
8086CPU 有4 个段存器:CS、DS、SS、ES。用来存放内存单元的段地址。
见:8086CPU 寄存器
2.10 CS和IP
CS:代码段寄存器。存放当前执行指令的代码段的基地址。
IP:指令指针寄存器。保存着将要执行的指令在段中的偏移量。
CS:IP:指向接下来要执行的指令的物理地址。
在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=FFFFH,P=0000H,
即在 8086PC 机刚启动时,CPU 从内存 FFFFOH 单元中读取指令执行,
FFFFOH单元中的指令是8086PC机开机后执行的第一条指令。
8086机中,任意时刻,CPU将 CS:IP 指向的内容当作指令执行。.
执行过的一段信息对应的内存单元必然被 CS:IP 指向过。
图 2.10 展示了 8086CPU 读取、执行指的工作原理(图中只包括了和所要说明的问题密切相关的部件,图中数字都为十六进制)。
图2.10说明如下。
- 8086CPU当前状态:
CS
中的内容为2000H
,IP
中的内容为0000H
; - 内存
20000H
~20009H
单元存放着可执行的机器码; - 内存
20000H
~20009H
单元中存放的机器码对应的汇编指令如下。
地址 | 内容 | 长度 | 对应汇编指令 |
---|---|---|---|
20000H ~20002H | B8 23 01 | 3Byte | mov ax,0123H |
20003H ~20005H | BB 03 00 | 3Byte | mov bx, 0003H |
20006H ~20007H | 89 D8 | 2Byte | mov ax,bx |
20008H ~20009H | 01 D8 | 2Byte | add ax,bx |
下面的一组图(图2.11~图 2.19),以图 2.10 描述的情况为初始状态,展示了8086CPU读取、执行一条指令的过程。注意每幅图中发生的变化(下面对 8086CPU 的描述,是在逻辑结构、宏观过程的层面上进行的,目的是使读者对 CPU 工作原理有一个清晰、直观的认识,为汇编语言的学习打下基础。其中隐蔽了 CPU 的物理结构以及具体的工作细节)。
总结 8086CPU的工作过程可以简要描述如下:
- 首先:
CS
和IP
送入地址加法器,得到CS:IP
。
例:CS
= 2000h,IP
= 0000h
CS:IP = CS * 16 + IP
CS:IP = 2000h * 16 + 0000h ;16进制数 *16 等于左移1位。(进位了嘛)
CS:IP = 20000h + 0000h
CS:IP = 20000h
- 到
20003H
~20005H
获取mov bx, 0003H
执行, IP=IP+3 - 到
20006H
~20007H
获取mov ax,bx
执行, IP=IP+2 - 到
20008H
~20009H
获取add ax,bx
执行, IP=IP+2
2.11 修改 CS、IP 的指令
在 CPU 中,程序员能够用指令读写的部件只有寄存器,通过改变寄存器中的内容实现对 CPU 的控制。程序员改变CS、IP 就实现了控制 CPU执行目标指令。
mov
不能修改 CS
、IP
它有专用的指令如:jmp
指令 | 说明 |
---|---|
jmp 2AE3:3 | 用给定的地址修改CS ,IP 执行后: CS =2AE3H ,IP =0003H 。 |
jmp ax | 用寄存器ax 中的值修改IP 执行前: ax=1000H ,CS=2000H ,IP=0003H 执行后: ax=1000H ,CS=2000H ,IP=1000H |
CPU将从修改后的地址读取指令。
2.12 代码段
在2.8 段的概念中我们知道了什么是段。
那么这段内存中如果存放的是指令,我们认为代是个代码段。
但它本质还只是内存中的一堆01
,当CS:IP
指向它,CPU就会把它当指令来执行。
例:
mov ax, 0000 (B8 00 00)
add ax, 0123H (05 23 01)
mov bx, ax (8B D8)
jmp bx (FF E3)
这段长度为 10个字节的指令,存放在 123B0H~123B9H
的一组内存单元中。
假如(使用 jmp)将CS:IP
设置为123B:0000
(指向了代码段中的第一条指令的首地址)。CPU就会执行它了。
2.9~2.12 小结
- 段地址在8086CPU的段寄存器中存放。当8086PU要访问内存时,由段寄存器提供内存单元的段地址。8086CPU有4个段寄存器,其中CS用来存放指令的段地址
- CS存放指令的段地址,IP存放指的偏移地址。8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行
- 8086CPU的工作过程:
- 从
CS:IP
指向的内存单元
读取指令
,读取的指令进入指令缓冲器
IP
指向下一条指令;- 执行指令。(转到步骤1,重复这个过程。)
- 从
- 8086CPU提供转移指令修改CS、IP的内容。