3.2 内存组织和寻址
我们已经看到,触发器在需要记住一个位时很有用,寄存器在需要记住一组位时很方便。可当我们需要记住更多的信息时,应该使用什么呢?例如,如果我们希望存储几个不同的加法结果呢?
我们可以使用一大堆寄存器。但是现在我们遇到了一个新问题:如何指定要使用的寄存器,如图3-19所示。
图3-19 多个寄存器
解决这个问题的一种方法是为每个寄存器分配一个编号,如图3-19所示。我们可以根据第2.5.2节中的标准构件解码器使用编号或地址指定寄存器。解码器的输出与寄存器上的使能输入连接。
接下来,我们需要从寄存器中挑选出一个输出。幸运的是,第2.5.4节中已经介绍了如何构建选择器,这正是我们所需要的。
系统通常包括多个连接在一起的内存组件。现在来介绍另一个标准构件:三态输出模块。
把寄存器、选择器、解码器三者组合在一起即为一个内存组件,如图3-20所示。
图3-20 内存组件
内存组件有很多电气连接。如果想处理32位数字,我们需要输入和输出各32个连接,加上地址、控制信号和电源的连接。程序员不必关心如何将电路装入软件包或如何布线,但硬件设计师却需要关心。认识到一点:很少需要同时读取和写入内存,我们就可以减少连接的数量。我们可以简化为一组数据连接加上一个控制。图3-21为一个简化的存储芯片的示意图。使能控制可以打开和关闭整个设备,以便多个存储芯片可以连接在一起。
图3-21 简化存储芯片
你会注意到,图3-21中地址和数据使用了大而粗的箭头,而不是使用单个指示符号。我们把一组相关的信号称为总线,因此存储芯片有一个地址总线和一个数据总线。
封装存储芯片的一个挑战是当内存大小增加时,需要连接大量地址位。回顾第1章的表1-2,对于一个4GiB内存组件,我们需要32个地址连接。
内存设计者和道路规划师一样需要处理类似的交通管理问题。许多城市按网格规划,存储芯片内部布局的方式也是如此。在图2-3所示的CPU显微照片中可以看到几个矩形区域,它们是内存块。地址被分成两块:行地址和列地址。内存位置使用行和列的交集进行内部寻址,如图3-22所示。
图3-22 行寻址与列寻址
显然,我们不需要担心图3-22所示的16位内存中地址行的数量。但如果有更多的地址行数量呢?我们可以通过多路复用行地址和列地址将地址行数减半。我们需要的只是用存储芯片上的寄存器保存它们,如图3-23所示。
图3-23 使用地址寄存器的内存
由于地址分为两部分,因此如果只更改一部分,例如先设置行地址然后改变列地址,性能会更好。我们可以发现如今的大型存储芯片确实是这样的。
存储芯片的大小是以深度×宽度来描述的。例如,一个256×8的芯片有256个8位宽的内存位置,一个64 Mib×1的芯片有64个兆比特宽的内存位置。
3.2.1 随机存取存储器
到目前为止,我们所讨论的内存称为随机存取存储器(Random-Access Memory, RAM)。使用RAM,任何内存位置的整个宽度可以以任何顺序读写。
静态RAM或SRAM虽然成本很高但速度很快。每个位需要6个晶体管。因为这些晶体管占用不少的空间,SRAM并不是存储数十亿或万亿位的好选择。
动态内存(DRAM)是一个聪明的黑客。电子被储存在称为电容器的微型桶中,只使用一个晶体管作桶盖。问题是,这些存储桶可能泄漏电子,所以需要每隔一段时间刷新一次内存,这意味着需要定期将存储桶加满。你必须小心,不要在与访问内存发生冲突的时刻将存储桶加满;第一批基于DRAM的计算机DEC LSI-11就存在这样的问题。DRAM的一个有趣的副作用是,当光线照射到充满电子的存储桶时,它们会漏出更多的电子,这使得存储桶可以用在数码相机中。
DRAM由于其高密度(每个区域的位数)而被用于制作大容量存储芯片。大容量存储芯片意味着大量的地址,大量的地址意味着DRAM芯片使用前面讨论的多路寻址方案。由于其他内部设计考虑因素,使用行地址选通存储行地址,然后通过列地址选通改变列地址会更快。行有时被称为页,这是一个被过度使用的术语。读内存地址和阅读一本书差不多,浏览一页比翻页容易得多。正如伟大的表演先驱Jimmy Durante所言,最好的表演是a-ras-a-ma-cas。这是一个编程中非常重要的考虑因素:将一起使用的东西放在同一行可以大大提高性能。
SRAM和DRAM都是易失性存储器,这意味着当电源中断时,数据可能会丢失。磁芯存储器是一种古老的非易失性RAM,它将位存储在圆环形(甜甜圈形状)铁片中,如图3-24所示。圆环体在一个方向被磁化为0,另一个方向为1。圆环体的物理性质很酷,因为它们抵抗来自圆环外部电磁干扰的能力很强。在这种类型的存储器中,磁芯排列在一个称为平面的网格中,其中成行列的导线穿过它们。还有第三条线,叫作感知线,因为读取位的状态的唯一方法就是尝试改变位,然后感知发生了什么。当然,如果感知到位变了,就必须把它改回去,否则数据就会丢失,位就会变得毫无用处。除所有的拼接处外,实现这点还需要大量的电路。磁芯实际上是三维存储的,就像是多个平面被组装成积木一样。
图3-24 磁芯存储器
虽然磁芯是一种古老的技术,但它的非易失性仍然备受重视,研究人员还在继续开发商业化实用磁阻存储器,将磁芯存储器和RAM的优点结合起来。
3.2.2 只读存储器
只读存储器(Read-Only Memory, ROM)并不是一个非常准确的名字。只能读而不能写的存储器是没有用的。这个名字已经过时了,更准确的说法是一次写入存储器。ROM可以写入一次,然后读取多次。ROM对于那些需要内置程序的设备(比如微波炉)很重要,毕竟大家都不想每次爆米花时都要对微波炉现场编程。
ROM的早期形式之一是Hollerith卡(后被称为IBM卡),如图3-25所示。位被打散到一张纸上。IBM卡相当便宜,因为它的发明者赫尔曼·何乐礼(Herman Hollerith)(1860—1929)非常擅长“偷工减料”。
图3-25 IBM卡
19世纪末,Hollerith发明了Hollerith卡,更准确地说,他是从1801年约瑟夫·玛丽·雅卡尔(Joseph Marie Jacquard)发明的提花织机中汲取了灵感。提花织机用穿孔卡片来控制织布图案。当然,提花织机的创意来自Basile Bouchon,Basile Bouchon在1725年发明了穿孔纸带控制织机。有时很难区分发明和借鉴,毕竟未来就是建立在过去的基础上的。当听到有人主张延长专利和限制版权法时,请记住这一点:如果不能在前人的基础上再接再厉,人类的进步就会减慢。
早期的IBM读卡器使用开关来读取位。卡片会在一排有弹性的金属丝下面滑动,这些金属丝会穿过孔与另一边的金属接触。后来的IBM读卡器是通过孔将光线照射到另一边的一排光电探测器上,这样读卡器的运行速度会快得多。
穿孔纸带是一种与ROM相关的技术,一卷带孔的纸带可以用来表示位(见图3-26)。相比于卡片,纸带更有优势,弄丢一张卡片会使数据混乱,而纸带则不存在这个问题。不过,纸带可能会被撕裂,而且很难修复,许多修复过的纸带都会阻塞读卡器正常工作。
图3-26 穿孔纸带
卡片和纸带的速度非常慢,因为它们必须被移动才能被读取。
阿波罗飞行计算机使用了一种称为奥尔逊存储器的ROM变体(见图3-27)。因为它只能通过针脚写入,所以它不受干扰,在恶劣的太空环境中,不受干扰的特点很重要。
图3-27 阿波罗飞行导航计算机的奥尔逊存储器
IBM卡和纸带是顺序存储器,即数据是按顺序读取的。读卡器不能倒转,所以它们只适合长期存储数据。为了方便使用,内容必须被读入某种RAM中。1971年首次推出的商用单芯片微处理器英特尔4004,为更好的程序存储技术创造了需求。这些最初的微处理器用于运行固定程序的计算器等设备。在单芯片微处理器之后而来的是掩模式可编程只读存储器。掩模是集成电路制造过程中使用的模板。你需要编写一个程序,然后把位型和一张大额支票发送给半导体制造商。半导体制造商会把位型变成一个掩模,然后制造出包含程序的芯片。它是只读的,因为如果不写另一张大额支票且不做另一个不同的掩模,是没有办法改变它的。掩模式可编程只读存储器可以随机存取的方式读取。
掩模成本非常高昂,只能用于大容量应用设备。在掩模之后而来的是可编程只读存储器(Programmable Read-Only Memory, PROM),它是一种可以让你自己编程的只读存储器(ROM)芯片,但只能编写一次。PROM最初的机制涉及在芯片上熔化镍铬(一种镍铬合金)熔断器。镍铬合金和烤箱里发光丝的材质是一样的。
开发程序时,人们需要快速浏览一大堆PROM芯片。工程师不喜欢麻烦,所以接下来出现了可擦可编程只读存储器(Erasable Programmable Read-Only Memory, EPROM)。这些芯片与可编程只读存储器类似,只不过它们上面有一个石英窗,你可以把它们放在特殊的紫外线下擦掉它们。
随着电擦除可编程只读存储器(Electrically Erasable Programmable Read-Only Memory, EEPROM)的引入,生活变得更好了。EPROM芯片可以用电擦除,不需要紫外光,也没有石英窗。相对来说,擦除EEPROM的速度非常慢,所以人们不太想经常做这样的事情。
从技术角度讲,EEPROM是一种RAM,因为它可以按任何顺序读写内容。但由于它们写得慢而且比RAM贵,所以它们只被用作ROM的替代品。