前言
上一节中我们讲到如何用逻辑门来构建一个ALU,它可以进行算术运算和逻辑运算,那么如果将算出来的结果存起来呢?这就要讲到今天的主角:「 内存 」了。
大家都有这样的经验,在计算机上进行文件编辑,或者正在看电视/电影,如果突然遇到断电,那么之前编辑的内容将没有保存,因为这些内容存储在内存中!电脑用的是"随机存取存储器",简称为"RAM"!遇到这种状况,只是郁闷的份了。
存储 1bit 的电路
我们之前讲过的电路都是单向的,就是说有输入,经过电路运算得到输出。现在假如我们将输出连回输入,有趣的事情将会发生!
让我们拿一个 OR 门,将输出传回输入,看看会发生什么。
首先,两个输入都设为 0,电路输出0;如果将 A 变成1,“1 OR 0”为 1,所以输出 1;
一转眼的功夫,输出回到 B,OR门看到两个输入都是 1,“1 OR 1”仍然为1,所以输出不变;
如果这时再将 A 变成 0,OR门依然输出 1!并且无论怎么试,都没法再从 1 变回 0。
类似的方法,如果将OR门换成AND门,情况正好相反。
A 和 B 都设为 1,“1 AND 1”的输出永远是 1;如果之后 A 设为 0,由于是 AND 门,输出会变成 0;就像之前,之后无论 A 设什么值,电路始终输出 0。
“AND-OR 锁存器”
为了做出有用的存储 (memory),我们将两个电路合起来,变成“AND-OR 锁存器”。它有两个输入,“设置”( SET ) 输入1,将输出变成 1 ;"复位" ( RESET )输入1,将输出变成 0;如果“设置”和“复位”都是 0,电路会输出最后放入的内容,也就是说,它存住了 1 bit 的信息!这就是存储!
之所以叫“锁存”,是因为它“锁定”一个特定值并保持状态,将数据放入叫“写入”,将数据输出叫“读取”。
麻烦的是,用两条线来输入,也就是 SET 和 RESET,有点难理解,为了更容易用,我们希望只有一条输入线,将它设为 0 或 1 来存储值,还需要一根线来“启用”(enable) 内存,启用时允许写入,没启用时“锁定”,这条线叫“允许写入线”!
我们将整个电路抽象一下,输入现在只有“允许写入线”和“数据线”,有1个数据输出。如果将 "数据线" 从 0 换到 1 或 从 1 换到 0,什么也不会发生 - 输出依然是 0,因为“允许写入线”是关闭的(0)来防止内容变化;
当“允许写入线” 输入 1,现在可以在“数据线”上放 1,将 1 存起来。注意输出这时候会变成1了,然后可以关掉 “允许写入线”,这样输出就会保持 1 而无论输入端再输入什么!
寄存器
只能存1bit 没什么大用,但是如果我们并排放8个锁存器,这样就可以存8 位信息,比如一个8bit数字,一组这样的锁存器叫“寄存器”。写入寄存器之前,首先要启用里面所有锁存器,我们可以用一根线连接所有“允许输入线”,然后设为1,然后用8条数据线发数据,然后将“允许写入线”设回 0,现在 8 bit 的值就存起来了。
寄存器能存多少个bit叫“位宽”,早期电脑用8位寄存器,然后是16位,32 位。如今许多计算机都有64位宽的寄存器。
对于很少的 bit,并排放锁存器勉强够用。但是如果是64 位寄存器,要64 根数据线+64根连到输出端,如果我们只要1根线启用所有锁存器,但加起来也有129条线了;如果是256位寄存器,要513条线,解决这个问题的方法是用「矩阵」!
矩阵存储
在矩阵中,我们不并列排放锁存器,而是做成网格,这样存256 位,我们需要用 16x16 的锁存器,要启用某个锁存器,就打开相应的 行线和列线。
行选和列选总共有有 16+16 =32根线,再加上1条“数据线”,1条“允许写入线”,1条“允许读取线”,总共也只需要35根线!
内存地址
我们需要有一种方法来唯一指定这个交叉的点,这就是地址。比如一个bit 的地址是“12行 8列”,由于最多 16 行,用 4 个二进制 bit 就够了,“12”用二进制表示为“1100”,“8”用二进制表示为“1000”,所以刚才说的地址可写作“11001000”。
为了将地址转成 行和列,我们还需要一个部件叫 “多路复用器”,多路复用器有不同大小,因为我们有 16 行,我们需要 1 到 16 多路复用器,它的工作方式是:输入一个4bit数字,它会把那根线连到相应的输出线,如果输入 0000,它会选择第一列;输入 0001,则选择下一列,依此类推。
一个多路复用器处理行(row),另一个多路复用器处理列(column)。
内存抽象
我们将这个能够存储256 bit的内存经行抽象,它输入一个 8 位地址:4 位代表列,4 位代表行,我们还需要 "允许写入线" 和 "允许读取线",最后,还需要一条数据线,用于读/写数据。
如果我们将更多的这样的单元连接在一起,就可以组成更大的存储单元。
如果将8个这样的256 bit 内存组在一起,就可以构建一个具有256 个地址,每个地址可以存储1个byte的内存!
现代计算机的内存扩展到千兆字节(GB)的方式,和我们这里做的一样,就是不断把内存打包到更大规模。如下是一条真的内存,上面焊了 8 个内存模块,如果打开其中一个,然后放大,会看到 32 个内存方块,放大其中一个方块,可以看到有 4 个小块,如果再放大,就可以看到存一个"位"的矩阵。
总结与展望
在这一期里,我们从基本的锁存器一步步构建出了寄存器,再到大型存储器,就像计算机中的很多事情,底层其实都很简单,让人难以理解的,是一层层精妙的抽象!
那么如何利用内存和上一期里的ALU 来构建一个CPU呢?
关于这个话题,我们下一期再讲~
PS:本系列文章首发于同名公众号:「 三邵爷的梦呓 」,关注并回复关键字「 1024 」,你懂得!