一个典型的CPU由运算器、控制器、寄存器等器件构成,这些器件靠内部总线相连。第一章说的总线是外部总线。在CPU中:
- 运算器进行信息处理
- 寄存器进行信息存储
- 控制器控制各种器件进行工作
- 内部总线连接各种器件,在他们之间进行数据的传送
不同的CPU,寄存器的个数、结构是不相同的。例如8086CPU有14个寄存器,都是16位:AX, BX, CX, DX, SI, DI, SP, BP, IP, CS, SS, DS, ES, PWD。
2.1 通用寄存器
8086CPU中,AX, BX, CX, DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。以AX为例,其逻辑结构如图:
数据在寄存器中的存放情况如图:
8086CPU的上一代CPU中的寄存器是8位的,为了保证兼容,8086CPU的4个通用寄存器分为两个可独立使用的8位寄存器:
- AX可分为AH和AL
- BX可分为BH和BL
- CX可分为CH和CL
- DX可分为DH和DL
以AX为例:
2.2 字在寄存器中的存储
- 字节:Byte,一个Byte有8个bit,可以存放在8位寄存器中
- 字:word,一个字有2个Byte,这两个字节分别称为这个字的高位字节和低位字节
一个字可以存在一个16位寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高8位寄存器和低8位寄存器中。
2.3 几条汇编指令
通过汇编指令控制CPU进行工作,如图:
不区分大小写。
执行前AX:00C5H
执行前BX:4026H
执行:add al,93H
分析:
al中的数据位C5H,相加后得158H,但是al为8位寄存器,只能存放两位的十六进制数据,因此最高位的1丢失,ax中的数据位0058H。(丢失并不是CPU真的丢弃这个值)
此时的al是作为一个独立的8位寄存器来使用,和ah没有关系。
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的。
mov ax, bl 错,在8位寄存器和16位寄存器之间传送数据
mov al, 20000 错,8位寄存器最大可存放值位255的数据
add al, 100H 错,将一个高8位的数据加到一个8位寄存器中
2.4 物理地址
CPU访问内存单元时,要给出内存单元的地址。所有内存单元构成的存储空间是一个一维的线性空间,每一个内存单元都有唯一的地址,称为物理地址。
CPU通过地址总线送入的必须是一个内存单元的物理地址,在CPU发出物理地址之前,必须要在内部先形成这个物理地址。不同的CPU可以有不同的形成物理地址的方式。
2.5 16位结构的CPU
16位结构,即16位机、字长为16位,其含义都相同。都描述了以下几方面的特性:
- 运算器一次最多可以处理16位的数据
- 寄存器的最大宽度位16位
- 寄存器和运算器之间的通路为16位
即:8086是16位结构的CPU。在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位。内存单元的地址在被送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位CPU,能一次性处理、传输、暂时存储16位的地址。
2.6 8086CPU给出物理地址的方法
8086CPU有20位的地址总线,即1MB的寻址能力。但是内部一次性只能处理16位的,即64KB的寻址能力。因此8086CPU采用了两个16位地址合成一个20位物理地址的方法:
- CPU内的相关部件提供两个16位的地址,分别为段地址和偏移地址。
- 段地址和偏移地址通过内部总线送入一个地址加法器中。
- 地址加法器将两个16位地址合成一个20位的物理地址。
- 地址加法器通过内部总线将20位的物理地址送入输入输出控制电路。
- 输入输出控制电路将20位物理地址送上地址总线。
- 20位的物理地址被地址总线送到存储器。
地址加法器采用物理地址=段地址X16 + 偏移地址的方法合成20位物理地址。例如8086CPU要访问123C8H:
段地址X16意味着左移4位,指的是二进制位。
- 一个数据的二进制位形式左移N位,相当于该数据乘以2的N次方。
- 一个X进制的数据左移1位,相当于乘以X。
有关左移/右移的内容可看 CSAPP第二章中的2.1.9。
2.7 “段地址X16 + 偏移地址 = 物理地址”的本质含义
物理地址=SA x 16 + EA
2.8 段的概念
段地址中的“段”不是指内存被分为一个一个的段,每一个段有一个地址。内存并没有分段,段的划分来自于CPU。
以后编程需要时,可以将若干地址连续的内存单元看做一个段,用段地址X16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。
注意:一个段的起始地址一定是16的倍数;偏移地址位16位,16位地址的寻址能力为64KB,所以一个段的长度最大为64KB。
2.9 段寄存器
段寄存器提供段地址并存放段地址,8086CPU有4个段寄存器:CS、DS、SS、ES。
2.10 CS和IP
CS和IP是8086CPU中最关键的两个寄存器。它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器。
从书中展示的8086CPU工作过程可以简要描述如下:
- 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器。
- IP=IP+所读取指令的长度,从而指向下一条指令。
- 执行指令。重复以上步骤。
8086CPU加电启动或复位后(即CPU刚开始工作时),CS和IP被设置为CS=FFFFH,IP=0000H。FFFF0H单元中的指令是8086CPU开机后执行的第一条指令。
第一章讲过,在内存中,指令和数据没有任何区别,都是二进制信息。那么什么时候CPU将内存中的信息看做指令呢?答案就是CPU将CS:IP指向的内存单元中的内容看作指令。
2.11 修改CS、IP的指令
8086CPU大部分寄存器的值都可以通过mov
指令来改变,被称为传送指令。但是不能用来更改CS、IP的值。
能够更改CS、IP的内容的指令被统称为转移指令。先介绍一个最简单的jmp
指令。
同时修改CS、IP的内容,格式为:jmp 段地址:偏移地址:
jmp 2AE3:3
,执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H处读取指令
只想修改IP的内容,格式为:jmp 某一合法寄存器:
jmp ax
,指令执行前:ax=1000H,CS=2000H,IP=0003H。指令执行后:ax=1000H,CS=2000H,IP=1000H
该指令的功能为:用寄存器中的值修改IP。在含义上类似于:mov IP, ax。
适当的时候,我们会用“已知的汇编指令的语法”去描述新学习的汇编指令的功能。但是不代表其是正确的。比如:mov IP,ax。并不是说真的有这样的指令。注意区分。
2.12 代码段
在编程时,根据需要,可以将一组内存单元定义为一个段。例如我们可以将长度为N(N<=64KB)的一组代码,存放在一组地址连续、起始地址为16的倍数的内存单元中。
但是CPU不会认为这是一个代码段,这只是我们在编程时的一种安排。CPU只会将CS:IP指向的内存单元中的内容当做指令。 所以要想让CPU执行我们的指令,必须要将CS:IP指向所定义的代码段中的第一条指令的首地址。