简易CPU的设计和实现

一.CPU的简介:

     此CPU为冯·诺伊曼架构的,顾名思义程序存储器和数据存储器共用了一组数据和地址总线,当然有兴趣的人可以在此基础上实现下哈佛架构的CPU。

     本CPU内部主要由五大部件组成,每个部件的相互配合,实现了每条指令的有序执行。

二.CPU设计准备:

     所采用软件为QuartusII 9.0,所使用语言为Verilog HDL。

三.CPU架构的设计:

 

四.CPU各个部件的功能简述:

     1.程序计数器(PC):包含当前正在执行的指令的地址,当指令被获取之后,一般情况下,指向下一条指令。

     2.存储器(Memory):主要有三个作用:

            a.存储CPU运行的指令
            b.保存指令运行过程中的临时变量
            c.在指令执行前存放初始化数据

      在本示例中,即是指令存放的地方又是操作数所存放的地方

      3.指令解码器(Idec):

            a.将从指令存储器(本示例中即是从memory中读出)中读出的指令进行翻译,CPU根据翻译后的代码执行不同的操作
            b.将所读取到的指令分为指令码和操作码(本示例中实现6条计算机指令,故指令码采取3位)

      4.算术逻辑单元(ALU):实现数据的二进制运算及判断标志位(负数标志,溢出标志等)的输出。

     5.控制单元(Control):  此部件是本CPU的核心模块,控制着整个CPU有条不紊地运行,它控制着每个部件何时使能工作,ALU何时进行什么样的运算,这个功能在CPU的顶层原理图体现的淋漓尽致。

五.各个部件的代码实现

  1.PC部件的代码实现

module pc (clock,reset,en,pc);
input clock, reset, en;
output reg [4:0] pc;wire [4:0] pc_next;                       //欲寻址的下一条指令//always过程快
always@ (posedge clock or posedge reset)
beginif(reset)                              //系统复位,pc清0pc <= 0;elseif(en)                             //如果使能pc模块,则将下一条指令付给pc端口输出pc <= pc_next;elsepc <= pc;                    //否则,pc保持即不工作
end//assign持续赋值语句
assign pc_next = pc + 1;                 //本处理器中下一条指令的地址为当前地址加1
endmodule 

   2.存储器(Memory)的代码实现

  

module memory (clock,reset,addr,din,dout,wr,rd);input clock;       //时钟信号线
input reset;       //复位信号,高电平有效
input [4:0] addr;  //存储器地址
input [7:0] din;   //数据线输入
output reg [7:0] dout;  //数据线输出
input wr;          //写使能端,高电平有效
input rd;          //读使能端,高电平有效reg [7:0] mem [0:31];  //内部的存储空间always @(posedge clock or posedge reset) beginif (reset) beginmem [0] <= 'b00001011;      //LDA 01011mem [1] <= 'b01001100;      //ADD 01100mem [2] <= 'b00101101;      //STA 01101mem [3] <= 'b00001011;      //LDA 01011mem [4] <= 'b10001100;      //AND 01100mem [5] <= 'b00101110;      //STA 01110mem [6] <= 'b00001011;      //LDA 01011mem [7] <= 'b01101100;      //SUB 01100mem [8] <= 'b00101111;      //STA 01111mem [9] <= 'b10100000;      //HLTmem [10] <= 'b00000000;mem [11] <= 'b10010101;mem [12] <= 'b01100101;mem [13] <= 'b00000000;mem [14] <= 'b00000000;mem [15] <= 'b00000000;mem [16] <= 'b00000000;mem [17] <= 'b00000000;mem [18] <= 'b00000000;mem [19] <= 'b00000000;mem [20] <= 'b00000000;mem [21] <= 'b00000000;mem [22] <= 'b00000000;mem [23] <= 'b00000000;mem [24] <= 'b00000000;mem [25] <= 'b00000000;mem [26] <= 'b00000000;mem [27] <= 'b00000000;mem [28] <= 'b00000000;mem [29] <= 'b00000000;mem [30] <= 'b00000000;mem [31] <= 'b00000000;endelse beginif (wr)mem [addr] <= din;if (rd)dout <= mem [addr];		end
end
endmodule

  3.指令解码器(Idec)的代码实现

module idec (clock,   //时钟端口reset,   //复位端口en,      //译码使能端口instruction,  //指令输入端口opcode,       //操作吗输入端口addr,         //存储器地址输入端口);input clock,reset,en;
input [7:0] instruction;
output reg [2:0] opcode;
output reg [4:0] addr;always @(posedge clock or posedge reset) beginif (reset) beginopcode <= 0;addr <= 0;// reset		endelse if (en) beginopcode <= instruction [7:5];addr <= instruction [4:0];end
end
endmodule

4.算术逻辑单元(ALU)的代码生成:

module alu (clock,      //时钟端口reset,      //复位端口en,         //alu使能端口a,          //累加器输出寄存器din,        //操作数1输入   n,          //负标志z,          //0标志c,          //输出进位标志v,          //输出溢出标志add_en,     //加法使能运算sub_en,     //减法使能运算and_en,     //与运算pass_en,    //使din直通累加器A,不做运算(部分运算需要));input clock,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 clock or posedge reset) if (reset) begina <= 0;      //复位累加器清0,c <= 0;// reset	endelse beginif(en) beginif(add_en){c,a} <= a [7:0] + din;else if(sub_en){c,a} <= a [7:0] - din;else if(and_en)a <= a & din;else if(pass_en)a <= din; endendassign z = (a == 8'b0) ? 1: 0 ;    //0标志,如果累加器为0,z=1
assign n = (c == 1) ? 1: 0 ;       //负数标志,如果借位为1,则n=1
assign v = ((a>127) || (a<-128) ? 1:0 );  //溢出标志endmodule

5.控制单元(Control)的代码实现:

module control (input clock,input reset,         //异步复位端端口output reg s0,       //分别作用各阶段的使能信号个端口output reg s1,output reg s2,output reg s3,output reg s4,output reg s5,output reg addrsel,   //选择程序的地址或者选择数据的地址output reg instr_add, //加法端口使能信号,以下类似output reg instr_sub,output reg instr_and,output reg instr_pass,input [2:0] opcode    //解码器解码后将指令码传给控制器);parameter [2:0]  LDA = 3'b000, STA = 3'b001, ADD = 3'b010, SUB = 3'b011, AND = 3'b100 , HLT = 3'b101;reg [2:0] cnt;  //指令执行需要6个阶段,用cnt计数来表示不同的阶段always @(posedge clock or posedge reset) if (reset) // resetcnt <= 0;elseif (cnt==5)cnt <= 0;else cnt <= cnt+1;always@ *begincase(cnt)0: begin     //取指s0<=1; s1<=0; s2<=0; s3<=0; s4<=0; s5<=0;addrsel<=0;end1:begin      //解码s0<=0; s1<=1; s2<=0; s3<=0; s4<=0; s5<=0;addrsel<=0;end2:begin      //根据操作码决定是否从存储器中读取数据s0<=0; s1<=0; s2<=1; s3<=0; s4<=0; s5<=0;addrsel<=1;if( (opcode==LDA)  ||(opcode==ADD)  ||(opcode==SUB)  ||(opcode==AND)   )s2<=1;elses2<=0;end3:begin     //确定ALU的运算s0<=0; s1<=0; s2<=0; s3<=1; s4<=0; s5<=0;addrsel<=1;if (opcode==LDA) begininstr_add<=0;instr_sub<=0;instr_and<=0;instr_pass<=1;endelse if(opcode==ADD) begininstr_add<=1;instr_sub<=0;instr_and<=0;instr_pass<=0;endelse if(opcode==SUB) begininstr_add<=0;instr_sub<=1;instr_and<=0;instr_pass<=0;endelse if(opcode==AND) begininstr_add<=0;instr_sub<=0;instr_and<=1;instr_pass<=0;endelse if(opcode==STA) begininstr_add<=0;instr_sub<=0;instr_and<=0;instr_pass<=0;endelse begininstr_add<=0;instr_sub<=0;instr_and<=0;instr_pass<=0;endend4:begin   //必要时往存储器中写数据s0<=0; s1<=0; s2<=0; s3<=0; s4<=1; s5<=0;addrsel<=1;if(opcode==STA)s4<=1;elses4<=0;end5:begin   //使能PC准备开始读取下一条指令s0<=0; s1<=0; s2<=0; s3<=0; s4<=0; s5<=1;addrsel<=1;endendcaseend
endmodule

六.CPU的顶层原理图:

  

七.CPU顶层原理图的功能仿真结果:

八.总结:

     1.从对顶层原理图的功能仿真结果来看,我们已经实现相应的功能,结果也以在图中标出

     2.此CPU中每条指令的执行包括六个阶段:取指令、指令解码、根据操作码决定是否从存储器中读取数据、确定ALU的运算、必要时往存储器中写数据、使能PC准备开始读取下一条指令。从结果图中可以看出,使用cnt来标记指令所处于的哪一个阶段,故可以在图中清楚的分辨出第几条指令的执行结果。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部