CPU 到底是怎么识别代码的?( 二 )


那我要是想算呢?

AX2+B
简单,你把加法器模块和位移模块的接线改一下就行了,改成输入A先过位移模块,再进加法器就可以了 。
啥????你说啥???你的意思是我改个程序还得重新接线?
所以你以为呢?编程就是把线来回插啊 。
CPU 到底是怎么识别代码的?

文章插图
 
惊喜不惊喜?意外不意外?
早期的计算机就是这样编程的,几分钟就算完了但插线好几天 。而且插线是个细致且需要耐心的工作,所以那个时候的程序员都是清一色的漂亮女孩子,穿制服的那种,就像照片上这样 。是不是有种生不逢时的感觉?
虽然和美女作伴是个快乐的事,但插线也是个累死人的工作 。所以我们需要改进一下,让CPU可以根据指令来相加或者乘2 。
这里再引入两个模块,一个叫flip-flop,简称FF,中文好像叫触发器 。
 
CPU 到底是怎么识别代码的?

文章插图
 
这个模块的作用是存储1bit数据 。比如上面这个RS型的FF,R是Reset,输入1则清零 。S是Set,输入1则保存1 。RS都输入0的时候,会一直输出刚才保存的内容 。
我们用FF来保存计算的中间数据(也可以是中间状态或者别的什么),1bit肯定是不够的,不过我们可以并联嘛,用4个或者8个来保存4位或者8位数据 。这种我们称之为寄存器(Register) 。
另外一个叫MUX,中文叫选择器 。
CPU 到底是怎么识别代码的?

文章插图
 
这个就简单了,sel输入0则输出i0的数据,i0是什么就输出什么,01皆可 。同理sel如果输入1则输出i1的数据 。当然选择器可以做的很长,比如这种四进一出的
 
CPU 到底是怎么识别代码的?

文章插图
 
具体原理不细说了,其实看看逻辑图琢磨一下就懂了,知道有这个东西就行了 。
有这个东西我们就可以给加法器和乘2模块(位移)设计一个激活针脚 。
这个激活针脚输入1则激活这个模块,输入0则不激活 。这样我们就可以控制数据是流入加法器还是位移模块了 。
于是我们给CPU先设计8个输入针脚,4位指令,4位数据 。
我们再设计3个指令:
0100,数据读入寄存器
0001,数据与寄存器相加,结果保存到寄存器
0010,寄存器数据向左位移一位(乘2)
为什么这么设计呢,刚才也说了,我们可以为每个模块设计一个激活针脚 。然后我们可以分别用指令输入的第二第三第四个针脚连接寄存器,加法器和位移器的激活针脚 。
这样我们输入0100这个指令的时候,寄存器输入被激活,其他模块都是0没有激活,数据就存入寄存器了 。同理,如果我们输入0001这个指令,则加法器开始工作,我们就可以执行相加这个操作了 。
这里就可以简单回答这个问题的第一个小问题了:
那cpu 是为什么能看懂这些二级制的数呢?
为什么CPU能看懂,因为CPU里面的线就是这么接的呗 。你输入一个二进制数,就像开关一样激活CPU里面若干个指定的模块以及改变这些模块的连同方式,最终得出结果 。
几个可能会被问道的问题
Q:CPU里面可能有成千上万个小模块,一个32位/64位的指令能控制那么多吗?
A:我们举例子的CPU里面只有3个模块,就直接接了 。真正的CPU里会有一个解码器(decoder),把指令翻译成需要的形式 。
Q:你举例子的简单CPU,如果我输入指令0011会怎么样?
A:当然是同时激活了加法器和位移器从而产生不可预料的后果,简单的说因为你使用了没有设计的指令,所以后果自负呗 。(在真正的CPU上这么干大概率就是崩溃呗,当然肯定会有各种保护性的设计,死也就死当前进程)
细心的小伙伴可能发现一个问题:你设计的指令
【0001,数据与寄存器相加,结果保存到寄存器】
这个一步做不出来吧?毕竟还有一个回写的过程,实际上确实是这样 。我们设计的简易CPU执行一个指令差不多得三步,读取指令,执行指令,写寄存器 。
经典的RISC设计则是分5步:读取指令(IF),解码指令(ID),执行指令(EX),内存操作(MEM),写寄存器(WB) 。我们平常用的x86的CPU有的指令可能要分将近20个步骤 。
你可以理解有这么一个开关,我们啪的按一下,CPU就走一步,你按的越快CPU就走的越快 。咦?听说你有个想法?少年,你这个想法很危险啊,姑且不说你有没有麒麟臂,能不能按那么快(现代的CPU也就2GHz多,大概也就一秒按个20亿下左右吧)


推荐阅读