文章目录
前言
对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件,可通过改变各种寄存器中的内容来实现对CPU的控制。
不同CPU的寄存器的个数与结构是不同的。8086CPU有14个寄存器:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
一、通用寄存器
8086CPU的所有寄存器都是16位的,可存放两个字节。AX,BX,CX,DX这四个寄存器通常用来存储一般性的数据,称为通用寄存器。
8086CPU的每个通用寄存器都可以分离为两个独立的8位寄存器(高8位和低8位)来使用。
AX可分为AH和AL
BX可分为BH和BL
CX可分为CH和CL
DX可分为DH和DL
出于兼容性的考虑,8086CPU可以一次性处理以下两种尺寸的数据:
字节(byte),可寄存在8位寄存器中。
字(word),由两个字节组成,分别称为这个字的高位字节和低位字节。
任何数据,在计算机中都以二进制的形式存储。为了描述不同的问题,常常将它们用其他的进制来表示,如0100111000100000可表示成4(0100)、E(1110)、2(0010)、0(0000)四位十六进制数。计算机中一个内存单元可存放8位数据,CPU中的寄存器又可存放N个8位数据,也就是说,计算机中的大多数数据是由1~N个8位数据构成的,用十六位数据来表示可以更直观地看出组成数据的各字节数据的值,因此后面我们多用十六进制来表示一个数据。为区分不同的进制,在十六进制数后加H,在二进制数后加B,十进制数后什么也不加。如:
十进制:20000
二进制:0100111000100000B
十六进制:4E20H
二、mov,add与sub指令
1.mov
mov是数据传送指令,用于将数据从一个位置复制到另一个位置。例如:
mov ax,18
表示将18送入寄存器AX,指令执行成功后AX的值变为0012H。
注:在写一条汇编指令或一个寄存器的名称时不区分大小写
2.add与sub
add用于将目标寄存器与某个数据或某特定寄存器中的数据相加,并将结果保存在目标寄存器中;
sub则是令目标寄存器减去某个数据或某特定寄存器中的数据,并保存结果于目标寄存器中。
例如:
初始时AX=0012H(18),BX=0101H(257),CX=2233H
add ax,78
执行成功后AX=0060H(96)
add bl,al
执行成功后BX=0161H(将AX的低8位加至BX的低8位)
sub ch,11H
执行成功后CX=1133H
sub bl,ch
执行成功后BX=0150H(将BX的低8位减去CX的高8位)
若AX=0083H,在成功执行add al,81H指令后,AX的值为多少?
首先83H加上81H的结果是104H,但是al是8位寄存器,只能存放两位十六进制数据,所以最高位的1丢失,此时AX的数据应为:0004H(这里的“丢失”指的是进位值不能在8位寄存器中保存,但是CPU并不是真的丢弃这个进位值
)
因为此时al是作为一个独立的8位寄存器来使用的,和ah并没有关系,CPU在执行这条指令时认为ah和al是两个不相关的寄存器。不要错误地认为此类指令产生的进位会存储在ah中。
注:进行数据传送或运算时,要注意指令的两个操作对象的位数是一致的
如(以下都为错误指令):
mov ax,bl(在8位寄存器与16位寄存器之间传送数据)
mov bh,ax(在16位寄存器与8位寄存器之间传送数据)
mov al,20000(8位寄存器最大可存放255的数据)
add al,200H(将一个高于8位的数据加到一个8位寄存器中)
三、物理地址
CPU在访问内存单元时,要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们称这个唯一的地址为物理地址。
1.16位结构的CPU
8086是典型的16位结构的CPU,其具有以下几方面的结构特性:
- 运算器一次最多可以处理16位的数据
- 寄存器的最大宽度为16位
- 寄存器和运算器之间的通路为16位
2.8086CPU给出物理地址的方法
内存单元的地址在送上地址总线之前,必须在CPU中处理,传输,暂时存放。8086CPU有20位地址总线,可传达20位地址,达到1MB寻址能力。但8085是16位结构,在内部一次性处理、传输。暂时存储的地址为16位,如果只是将地址从内部简单地发出,那么它只能送出16位的地址,寻址能力只能达到64KB。8086CPU采用一种在内部用两个16为地址合成的方法来形成一个20位的物理地址。
当8086CPU要读写内存时:
1)CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
2)段地址和偏移地址通过内部的总线送入一个称为地址加法器的部件;
3)地址加法器将两个16位地址合成位一个20位的物理地址;
4)地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
5)输入输出控制电路将20位物理地址送上地址总线;
6)20位物理地址被地址总线送到存储器。
在上面第3步中,地址加法器采用物理地址=段地址*16+偏移地址的方法用段地址和偏移地址合成物理地址。例如,8086CPU要访问地址为123C8H的存储单元,此时地址加法器的工作过程如图所示:
3.“段地址*16+偏移地址=物理地址”的本质含义
“段地址16+偏移地址=物理地址”的本质含义是:CPU在访问内存时,用一个基础地址(段地址16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。即基础地址+偏移地址=目标地址。例如,假定学校、体育馆与图书馆处在同一条直线上,以我们所在的学校为基点,图书馆的地址可以描述为:从学校走2000m到图书馆,也可描述为从学校走1200m到体育场,再走800m到达图书馆。从该例子上看,2000m便是目的地址,也可认为“物理地址”,1200m可认为成“基础地址”,即“段地址*16”,800m则可认为是“偏移地址”。8086CPU就是如此描述物理地址的。
4.段的概念
“段地址”名称中虽包含了段,但内存本身并没有被分段,段的划分来自于CPU。由于CPU用“段地址*16+偏移地址=物理地址”的方式给出内存单元物理地址,使我们可以用分段的方式管理内存。
如上图,我们可以以10000H作为基础地址,将10000H ~ 100FFH作为一个段,段地址为1000H,大小为FFH;我们也可以以10000H和10080H作为基础地址,将10000H ~ 100FFH分为两个段,段地址为1000H和1008H,大小都为80H。
四、段寄存器
前面讲到,8086CPU在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。这里,段地址在8086CPU的段寄存器中存放。8086CPU有4个段寄存器:CS、DS、SS、ES。当CPU要访问内存时由这4个段寄存器提供内存单元的段地址。
1.CS和IP
CS、IP是8086CPU中最关键的寄存器,CS为段寄存器,IP为指针指令寄存器。
在8086机的任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存M*16+N单元开始,读取一条指令并执行。
换句话说,8086机中,任意时刻,CPU将CS:IP指向的内容当做指令执行。
如上图,在CS=2000H,IP=0000,CPU将从2000H+0000H处开始读取指令。
CS、IP的内容送入地址加法器。
地址加法器将物理地址送入输入输出控制电路。
输入输出控制电路将物理地址20000H送上地址总线。
从内存20000H单元开始存放的机器指令B8 23 01通过数据总线被送入CPU。
输入输出控制电路将机器指令B8 23 01送入指令缓冲器。
IP中的值自动增加。
执行控制器执行指令B8 23 01。
指令B8 23 01被执行后AX中的内容为0123H。
通过上面的过程展示,8086CPU的工作过程可以简略描述如下:
- 从CS:IP指向的内存单元读取指令、读取的指令进入指令缓冲器。
- IP=IP+所读取的指令长度,从而指向下一条指令。
- 执行指令,转到步骤(1),重复这个过程。
在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=FFFFH,IP=0000H,即在8086机刚启动时,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令是8086机开机后执行的第一条指令。
在上一章中我们讲过,在内存中,指令和数据没有任何区别,都是二进制信息。那么CPU根据什么将内存中的二进制信息看做指令?现在我们可以知道,CPU将CS:IP指向的内存单元中的内容看做指令如果说,内存中的一段信息曾被CPU执行过的话,那么,它所在的内存单元必然被CS:IP指过。
2.jmp指令
我们现在知道,CPU从何处执行指令是由CS、IP中的内容决定的,那么,我们是否能够改变CS、IP中的值,从而控制CPU执行目标指令呢?
答案当然是可以的,我们可以通过jmp指令来达到这一目的。
若想同时修改CS.IP的内容,可用“jmp 段地址:偏移地址”的指令完成。如:
jmp 2AE3,3
指令执行成功后CS=2AE3H,IP=0003H,CPU将从2AE33H处读取命令。
若想仅修改IP的内容,可用“jmp 某一合法寄存器”的指令完成,其功能可表示为:用寄存器中的值修改IP,如:
执行前,AX=1000H,CS=2000H,IP=0003H
jmp ax
执行后,AX=1000H,CS=2000H,IP=1000H
3.代码段
对于8086PC机,在编程时,可根据需要,将一组内存单元定义为一个段,我们可以将长度<=64KB的一组代码,存放在一组地址连续、起始地址为16的倍数的内存单元中,我们可以认为,这段内存时用来存放代码的,从而定义了一个代码段。例如,将:
mov ax,0000(B8 00 00)
add ax,0123H(05 23 01)
mov bx,ax(8B D8)
jmp bx(FF E3)
这段指令存放在123B0H ~ 123B9H的一组内存单元中,我们就可以认为,这一段内存是用来存放代码的,是一个代码段。段地址位123BH。那么如何使得这段代码的指令被执行呢?首先,代码段仅仅只是我们自己的安排,CPU并不会因为这些安排而自动地执行这些代码,而是需要我们通过修改CS和IP的内容,使得CS:IP指向123B0H,CPU才会去执行这段代码。