此去经年,我在这个博客上发表了一篇文章,内容是关于CPU运作原理的,时隔一年,再去看这篇博客,简直不知所云:这他妈写的是个锤子啊?好吧,大体框架也许是对的,但是主要的实现细节全都没写。。那时的我也的确写不出来。但是,骚年我不会放弃治疗啊,经过一年多的努力,我终于可以自豪的说,老子懂了。
期间多亏找到了这两本书:《编码:隐匿在计算机软硬件背后的语言》和《深入理解计算机系统》,果然,要看好书还是找外国人。。。国人写的那些计算机原理之类的我实在是累觉不爱了,这个栗子也说明,只要不肯放弃治疗,药总是会有的。第一本书用几乎小学生都能读懂的语言(这样的人称得上是大师),从信号这个原始的话题开始,逐渐深入到一台计算机的构造,读完之后会有一种错觉:给我一堆继电器(呃,真空管也行),我也能造出一个ENIAC。第二本书也极其经典,但是正如作者所说,他是从程序员的角度展开论述的,也就是有一定基础的人才能读懂,至少要懂一些C语言。如果说第二本书对CPU的描述还停留在概念与框架上(我承认这也非常重要),那么第一本就是实打实的细节了,他更多的描述了硬件层面的实现,这也是最令我兴奋的,我是个动手能力比较强的人,这些东西最能让我跃跃欲试。
在此,要感谢一些这两本书的作者以及中文译者,正是他们的辛勤劳作,才让知识的传承得以继续。
好了,这篇文章仍然不打算深入到CPU的具体细节中去,而是从整体上描述一下我理解CPU之后的一些感受。CPU的设计与运行是个及其宏大的事情,要考虑的细节非常多,一篇文章根本写不完,后面我会陆续写文章,尽量把整个图景展现出来。
说CPU就不得不说ISA,即指令集,因为CPU就是用来执行指令的。可以说,先有ISA,再有CPU的架构体系,不知道当前工业界是不是按照这个顺序来的。ISA的本质,就是把我们想要CPU的事情拆分成一个一个的步骤,这些步骤肯定是标准化的可以重复使用的,然后运行的程序比如浏览器,就是这些标准步骤的重新排列组合。每个步骤称为一条指令,所有的步骤集合在一起称为指令集。
指令,代表人的需求,然后根据需求做事,也就是根据指令来设计电路满足需求。CPU本质上做的事情没什么分别,但是之所以世界上有不同的CPU体系架构,那是因为不同的公司有不同的需求,亦即他们对所要做的事情的步骤理解不一致,于是出现了不同的划分步骤的方法。比如,求3+4=?,按照冯*诺依曼体系,其基本步骤应该是这样:1、从内存取出指令放到某个寄存器中;2、对寄存器中的指令进行拆解,操作码被传进某个组合逻辑,地址码被传进另一个(两个)寄存器;3、组合逻辑分析操作码产生控制信号并传进ALU,同时寄存器中的操作数(即地址码)也传进ALU;4、ALU根据控制信号计算操作数;5、ALU得出的结果传进又一个寄存器(然后可能根据需求又传回内存)。有的体系可能会把1和2合并成一个步骤,然后用一条特定的指令就可以实现;而有的可能把2和3合并成一个步骤,关键在于有对应的硬件支撑。再比如程序计数器这个东西,根据我的调查,在x86架构中,是不存在这样一个寄存器实体的,其概念的功能由其他硬件实现;而在其他的架构里面可能是存在的。还有,如乘法指令,在有的架构中,有专门的硬件单元来处理乘法,于是一条乘法指令就可以解决问题;但是有些架构中,乘法是没有对应的指令的,只能靠加法指令的循环来实现。
指令结构划分的不同导致对应的底层硬件布局也不尽相同,比如有些本来该在某个组件的电路被拆分出来称为独立的组件,或者某两个组件被合并到一起,但是基本的那几个组件几乎都是必不可少的,正如《深入。。。》书中所说:
要实现一个数字系统需要三个主要的组成部分:计算对位进行操作的函数的组合逻辑、存储位的存储器元素以及控制存储器元素更新的时钟信号。
这一篇博客不打算详述这三个组件的逻辑结构,但我觉得介绍组成它们的最基本的几个元素倒是很重要的,这就是霍霍有名的或、与、非门电路,它们是对应的逻辑的物理实现,整台计算机就是建立在这三个小小的部件的各种排列组合之上,而相应的,计算机背后的指导思想也就是或、与、非这三个二值逻辑(即布尔代数)的堆积,而这个逻辑基础也就决定了计算机能做的事的局限性。