文章目录
- 前言
- 一、什么是寄存器
- 二、8086寄存器
- 1. 8086通用寄存器
- 2. 段寄存器
- 3.专用寄存器
- 3.1 标志寄存器内部具体标志及其作用
- tips: 不同尺寸数据在存储器中存储
- 三、 实模式存储器寻址
- 逻辑段与小段
- 物理地址计算方式
前言
本文以清华大学出版社的《80x86汇编语言设计》和李忠、王晓波、余洁老师的《x86汇编语言 从实模式到保护模式》为参考,附其他补充。
一、什么是寄存器
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个锁存器或触发器可以构成N位寄存器。
- 按功能划分,寄存器主要分为基本寄存器和移位寄存器两大类。基本寄存器只能并行送入数据,并行输出。移位寄存器中的数据可以在移位脉冲作用下依次逐位右移或左移,数据可以串/并型输入输出
- 程序员可见的寄存器可以分为通用寄存器、专用寄存器和段寄存器。
由于16位/32位CPU为MCU中CPU的两个重要代表,此文只介绍它们内部寄存器的名称及其主要功能
二、8086寄存器
8086是Intel公司第一款16位处理器,诞生于1978年。
其占有很重要的地位,是整个 Intel 32位架构处理器(IA—32)的开山鼻祖。
- 下图为80x86的程序可见寄存器组,8086的所有寄存器都为16位(透明区域),E指Extra
- 下图为8086内部组成框图
1. 8086通用寄存器
8086 处理器内部有8个16位的通用寄存器,分别被命名为AX、BX、CX、DX、SI、DI、BP、SP。“通用”的意思是,它们之中的大部分都可以根据需要用于多种目的。
- 4个数据寄存器(AX、BX、 CX和DX)
AX(Accumulator)寄存器称为累加器 | 使用频度最高用于算术、逻辑运算以及与外设传送信息等 |
BX(Base Address Register)寄存器称为基址寄存器 | 常用于存放存储器地址 |
CX(Count Register)寄存器称为计数器 | 一般作为移位指令、 循环和串处理指令中用作隐含的计数器 |
DX(Data Register)寄存器称为数据寄存器 | 常用来存放双字数据的高16位,在进行乘、除运算时,它可作为默认的操作数参与运算,亦可存放外设端口地址 |
-
2个变址寄存器 (SI和DI)
寄存器SI和DI称为变址寄存器(Index Register), 主要用于存放某个存储单元的偏移地址。- SI(Source Pointer)是源变址寄存器,DI(Destination Index)是目的变址寄存器
- 在字符串操作中,SI和DI都具有自动增量或减量的功能。它们主要用于存放存储单元段内的偏移量,用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
-
2个指针寄存器(SP和BP)
- SP(Stack Pointer)为堆栈指针寄存器,用于存放当前堆栈段中栈顶的偏移地址;
- BP(Base Pointer)为基址指针寄存器,用于存放堆栈段中某一存储单元的偏移地址。
值得一提的是, 在16位CPU(8086/8088/80286)中,AX、CX和DX不 能作为基址和变址寄存器来存储器寻址。
但在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX 不仅存放数据、也可存放地址,即这些寄存器都可以用于存储器寻址,所以,这些32位寄存器更具有通用性。
2. 段寄存器
段寄存器本质其实也是一种专用寄存器,它专用于存储器寻址,用来直接或间接地存放段地址。
段寄存器长度为16位。在80286之前,段寄存器只有四个:
- 代码段寄存器:CS
- 数据段寄存器:DS
- 堆栈段寄存器:SS
- 附加数据段寄存器: ES
段寄存器来确定该段在内存中的起始地址。
从80386开始增加了FS和GS。
3.专用寄存器
-
IP(Instruction Pointer)指令指针寄存器:8086CPU中的指令指针,它总是保存下一次将要从主存中取出指令的偏移地址,偏移地址的值为该指令到所在段段首址的字节距离。IP与段寄存器CS联用确定下一条指令的物理地址。
在程序运行时,IP的内容由微处理器硬件自动设置,程序不能直接访问IP。计算机用IP寄存器来控制指令序列的执行流程的,因此IP寄存器是计算机中很重要的一个控制寄存器。 -
SP( Stack Pointer ) 堆栈指针寄存器:它与堆栈段寄存器SS联用确定堆栈段中栈顶的地址。SP用来存放栈顶的偏移地址。
-
( FLAGS / PSW )标志寄存器:存放条件码标志、控制标志和系统标志的寄存器。
80386及其后续机型也有3个32位专用寄存器,它们分别是EIP 、ESP、EFLAGS。它们的作用和相应的16位寄存器相同。
3.1 标志寄存器内部具体标志及其作用
下图为8086中16位FLAGS寄存器
- 条件码标志(或状态标志) 用来记录程序运行结果的状态信息,许多指令的执行都将相应地设置它。
- 控制标志和系统标志 可由程序根据需要用指令设置,用于控制处理器执行指令的方式。
下列讲几个常见的标志作用(此处为16位机器):
- 零标志ZF(Zero Flag):若运算结果为0,则ZF = 1,否则ZF = 0。
例如:3AH + 7CH=B6H,结果不是零:ZF = 0;86H + 7CH=(1)00H,结果是零:ZF = 1。 - 符号标志SF(Sign Flag):运算结果最高位为1,则SF = 1;否则SF = 0。
例如:3AH + 7CH=B6H,最高位=1:SF = 1;86H + 7CH=(1)00H,最高位=0:SF = 0。
有符号数据利用最高有效位表示数据的符号。所以,最高有效位就是符号标志的状态 - 奇偶标志PF(Parity Flag):当运算结果最低字节(8位二进制)中“1”的个数为零或偶数时,PF = 1;否则PF = 0。
例如:3AH + 7CH=B6H=10110110B,结果中有5个1,是奇数:PF = 0。
注意:PF标志仅反映最低8位中“1”的个数是偶或奇,即使是进行16位字操作。 - 溢出标志OF(Overflow Flag):若算术运算的结果有溢出,则OF=1;否则 OF=0。
- 陷阱标志TF(Trap Flag):用于控制处理器是否进入单步操作方式:设置TF=0,处理器正常工作;设置TF=1,处理器单步执行指令。
- 单步执行指令——处理器在每条指令执行结束时,便产生一个编号为1的内部中断。这种内部中断称为单步中断,所以TF也称为单步标志。利用单步中断可对程序进行逐条指令的调试。这种逐条指令调试程序的方法就是单步调试。
以下为DEBUG时符号表示某些标志位的值
标志名 | 标志为1 | 标志为0 |
---|---|---|
OF溢出(是/否) | OV | NV |
DF方向(减量/增量) | DN | UP |
IF中断(允许关闭) | EI | DI |
SF 符号(负/正) | NG | PL |
ZF零(是/否) | ZR | NZ |
AF辅助进位(是/否) | AC | NA |
PF奇偶(偶/奇) | PE | PO |
CF进位(是/否) | CY | NC |
tips: 不同尺寸数据在存储器中存储
计算机存储信息的基本单位是1个二进制位,一位可存储一个二进制数:0或1。每8位组成一个字节。计算机字长有8位(字节)、16位(字)、32位(双字)、64位(四字)。
- 字节:8个二进制位,D7~D0。(位编号)
- 字:16位,2个字节,D15~D0。
- 双字:32位,4个字节,D31~D0。
- 四字:64位,8个字节,D63~D0。
在存储器里以字节为单位存储信息。,每个字节单元都有一个唯一的存储器地址,称为物理地址。
存储器的物理地址空间呈线性增长(从0开始编号,依次加1),在机器里地址也是用二进制数来表示,用无符号整数来表示,书写格式为16进制。
存储单元的内容:一个存储单元中所存放的二进制信息。
对于8086,其为小端对齐,故存储一个字要占用相继的两个字节,低位字节存入低地址,高位字节存入高地址(大端存储则反之),字单元地址用它的低地址来表示。
如下图为8086存储0x5678、0x1234方式(常见的PC机器、Linux、龙芯都是小端对齐)
字或双字或4字单元地址用它的最低地址来表示
- 一个字节的内容是该字节单元内存放的二进制信息;
- 一个字的内容是该字地址所指向的单元及其后继一个单元的内容组成;
- 一个双字的内容是该字地址所指向的单元及其后继三个单元的内容组成。
机器以偶地址或4的整数地址倍访问(读/写)存储器
三、 实模式存储器寻址
实模式:(即实地址访问模式)它是Intel公司80286及以后的x86(80386,80486和80586等)兼容处理器(CPU)的一种操作模式。实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是2的20次幂(1M)的可访问内存空间(物理内存和BIOS-ROM)
在理解为什么8086采用特殊的寻址方式之前,我们需要理解16位代表什么:
概括地讲,16位结构(16位机、字长为16位等常见说法,与16位结构的含义相同)描述了一个CPU具有下面几方面的结构特性。
- 运算器一次最多可以处理16位的数据;
- 寄存器的最大宽度为16位;
- 寄存器和运算器之间的通路为16位。
8086是16位结构的CPU,这也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位CPU,能一次性处理、传输、暂时存储16位的地址。而8086/8088的地址总线是20位,它最大可寻址空间为2^20=1M字节(实际上,实模式就是为8086/8088而设计的工作方式,后续为了兼容才继续保留了实模式)
那么在16位字长的机器里怎么提供20位地址? —— 存储器地址分段存储
以下为20位地址总线可寻址的范围(2^20=1M)
在1MB字节的存储器里,每个存储单元都有一个唯一的20位地址,称为存储单元的物理地址。CPU访问存储器时,必须先确定要访问存储单元的物理地址,才能取得或存入该单元中的内容。20位物理地址是由16为段地址和16偏移地址组成。其中段地址是指每一段的起始地址(又称段基地址),偏移地址(也称为有效地址EA:Effective Address )是在段内相对于起始地址的位移量offset(或距离)。有了段地址和偏移量,就能唯一地确定某一内存单元在存储器内的具体位置
逻辑段与小段
- 逻辑段:在不允许段之间重叠的情况下,每个段的最大长度是64KB(因为16位,216=64K),因为偏移地址也是16位的,从0000H到FFFFH。在这种情况下,1MB的内存,最多只能划分成16个段(220% 216=16),每段长64KB,逻辑段地址分别是0000H、1000H、2000H、3000H,···,一直到F000H。
- 小段:机器规定:从0地址开始,每16个字节为一小段。段不能起始于任意(物理)地址,必须从任一小段的首地址开始。
上图中蓝色地址即20位寻址空间中小段的首地址。其特征是:在十六进制表示的地址中,最低位为0(即20位地址的低4位为0)。这样,省略低位0,段起始地址也可以用16位数据表示,通常被保存在16位段寄存器中。
在1MB的地址空间里,共有64K个小段地址。
每个逻辑段可以独立占用64KB存储区。实际上,可以根据实际需要来确定段的大小,它可以是1B、100B、1000B或在64KB范围内的任意字节,各段也允许重叠。当然每个存储单元的内容是不允许发生冲突的,所谓重叠只是指每个段区的大小允许根据实际需要来分配,而不一定要占用64KB的空间。一般情况下,各段在存储器中的分配是由操作系统完成的。但是,
系统允许程序员在必要时指定所需占用的内存区。
物理地址计算方式
由于规定(物理)段地址必须是小段首地址,即是16的倍数,所以,其值的一般形式为:XXXX0H,即:前16位二进制位(有效地址)是变化的,后四位是固定为0。鉴于段地址的这种特性,我们可以仅保存其前16位二进制来达到保存整个段地址,其后四位可通过“左移补0”来获得。在确定了某个存储单元所属的内存段后,要想确定内存单元的具体位置,还必须知道该单元离该段地址有多远。即段内偏移量。
即物理地址为物理地址((PA—Physical Address)=段地址(此处指有效地址)×16(即十六进制数后加一个0) + 偏移量
值得强调的是,段地址必须以16的倍数起始是指物理地址,有时表示的段地址并未以XXXX0H格式,而是以XXXXH(有效地址)格式展示,这并未错误,但对初学来说确实容易引起困惑