接着上次的博客继续写,今天主要写内存空间地址、逻辑存储器
1.6 内存空间地址
上次我们说到CPU和内存的信息交互需要通过三种总线,其中地址总线是要去内存中找我们需要的地址,那么这个地址又是怎么找的呢?
这就需要另外一个概念,内存地址空间。
我们上次说,若CPU的地址总线宽度为N,它的寻址空间就为2的N次方Byte(一个内存单元为1Byte)。
我们以8086处理器来举例,它的地址总线的宽度为20,则可寻址2的20次方——1MB个内存单元,所以它的内存空间地址是1MB。
那么这些0到1MB的内存空间是怎么分配的呢?
这里需要结合一下内存的器件去看一下。我们都知道内存分为RAM和ROM两种。
RAM的特点是可读可写但缺电就没了;
ROM是在造这个东西的时候就直接写好了里面的东西,所以只能读取。
从功能分配上来讲,RAM里面存放的是计算机运行期间一直在动态变化的数据。而ROM里面存放的是计算机启动时就要用到的信息 或者其他固定的信息。
实际例子如下:
注:接口卡的意思是:由于CPU无法直接控制外设,比如显示器打印机什么的,这时候需要插在扩展插槽上的接口卡去受CPU的控制,从而控制外设。(这里我从网上了解的和书上有冲突,建议只在考试的时候这样写)
而接口卡上的BIOS意思是:因为你的显卡啊网卡啊什么的都是可以更换的,所以不可能在主板的系统BIOS上就把所有需要的信息都写好,即很多东西都有自己的BIOS。
以上所说的所有内容共同构成了这个内存地址空间。
1.7 逻辑存储器——统一编址
正如上面所说,整个电脑有太多太多存储器,每个器件上面都还有各自单独的存储器,这些都叫物理存储器。
我们为了方便管理,将所有的物理存储器在逻辑上都看做一个由若干个存储单元组成的逻辑存储器。
而每个物理存储器都在这个逻辑存储器中占有一个地址段,即一段地址空间。这样就做到了统一编址,即我们说一个地址,就能知道是哪个器件的哪一块东西。
还记得上次说总线的时候的寻址吗?CPU寻到的地址,就是我们现在说的统一编址后的地址。
我们还是以8086处理器来举例,看看它是如何分配的:
由图可知,从00000到9FFFF这共640K的空间,是给主存储器的(内存条等)。A0000(也就是9FFFF的下一位)开始,到BFFFF共128K的空间给显存。剩下的分配给ROM们,比如各种BIOS什么的。
这个是8086PC机的分配方案,换个其他的处理器可能就不是这样的分配了(毕竟本身从存储单元的数量上就不一样)。所以我们在写汇编语言的时候,要先了解了我们的目标机器的分配方案。
1.8 物理地址
上面两部分我们讲了CPU需要寻址的那个“址”是什么,有多大,怎么分配的?现在我们要说的是更细一点的,CPU在访问内存单元的时候是怎么样的。
我们还用上面的那张8086的内存空间地址图。可以看到,所有的内存单元构成了一个一维线性空间,而其中每个内存单元都在这个空间有唯一的地址,就叫做物理地址。
我们知道8086CPU有20位地址总线,寻址能力为1M。但是我们也知道8086是16位的CPU,也就是说它的运算器一次最多可以处理16位的数据(超过16位的数据就算溢出,就被舍掉了),寄存器的最大宽度为16(也就是字长)。
这就导致在8086CPU里面传输的、处理的、临时存放的地址,都必须是16位的。这样的限制就导致8086实际的寻址能力只有2的16次方——64KB。
这就好比考试的时候把答案给你放面前,但是由于你近视,只能看到离你最近的答案,导致你得的分数差了很多一样。
那么8086是如何解决这个问题呢?
8086给出了一个很完美的答案——用两个16位的地址合成一个20位的物理地址。
我们把这两个16位的地址分别叫做段地址和偏移地址。
8086总线接口中有一个元件叫做地址加法器,其用来负责合成物理地址:
- 物理地址 = 段地址 *16 + 偏移地址
我们用图片来解释
图中的基地址就是段地址变化后的地址。我们可以看到先是段地址向左移动了4位,相当于乘以2的4次方也就是16,这样就构成了20位地址,然后再加上16位的偏移地址,就成为了20位的物理地址。
这种计算方法我们用一个例子来看一下:
注意这里写的是16进制的数,16进制偏移一位就相当于2进制偏移4位。
那可能你也发现了,这看上去只是个错位加法而已。1+3=4,那2+2也等于4呢!那是不是说明物理地址是123C8的,也可以是123C+0008呢?
答案是肯定的。不仅如此,还可以是123B+0018等等。
所以说,并不是我们知道了一个内存单元的物理地址,就能够知道它的段地址和偏移地址,而是我们决定了段地址以后,可以通过适当的调整(偏移地址)来得出物理地址。
偏移地址可以看做是我们为了达到匹配宽度而引入的概念,那么什么又是段地址呢?这就要讲到内存的分段表示法了。
1.9 内存的分段表示
我们讲的确定物理地址的方法中的段地址,这个“段”字意思就是内存的分段。
这样来看的话,8086是把整个内存分成了很多的段,从而有了段地址,然后我们再依靠偏移地址,去确定该内存单元在这个段中的位置。这是求出物理地址方法的本质。
这里我们需要注意的是:内存本身并没有分段,它依然是一个线性的结构。对于段的划分其实是CPU自己干的事。
对于同一段内存,我们可以有多种分段的方案。
两张图都是表示的10000H到100FFH这个区间的物理地址。这个区间本身就是划分出来的一个段,它还可以变成很多段。
对于图一来讲,它的起始地址(基地址)是10000H,这是一个20位的地址。那么显而易见,段地址就是1000H。这个段的大小为100H。
图二基地址为10000H和10080H,段地址为1000H和1008H,大小均为80H。
这部分内容我们需要注意的两点是:
- 段地址 x 16 后,一定是16的倍数,所以一个段的起始地址也一定是16的倍数;
这样的特点是:就像我们任何十进制整数10以后,最后一位都是0,所以16进制数16后最后一位也都是0 - 偏移地址是16位的,寻址能力为64K,所以一个段的最大长度就是64K(因为偏移地址决定了在段中的哪个位置)
我们之前提到过,就和加法一样,得数相同可以导致两个加数有许多变化。那么我们怎么确定的表示一个地址呢?
如果你做过一些debug的实验,你应该见到过2000:1F60这样的地址。这个意思就是指数据存在21F60这个单元中,且段地址2000H,偏移地址为1F60. 还有一种叫法是:数据存在内存的2000H段中的1F60单元中。
段地址是一个非常重要的东西,所以CPU中专门有一个寄存器去存储它——段寄存器
学习汇编需要搭配实验,之后也会就实验去写一些博客,正在学习汇编的朋友可以关注一波~