2021-7-22~23 汇编语言 寄存器-CPU 的办事大厅【完成版】(炉边小坐)

一个 CPU 由运算器、控制器和寄存器组成,这些器件通过(内部)总线连接,在 CPU 中,运算器进行信息处理,寄存器实现信息储存,控制器控制各器件工作,而内部总线在其中传递信息,串联起三大元器件。

 对于一个程序员来说,CPU 的主要部分是寄存器,这是程序员可以通过指令来读写的部件。

不同的 CPU 寄存器个数也不同。现在主流寄存器是 32bit 的,8086CPU 寄存器是 16bit 的,AX,BX,CX,DX,这四个寄存器用于存放一般数据,被称为通用寄存器。以 8086CPU 的寄存器为例,一个寄存器可以储存 一个 16bit 的数据。

字在寄存器中的存储有两种方式,这两种方式都是基于兼容性的考虑:1、字节:记作 byte,一个字节有 8 个 bit组成可以存在于 8bit 寄存器内;2、字:记为 word,由高低两个字节组成,它可以存放在 16 位寄存器内。

关于“数”的讨论——从计算机的角度

我们知道计算机中的数据都是以二进制形式存放,比如一个数0100111000100000存放在 AX,它在 AX 里是一个数据,你也可以将它看作 20000。


当然,二进制数0100111000100000 本身也可表示一个数值的大小,但人类习惯的是十进制,用十进制20000表示可以使我们直观地感受到这个数值的大小。


十六进制数的一位相当于二进制数的四位,如 0100111000100000 可表示成:4(0100)E(1110)、2(0010)、0(0000)四位十六进制数。

由于一个内存单元可存放8位数据,CPU中的寄存器又可存放n个8位的数据。也就是说,计算机中的数据大多是由1~N个8位数据构成的。很多时候,需要直观地看出组成数据的各个字节数据的值,用十六进制来表示数据可以直观地看出这个数据是由哪些8位数据构成的。比如20000写成4E20就可以直观地看出,这个数据是由4E和20两个8位数据构成的,如果AX中存放4E20,则AH里是4E,AL 里是 20.这种表示方法便于许多问题的直观分析。在以后的课程中,我们多用十六进制来表示一个数据。为了区分不同的进制,在十六进制表示的数据的后面加 H,在二进制表示的数后面加B,十进制表示的数据后面什么也不加。如:可用3种不同的进制表示图2.4中AX里的数据,进制:20000,十六进制:4E20H,二进制:0100111000100000B.

下面介绍几条汇编指令,我们可以通过汇编指令控制 CPU工作

我将会用易于理解的高级语言解释这些指令。在写一条汇编指令或者一个寄存器名称时我们不区分大小写(这和 C 语言等高级语言不同)接下来看一下具体指令的作用。设:AX 中值为 000H;BX 中值为 000H;

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

? 

8226H

指令执行后AX中的数据为多少?思考后看分析。

程序段中的最后一条指令add ax,bx,在执行前axbx中的数据都为8226H,相加后 所得的值为:1044CH,但是ax为16位寄存器,只能存放4位十六进制的数据,所以最 高位的1不能在ax中保存,ax中的数据为:044CH。(注意这里是采用8086CPU 的环境,寄存器是 16bit) 

下面补充一点,前面说到 8086CPU 的寄存器是 16bit 的,这意味着它数据的存储是以字为单位的,意味着有高低字节之分,而 AX 的高字节为 AH,低字节则为 AL,AH 与 AL 构成 AX,其余同理。

2.3程序段中指令的执行情况之二

程序段中的指令

指令执行后AX中的数据

指令执行后BX中的数据

mov ax,001AH

001 AH

0000H

mov bx,0026H

001 AH(AL=1AH)

0026H(BL=26H)

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

?

4026H

指令执行后AX中的数据为多少?

程序段中的最后一条指令 add al,93H 在执行前,al中的数据为C5H,相加后所得的值为:158H,但是al8位寄存器,只能存放两位十六进制的数据,所以最高位的1丢失,也就是数据溢出了,但是我们看到,高字节不受低字节数据溢出影响,因为计算机认为 al 与 ah 是两个不相干的寄存器,因此ax中的数据为:0058Ho (这里的丢失,指的是进位值不能在8位寄存器中保存,但 CPU并不真的丢弃这个值,关于这个问题,我们后文再续。)再有,在进行数据传输和运算时,要注意指令的两个操作对象之位数应该是相同的。否则会报错。

8086CPU 是16 位机,而 8085 和 8080 却是 8 位机,我们主流的 CPU 如 intel 的酷睿 i7 和 Apple 的 M1 则都是 64 位机,什么叫 N 位机?或者是什么叫 N 位结果的 CPU?总的来说,含义为:运算器一次最多可处理 N 位数据;寄存器最大宽度为 16 位(最大可读 16 位的地址,宽度指的是控制总线的条数??存疑!读者知情可赐教);还有就是寄存器和运算器之间的通路为 16 位。

808616位结构的CPU,这也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。内存单元的地址在送上地址总线之前,必须在CPU 中处理、传输、暂时存放对于16CPU,能一次性处理、传输、暂时存储16位的地址。

8086CPU20位地址总线,可以传送20位地址8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。从8086CPU的内部 结构来看,如果将地址从内部简单地发出,那么它只能送出16位的地址。8086CPU釆用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

如图2.6所示,当8086CPU要读写内存时:

  1. CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
  2. 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
  3. 地址加法器将两个16位地址合成为一个20位的物理地址;
  4. 地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
  5. 输入输出控制电路将20位物理地址送上地址总线;
  6. 20位物理地址被地址总线传送到存储器。       ——《汇编语言》第三版 王爽

 地址加法器采用理地址=段地址X16+偏移地址的方法用段地址和偏移地址合成物理 地址。例如,8086CPU要访问地址为123C8H的内存单元,此时,地址加法器的工作过程 如图2.7所示(图中数据皆为十六进制表示)。

 妙啊!!在十六进制内,*16 相当于左移半个字节(4 个bit)这样就可以合成一个 20bit 的物理地址,8086CPU 通过这样来扩大物理储存空间,当然,这是以降低寻址效率为前提的。

有一个严重的问题,我不说也许你没有察觉,理地址=段地址X16+偏移地这条公式计算是搞懂了,那它的具体含义是什么?

“段地址X16+偏移地址=物理地址”的本质含义是:CPU在访问内存时,用一个基础地址(段地址X16),也就是参考系,和一个相对于基础地址的偏移地址(相对参考系定点的偏移量)相加,给出内存单元的物理地址。说到参考系和偏移量,大家应该就明白了。

举个毫不相干却可以理解的例子:有一款地图精确度十分差劲,你只能从地图上分辨出深圳市市府在福田区(基础坐标),却无法看出哪个是南山区(具体坐标),你很苦恼,但是还有解决办法,你知道福田区往西走 30 公里(偏移量)是南山,这样一比划,噢,你找到了目标,大概就是这样。

现在你大概理解了 8086CPU 的物理地址分配原理了,但是可能段地址中“段”这个概念大家还不是很懂。段是啥?把内存分成一段一段,然后每一段赋予一个地址吗?其实不太准确。内存是连续的,并没有分块,所谓对段的划分是由 8086CPU 物理地址给出方式划分的。

如上图所示,我们可以认为:地址10000H100FFH的内存单元组成一 个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H我们也可 以认为地址10000H1007FH10080H100FFH的内存单元组成两个段,它们的起始地址 (基础地址)为:10000H10080H,段地址为:1000H1008H,大小都为80H。我们在思考时可以将若干地址连续的内存单元看作一个段,用段地址X16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元。有两点需要注 意:段地址X16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;关于段地址的提供,即段寄存器的内容我们先按下不表。

前面说过,我们可以根据需要,将若干地址连续的内存单元看作一个段,而我们可以将长度为段大小的代码存入段内,我们即认为,这段内存是用于存放代码的,从而定义了一个代码段。代码段的功用我们先按下不表。

2021-7-25 补充:大部分为原书表述

前面讲到,8086CPU在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。这里,需要看一下,是什么部件提供段地址。段地址在8086CPU的段寄存器中存放。8086CPU4个段寄存器:CSDSSSES8086CPU要访问内存时由这4个段寄存器提供内存单元的段地址。我们只研究CS。

CSIP8086CPU中两个最关键的寄存器,它们指示了 CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器,从名称上我们可以看出它们和指令的关系。在8086PC机中,任意时刻,设CS中的内容为M, IP中的内容为N, 8086CPU将从 内存MX16+N单元开始,读取一条指令并执行。也可以这样表述:8086机中,任意时刻,CPUCS:IP指向的内容当作指令执行。

CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器 中的内容实现对CPU的控制。CPU从何处执行指令是由CSIP中的内容决定的,程序员可以通过改变CSIP中的内容来控制CPU执行目标指令。

我们如何改变CSIP的值呢?显然,mov指令不能用于设置CSIP的值,8086CPUCSIP提供了另外的指令来改变它们的值。能够改变CSIP的 内容的指令被统称为转移指令。我们现在介绍一个最简单的可以修 改CSIP的指令:jmp指令。

若想同时修改CSIP的内容,可用形如“jmp段地址:偏移地址”的指令完成,如

jmp 2AE3:3,执行后:CS=2AE3H, IP=OOO3H, CPU 将从 2AE33H 处读取指令。

jmp3:0B16,执行后:CS=OOO3H, IP=0B16H, CPU 将从 00B46H 处读取指令。

“jmp段地址:偏移地址”指令的功能为:用指令中给出的段地址修改CS,偏移地 址修改IP。

若想仅修改IP的内容,可用形如“jmp某一合法寄存器”的指令完成,如

jmp ax,指令执行前:ax=1000H, CS=2000H, IP=0003H

            指令执行后:ax=1000H, CS=2000H, IP=1000H

jmp bx,指令执行前:bx=0B16H, CS=2000H, IP=0003H

            指令执行后:bx=0B16H, CS=2000H, IP=0B16H

“jmp某一合法寄存器”指令的功能为:用寄存器中的值修改IP

jmp ax,在含义上好似:mov IP,ax

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值