![c10a05ae8e3d96e60d04e072820ccbe0.png](https://i-blog.csdnimg.cn/blog_migrate/e3757b4766c0e2d66988a3ce6dd64093.jpeg)
1、什么是触发器
2、什么是8位寄存器
3、什么是总线
4、什么是内存
计算机是如何读懂0和1的?这个问题曾经困扰了我很久,直到看到一本书《BUT HOW DO IT KNOW – The Basic Principles of Computer for everyone 》,作者用平实的语言,几乎手把手搭建了一个简单的8位CPU,看完之后心情非常愉悦。鉴于原书是英文版,书也非常贵,接下来将我自己的读书笔记摘录下来, 与大家共享。文章绝大部分图片来自于这本书,只不过我用visio重新绘制了,并增加不同的颜色,更便于阅读。
计算机是什么呢?——简而言之,可以看成是一个“自动干活的设备”。说起来并不复杂,我们一一拆解一下这句话。首先“设备”很好理解,不用多解释。“干活”也好理解,就是要能实现一定的功能。“自动”是啥意义呢?——就是在初始人为干预结束后,设备能自动运行,也就是说,机器能自己存储并执行某种预设的“指令”。按照这个理解,我们基本就可以得到计算机的组成了:负责干活的设备和负责存储的设备。我们把前者叫做CPU,后者叫做RAM。当然还需要一些辅助设备将这两个东西连接起来,简要模型如下:
![6069c46f038a244e0776741e3980dccb.png](https://i-blog.csdnimg.cn/blog_migrate/301792f3357c1b21f2c19c6b8bee4f06.png)
和CPU相比,RAM相对简单一些,先来说说这个。
1、什么是触发器
前面说了,RAM的作用是存储数据,我们知道,要存储信息,至少要有两个状态,且都必须是稳定的,我们把这样的器件称为双稳态器。最简单的双稳态器组成非常简单——两个非门串联反馈在一起,如下图所示:
![918b73894a5d252c6793a6dcd963dcd8.png](https://i-blog.csdnimg.cn/blog_migrate/61ee8f657a9f83134db714832d93dbc2.png)
经过简单分析这个电路,很容易发现:上图中红色部分信号既可以是高电平,也可以是低电平!也就是说,原来电路上是高电平的话,就一直维持在高电平,原来低电平的话,就一直维持在低电平——这个电路有两个稳定状态,也就是有最简单的记忆功能。
大家都知道,触发器是现代电子技术中一个非常核心的器件,其实触发器的本质就是通过两个非门串联反馈在一起的双稳态器。关于这一点,三郎:计算机数学小书2-D触发器的进化之路 这篇文章中有一个很好的介绍,非常容易理解,这里也借用作者的思路。
但是呢,基于两个非门串联反馈在一起的双稳态器有一个缺点:
状态一旦确定了之后就不在变化了,也就是说,我们没有办法改变这个系统的记忆,因为没有控制接口。
这当然难不倒我们,我们可以自己加上,比如,可以用两个与非门来代替非门,这样就可以增加两个控制端:
![51d54a69c7a1a9bd04006b466a0bb1eb.png](https://i-blog.csdnimg.cn/blog_migrate/9aba168d2ae4fd9b88f76cb921b7fbea.png)
当然,也可以用或非门来代替非门,感兴趣的可以自己试一下。
如果将上图的与非门翻转180°,就会变成下面的图:
![c60ea976aec5a1e314c0117720969d43.png](https://i-blog.csdnimg.cn/blog_migrate/78731ddd859b0bdc9474e1d44bb15359.png)
有没有一种似曾相识的感觉?没错,这就是RS触发器,它有四种状态:
a=1,b=1,为保持状态,也就是退化为两个非门的反馈串联;
a=0,b=1或a=1,b=0,就会控制记忆和输出;
a=0,b=0,o和 都是1,应避免出现该种状态,我们称之为非法态。
有两个bug:
能够控制记忆,但是有非法状态;
整个系统不受控,一直在工作,当输入端变化时,输出端也跟着变化。
我们可以在输入端再增加两个或门,这样的话,中间这个输入引脚为1的话,电路处于保持状态,就自动屏蔽外部输入,也就是老子不干活了。只有中间这个引脚为0的时候,才工作。
![73cbe37d7bb7a1f18366b2512d711cb8.png](https://i-blog.csdnimg.cn/blog_migrate/bc4acca742099c87560248fc7e0699c1.png)
这样就就解决了第二个bug,但是依然有存在非法态的可能,怎么干掉呢?
既然中间引脚解决了保持记忆的问题,那我们最后只要保证输入的两个引脚不同,就可以避免全0的情况,加个非门不就完事了?两个输入永远不会同时为0。
![7fdaf07d9fc05cd3fa8baeba684d1cac.png](https://i-blog.csdnimg.cn/blog_migrate/e3b0706434d993e0270f01b43be76fb0.png)
这就是电平型D触发器。
前面我们说了,只有当s=0时,输出才等于输入,系统才开始干活,我们更习惯s=1时干活,这样也好办,再加一个非门。同时,我们把表示a改为i,意为input。
![3db647f9ff5ac30189b75503273d20c0.png](https://i-blog.csdnimg.cn/blog_migrate/e20f6acc39c25848cc8f56810c5e485d.png)
这样显得略臃肿,我们知道:
![590b8257024e408fecce001867af7e41.png](https://i-blog.csdnimg.cn/blog_migrate/9932e8782b5ba486a32c518ccea45b60.png)
即:
这样左上方的或门就可以变为与非门,所以有:
![26dafa22b788bbe9774b60e90b02185a.png](https://i-blog.csdnimg.cn/blog_migrate/92107a1cf91b3a3f3fd7a32ba29d85f2.png)
同时,我们又知道:
![de422fa8478bf33df0aec83ea4859618.png](https://i-blog.csdnimg.cn/blog_migrate/f2b5f916c06853ca2c22b6032e9b04d3.png)
即
所以,此时:
可以进一步简化成4个与非门的形式。
![37c429cea40aa8fdf0190743458065d3.png](https://i-blog.csdnimg.cn/blog_migrate/10820aad7fa1f17a7bb2f9b3a3c4adfe.png)
这就是1位寄存器了。简写形式如下:
![7f1ccc91a31fb3d7f93889a755d17a2c.png](https://i-blog.csdnimg.cn/blog_migrate/59f7523e89f93f1295db55c14b49d7c8.png)
其功能是:
当s=1时,o=i;当s=0时,o保持原来的状态。
2、什么是8位寄存器
前面说的是1寄存器,我们可以很容易扩展到8位,数据输入端i是相互独立的,“写”信号s并在一起,对8位信号输入统一控制:
![f46a97d4c6e9e8757a2482b301789163.png](https://i-blog.csdnimg.cn/blog_migrate/a9f1e519f1166a80dca368b7f7b41f58.png)
也就是说,当s=1时,o=i;当s=0时,o处于保持状态。
8bit=1byte,可以把上面电路抽象成:
![da5dfa522acc68b51938d98ec5db772e.png](https://i-blog.csdnimg.cn/blog_migrate/824cf3259456664f014e7f24a4409296.png)
我们知道,每一位都有0和1两个状态,对于8位锁存器,有2^8=256个状态。
前面我们已经搞定如何控制将8位数据“写入”,那如何控制数据的“读出”呢?——很简单,再增加一个“使能器”:
![7229ab9382fe4f0dd87a042e4a302e46.png](https://i-blog.csdnimg.cn/blog_migrate/0319f353962f9560e870b99a8b20e2b0.png)
组成很简单,8个与门,当e=1时,o=i;e=0时,o=0;可以抽象成:
![ed7bf1a81e91a96788445f9d821e74be.png](https://i-blog.csdnimg.cn/blog_migrate/1f488aecbef5a998d2f12a3de56d8f01.png)
把8位触发器和使能器串联在一起:
![7cf9673d66f89134a437ed6ccaf24270.png](https://i-blog.csdnimg.cn/blog_migrate/baa1b55760c99c5374b0eba1a4b534b2.png)
s相当于“写”的使能端,e相当于“读”的使能端。放在一起就是一个8位寄存器了,抽象如下:
![57dfb479d50f46416d72dafa7413c159.png](https://i-blog.csdnimg.cn/blog_migrate/d56570a59538fa39c9b3b35bdb064b30.png)
其中R表示register。顾名思义,存储器的作用就是存储信息,并且能通过使能端控制信息的写入和读出。
3、什么是总线
计算机里面很多时候都需要把上面的8位寄存器的8根输入线或8位输出线连接在一起,为方便起见,我们可以用一个双线代替,这样8位寄存器就可以表示成如下样式:
![e53a55ec6a741b6da363e8ab0cb7eb93.png](https://i-blog.csdnimg.cn/blog_migrate/ccbbb3b3498fd8f165045a8454fef8e3.png)
当有两组8根线相互连接时,也可以简化成两个双线的样式:
![6c9637109162fc6a13b4db04a4c5f657.png](https://i-blog.csdnimg.cn/blog_migrate/6ca9c5eec1abae596afb33865611e7fe.png)
有了线束与线束之间的连接,我们就可以在上面挂很多寄存器了:
![0fccee93bd77060d6cf53db3e92144b1.png](https://i-blog.csdnimg.cn/blog_migrate/e251bf9cd66b1a555d5beb3ef510b6e3.png)
这种传送公共信息的干线称之为“总线”。同样,寄存器可以以各种形式挂在总线上。
![7683708bc7b43186233f84447b7a2f9d.png](https://i-blog.csdnimg.cn/blog_migrate/14fc59ff70024ac7200f3b1cfe33d50c.png)
4、什么是译码器
我们现在是要做一个内存,想要存储很多信息的话,就要很多bit。就像人都有名字一样,每个bit也要增加一个识别号,我们称之为“地址”,主要靠译码器来实现。
我们从最简单的两位译码器来说,就是两个输入,怎么来实现四个状态。抽象成数学的形式就是:
![0a8f991ac8e81b0d011c6808868b7304.png](https://i-blog.csdnimg.cn/blog_migrate/7531a971b75a8ee7afaa1e1ff337a6cc.png)
数学关系为:
具体的逻辑实现为:
![6c6dc759b22b0c7df5d76695ada8c94a.png](https://i-blog.csdnimg.cn/blog_migrate/3b9cf0e6e5efeaa7809d1b1295befd3e.png)
这称之为译码器。
同理可实现译码器如下:
![5152db97e1d809da1184aa253e22a4da.png](https://i-blog.csdnimg.cn/blog_migrate/ac6d52106f809a0fa9ac7c69d6292eb5.png)
数学逻辑为:
![54ace212405e9baa2424403b42e15ab3.png](https://i-blog.csdnimg.cn/blog_migrate/134639ba3d42a7182c46eb50fe91e891.jpeg)
一般可以将译码器简化成:
![dd7b2f52df6e610e5e7d9393dbd3e15a.png](https://i-blog.csdnimg.cn/blog_migrate/05d0c2464f002e0d3299a486c1cb70d7.png)
这样我们有三位地址线,有可以得到8个编号,从而分配给不同的寄存器单元。
4、什么是内存
有了8位寄存器,有了译码器,我们现在就可以磨刀霍霍,去搞一个内存啦。不过,我们现在胃口大了,不能再搞1个8位寄存器了,我们想搞个256个8位寄存器,也就是2^8byte。
根据前面的分析,我们知道,需要8位地址线来实现2^8个状态。前面我们已经看到,译码器已经有点小复杂了,现在搞一个译码器,输出有256根线,想想就害怕,还是算了吧,必须要想别的辙。
一个很简单想法就是拆分,把8位地址线拆成两个4位地址线,这样只需要两个译码器即可,这个复杂程度就可以接受了,如下图所示,主要包括三个部分:两个译码器,一个8位寄存器,寄存器的输出分成两路,分别作为译码器的输入。
![b22a3addfc3576f76dd4947a42abf91f.png](https://i-blog.csdnimg.cn/blog_migrate/e9cd5a792c9b0c29c460d59416d44681.png)
两个译码器的组合,就可以得到一个矩阵,矩阵大小为16x16,这样矩阵中的每一个点代表一个8位寄存器,每个点都可以通过纵、横两个坐标来唯一的表示,其中横坐标由寄存器前四位确定,纵坐标由寄存器的后四位确定,示意图如下:
![0419f38212bf6582bdc36b9a2c38111d.png](https://i-blog.csdnimg.cn/blog_migrate/e9d8bdf64891fc287855c1ee11ce2913.png)
这样每个8位寄存器的坐标都可以确定了。当然,光有坐标还不够,我们好需要对每个寄存器进行“写”和“读”的操作,因此,每个寄存器还要加入这两个输入端,具体怎么实现先不管,大致样子如下:
![321d854ffde496f7625e6397c039c83c.png](https://i-blog.csdnimg.cn/blog_migrate/766816d26ca5e831a0b0f4773b311432.png)
当然,能够控制“读”和“写”的操作外,还需要读写的数据,这个也不难实现,把每个寄存器都连到“总线”上。
![f98b8a5a6c07ddaf087c68072245d481.png](https://i-blog.csdnimg.cn/blog_migrate/bf3202e8eb84f407a4a7a2eb2fe22e27.jpeg)
好了,我们有了大概的内存的样子,我们需要来考虑细节了:每个寄存器是怎么和地址线、“读”“写”使能线以及总线连接在一起的?
我们把上图中红色圈内的一个寄存器打开,看看里面是如何实现的:
![e8f5498b2d816fadb37ac5a6b152a3c3.png](https://i-blog.csdnimg.cn/blog_migrate/7e67dc2c66d001c9f07aeb992d4f6991.jpeg)
如果只聚焦每个byte的连接方式:
![e54daebf6b5a3519c056c384e858a8ae.png](https://i-blog.csdnimg.cn/blog_migrate/35f1f03a5ee74d7d34b29bfef40b3098.png)
里面包含三个与门,我们来分别解读一下每个与门代表的意思:
第一个与门:vertical grid line和horizontal grid line就是前面所说的纵坐标和横坐标,通过与门的形式输出,代表的意思就是纵坐标和横坐标都是高电平时,该寄存器才被选中,才能进行下一步的操作;
第二个与门:第一个输入是与门输出,也就是代表该寄存器是否被选中,第二个输入时s“写”信号,两个输入“与”之后连接到该寄存器,表示该寄存器被选中,并可以对该寄存器进行“写”操作;
第三个与门:第一个输入第一个与门输出,第二个输入时e“读”信号,两个输入“与”之后连接到该寄存器,表示该寄存器被选中,并可以对该寄存器进行“读”操作;
同时,该寄存器通过总线与其他设备交换数据。
把每一个寄存器都按照此方式连接,就可以得到一个256byte的内存。抽象如下:
![8e42ecae663716220c22b37be606fc8a.png](https://i-blog.csdnimg.cn/blog_migrate/0c284d4dda5572cf57a7e75d78906391.png)
可以采用总线的形式进行抽象:
![1668018ed80085b7f081df98ce9745f8.png](https://i-blog.csdnimg.cn/blog_migrate/8e0a5272ac3f0286dfefcec3888641c4.png)
我们把这种内存称之为Random Access Memory,简称RAM,也就是随机访问存储器。为什么是随机访问呢?——因为地址可以是随机的,内存中的任何寄存器都可以以任何顺序进行访问,不存在先后依存关系。
如想继续了解CPU相关知识,可移步后续系列文章:
J Pan:(2)计算机是如何读懂0和1的?- CPU (上)
J Pan:(2)计算机是如何读懂0和1的?- CPU (下)