作为电子或计算机专业的学生,电脑(计算机)对于大家已经不再是什么新鲜的东西了。大家都知道,计算机可以为我们做很多的事情,替我们节约很多时间,为我们计算各种复杂的数据并且准且无误。那么,计算机为什么能够做这些事情呢?计算机内部到底是怎么工作的呢?本章将为你展示计算机的主要部件的设计过程。计算机最核心的部分叫做中央处理器,也就是我们常说的CPU,计算机所做的工作都是由CPU来完成的。当然,作为学习,我们不能够设计出类似奔腾处理器(Pentiummicroprocessor)的CPU,我们用一个能够完成简单功能的简单的CPU作为讲解,麻雀虽小,五脏俱全,这个简单的cpu具有一般CPU的全部基本特征。CPU概览众所周知,cpu只能识别二进制数据,也就是机器码。所以,在CPU内部靠不同的二进制序列来区别不同的机器码。我们把这些机器码存储在一个存储器中,共CPU读取使用。同时,为了用户和程序员能够更好的记住机器码的含义,采用相应的助记符来表示这些机器码,如:用LDA表示二进制的000等。这些助记符通常被称为汇编语言,不同架构的计算机的汇编语言通常都是各不相同的。CPU的内部框架下图是本章准备设计的一个CPU内部结构框架。CPU的内部工作原理不同架构的计算机工作原理也是不同的,此处仅以本课本中讲授的CPU工作原理为例讲解。首先,CPU的指令是存储在存储器中的,所以cpu执行指令的第一步是从存储器中取出(fetch)指令,第二步,将取出的指令解码,第三步,根据指令解码出的功能决定是否再从存储器中取出需要处理的数据,第四步,根据解码出的指令决定进行相应的计算,这由(ALU)完成。第五步,根据解码出的指令决定是否将计算结果存入存储器,第六步,修改PC指针,为下一次取指令做准备。整个执行过程由控制器控制。存储器ALU控制器指令解码器PC在介绍具体的CPU硬件架构之前,我们先确定一些CPU能够执行的指令,在这里,为了教学演示,我们设定6个计算机指令,分别为:LDA指令、STA指令、ADD指令、SUB指令、AND指令和HLT指令。指令集表示的含义见下表:操作码助记符执行的功能000LDAaddr将地址为addr处的存储器中的内容装载到A寄存器001STAaddr将A寄存器的内容存储到存储器中的addr地址处010ADDaddr将A寄存器的内容加上存储器中的addr地址处的内容011SUBaddr将A寄存器的内容减去存储器中的addr地址处的内容100ANDaddr将A寄存器的内容与上存储器中的addr地址处的内容101HLT停止指令的执行前两条指令,“LDA”和“STA”是数据传输指令,就像助记符表示的那样,这些指令在A寄存器和存储器之间传送数据。对于LDA指令,“源”数据是存储器的addr地址处的值(也称为内容),目的寄存器是A寄存器;对于STA指令,“源”数据是A寄存器,目的寄存器是存储器的addr地址处的存储空间。这里为了以后的表达方便,我们采用一种简单的方式来表示上述指令的功能,如:表示LDAaddr指令可以用A(addr),而STAaddr可以用(addr)A来表示。同样,加法指令ADDaddr用AA+(addr)表示,减法指令SUBaddr用AA-(addr)表示。“ANDaddr”用AA&(addr)表示。注意,由于这里涉及到计算的结果,我们设置了一些标志用来标识结果的特殊性,如:Z(零标志),标识运算的结果A中为0;N(负数标志),标识运算的结果A中小于0;V(溢出标志),标识运算的结果A溢出;C(进位标志),标识运算的结果A中产生了进位;值得一提的是C位的处理,加法和减法对于C的处理是不一样的。对于ADD,进位标志是A中的最高位产生了进位;对于减法,最高位产生借位将C为置1。为了能够更好的理解CPU的运行,我们以一个简单的汇编程序的执行来讲解。这个程序将使用以上的全部指令。在这里,我们使用助记符的方式写汇编程序,实际在,在存储器内部是以二进制码来存储的,例如:第一行“LDA01011”在存储器中为00001011。LDA01011A(01011)ADD01100AA+(01100)STA01101(01100)ALDA01011A(01011)AND01100AA&(01100)STA01110(01110)ALDA01011A(01011)SUB01100AA-(01100)STA01111(01111)AHLThaltthecomputer我们把这段程序放在存储器的开始(更方便程序的启动)。由于在代码中我们用到了存储器地址为01011和01100中的数据,所以我们可以在那两个位置放置一些要处理的数据。存储器中的详细内容参见下表。存储器地址内容(指令或者数据)00000000010110000101001100000100010110100011000010110010010001100001010010111000110000010110011101101100010000010111101001101000000101001011101010100110001010101011010111001111…现在,我们逐步分析汇编程序的执行情况,根据上表,我们看到,前三条指令的目的是将01011地址处对应的数据和01100处对应的数据进行相加,并且把结果存储到地址01101处。见下表阴影处。由于计算结果为11111111,所以,影响标志位NF。存储器地址内容(指令或者数据)00000000010110000101001100000100010110100011000010110010010001100001010010111000110000010110011101101100010000010111101001101000000101001011101010100110001010101011011111111101110ADDADD:10101010+0101010111111111CF=0NF=1VF=0ZF=001111…第3,4,5条指令是将01011地址处对应的数据和01100处对应的数据进行相“与”,并且把结果存储到地址01110处。此时,与运算的结果为00000000,所以影响标志位ZF,同时将NF标志清0。存储器地址内容(指令或者数据)000000000101100001010011000001000101101000110000101100100100011000010100101110001100000101100111011011000100000101111010011010000001010010111010101001100010101010110111111111011100000000001111…接下来的3条指令是将01011地址处对应的数据和01100处对应的数据进行相“减”,并且把结果存储到地址01110处。此时,相减运算的结果为00000000,所以影响标志位ZF,同时将NF标志清0。CF不受影响NF=0VF不受影响ZF=1ANDAND:10101010&0101010100000000存储器地址内容(指令或者数据)00000000010110000101001100000100010110100011000010110010010001100001010010111000110000010110011101101100010000010111101001101000000101001011101010100110001010101011011111111101110000000000111101010101…最后一条指令(地址01001处)是告诉计算机停止执行任何指令,计算机停在那里。计算机各个组成模块的设计在前面的CPU内部结构框架图中,由于部分总线使用的双向总线,为了简化设计,我们将其修改为单向总线,见下图:CF=0NF=0VF=1ZF=0SUBSUB:10101010-0101010111111111ADD:10101010101010101)01010101+1结果溢出!下面我们将对计算机的各个组成部分分别用HDL的方式将其描述出来。为了能够对各个部分灵活的控制,我们建议,对于时序电路,一般设有时钟端、同步或者异步复位端、使能端,对于组合逻辑电路,至少要有使能端,且设计的电路要尽可能有扩展性和可控制性。PC部分PC(程序计数器)负责生成存储器的地址值(在下一步骤中会将对应地址的存储器中的指令取出),然后将自身+1,使其指向下一条将要执行的指令,为取下一条指令的执行做好准备。根据这些,我们设计的PC端口有以下时钟端clock:异步复位端reset,也可以设计成同步复位En,使能端,当en为高电平的时候,允许pc工作Pc,当前程序计数器的值,此处拟设计的计算机可以寻址32个字节,故pc是一个5位宽总线在模块内部有pc_next,指向下一个pc(即:pc+1),五位宽。在下一个时钟信号上升沿的时候将pc+1赋值给pc。pc的顶层模块应该如下图存储器ALU控制器指令解码器PC数据出数据入PCPC模块clockresetpcenmodulepc(clock,reset,en,pc);inputclock,reset,en;outputreg[4:0]pc;reg[4:0]pc_next;(内部的一个值)always@(posedgeclockorposedgereset)beginif(reset)pc=0;elseif(en)pc=pc_next;elsepc=pc;end/*always@(posedgeclockorposedgereset)beginif(reset)pc_next=0;elseif(en)pc_next=pc+1;elsepc_next=pc_next;end*/Assignpc_next=pc+1;endmodule这里使用了两个always进程块(或者是一个always,一个assign),根据HDL特点,这两个进程同时执行;第一个进程在clock上升沿的时候将pc_next赋值给pc,第二个进程在clock上升沿的时候将实现pc_next+1的操作以下为pc的仿真结果。此时刻异步复位,pc为5’h00实际生成的RTL级电路图如下:+A[4..0]B[4..0]ADDERDQPREENACLRpc[4..0]clockenresetpc[4..0]~reg0Add05'h01--clockresetenpc[4..0]pcinst存储器的设计根据实际应用进行简化,实际的存储器一般有数据线口(双向的),地址线,读使能、写使能和片选信号线等,此处由于双向信号线处理起来比较烦琐,拟使用两组数据线,一组为输入数据线,一组为输出数据线,当需要将数据存储到存储器的时候,数据由输入总线输入,当需要从存储器读取数据的时候,数据由输出总线输出。另外,增加异步复位和时钟端,使数据的存取进行同步。实际用到的端口如下:clock:时钟信号线reset:复位信号,高电平有效。addr:存储器地址线,5位宽din:数据线输入dout:数据线输出wr:写使能端,高电平有效rd:读使能端,高电平有效模块的原理图如下:存储器存的是指令,通过地址找到相应指令实现的源代码为:modulememory(clock,//:时钟信号线reset,//:复位信号,高电平有效。addr,din,//:数据线输入dout,//:数据线输出wr,//:写使能端,高电平有效rd//:读使能端,高电平有效);inputclock;//:时钟信号线inputreset;//:复位信号,高电平有效。input[4:0]addr;//存储器地址input[7:0]din;//:数据线输入output[7:0]dout;reg[7:0]dout;//数据线输出//:数据线输出inputwr;//:写使能端,高电平有效inputrd;//:读使能端,高电平有效Memory