浅谈地址和储存

    我们在学计算机导论的时候,有在讲诺伊曼架构和哈佛架构,这两种架构贯穿了整个计算机硬件,无论这个产业怎么变化,你今天速度达到多少G,64位的寻址能力已经达到多多少啦,几核的芯片又出来啦,这都没关系,本质还是一样的,都是一个CPU通过三总线与外设构成的一个系统。所以要说这个产业天天变,其实也没本质的东西也没变多少。
  
   早期的计算机速度很慢,无论是我CPU还是外设,都是乌龟或者蜗牛。后来经过一段时间的发展,CPU突然迅速成长起来了,它变成了飞毛腿君。早期大家都很慢,直接接在同一总线上,但是后来的我们的储存已经跟不上CPU的速度了,于是我们把CPU和储存分开来接,CPU的时钟通过倍频与外设通信。电脑主板里面高速外设和低速外设分别接在南桥北桥就是这个道理。在PC主板上稍微复杂,但是大家看一下51的内部结构图就会发现,我们的CPU和中断控制器中间没有桥芯片,直接连在一起了,而定时器与CPU之间有一BUS,因为中断的相应对实时性要求高,而定时器则没有严格的要求。
   在CPU的速度飞速提升的同时,我们储存器的结构也在提升,但很遗憾,储存器的速度远没有跟上CPU的速度,所以为了满足告诉CPU的需求,人们开始对储存器用了分级的策略。最快的高速缓存最厉害,它速度很快,可以直接跟CPU连在一起,同样告诉的还有寄存器,它属于CPU内部(有些寄存器有特殊功能,比如说X86 的EIP CR,ARM的PC SP等等)。接下来次一点的就有我们的RAM ROM 。更次的就是磁盘了。从上往下,速度和容量一次递减。这样做有什么好处?386没有高速缓存,而486带了高速缓存,这点不一样,带来了十倍甚至更高的性能。为什么呢。因为计算机对内存的读写很慢,如果每次我们访问一个变量,比如说对变量赋值都要去读写一遍内存,那么CPU的速度就会被大大拖慢,而很不幸,我们的程序百分之90的时间时间都是耗在了循环上,比如说for (count = 0 ;count < MaxCount ;count ++);这样的语句,我们就要对count读写操作 MaxCount次,如果没有告诉缓存,就会造成对内存的多次读写,这是无法接受的。但是有了告诉缓存,情况会是这样的:如果我们上一次访问的是count,在这一次访问的还是count (命中)那么count 的读写就会在高速缓存里面完成,等到第MaxCount 完了之后我们再把结果回写,这样就能大大提升程序执行的速度了。(注意一点:计算机启动的时候高速缓存是不打开的)。缓存是一种很有用的思想(啊哈哈我更愿意把这个看成是设计思想而不是技术),这个思想被设计到了LINXU里面,LINXU操作磁盘的时候速度快,一大因素就是LINXU划分出来一个RAM缓冲区,作为磁盘数据的缓存,在关机的时候就会执行sync把最终的数据回写。这个缓存的思想同样可以在我们写程序的时候用到,比如说写单片机程序的时候,我们可以划分一个RAM去出来给循环用(注:单片机的数据段(RW段)在RAM内,程序段(RO段)在ROM内)。
  在解决了储存速度的同时,我们还要解决的是储存大小问题。这是一个复杂的问题,因为我们程序体积爆炸性增长的同时,我们的储存并没能相应增长。于是出现了虚拟内存的技术。这时候MMU登场了。
  MMU解决的一大问题就是内存和地址的关系。有的小伙伴一提到地址就与内存对等起来,一提到IO就与管脚对等起来。这个是不大合适滴。
  这样字来说一块内存(物理的)就是一大堆半导体做成的矩阵 ......额.....不对,咱们把戴维南定理拿过来用一用吧(不要惊讶呀小伙伴,知识是相通的)。我们来把内存卡看作是一个黑匣子,黑匣子有一个输入端输入地址,一个输出端输出数据,而我们每输入一个地址都会对应一个输出数据,这个就是映射啦,当然不是地址和数据的映射,而是每输入一个地址,就选择对应的最小储存单元(大概就是一大堆半导体小开关010101^_^),这个最小单元对应一个数据,所以说,地址是内存的映射。在说明白一点,说这么个技术,我们在ARM里面0地址本来是ROM的,经过地址重映射可以把0地址和RAM对应起来,也就是说刚开始我们访问0地址明明是访问ROM ,最后地址重映射之后,访问0就变成了访问RAM。

  再说得明白一点, 地址和内存(物理的)之间是一个映射关系,从地址到储存的映射。什么叫映射?小伙伴!如果你问这个问题,你的高数一定没有学好哈哈哈。
  既然是一个映射,我们就可以把它说成是一个函数,这个函数的自变量是地址,因变量是储存。就像这样:

    令addr  = x ,mem = y.

    然后我们通过某种方式来建立一个函数关系式,最简单的函数关系式就是直接使用物理地址,也就是y = x;像是这样,我们访问0x00012这个地址就是访问储存里卖弄0x00012这个储存单元。当然,这个映射关系(函数关系式)是我们通过某种方式建立起来的,我们也可以通过某种方式改变它。这个某种方式叫做MMU,Memory Manage Unite储存器管理单元。

    这时候我们就可以随意改变这个函数关系,达到分配地址的目的。比如说,我以段的方式来管理,那么这个函数关系式应该就是这样:

                    y= x + base;

这个base就是一个基址,可以通过一些手段(描述符)来确定的。这时候,假设这个base被设置为0x30000000那么我们再来访问0x00012这个地址的时候,实际上就是访问0x30000012这个地址。

我们还有页的方式来管理内存。那时候我们也会建立新的函数关系,原理都一样。

  另外MMU的出现解决了一个内存空间的问题,所有进程可以通过它得到完整的地址,什么是完整的地址呢?比如说,如果我们的51的地址能达到16位,也就是有64K的寻址能力,那么我们可以通过MMU让每个进程得到64K的地址。实现的方法就是,地址的重映射,如果进程A访问0xffff这个地址,那么MMU想法设法给A一个没有使用过的空间然后告诉A这是0xffff。如果所有的地址都被使用,那么就把一些进程使用到的空间备份到磁盘,然后腾出来空间。(这其中涉及到一些页面分配的算法详情见微机原理和操作系统原理两门课程)。
  MMU的出现还提供了内存保护的基础,但是这个是操作系统内核的内容,有兴趣可以看《现代操作系统》,或者上网查查资料,或者戳我,或者等我下次有时间出来跟大家探讨探讨。

  总结完最重要的储存,还有外设,中断控制器啦,IO端口控制器啦,这些都不大难。但还是有好多小伙伴看到“外设地址空间”或者是“IO地址空间“的时候比较迷糊。需要说一下。

   CPU读到一个机器码,然后,解释这个机器码,如果说这个机器码是OUT指令,那么CPU就会向特定的控制器寄存器(注意,不是CPU的寄存器)写一个命令,既然是一个写访问,那么这个控制寄存一定需要地址,好让我们能找到他,不然这个命令写给谁啊?这个控制器寄存器就被分配到某个地址上面去。分配到某个地址上面去,这个怎么理解?说实话,对某个地址的访问,计算机不会管你是ROM RAM 还是什么其他的东西,它只是在地址总线上输出一个地址,控制总线上面输出相应的控制信号,谈后再从数据总线上面进行读写。所以小伙伴们不要说IO又不是内存,怎么能酱紫!这个控制命令就是这样,被送到了控制寄存器去,然后外设就会自己完成相应的功能,比如说IO输出高电平什么的。这个是外设的事情,我们不用管,它会自动完成的,比如说IO口的施密特触发器会完成这个工作,只要给一个触发信号。

  基本上就这么多了。好了,我要睡觉。明天去图书馆战高数。

你可能感兴趣的:(浅谈地址和储存)