西安邮电学院计算机系西安邮电学院计算机系西安邮电学院计算机系简化的简化的RISCCPURISCCPU设计简介设计简介前言这个CPU模型只是一个教学模型,设计也不一定合理,只是从原理上说明了一个简单的RISC_CPU的构成。我们在这里介绍它的目的是想说明:VerilogHDL仿真和综合工具的潜力和本文介绍的设计方法对软硬件联合设计是有重要意义的。我们也希望这一章能引起对CPU原理和复杂数字逻辑系统设计有兴趣的同学的注意,加入我们的设计队伍。由于我们的经验与学识有限,不足之处敬请读者指正。什么是CPU?CPU即中央处理单元的英文缩写,它是计算机的核心部件。计算机进行信息处理可分为两个步骤:1)将数据和程序(即指令序列)输入到计算机的存储器中。2)从第一条指令的地址起开始执行该程序,得到所需结果,结束运行。CPU的作用是协调并控制计算机的各个部件执行程序的指令序列,使其有条不紊地进行。因此它必须具有以下基本功能:a)取指令:当程序已在存储器中时,首先根据程序入口地址取出一条程序,为此要发出指令地址及控制信号。b)分析指令:即指令译码。是对当前取得的指令进行分析,指出它要求什么操作,并产生相应的操作控制命令。将其功能进一步细化,可概括如下:1)能对指令进行译码并执行规定的动作;2)可以进行算术和逻辑运算;3)能与存储器,外设交换数据;4)提供整个系统所需要的控制;c)执行指令:根据分析指令时产生的“操作命令”形成相应的操作控制信号序列,通过运算器,存储器及输入/输出设备的执行,实现每条指令的功能,其中包括对运算结果的处理以及下条指令地址的形成。尽管各种CPU的性能指标和结构细节各不相同,但它们所能完成的基本功能相同。由功能分析,可知任何一种CPU内部结构至少应包含下面这些部件:1)算术逻辑运算部件(ALU);2)累加器;3)程序计数器;4)指令寄存器,译码器;5)时序和控制部件。RISC即精简指令集计算机(ReducedInstructionSetComputer)的缩写。它是一种八十年代才出现的CPU,与一般的CPU相比不仅只是简化了指令系统,而且是通过简化指令系统使计算机的结构更加简单合理,从而提高了运算速度。从实现的途径看,RISC_CPU与一般的CPU的不同处在于:它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓硬布线逻辑也就是用触发器和逻辑门直接连线所构成的状态机和组合逻辑,故产生控制序列的速度比用微程序控制方式快得多,因为这样做省去了读取微指令的时间。RISC_CPU也包括上述这些部件,下面就详细介绍一个简化的用于教学目的的RISC_CPU的可综合VerilogHDL模型的设计和仿真过程。RISCCPU结构RISC_CPU是一个复杂的数字逻辑电路,但是它的基本部件的逻辑并不复杂。可把它分成八个基本部件:1)时钟发生器2)指令寄存器3)累加器4)RISCCPU算术逻辑运算单元5)数据控制器6)状态控制器7)程序计数器8)地址多路器DATA7..0ALU_OUT7..0ACCUM7..0zeroalu_clkaluopcode2..0data7..0opc_iraddr15..0enarstregisterclk1data7..0accum7..0enaaccumrstclk1CLK1INC_PCZEROLOAD_ACCFETCHLOAD_PCRSTCONTROLRDWROPCODE2..0LOAD_IRHALTDATACTL_ENAIn7..0data7..0datactldata_enafetchaddr12..0ir_addr12..0adrpc_addr12..0ir_addr12..0pc_addr12..0loadclockcounterrstclk1fetchclkalu_clkclk_genDATA7..0\IRST\ICLK\IOPCODE2..IR_ADDR12..0ALU_OUT7..0ACCUM7..0ZEROOPCODE2..0DATA_ENAPC_ADDR12..0ADDR12..0DATA7..0\IHALT\ILOAD_IRIR_ADDR2..0WR\IRD\ILOAD_ACCINC_PCLOAD_PCRISC——CPU中各部件的相互连接关系1时钟发生器CLKCLK1CLKGENALU_CLKFETCHCLKCLK1ALU_CLKFETCH时钟发生器RESETRESET时钟发生器clkgen利用外来时钟信号clk来生成一系列时钟信号clk1、fetch、alu_clk送往CPU的其他部件。其中fetch是外来时钟clk的八分频信号。利用fetch的上升沿来触发CPU控制器开始执行一条指令,同时fetch信号还将控制地址多路器输出指令地址和数据地址。clk1信号用作指令寄存器、累加器、状态控制器的时钟信号。alu_clk则用于触发算术逻辑运算单元。clkclk1clk2clk4fetchalu_clk时钟发生器clkgen的波形moduleclk_gen(clk,reset,clk1,clk2,clk4,fetch,alu_clk);inputclk,reset;outputclk1,clk2,clk4,fetch,alu_clk;wireclk,reset;regclk2,clk4,fetch,alu_clk;reg[7:0]state;parameterS1=8'b00000001,S2=8'b00000010,S3=8'b00000100,S4=8'b00001000,S5=8'b00010000,S6=8'b00100000,S7=8'b01000000,S8=8'b10000000,idle=8'b00000000;assignclk1=~clk;always@(negedgeclk)if(reset)beginclk2=0;clk4=1;fetch=0;alu_clk=0;state=idle;endelsebegincase(state)S1:beginclk2=~clk2;alu_clk=~alu_clk;state=S2;endS2:beginclk2=~clk2;clk4=~clk4;alu_clk=~alu_clk;state=S3;endS3:beginclk2=~clk2;state=S4;endS4:beginclk2=~clk2;clk4=~clk4;fetch=~fetch;state=S5;endS5:beginclk2=~clk2;state=S6;endS6:beginclk2=~clk2;clk4=~clk4;state=S7;endS7:beginclk2=~clk2;state=S8;endS8:beginclk2=~clk2;clk4=~clk4;fetch=~fetch;state=S1;endidle:state=S1;default:state=idle;endcaseendendmodule2指令寄存器DATA[7:0]RSTENACLK1opc_iraddrs[15:0]REGISTERINSTRUCTIONREGISTERDATA[7:0]LOAD_IRCLK1RESETOPCODE[2:0]IR_ADDR[12:0]顾名思义,指令寄存器用于寄存指令。指令寄存器的触发时钟是clk1,在clk1的正沿触发下,寄存器将数据总线送来的指令存入高8位或低8位寄存器中。但并不是每个clk1的上升沿都寄存数据总线的数据,因为数据总线上有时传输指令,有时传输数据。什么时候寄存,什么时候不寄存由CPU状态控制器的load_ir信号控制。load_ir信号通过ena口输入到指令寄存器。复位后,指令寄存器被清为零。每条指令为2个字节,即16位。高3位是操作码,低13位是地址。(CPU的地址总线为13位,寻址空间为8K字节。)本设计的数据总线为8位,所以每条指令需取两次。先取高8位,后取低8位。而当前取的是高8位还是低8位,由变量state记录。state为零表示取的高8位,存入高8位寄存器,同时将变量state置为1。下次再寄存时,由于state为1,可知取的是低8位,存入低8位寄存器中。moduleregister(opc_iraddr,data,ena,clk1,rst);output[15:0]opc_iraddr;input[7:0]data;inputena,clk1,rst;reg[15:0]opc_iraddr;regstate;always@(posedgeclk1)beginif(rst)beginopc_iraddr=16'b0000_0000_0000_0000;state=1'b0;endelsebeginif(ena)//如果加载指令寄存器信号load_ir到来,begin//分两个时钟每次8位加载指令寄存器casex(state)//先高字节,后低字节1’b0:beginopc_iraddr[15:8]=data;state=1;end1’b1:beginopc_iraddr[7:0]=data;state=0;enddefault:beginopc_iraddr[15:0]=16'bxxxxxxxxxxxxxxxx;state=1'bx;endendcaseendelsestate=1'b0;endendendmodule3.累加器DATA[7:0]RSTENACLK1ACCUM[7:0]ACCUMULATORACCUMULATORALU_OUT[7:0]LOAD_ACCCLK1RSTACCUM[7:0]累加器用于存放当前的结果,它也是双目运算其中一个数据来源。复位后,累加器的值是零。当累加器通过ena口收到来自CPU状态控制器load_acc信号时,在clk1时钟正跳沿时就收到来自于数据总线的数据。moduleaccum(accum,data,ena,clk1,rst);output[7:0]accum;input[7:0]data;inputena,clk1,rst;reg[7:0]accum;always@(posedgeclk1)beginif(rst)accum=8'b0000_0000;//Resetelseif(ena)//当CPU状态控制器发出load_acc信号accum=data;//Accumulateendendmodule4.算术运算器DATA[7:0]ACCUM[7:0]ALU_CLOCKOPCODE[2:0]ZEROALU_OUT[7:0]ALUDATA[7:0]ACCUM[7:0]ZEROALU_OUT[7:0]ALU_CLOCKOPCODE[2:0]算术逻辑运算单元根据输入的8种不同操作码分别实现相应的加、与、异或、跳转等8种基本操作运算。利用这几种基本运算可以实现很多种其它运算以及逻辑判断等操作。modulealu(alu_out,zero,data,accum,alu_clk,opcode);output[7:0]alu_out;outputzero;input[7:0]data,accum;input[2:0]opcode;inputalu_clk;reg[7:0]alu_out;parameterHLT=3’b000,SKZ=3’b001,ADD=3’b010,ANDD=3’b011,XORR=3’b100,LDA=3’b101,STO=3’b110,JMP=3’b111;assignzero=!accum;always@(posedgealu_clk)begin//操作码来自指令寄存器的输出opc_iaddr15..0的//低3位casex(opcode)HLT:alu_out=accum;SKZ:alu_out=accum;ADD:alu_out