第五章、基于Verilog的CPU设计_第1页
第五章、基于Verilog的CPU设计_第2页
第五章、基于Verilog的CPU设计_第3页
第五章、基于Verilog的CPU设计_第4页
第五章、基于Verilog的CPU设计_第5页
已阅读5页,还剩17页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、作为电子或计算机专业的学生,电脑(计算机)对于大家已经不再是什么新鲜的东西了。大家都知道,计算机可以为我们做很多的事情,替我们节约很多时间,为我们计算各种复杂的数据并且准且无误。那么,计算机为什么能够做这些事情呢?计算机内部到底是怎么工作的呢?本章将为你展示计算机的主要部件的设计过程。计算机最核心的部分叫做中央处理器,也就是我们常说的CPU,计算机所做的工作都是由CPU来完成的。当然,作为学习,我们不能够设计出类似奔腾处理器(Pentium microprocessor)的CPU,我们用一个能够完成简单功能的简单的CPU作为讲解,麻雀虽小,五脏俱全,这个简单的cpu具有一般CPU的全部基本特征

2、。CPU概览众所周知,cpu只能识别二进制数据,也就是机器码。所以,在CPU内部靠不同的二进制序列来区别不同的机器码。我们把这些机器码存储在一个存储器中,共CPU读取使用。同时,为了用户和程序员能够更好的记住机器码的含义,采用相应的助记符来表示这些机器码,如:用LDA表示二进制的000等。这些助记符通常被称为汇编语言,不同架构的计算机的汇编语言通常都是各不相同的。CPU的内部框架下图是本章准备设计的一个CPU内部结构框架。存储器ALU控制器指令解码器PCCPU的内部工作原理不同架构的计算机工作原理也是不同的,此处仅以本课本中讲授的CPU工作原理为例讲解。首先,CPU的指令是存储在存储器中的,所

3、以cpu执行指令的第一步是从存储器中取出(fetch)指令,第二步,将取出的指令解码,第三步,根据指令解码出的功能决定是否再从存储器中取出需要处理的数据,第四步,根据解码出的指令决定进行相应的计算,这由(ALU)完成。第五步,根据解码出的指令决定是否将计算结果存入存储器,第六步,修改PC指针,为下一次取指令做准备。整个执行过程由控制器控制。在介绍具体的CPU硬件架构之前,我们先确定一些CPU能够执行的指令,在这里,为了教学演示,我们设定6个计算机指令,分别为:LDA指令、STA指令、ADD指令、SUB指令、AND指令和HLT指令。指令集表示的含义见下表:操作码助记符执行的功能000LDA ad

4、dr将地址为addr处的存储器中的内容装载到A寄存器001STA addr将A寄存器的内容存储到存储器中的addr地址处010ADD addr将A寄存器的内容加上存储器中的addr地址处的内容011SUB addr将A寄存器的内容减去存储器中的addr地址处的内容100AND addr将A寄存器的内容与上存储器中的addr地址处的内容101HLT停止指令的执行前两条指令,“LDA”和“STA”是数据传输指令,就像助记符表示的那样,这些指令在A寄存器和存储器之间传送数据。对于LDA指令,“源”数据是存储器的addr地址处的值(也称为内容),目的寄存器是A寄存器;对于STA指令,“源”数据是A寄存

5、器,目的寄存器是存储器的addr地址处的存储空间。这里为了以后的表达方便,我们采用一种简单的方式来表示上述指令的功能,如:表示LDA addr指令可以用Aß(addr),而STA addr可以用(addr)ßA来表示。同样,加法指令ADD addr用AßA+(addr)表示,减法指令SUB addr用AßA (addr)表示。“AND addr”用AßA & (addr)表示。注意,由于这里涉及到计算的结果,我们设置了一些标志用来标识结果的特殊性,如:(零标志),标识运算的结果中为;(负数标志),标识运算的结果中小于;(溢出标志),标识

6、运算的结果溢出;(进位标志),标识运算的结果中产生了进位;值得一提的是位的处理,加法和减法对于的处理是不一样的。对于,进位标志是中的最高位产生了进位;对于减法,最高位产生借位将为置。为了能够更好的理解CPU的运行,我们以一个简单的汇编程序的执行来讲解。这个程序将使用以上的全部指令。在这里,我们使用助记符的方式写汇编程序,实际在,在存储器内部是以二进制码来存储的,例如:第一行“LDA 01011”在存储器中为00001011。LDA 01011 Aß(01011)ADD 01100 AßA+(01100)STA 01101 (01100)ßALDA 01011 A&

7、#223;(01011)AND 01100 AßA & (01100)STA 01110 (01110)ßALDA 01011 Aß(01011)SUB 01100 AßA(01100)STA 01111 (01111)ßAHLT halt the computer我们把这段程序放在存储器的开始(更方便程序的启动)。由于在代码中我们用到了存储器地址为01011和01100中的数据,所以我们可以在那两个位置放置一些要处理的数据。存储器中的详细内容参见下表。存储器地址内容(指令或者数据)000000000101100001010011000

8、00100010110100011000010110010010001100001010010111000110000010110011101101100010000010111101001101000000101001011101010100110001010101011010111001111现在,我们逐步分析汇编程序的执行情况,根据上表,我们看到,前三条指令的目的是将01011地址处对应的数据和01100处对应的数据进行相加,并且把结果存储到地址01101处。见下表阴影处。由于计算结果为11111111,所以,影响标志位NF。存储器地址内容(指令或者数据)00000ADD:1010101

9、0+ 01010101 1111111100001011000010100110000010001011010001100001011001001000110000101CF = 0NF = 1VF = 0ZF = 000101110001100000101100111011011000100000101111010011010000001010010111010101001100ADD0101010101101111111110111001111第3,4,5条指令是将01011地址处对应的数据和01100处对应的数据进行相“与”,并且把结果存储到地址01110处。此时,与运算的结果为0000

10、0000,所以影响标志位ZF,同时将NF标志清0。存储器地址内容(指令或者数据)00000AND:10101010& 01010101 0000000000001011000010100110000010001011010001100001011001001000110000101001011100011000001011001110110110001000001011110100110100000010100101110101010011000101010101101AND11111111011100000000001111CF不受影响NF = 0VF不受影响ZF = 1接下来的3条

11、指令是将01011地址处对应的数据和01100处对应的数据进行相“减”,并且把结果存储到地址01110处。此时,相减运算的结果为00000000,所以影响标志位ZF,同时将NF标志清0。存储器地址内容(指令或者数据)00000SUB:0000101100001101010100100110000010 11111111 0101010100101101000110000101100100ADD:1000110000101 10101010101010100010111000110+ 10000101100111 1)010101010110110001000结果溢出!0010111101001

12、101000000101001011101010100110001010101011011111111101110SUB000000000111101010101CF = 0NF = 0VF = 1ZF = 0最后一条指令(地址01001处)是告诉计算机停止执行任何指令,计算机停在那里。计算机各个组成模块的设计在前面的CPU内部结构框架图中,由于部分总线使用的双向总线,为了简化设计,我们将其修改为单向总线,见下图:存储器ALU控制器指令解码器PC数据出数据入下面我们将对计算机的各个组成部分分别用HDL的方式将其描述出来。为了能够对各个部分灵活的控制,我们建议,对于时序电路,一般设有时钟端、同步

13、或者异步复位端、使能端,对于组合逻辑电路,至少要有使能端,且设计的电路要尽可能有扩展性和可控制性。PC部分PC(程序计数器)负责生成存储器的地址值(在下一步骤中会将对应地址的存储器中的指令取出),然后将自身+1,使其指向下一条将要执行的指令,为取下一条指令的执行做好准备。根据这些,我们设计的PC端口有以下时钟端 clock:异步复位端reset,也可以设计成同步复位 En,使能端,当en为高电平的时候,允许pc工作Pc,当前程序计数器的值,此处拟设计的计算机可以寻址32个字节,故pc是一个5位宽总线在模块内部有pc_next,指向下一个pc(即:pc + 1),五位宽。在下一个时钟信号上升沿的

14、时候将pc + 1赋值给pc。PCPC模块clockresetpcenpc的顶层模块应该如下图module pc(clock,reset,en,pc);input clock,reset, en;output reg 4:0 pc;reg 4:0 pc_next; (内部的一个值)always(posedge clock or posedge reset)begin if(reset) pc <= 0; else if(en) pc <= pc_next; else pc <= pc;end/*always(posedge clock or posedge reset)beg

15、in if(reset) pc_next <= 0; else if(en) pc_next <= pc + 1; else pc_next <= pc_next ;end*/Assign pc_next=pc+1;endmodule这里使用了两个always进程块(或者是一个always,一个assign),根据HDL特点,这两个进程同时执行;第一个进程在clock上升沿的时候将pc_next赋值给pc,第二个进程在clock上升沿的时候将实现pc_next+1的操作此时刻异步复位,pc为5h00以下为pc的仿真结果。实际生成的RTL级电路图如下: 存储器的设计根据实际应用

16、进行简化,实际的存储器一般有数据线口(双向的),地址线,读使能、写使能和片选信号线等,此处由于双向信号线处理起来比较烦琐,拟使用两组数据线,一组为输入数据线,一组为输出数据线,当需要将数据存储到存储器的时候,数据由输入总线输入,当需要从存储器读取数据的时候,数据由输出总线输出。另外,增加异步复位和时钟端,使数据的存取进行同步。实际用到的端口如下:clock:时钟信号线reset:复位信号,高电平有效。addr:存储器地址线,5位宽din:数据线输入dout:数据线输出wr:写使能端,高电平有效rd:读使能端,高电平有效模块的原理图如下:存储器存的是指令,通过地址找到相应指令Memory模块 c

17、lockresetrdwrdin 8dout 8addr 5 实现的源代码为:module memory(clock,/:时钟信号线reset,/:复位信号,高电平有效。addr,din,/:数据线输入dout,/:数据线输出wr,/:写使能端,高电平有效rd /:读使能端,高电平有效);inputclock;/:时钟信号线inputreset;/:复位信号,高电平有效。input4:0 addr;/存储器地址input7:0din;/:数据线输入output7:0dout; reg7:0dout;/数据线输出/:数据线输出inputwr;/:写使能端,高电平有效inputrd;/:读使能端,

18、高电平有效reg7:0 mem0:31;always(posedge clock or posedge reset)beginif(reset) begin 指定mem每一个地址存的是什么指令想到RAM的结构 mem0 <= 'b00001011;/ LDA 01011 Aß(01011)mem1 <= 'b01001100;/ ADD 01100 AßA+(01100)mem2 <= 'b00101101; /STA 01101 (01100)ßAmem3 <= 'b00001011;/ LDA 01011

19、 Aß(01011)mem4 <= 'b10001100;/ AND 01100 AßA & (01100)mem5 <= 'b00101110;/ STA 01110 (01110)ßAmem6 <='b00001011;/ LDA 01011 Aß(01011)mem7 <='b01101100;/ SUB 01100 AßA(01100)mem8 <='b00101111;/ STA 01111 (01111)ßAmem9 <='b101

20、00000;/ HLT halt the computermem10<='b00000000;/mem11<='b10101010;/haamem12<='b01010101;/h55mem13<='b00000000;mem14<='b00000000;mem15<='b00000000;mem16<='b00000000;mem17<='b00000000;mem18<='b00000000;mem19<='b00000000;mem20<=&#

21、39;b00000000;mem21<='b00000000;mem22<='b00000000;mem23<='b00000000;mem24<='b00000000;mem25<='b00000000;mem26<='b00000000;mem27<='b00000000;mem28<='b00000000;mem29<='b00000000;mem30<='b00000000;mem31<='b00000000; endelse beg

22、in if(wr) memaddr <= din; if(rd) dout <= memaddr; end endendmodule此模块的仿真电路如下:指令解码器的设计指令解码器的作用就是将从指令存储器中读出的指令进行翻译,是cpu能够根据翻译后的代码执行不同的操作。这里拟将指令分成两个组成部分:第一部分为操作码部分,由指令中的高三位组成,第二部分为存储器的地址,由指令的低五位组成。D7D6D5D4D3D2D1D0操作码操作数的地址从存储中取出的指令根据前面的已经设置好的操作码和助记符的关系,可以使用if语句或者case语句来表述:例如:(用if语句描述) if(instruct

23、ion7:5 = 3b000) /LDA指令 else if(instruction7:5 = 3b001) /STA指令 用case语句描述 case(instruction7:5) 3b000: /LDA指令 3b001: /STA指令endcase根据以上,设置指令译码器主要有以下一些端口clock时钟端口reset 复位端口en 译码使能端instruction 指令输入端口opcode 操作码输出端口addr 存储器地址输出端口模块对应的符号如下:仿真波形图如下:算数逻辑单元(ALU)算数逻辑单元完成各种运算功能,此处设计的alu具有一个寄存器A(通常称作累加器),alu具有一个输入

24、端口,使用累加器A和这个输入端口作为两个运算数据的输入,并将运算结果存放在累加器A中。为了使所有的单元都受控制器的控制,使设计简单化,分别设置几个运算控制使能端,完成不同的运算使能。另外,为了能够监测运算结果的特殊性,设置以下相应的标志位,如进位位、溢出位、零标志位和负数标志位。本算数逻辑运算单元拟设计的端口有几下几种clock时钟reset复位端en使能ALUa累加器输出寄存器din操作数1输入n输出负标志z输出0标志c输出进位标志v输出溢出标志add_en使能加法运算sub_en使能减法运算pass_en使din直通至累加器A,部分指令需要and_en使能“与”运算模块图如下:实现的源代码

25、为:module alu(clk,reset,en, a,din,n,z,c,v,add_en,sub_en,and_en,pass_en);input clk,reset,en,add_en,sub_en,and_en,pass_en;input 7:0 din;output n,z,c,v;output reg 7:0 a;reg c;always(posedge clk or posedge reset)if(reset) begina<=0;c<=0;endelse begin if(en) beginif(add_en)c,a<=a7:0+din;else if(s

26、ub_en)c,a<=a7:0-din;else if(and_en)a<=a&din;else if(pass_en)a<=din;endendassign z=(a=8'b0)?1:0;assign n=(c=1)?1:0;assign v=(a>127)|(a<-128)?1:0;endmodule仿真波形如下图:控制单元接下来就是控制单元的设计了。控制单元需要做以下一些事情:1) 给出操作时序。上述的单元模块必须在一定的顺序下工作,从存储器中取指令->译码->根据操作码决定是否从存储器中取数据->确定ALU的运算。此工作可

27、以通过设置一些时能端口,如:按照一定的顺序使能相应的模块即可。2) 控制器必须能够识别译码器输出的指令,并且根据指令发出不同的命令信号,故需要有一个指令输入端口,opcode2:0 3) 如果需要做ALU运算的话,给出需要做相应运算的使能。如:给出使能加法运算信号instr_add使能 add_en4) 在一条指令中,如果即需要从存储器中取指令,又需要从存储器中取数据的话,则,需要在不同的阶段选择不同的存储器地址输入。故:需要一个地址选择端口。所以控制单元应有以下一些端口Clock:时钟端口Reset:异步复位端口s0s5:分别用作各个阶段的使能信号端口Addrsel:选择程序的地址或者是数据

28、的地址Instr_add:给alu的加法运算使能Instr_sub:给alu的减法运算使能Instr_and:给alu的 “与” 运算使能Instr_pass:给alu的直通运算使能,即不做运算opcode2:0 :解码器解码后的指令输出给控制器模块图如下:实现的源代码为:module control(input clock,input reset,output reg s0, / fetch instruction (各个指令)output reg s1, / decodeoutput reg s2, / read memory data for processoutput reg s3,

29、/ enable alu to computeoutput reg s4, / write to memory if nessaryoutput reg s5, / increase pcoutput reg addrsel,output reg instr_add,output reg instr_sub,output reg instr_and,output reg instr_pass,input 2:0 opcode);(控制它输出是哪个指令)parameter LDA=3'b000,STA=3'b001,ADD=3'b010, SUB=3'b011,A

30、ND=3'b100,HLT=3'b101;/ JMP=3'b110, JZF=3'b111;reg 2:0 cnt; /*mem2 <= 'b00101101; /STA 01101 (01100)ßAmem3 <= 'b00001011;/ LDA 01011 Aß(01011)mem4 <= 'b10001100;/ AND 01100 AßA & (01100)mem5 <= 'b00101110;/ STA 01110 (01110)ßAmem6 &l

31、t;='b00001011;/ LDA 01011 Aß(01011)mem7 <='b01101100;/ SUB 01100 AßA(01100)mem8 <='b00101111;/ STA 01111 (01111)ßAmem9 <='b10100000;/ HLT halt the computermem10<='b00000000;/mem11<='b10101010;/haamem12<='b01010101;/h55 */(注释掉的)always(posed

32、ge clock or posedge reset)if(reset)cnt <= 0;elseif(cnt = 5) cnt <= 0;else cnt <= cnt +1;always*begincase(cnt)0:begin/ fetch instructions0 <=1;s1<=0;s2<=0;s3<=0;s4<=0;s5<=0;/mem0 <= 'b00001011;/ LDA 01011 Aß(01011)addrsel<=0; end1:begin/ decodes0 <=0;s1<

33、;=1;s2<=0;s3<=0;s4<=0;s5<=0;/ mem1 <= 'b01001100;/ ADD 01100 AßA+(01100)addrsel<=0;end2:begin/ read memory data for process if nessary s0 <=0;s1<=0;/*s2=1;*/s3<=0;s4<=0;s5<=0; addrsel<=1;if(opcode = LDA )|(opcode = ADD)|(opcode = SUB)|(opcode = AND)s2<

34、=1;elses2<=0;end3:begin /enable ALU to computes0 <=0;s1<=0;s2<=0;s3<=1;s4<=0;s5<=0; addrsel<=1; if(opcode = LDA) begin instr_add <=0;instr_sub <=0;instr_and <=0; instr_pass<=1; endelse if(opcode = ADD) begin instr_add <=1;instr_sub <=0;instr_and <=0; inst

35、r_pass<=0; endelse if(opcode = SUB) begin instr_add <=0;instr_sub <=1;instr_and <=0; instr_pass<=0; endelse if(opcode = AND) begin instr_add <=0;instr_sub <=0;instr_and <=1; instr_pass<=0; endelse if(opcode = STA) begin instr_add <=0;instr_sub <=0;instr_and <=0; i

36、nstr_pass<=0; endelse begin instr_add <=0;instr_sub <=0;instr_and <=0; instr_pass<=0; endend4:begin/ write to memory if nessarys0 <=0;s1<=0;s2<=0;s3<=0;/*s4<=1;*/s5<=0; addrsel<=1;if(opcode = STA) s4<=1;else s4<=0;end5:begin s0 <=0;s1<=0;s2<=0;s3<

37、;=0;s4<=0;s5<=1;addrsel<=1; endendcaseendendmodule仿真图如下:其中opcode代表着不同的操作,在不同的操作下,使能各个部件的s*端口有效与否也是不一样的。Cpu顶层设计将各个单元模块生成符号,并且在图形输入中进行调用和连接,就可以进行cpu的仿真了。顶层原理图如下:其中sel2_1的代码如下:module sel2_1(input 4:0 a,input 4:0 b,input sel,output 4:0 c);assign c=sel?a:b;endmodule用于选择memory的地址。当取指令时,将pc连接到memo

38、ry地址线上。当从存储器中取操作数时,将解码后的地址连接到memory的地址线上。以下是cpu顶层设计的仿真时序图:第3条指令执行结果第1条指令第2条指令第6条指令执行结果第2条指令从仿真结果来看,该cpu实现了相应指令功能。下面给本CPU增加输入和输出端口,根据微机原理相关知识。输入输出口(即IO口)有两种编址方式,一种是独立编址,一种是统一编址。此处为了设计的简便,采用统一编址的方式进行cpu的修改。本设计中CPU的寻址空间是32字节。将IO加在存储器空间的最高位地址,即:从mem31读数改为从输入端口读数,这样就可以将输入端口(可以用键盘)的数据读入累加器A了;向mem31写数据改为向输

39、出端口写数据,这样就可以将累加器A中的值写到端口了(可以用来驱动LED的哦)。修改memory中的代码:module memory(clock,reset,addr,din,dout,rd,wr,IN,OUT);input clock,reset;input 7:0 din;input 4:0 addr;output reg 7:0 dout;input rd,wr; input 7:0 IN; /修改的部分 output reg 7:0 OUT; /修改的部分 /reg7:0 mem31:0;reg7:0 mem30:0;always(posedge clock or posedge res

40、et)if(reset)beginmem0 <='b00001011; /LDA 11mem1 <='b01001100; /ADD 12mem2 <='b00101101; /STA 13/mem3 <='b00001011; /LDA 11mem3 <='b00011111; /LDA 31 /修改的部分mem4 <='b10001100; /AND 12/mem5 <='b00101110; /STA 14mem5 <='b00111111; /STA 31 /修改的部分mem6 <='b00001011; /LDA 11mem7 <='b01101100; /SUB 12mem8 <='b00101111; /STA 15mem9 <='b10100000; /HLTmem10<='b1;mem11<='b10101010;mem12<='b01010101;mem13<='b1;mem14<='b1;mem15<='b1;mem16<='b1;m

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论