简易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来标记指令所处于的哪一个阶段,故可以在图中清楚的分辨出第几条指令的执行结果。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
