3.1.2 计算机语言——人与计算机沟通的桥梁
早期人们编程时,都是使用汇编语言进行编程,编译器将汇编语言翻译成机器语言,交由计算机执行,汇编语言描述了计算机的运算过程,但是却不符合人类的思维方式,程序员苦在其中。
1977年,巴库斯在图灵奖受奖演说时讲到:“程序设计能从冯·诺伊曼风格中解放出来吗?”巴库斯为什么能得到图灵奖,原因在于他发明了世界上第一个高级语言Fortran,他当时在IBM工作。巴库斯向人们介绍了一种全新的编程概念:程序员知道自己想要做什么,而并不需要知道是怎样做的。高级语言的编程风格更接近于人类的自然语言,有了高级语言后,程序员就摆脱了对计算机的依赖。
后来,又陆续出现了C/C++、Java等高级语言,在这些语言中,两个数求和就可以写成C = A + B,这样更符合人们的表达方式,编程也更为方便。
C/C++这些语言,离人们的自然语言还很远,编程语言也一直向着更智能的方向发展。在C语言中,矩阵的乘法运算要写3级for循环,而在Matlab中,只要一行语句就可以了。在数据库语言SQL中,在一个表中找什么字段,只要SELECT xx FROM xx就可以了,如果用C语言,则需要大量的循环和比较操作。
未来,编程语言将发展到和人类的自然语言统一,电脑能听懂人类的语言,这样人们就只要告诉电脑要做什么,而不用告诉电脑怎么做。最近,参加知识竞赛而闻名的IBM计算机Watson在人类语言理解上有了很大的突破,它还能够回答一些脑筋急转弯题目,相信未来会做得更好。
3.2 指令集发展的来龙去脉
3.2.1 CISC时代——粗放式扩张
CISC代表Complex Instruction Set Computer(复杂指令集计算机),其实最早并没有CISC这个词,只是后来出现了新的计算机设计思想,于是将采用新思想开发的计算机称为RISC(Reduced Instruction Set Computer,精简指令集计算机),将以前的计算机称为CISC。这就好比世上本没有旧中国,只是新中国出现了,才有了旧中国。CISC和RISC也分别代表了两种处理器的指令集类型。
计算机发展早期,人们使用汇编语言编程,自然更喜欢强大和好用的指令集,处理器的设计人员于是将指令集设计得更强大、更灵活。后来高级语言出现,处理器设计人员又在指令集中增加了一些指令集和特性直接完成高级语言对应的某些功能,如复杂的寻址模式,直接对应指针的运算。
那个时期的存储器既昂贵且速度慢,因此指令使用了变长编码,以节约存储空间。由于一条指令能完成很多的功能,对内存的访问也减少了,这样也减少了缓慢的存储器访问对程序性能的影响。
当下还在使用的最出名的CISC指令集是Intel的x86指令集。
3.2.2 RISC时代——优化配置资源,合理提升效率
上世纪70年代中叶,IBM的John Cocke发现,很多时候,处理器提供的大量指令集和复杂寻址方式并不会被编译器生成的代码用到,套用当下流行的二八定律,那就是20%的简单指令经常被用到,它们占程序总指令数的80%,而指令系统中其余80%复杂的指令则很少使用,只占程序总指令数的20%。
一些专家基于这种思想,将指令集和处理器进行了重新的设计,在新的设计中,只保留了常用的简单的指令,这样处理器就不需要浪费太多的晶体管去做那些很复杂又很少使用的功能。典型的例子就是Intel的x86指令集手册有一千多页,而一般的RISC处理器指令集手册则只有二、三百页。
由于简单指令大部分时间都能在一个cycle内完成,因此处理器的频率得以大幅提升。这个时期为了更好地实现流水线,指令集采用了定长编码,这样指令的译码过程就简单了。
由于指令集更精简,这种思想的指令集就叫RISC指令集,以前的指令集就叫CISC指令集。RISC是计算机历史上的一个飞跃,RISC先驱之一Steven Przybylski半开玩笑地把RISC定义为:“1985年之后发布的所有处理器”。ARM、MIPS、Power、DSP等都属于RISC体系,其中MIPS最遵守RISC规则。
IBM、加州大学伯克利分校的David Patterson、斯坦福大学的John Hennessy是RISC研究的先驱,后来很多商业的处理器都受到他们的影响,Power处理器来自IBM,PowerPC处理器起源于Power,ARM、SPARC处理器受到伯克利RISC的影响,MIPS来自斯坦福,Alpha处理器受到它的影响。
3.2.3 后RISC时代——不管黑猫白猫,抓到老鼠就是好猫
RISC处理器通过更合理的微架构,在性能上超越了传统的CISC,在最初的较量中,Intel处理器败下阵来,服务器的处理器大部分被RISC阵营所占据。在PC领域,由于众多的应用软件要求处理器后向兼容,因此Intel的地位暂时没有动摇。
Intel当时也尝试做RISC处理器,但是因为兼容性问题,市场不买账。《非诚勿扰2》中有句经典台词:“婚姻怎么选都是错,长久的婚姻就是将错就错。”秉持这一理念,Intel决定一条路走到黑,将兼容性进行到底,但是CISC架构很难提升性能的压力却仍然摆在Intel面前。不过世界上没有什么迈不过去的坎,任何困难都有解决的方法,Intel终于在Pentium Pro处理器问世时解决了这一问题。
David B. Papworth和他的同事一起设计了Pentium Pro处理器,它的微架构是Intel著名的P6,在很多教科书上都会介绍。在这个处理器中,x86指令集被先解码为类似于RISC指令的微操作(micro- operations,简称为uops),以后的执行过程采用RISC内核,这种架构一直延续至今,成为一代经典。CISC这种古老的架构,通过巧妙的设计,又一次焕发新春,可以说是老树发新芽的典范,Papworth也因此在Intel内获得很多奖项,成为Intel Fellow。
这种处理器结构相较于没有兼容性压力的纯RISC处理器要复杂,但好在有兼容性的优势来保证市场。80、90年代,服务器厂商很多,不少服务器厂商都自己生产处理器,而生产处理器是个烧钱的行当,如果没有一定销量的保证,就会得不偿失,这也限制了处理器芯片的研发,而Intel有良好的PC市场来保证研发,因此x86处理器的性能逐渐超过了同期的RISC处理器,抢占了服务器市场,导致其他的处理器厂商只能向低功耗,或面向专有领域的嵌入式方向发展。
RISC和CISC都是时代的产物,也无所谓谁好谁坏。RISC作为新兴事物,在很多思想上要更先进,不过CISC也有它的一些优点。
CISC指令的一条指令常常对应着RISC指令的多条指令,在RISC处理器中,过分精简的指令数量,使得RISC 处理器与存储器之间的数据交换增多,而存储器的工作速度远低于处理器,很容易导致性能恶化。
增加处理器性能的一种方法就是多提供指令功能,RISC中的“精简指令”也越来越变得不精简。x86处理器近几年逐渐增加了几百条MMX、SSE指令,用于提高多媒体程序和其他特殊程序的性能。DSP、ARM、MIPS等处理器每代也会增加不少的指令,用于完成特殊的任务,哪怕是这些功能很少被使用。
传统的RISC指令集为了译码方便,指令采用定长编码,因此程序空间较大,虽然存储成本相对较低,但是在很多应用下,程序空间较大会降低Cache的命中率,降低程序的执行效率。
TI C64 DSP采用定长指令编码,每个指令32bit,而在它的升级版本C64+内核中,就将一些指令改为16bit,这样大大减少了程序长度。Tensilica公司的可配置处理器内核Xtensa也是采用16bit/24bit的指令长度,同样的例子还有MIPS、ARM等处理器,ARM的Thumb指令集就是16bit的,这种简单的变长指令集,并没有增加多少译码电路,不过却能大幅度减少程序空间和功耗。
总结
处理器/指令集呈现出螺旋式的发展:逐渐做大,然后优化,然后又做大……从量变到质变,然后进入下一轮的量变和质变,只是此“质”已非彼“质”了。