查看原文
其他

自制了一台计算机,可编程哦!

脚本之家 2022-09-23

The following article is from 涛歌依旧 Author 点击关注👉👉

 关注脚本之家”,与百万开发者在一起

出品 | 涛歌依旧(ID:ai_taogeyijiu_2021)

已获得原公众号的授权转载

大家好,我是涛哥。
接触计算机多年,经常会有一种云里雾里的感觉。今天,一起动手来自制一台计算机,加深体会和理解。
必须说明的是,计算机有复杂的,也有简单的,但结构和原理基本相通,本文制作的是最简单的计算机。
我也会对自制的简单计算机进行编程,体会编程的感觉,知道编程是怎么回事,理解计算机工作的原理。

一. 自制计算机的外形

在很长一段时间内,总是搞不清楚一些基本的概念和原理:比如什么是硬件? 硬件内部是怎样运行的?什么是软件?软件在哪里?软件究竟是怎样在硬件上跑起来的?硬件究竟是怎样执行软件的?

我将自制一台简单计算机,从电路的角度理解计算机的工作原理,给这台计算机编程,体会硬件和软件之间的相互作用。如下图是我制作的一台最原始的计算机,先来一睹它的外形,看看长啥样:

冯诺依曼结构

自制计算机

CPU运算器

U3加法器

CPU控制器

U1计数器

U4触发器

U5非门

时钟信号

存储器

U2存储器

输入设备

不涉及

(因为输入内容已提前存放于U2中)

输出设备

数码管显示器



二. 自制计算机的构成

接下来,我们一起看看自制计算机的构成,从简单到复杂,我们一步一步地制作和讲解。
1. RS锁存器
来看RS锁存器电路,其特殊在于:U3的输出作为U2的输入,U4的输出作为U1的输入:

很容易分析出逻辑关系:

S

R

Q

Q’

1

0

1

0

0

1

0

1

0

0

保持

保持

1

1

0

0

有三点值得注意:
  • 当S=0,R=0时,对或门没有任何贡献,所以不会对电路产生影响。此时,Q和Q'是相反的,必有一个为0,另一个为1.

  • 当S=1,R=1时(这种输入并没有错),Q和Q'都为0,我们对这种情况并不感兴趣,所以可以忽略,故约定S和R不同时为1.

  • 不考虑S=1,R=1这种输入组合时,Q和Q'总是相反的。


2. D锁存器

来看D锁存器电路。可用多个器件来确保RS锁存器两个输入端不能都为1,下图R和S输出端永远不可能同时为1:

来分析上图电路动图: 
  • 当E=0时,无论D怎么变, 经历R和S两个与门后,R和S的输出端总是0,所以Q和Q'总是保持原状。
  • 当E=1时,经历R和S两个与门时,R和S输出端的值完全取决于D, 显然有Q=D.
可以看出:E是一个控制者,只有当E=1时,D的值才会保存到Q上。当E=0时,无论D怎么折腾,Q总是无动于衷。

3. D触发器
来看D触发器电路,它由两个D锁存器组成,构思非常巧妙,仅在上升沿触发时才有效:

来分析一下这个电路动图: 
  • 上下两个D锁存器的使能端是相反的,所以,无论控制开关E是0还是1,上下两个D锁存器必然有一个无效,导致不能把D数据保存到Q端。

  • 当E从1变为0时,下面的D锁存器无效,因此也不能把D数据锁存到Q端。

  • 当E从0变为1时,下面的D锁存器生效,上面的D锁存器无效,但U4的输出端之前已经获取了D端的数据,所以趁着下面的D锁存器的生效,把U4输出端的数据保存到Q端。因此,整体看来,当E从0变化到1时,能把D数据锁存到Q端。这种锁存,只在信号发生0到1的跳变瞬间,所以叫上升沿触发锁存。

可是,这个D触发器有点复杂,我们来抽象一下,直接使用封装好的D触发器,如下图,可以看到:当且仅当E从0变到1时,才把D保存到Q.

D触发器只能触发保存1位二进制,我们可以直接用封装好的74175芯片实现4位二进制的保存,如下图:

开关提供上升沿,需要手动掰弄开关,非常麻烦。能不能搞一个自动上升沿呢?当然可以。

我们引入时钟信号,它不停地在0和1之间做变换,从而产生上升沿。时钟信号很简单,看动图

想一下,为什么CPU需要时钟才能工作?这个问题很有趣,也很好回答,可以从两个方面来看:

  • 计算机的理论模型是图灵机,而图灵机是有限状态机,需要有时钟信号驱动状态变化。
  • 计算机中的数据需要按先后步骤进行保存和更新,以上述触发器为例,需要有上升沿信号来触发,所以需要时钟信号。

4. 计数器
利用D触发器,可以制作其他器件。如下动图中所示的计数器,遇到脉冲就计数:

时钟周期是1秒,每秒会有一个上升沿信号输入到U1的CLK端,于是U1的Q端就会每秒在0和1之间跳动一次,显然U1的Q'也是每秒在0和1之间跳动一次。
也就是说,对于U2的CLK而言,遇到一次上升沿需要2秒,因此U2的Q在0和1之间跳动1次需要2秒,看下表:

第n秒

U1

U2

U3

U4

U4U3U2U1

0

0

0

0

0

0

1

1

0

0

0

1

2

0

1

0

0

2

3

1

1

0

0

3

4

0

0

1

0

4

5

1

0

1

0

5

6

0

1

1

0

6

7

1

1

1

0

7

8

0

0

0

1

8

9

1

0

0

1

9

10

0

1

0

1

A

11

1

1

0

1

B

12

0

0

1

1

C

13

1

0

1

1

D

14

0

1

1

1

E

15

1

1

1

1

F

一目了然,U1的Q变化最频繁,U2的Q变化不频繁,U3的Q变化更不频繁,U4的Q最懒惰。很显然,上述电路是一个计数器,从0到F,  一个一个地计数。
计数器很重要,若要不断地从存储中取出程序或数据,就得靠它了。所以,计数器被用作程序计数器,即Program Counter. 抽象封装好的计数器如下:


5. 完整计算机
到此为止,我们制作并使用了计数器、加法器、触发器、时钟信号、非门以及数码管显示器,把上述器件组装在一起,形成一台完整的计算机,如下所示:

这台简单计算机的电路图硬件都搭建好了,软件在哪里呢?软件就是程序,包括指令和数据。我们把软件程序存放在存储器U2中,其中存放的程序内容是:

000000000000000100000010000000110000010000000101

其功能是:计算1+2+3+4+5,这台计算机工作过程的动图如下,可以看到:1+2+3+4+5=FH=15


现在最大的疑问是:为什么上面那段程序表示1+2+3+4+5呢?计算机电路又是如何执行程序的呢?我们来仔细分析一下。
U2存储器中的程序是:

000000000000000100000010000000110000010000000101

这个程序不直观,为便于阅读,我们来分割一下:

000000000000000100000010000000110000010000000101

可以看到,第一行是0,第二行是1,第三行是2,第四行是3,第五行是4,第六行是5. 存储器U2的输入端和输出端对应的关系如下:

U2输入端

A3A2A1A0

U2输出端

D3D2D1D0

其具体内容与我们写的程序有关

0000

0000

0001

0001

0010

0010

0011

0011

0100

0100

0101

0101

U2存储器左边的U1刚好是计数器,从0一直数到F,因此,当计数器数到3时,U2输入端刚好就是3,而U2此处存储的数据刚好是3.


我们对照上面的动图,整体理解一下计算机电路图的执行流程:

第1步:
开始,U1的输出值0,左边数码管显示0,U2输出值为0,U3加法器的输出值0,U4的输出值是0,右边数码管显示0.
第2步:
时钟信号经历上升沿,U1开始计数到1,U2输出值为1,左边数码管显示1,U3加法器的输出值还是1,但U4没有经历上升沿,故U4的输出值是0,右边数码管显示0.
第3步:
时钟信号经历下降沿,U1保持在1,U2输出值为1,左边数码管显示1,U3加法器的输出值还是1,U4刚好经历上升沿,故U4的输出值是1,右边数码管显示1.     
还有很多步骤没有列出,我们把所有步骤放到表格中:

时钟信号

U1输出

U2输出

U3输出

U4输出

 

0

0

0

0

0

上升沿

1

1

1

0

下降沿

1

1

1

1

上升沿

2

2

3

1

下降沿

2

2

3

3

上升沿

3

3

6

3

下降沿

3

3

6

6

上升沿

4

4

A

6

下降沿

4

4

A

A

上升沿

5

5

F

A

下降沿

5

5

F

F

对照电路图看表格,一目了然。可以看到,由于引入了U4触发器来保存数据,电路再也不会出现之前文章中遇到的死循环了。到此为止,我们的连续加法器终于实现了。
而且,这个连续加法器是自动的,这完全是因为有了时钟信号,它不断地制造上升沿,触发着计数器往前走,去存储器获取指令和数据,也触发着把U3加法器输出端的值安全地保存到U4的输出端,让它再次输入到U3参与计算。
如果没有时钟信号,我们还要去一个开关一个开关地掰弄,去构造上升沿来控制电路。我在仿真时,时钟信号频率是1Hz,也就是周期是1秒,信号为0的时间占0.5秒,信号为1的时间占0.5秒,1秒之内有1个上升沿和一个下降沿。
我把时钟的频率调快到10Hz,发现连续加法的计算时间也变快了10倍,这是因为:时钟信号的频率快了,上升沿的次数就更频繁了,自然能更快地迫使其他器件上的值进行变化。
我电脑的主频是3.6GHz,这就是时钟频率,它每秒产生几十亿次上升沿/下降沿信息,迫使着其他器件快速变化。一般来说,主频越大,CPU的运算速度就越快,道理显而易见。


6. 硬件与软件
电路是硬件,存储在U2中的信息是软件。我们买到手机后,基本不会对硬件进行变化,但经常安装或者卸载其中的软件,而正是不同的软件,使得手机有不同的功能。
在不改变上述电路硬件的情况下,我们可在U2中装入不同的软件,从而实现不同的功能。比如,我们写一个新程序:

00000000000000100000010000001000

把程序塞到U2存储器中,重新让电路通电。从如下动图中显而易见,这是在计算2+4+8=EH=14,由此可见:不同的软件程序,实现了不同的功能



三. 自制计算机的编程

用0和1写出来的程序,叫机器语言程序,直接在硬件上运行,比起掰弄电路开关,已经有很大进步。但是,如果一直用0和1来写程序,还不能出现一点点差错,谁受得了呢?

一大串的0和1,太难懂了,它是机器世界的语言,而人又有人的语言,这两种语言是不相通的,因此,我们需要探索出更好的编写程序的方法,让人更轻松点。怎么办?

我们回头看1+2+3+4+5的机器语言:

000000000000000100000010000000110000010000000101

怎么降低人编写程序的难度呢?我们可以考虑这么写:

ORG 0000HDB 00HDB 01HDB 02HDB 03HDB 04HDB 05HEND

这种语言叫汇编语言,看起来舒服多了。现在的问题是,需要一个工具把汇编语言转化为机器语言,这个转换的工具就叫汇编器,如下图:

现在编程就简单多了:先用汇编语言写程序,然后用汇编器这个工具,把汇编语言程序转化为机器语言程序。

如果要计算2+4+8,我们再也不用与0和1这种折磨人的机器语言打交道了,直接用汇编语言写汇编程序,如下:

ORG 0000HDB 00HDB 02HDB 04HDB 08HEND

经汇编器工具转换后,上述的汇编语言程序变为了机器语言程序,而这正是硬件电路所需要的语言,具体如下:

00000000000000100000010000001000

然后,我们自制的计算机执行这段机器语言程序,得到的结果是14. 可是,用汇编语言还是憋屈,不好理解,不近人情。

于是,需要再次抽象,越抽象越接近事物的本质,为了降低编程难度,我们再次优化编程方法,采用高级语言,如下:

int a=1+2+3+4+5;printf("%d", a);

然而,电路毕竟不认识高级语言,只认识高低电平,即1和0,所以,也需要工具来对高级语言进行转换,关系如下所示:

       

我们从如下表格中,可以看到机器语言、汇编语言以及高级语言的对比。显然,用高级语言编程更容易,更加直观:

目的

机器语言

汇编语言

高级语言

计算

1+2+3+4+5

000000000000000100000010000000110000010000000101

ORG  0000H

       DB  00H

       DB  01H

       DB  02H

       DB  03H

       DB  04H

       DB  05H

END

int a=1+2+3+4+5;

printf("%d", a);

计算

2+4+8

00000000000000100000010000001000

ORG  0000H

       DB  00H

       DB  02H

       DB  04H

       DB  08H

END


int a=2+4+8;

printf("%d", a);

这里有两点补充说明:
  • 上述的汇编语言很简单,不涉及到指令,只涉及到数据存放的位置。有一些朋友可能觉得上述汇编语言的指令是伪指令,但没有关系,我们依然把它当汇编语言理解,并无副作用。而且经汇编器转换后,生成的机器代码,确实可以在我们制作的计算机上运行。
  • 上述的高级语言,经通用的编译器和汇编器转换得到的机器语言程序,没法在我们自制的计算机上运行,必须经过特定的编译器才可以,我们无需对这种特殊的编译器做进一步了解,毕竟编译器只是个转换工具。
我们已经从原始的掰弄开关来控制电路,上升到利用机器语言0和1来控制电路,然后上升到用汇编语言来控制电路,最后上升到利用高级语言来控制电路。
逐步地,我们从纷繁复杂的电路细节中解脱出来,这是一个不断进行抽象、不断远离具体细节、不断接近事物本质的过程,从此,也站在更高的维度上了。

好的,到此为止,本文也将告一段落。对于想搞懂计算机原理的朋友而言,如果能亲自动手完成本文的实验,那么肯定会加深对计算机原理的理解,加油!

<END>

程序员专属卫衣

商品直购链接 👇

  推荐阅读:

终于!我找到程序员爱穿卫衣的原因了

卷不动了:互联网的尽头是外企?

23 张图详解路由协议:计算机网络的核心技术

炸了!实习生把代码仓库搞得一团糟…

使用 25 张图,深度剖析 Linux 的 3 种“拷贝”命令

48 张图 | 手摸手教你微服务的性能监控、压测和调优

每日打卡赢积分兑换书籍入口

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存