什么是计算机?计算机科学很高深吗?也许你会联想到集成电路,联想到汇编语言,操作系统之类的,然而真正的计算机本质上是很简单的,你自己都能自己动手做出来,所谓的集成电路只不过是实现计算机的一种方式而已,它能使计算机变得更快,更小,它纯属于另一个范畴,至于编程语言,那便是另另一个范畴了,如果你理解了计算机的本质,再理解这些概念就不会觉得难了。
本文我就带着想理解本质的同道中人自己动手做一台可以“编程”的计算机。首先计算机不一定非要是电子的,它完全可以是机械的,本文中我做的这台机器就不是电子的,因为如果想搞电子计算机,那还真得学学集成电路,我的机器是电气 + 机械的,然而它却实现冯诺依曼模型的很多特性,比如指令存储,顺序执行等,然而它毕竟很是简陋,不过了解计算机运行机理,那足够了。
我要是说电灯也是一台计算机科班出身的人一定认为我在侮辱他们的学科,而实际上它确实是一台计算机, why ?你按下了开关,然后灯就亮了,你关闭开关,灯就灭了,你的动作就是指令,而电灯的亮和灭就是输出,只不过它不是自动的,它依赖于你去按动开关发出指令,如果它能自己打开或者关闭那就完美了。如果说数据可编程可存储,那么磁带录音机或者 dvd 光碟机就是这一类,然而介质上所存储的都是数据,并不含指令,对于这一类机器,是没有“取指令”一说的,电机在不停的转动,带动磁带前进或者光盘转动,因而数据就不停的变换,出现不同的声音或者图画。要想实现一个冯氏机器,必须做到两点: 1. 指令可以存储在介质上; 2. 顺序执行指令。那么以下开始动手吧:
背景
1. 手上物质方面有导线若干根,干电池若干块,粗铁钉若干枚,可用剪刀剪开的铁片若干片,轻弹簧若干,灯泡若干个,木板一大块,另有剪刀,刨子,薄塑料板;
2. 脑中了解中学时学的安培力,洛仑兹力,知道电流的流向,知道电磁感应这些小知识点;
3. 没听过三极管和二极管,没听过集成电路,不知道二进制编码知识,更不知道什么是编程以及编程语言;
4. 小的时候玩过变形金刚。
第四点和计算机有什么关系呢?变形金刚不仅仅是一个玩具,它的设计师一定是个天才,如此精细的机关恰到好处的结合在一起,最终它们协同工作使得变形金刚可以变成各种形状,它使我一直都想自己动手做点什么类似变形金刚的东西,一是为了回忆一下童年,二是个人没有其它的不良爱好。
准备工作:
1. 将导线缠绕于粗铁钉上,然后导线两端通上电,这就是一个磁铁了,当不通电时,磁性就消了,可以亲手试一下。 ( 我尽量避免出现任何专业术语,比如电磁铁,继电器,左右手法则等,否则逃离了集成电路之后,又会面对理论物理 ) ,如下图所示,通电线圈上面有一个可以自动复位到水平位置的铁片:
2. 上述 1 中,电池反着接,磁极将会反向,,但是不管怎么接通电后都会对上面的铁片吸引,也可实验为证。
3. 通电线圈产生的磁性足以吸引铁片。
以下是我的计算机的电路图示:
图例如下:
深黑色的粗线:硬铁棍
深黑色的细线:硬塑料棍
深黑色的圆球:铁质导电体
浅黑色细线:软地指导线
大线圈:线圈 1
小线圈:线圈 2
大线圈上面的带有复位弹簧的开关: g1
小线圈上方的携带有纸带的小铁块:铁块 1
橘黄颜色的圆形:灯泡
其运行原理如下:
1.g1 闭合,线圈 1 产生磁性,将铁片 1 吸引下来;线圈 2 产生磁性,将带有胶纸带的铁块 1 吸引下来;
2. 由于铁片 1 被吸引下来,正好铁片 3 打在位置 1 ,此时如果该位置有小方块铁片,则回路 2 闭合,灯亮,如果没有小方块铁片,则回路 2 断路,灯不亮;
3. 由于铁片 1 被吸引下来,线圈 1 电流是逐渐减小的 ( 这是因为磁通量变化了,引起了感应电流 ) ,铁片 1 又由于弹簧弹力和磁力逐渐减小回到水平原位, g1 又一次闭合;
4. 由于铁片 1 被吸引下来,线圈 2 电流逐渐减小,当磁力小到和铁块的静摩擦力相等的时候,携带纸带的铁块停止移动;
4. 铁片 1 被弹回, g1 闭合,线圈 1 和线圈 2 通电,铁片 1 被吸引,携带胶纸带的铁块 1 受到线圈 2 的磁力推进到下一个位置;
5.... 重复,直到纸带到达终点。
这个计算机麻雀虽小,但五脏俱全,拥有“取指”和“执行”两大重要的模块,甚至拥有“电源”和“时钟”等必不可少的模块,取指和执行互相作用,互相影响,这就是它和磁带录音机的区别,否则我完全可以设计一个每秒可以将纸带移动一厘米的机械装置,然后将它和线圈 1 独立分开,单独安装,虽然这也可以实现和我的如上设计一样的效果,然而其取指模块和线圈 1 是独立的,也就是如果把线圈 1 作为时钟发生器的话,它将很不容易或者无法将 g1 的开闭信息,也就是时钟信号传输到取指模块从而影响它,也不容易实现“分支”和“跳转” ( 根据执行的结果 - 回路 2 的通断,影响线圈 2 的通电或者断开,以实现连续吸引铁块 1 使得“指令” - 纸带到达特定的位置 ) 。
还有一个问题,根据上面的线路图连接起来的“计算机”并不一定如你所愿的执行,因为木板的粗糙度以及线圈 2 的缠绕圈数和铁钉粗细影响了带有纸带小铁块的滑动距离,从而也就影响了“取指”和“执行”的时序,然而在长时间内确实是合理的,如果想要得到理想的效果,你不得不进行一些微调。
这台计算机完全实现了“指令存储”,纸带上有没有小方块铁片就是指令。如果胶纸带上面的小方块铁片在每一格的排列为下面的形式:
“小方块铁片 + 小方块铁片 + 白纸 + 小方块铁片 + 白纸”
则灯泡的序列就是“亮亮灭亮灭”
一个设计良好的计算机好在牵一发而动全身,这里的“一发”就是这个可“开关震荡”的“时钟”,而“全身”则是由于“时钟”的影响而断开或者闭合的“线圈 2 ”,“线圈 X ” ... 从而影响执行模块和取指模块,要知道,机器的执行顺序和我们所熟知的流程图有所区别,对于每一条指令,机器是“一次性”执行完毕的,一旦时钟有了信号,取指会自动取出一条指令,然后其余所有的负责执行该指令的电路几乎一同开始运作,完成指令的执行。另外可以由于这个“一发”之被牵制,而使得执行模块和取指模块相互影响,达到跳转的目的,然而要实现这样的功能,我们不得不把线路再理一下,使它更加模块化,我们有必要将时钟和取指模块分开,如下图:
然后再按照现代处理器的形式将取指和执行都封装成模块,甚至按照现代计算机的形式,将内存的概念引出,用内存这个概念代替纸带,如下图所示:
然而想实现我们前面所说的分支,跳转,容易吗?这里有两个问题:第一,纸带是一个机械装置,而内存中存储的却是 0 和 1 ,也就是内存中的元素本身就是一个电压 (1) 或者一个等势体 (0) ,并不是“有小方块铁片”或者“没有小方块铁片”,因此这必然需要将内存本身也实现“线圈化”,具体如何做,我们一会再谈;第二,我们的分支和跳转需要执行的结果影响下一步的执行,这就需要在执行模块和取指模块之间互相影响,分支需要判断,而跳转需要引出“地址”的概念,这些都是需要解决的问题。
然而以上的问题对于我们理解计算机的本质已经不重要了,它们属于计算机设计的范畴,但是为了做事及作文有头有尾,我还是做一番叙述吧。针对上述的两个问题,首先要说的是,你还真得学点数字电路方面的知识,其实也就三个电路比较重要,学会了这三个,其它再复杂的电路都逃不过这三者的组合,它们就是三个门电路,分别是非门,与门,或门。道生一,有了门,神说一生二,于是有了是与非,于是就有了二进制,非门如此而生,与门和或门仅仅是神星期日的产物,此后再没有别的能使神引以为豪的发明了。我们的世界就是是和非组成的,就连我们自己都是,计算机没有经过我们复杂的进化,因此它只能从基本的是和非做起,是与非组成了整个计算机系统,因此只要我们只要能用电池和线圈构造出这三个门电路,那么通过它们不同的组合,我们就可以造出一台类似银河三型的超级计算机,那么非门如何实现呢?如下图,很简单,在以下:
与门呢?看吧:
或门呢?如下:
自己想吧,哈哈
有了这三者,还有什么能难倒我们的呢?“地址”是什么概念?它在是与非的世界中无非就是一串 0 和 1 ,接下来,我们回归到地址的本源,它无非一个索引,我们说需要实现从地址 2 处 ( 以《另一个视角解读计算机编码 -补码编码》这篇 blog 的前提为准,以 8 位作为计算机表示的数字,地址 2 就是 00000010) 读出这里所存储的数字,我们需要做些什么呢?首先我们需要实现一个存储器节点,接下来我们需要实现一个多路选择器和多路复用器,除了科班出身的人都知道这无非一个矩阵,一般的人我想也能设计出精妙的结构,剩下的只是你有没有耐心将你的设计做出来了。如果你做出来了,那你会看到,你的计算机足有 N 间房子那么大 (N>3) ,你会惊讶自己完成了 20 世纪中叶这个星球上智慧最高的人的创举,而实际上你仅仅需要的是耐心,毕竟你只需要使用一些诸如电池,铁片,铁钉子之类随处可以买到的器件,然而你需要付出的最重要的不是搞清楚这些器件如何能和集成电路等效 ( 事实上确实等效 ) ,而是搞明白如何去组合它们,这才是最重要的事,真正的计算机科学家所作的就是这个事情,因此上世纪中叶即使那些科学家比现在的优秀,而他们却只能搞出几间房子那么大的机器 ( 现在的随便一个学生都能使用酷睿处理器 ) ,如果你能搞到现代处理器的图纸,那么剩下的工作就是无休止的连线和焊接了。
在我的最基本的设计中,纸带上有没有小方块铁片构成了 1 和 0 ,可以看出,整台机器只需要“时钟”不停运作,取指和执行都是有条不紊的执行,整个过程没有依靠机器外的任何因素,执行的结果是什么完全取决于你的纸带上在什么位置贴上了小方块铁片。终于有一天,有人发现了自然界存在一种物质,可以实现这三个所谓的基本“门”,于是这种物质被大规模采用,因此集成电路科学也就由运而生,计算机再也不需使用铁钉,线圈之类的半机械,半电气开关了,大自然的神奇物质为我们完成了很多的事。
至于编程问题,这就更简单了,程序设计语言和机器硬件的接口就是指令集,我们知道, Intel 和 AMD 是两家处理器公司,它们的处理器实现肯定不同,然而它们的处理器上却都能运行一套指令,这就是 ia32 兼容指令,这就涉及了一个叫做指令集的概念,一个指令集只是一个接口,至于怎么实现就无所谓了,各个厂商可以有不同的实现,只要相同的输入能得到相同的输出即可,比如一个指令为 a b( 可以是 add a) ,它被编码为 xyyx(x,y 为 0或 1) ,这个 xyyx 在首先存在指令寄存器中,比如是 0110 ,当它执行的时候,指令寄存器会在相应的导线上分别发射出“ 0V ”,“ 12V ”,“ 12V ”,“ 0V ”的电压,以表示 0110 ,这样这些电压就会影响接下来的执行序列,如果 xyyx 是 add a( 且 a 是一个寄存器 ) 的编码话,那么这个 0 , 12 , 12 , 0 的电压肯定要影响寄存器 a 的各相关引线,引起它的值加 1 ,这一切都是通过三个门的组合导致的哦,而且这一切都是同时发生的哦!
我们从机器的最底层的硬件开到指令集,速度迅猛,如果我现在开始说 c 语言的事,你会觉得意外吗?应该不会吧!但是我不想再细说 c 语言了,只想说一个要点,那就是 c 语言最重要的就是提供了一个方便的方式操作内存地址而不是寄存器,这样 c 语言就和具体的机器分离了。汇编语言程序员考虑的是寄存器和地址,而 c 语言程序员考虑的是指针 ( 地址的另一个名字 ) ,那么 java 呢?它连指针都没有了,它关注的是“对象”。从珍妮纺纱机到超级计算机,历经 N 个世纪,从业者从专业人员到现在的随便一个学生,真可谓是机器智能的一大进步,因此也就不要怪 java 程序员不懂处理器流水线啦,正是有了一帮人专门搞流水线,才会有另一帮人被解放出来专业搞业务,这正是社会化分工的优良产物啊!
参考:Charles Petzold所著《编码:隐匿在计算机软硬件背后的语言》