Verlog——单周期8指令CPU实现
1、综述:CPU模块分为:设计代码,测试代码
1.1、设计代码包括: 1.1.1、顶层模块代码 CPU.v 1.1.2、指令存储器 1.1.3、寄存器组 1.1.4、运算器 1.1.5、数据存储器 设计通路可以参考华中科技老师谭志虎老师布置的单周期CPU作业的网络答案,代码中保留了许多系统函数作为查看运行状况,如在使用或烧写可以删去,当然不删除也是可以综合的。 在写CPU顶层模块时候:每个调用的模块我都定义了wire型变量其作为输入输出的,这样设计主要便以我连接模块,对于模块的输入用xx_in_xx表示,输出用xx_out_xx表示;如果logism画的图出现了分线器,就会定义一个reg变量作为分线器的输出,我指令存储器初始化的指令是谭志虎老师的sort.hex中的数据,所有输出检测都是用于检测该sort程序在cpu的运行状况
2、指令存储器
对其有初始化,用于设置指令存储器存储的指令的,可以看到代码有readmemh()地址请自己修改指令用的是
module Instruct_Memory(
input rst_l,
input [9:0]ir_in_a,
output [31:0] ir_out_d
);
parameter dm_len=38;
reg [31:0] D_M[dm_len:0];
always @(*)
if(!rst_l)
begin
$readmemh("D:/Documents/Hardware_verlog/MIPS_CPU/Complete_Routine_Test_Data/sort.txt",D_M);
$monitor("D_M[ 0]=%h",D_M[ 0]);
end
assign ir_out_d=D_M[ir_in_a];
endmodule
3、寄存器组
对其也有初始化请注意readmemh自己修改新地址,(自己写一个32个0000_0000作为寄存器组的初值即可)
module Reg_File(
input clk,
input rst_l,
input [4:0] rf_in_ra1,
input [4:0] rf_in_ra2,
input rf_in_wre,
input [4:0]rf_in_wa,
input [31:0]rf_in_wd,
output reg[31:0]rf_out_rd1,
output reg[31:0]rf_out_rd2
);
reg[31:0] RF_Mem[31:0];
reg [4:0] i=0;
always @(posedge clk ,negedge rst_l)
begin
if(!rst_l)
;
else
begin
if(rf_in_wre==1'b1)
begin
RF_Mem[rf_in_wa]=rf_in_wd;
$display($time,"输出 写数据时:写读使能信号:rf_in_wre=%h,写数据:rf_in_wd=%h,寄存器组对应单元被写后单元的值:RF_Mem[%h]=%h",rf_in_wre,rf_in_wd,rf_in_wa, RF_Mem[rf_in_wa]);
end
end
end
always @(*)
if(!rst_l)
begin
$readmemh("D:/Documents/Hardware_verlog/MIPS_CPU/RF_data.txt",RF_Mem);
rf_out_rd1<=32'h0000_0000;
rf_out_rd2<=32'h0000_0000;
$display($time,,"初始化后各寄存器的值");
repeat(32)
begin
$display($time,,"RF_Mem[%h]=%h",i,RF_Mem[i]);
i=i+5'h1;
end
end
else
begin
rf_out_rd1 <=RF_Mem[rf_in_ra1];
rf_out_rd2 <= RF_Mem[rf_in_ra2];
$display($time,"输出 读数据1时:读输出的数据:rf_out_rd1=%h,对应被读单元内保存的值:RF_Mem[%h]=%h",rf_out_rd1,rf_in_ra1,RF_Mem[rf_in_ra1]);
$display($time,"输出 读数据2时:读输出的数据:rf_out_rd2=%h,对应被读单元内保存的值:RF_Mem[%h]=%h",rf_out_rd2,rf_in_ra2,RF_Mem[rf_in_ra2]);
i=5'h0;
repeat(32)
begin
$display($time,,"RF_Mem[%h]=%h",i,RF_Mem[i]);
i=i+1;
end
end
endmodule
4、运算器
循环移位有编写另外模块
module Arith_Logic_Unit
(
input rst_l,
input [31:0]alu_in_a,
input [31:0]alu_in_b,
input [3:0]alu_in_contr,
output reg alu_out_equ,
output reg [31:0] alu_out_rl,
output reg [31:0] alu_out_rh
);
reg LR;
wire [31:0]Temp_A;
always @(alu_in_a,alu_in_b,alu_in_contr,Temp_A,rst_l)
if(!rst_l)
begin
alu_out_equ=1'b0;
alu_out_rh=32'h0;
alu_out_rl=32'h0;
end
else
begin
alu_out_equ<=(alu_in_a==alu_in_b)? 1'b1 :1'b0;
case(alu_in_contr)
4'b0000:alu_out_rl<=alu_in_a<<alu_in_b[3:0];
4'b0001:
begin
LR=1;
alu_out_rl<=Temp_A;
end
4'b0010:alu_out_rl<=alu_in_a>>alu_in_b[3:0];
4'b0011:{alu_out_rh,alu_out_rl}<=alu_in_a*alu_in_b;
4'b0100:{alu_out_rh,alu_out_rl}<=alu_in_a/alu_in_b;
4'b0101:{alu_out_rh,alu_out_rl}<=alu_in_a+alu_in_b;
4'b0110:alu_out_rl<=alu_in_a-alu_in_b;
4'b0111:alu_out_rl<=alu_in_a&alu_in_b;
4'b1000:alu_out_rl<=alu_in_a|alu_in_b;
4'b1001:alu_out_rl<=alu_in_a^alu_in_b;
4'b1010:alu_out_rl<=alu_in_a^~alu_in_b;
4'b1011:
if(alu_in_a>alu_in_b)
alu_out_rl<=32'h0;
else
alu_out_rl<=32'h1;
4'b1100:
if(alu_in_a>alu_in_b)
alu_out_rl<=32'h0;
else
alu_out_rl<=32'h1;
4'b1101:;
4'b1110:;
4'b1111:;
endcase
end
Ring_Shift_LR T1(alu_in_a,alu_in_b[3:0],LR,Temp_A);
Ring_Shift_LR T2(alu_in_a,alu_in_b[3:0],LR,Temp_A);
endmodule
循环移位模块
module Ring_Shift_LR(
input [31:0]I,
input [3:0]n,
input r_or_l,
output reg[31:0]R
);
parameter MAX=31;
parameter MIN=0;
always @(I,n,r_or_l)
if(r_or_l)
case(n)
4'h0:R<=I;
4'h1:R<={I[0],I[31:1]};
4'h2:R<={I[1:0],I[31:2]};
4'h3:R<={I[2:0],I[31:3]};
4'h4:R<={I[3:0],I[31:4]};
4'h5:R<={I[4:0],I[31:5]};
4'h6:R<={I[5:0],I[31:6]};
4'h7:R<={I[6:0],I[31:7]};
4'h8:R<={I[7:0],I[31:8]};
4'h9:R<={I[8:0],I[31:9]};
4'ha:R<={I[9:0],I[31:10]};
4'hb:R<={I[10:0],I[31:11]};
4'hc:R<={I[11:0],I[31:12]};
4'hd:R<={I[12:0],I[31:13]};
4'he:R<={I[13:0],I[31:14]};
4'hf:R<={I[14:0],I[31:15]};
endcase
else
case(n)
4'h0:R<=I;
4'h1:R<={I[30:0],I[31]};
4'h2:R<={I[29:0],I[31:30]};
4'h3:R<={I[28:0],I[31:29]};
4'h4:R<={I[27:0],I[31:28]};
4'h5:R<={I[26:0],I[31:27]};
4'h6:R<={I[25:0],I[31:26]};
4'h7:R<={I[24:0],I[31:25]};
4'h8:R<={I[23:0],I[31:24]};
4'h9:R<={I[22:0],I[31:23]};
4'ha:R<={I[21:0],I[31:22]};
4'hb:R<={I[20:0],I[31:21]};
4'hc:R<={I[19:0],I[31:20]};
4'hd:R<={I[18:0],I[31:19]};
4'he:R<={I[17:0],I[31:18]};
4'hf:R<={I[16:0],I[31:17]};
endcase
endmodule
5、数据存储器
module Data_Memory(
input clk,
input rst_l,
input dm_in_wre,
input wire [9:0] dm_in_rwa,
input wire [31:0] dm_in_wd,
output reg[31:0] dm_out_rd
);
parameter DM_len=150;
reg [31:0]DM_Mem[ DM_len:0];
always @(posedge clk,negedge rst_l )
begin
if(!rst_l)
;
else
begin
if(dm_in_wre)
DM_Mem[dm_in_rwa]<= dm_in_wd;
end
end
always@(*)
begin
if(!rst_l)
dm_out_rd=32'h0000_0000;
else
dm_out_rd <= DM_Mem[dm_in_rwa];
$display("输出:数据存储器 在读写后 存储单元的值DM[80]=%h,DM[81]=%h,DM[82]=%h,DM[83]=%h,DM[84]=%h,DM[85]=%h,DM[86]=%h,DM_Mem[87]=%h"
,DM_Mem[8'h80],DM_Mem[8'h81],DM_Mem[8'h82],DM_Mem[8'h83],DM_Mem[8'h84],DM_Mem[8'h85],DM_Mem[8'h86],DM_Mem[8'h87]);
end
endmodule
符号扩展器
module Sign_Extender(
input se_in_sign,
output reg [31:0] se_out_data
);
always@(*)
if(se_in_sign==1'b1)
se_out_data<=32'hffff_ffff;
else
se_out_data<=32'h0000_0000;
endmodule
7、控制器
module Controller_Uint(
input [5:0]cu_Op,
input [5:0]cu_Func,
output wire cu_Halt,
output wire cu_MemtoReg,
output wire cu_MemWrite,
output wire cu_Beq,
output wire cu_Bne,
output reg[3:0] cu_AluOP,
output wire cu_AluSrcB,
output wire cu_RegWrite,
output wire cu_RegDst
);
reg LW=1'b0,SW=1'b0,BEQ=1'b0,BNE=1'b0,ADDI=1'b0,R=1'b0;
reg ADD=1'b0,SLT=1'b0,SysCall=1'b0;
wire R_TYPE;
always @(*)
case(cu_Op)
6'h23:
begin
LW<=1'b1;
SW<=1'b0;BEQ<=1'b0;BNE<=1'b0;ADDI<=1'b0;R<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
6'h2b:
begin
SW<=1'b1;
LW<=1'b0;BEQ<=1'b0;BNE<=1'b0;ADDI<=1'b0;R<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
6'h04:
begin
BEQ<=1'b1;
SW<=1'b0;LW<=1'b0;BNE<=1'b0;ADDI<=1'b0;R<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
6'h05:
begin
BNE<=1'b1;
BEQ<=1'b0;SW<=1'b0;LW<=1'b0;ADDI<=1'b0;R<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
6'h08:
begin
ADDI<=1'b1;
BNE<=1'b0;BEQ<=1'b0;SW<=1'b0;LW<=1'b0;R<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
6'h00:
begin
R<=1'b1;
ADDI<=1'b0;BNE<=1'b0;BEQ<=1'b0;SW<=1'b0;LW<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b0;
end
endcase
always @(*)
if(R==1'b1)
case(cu_Func)
6'h20:
begin
R<=1'b1; ADDI<=1'b0;BNE<=1'b0;BEQ<=1'b0;SW<=1'b0;LW<=1'b0;
ADD<=1'b1;SLT<=1'b0;SysCall<=1'b0;
end
6'h2a:
begin
R<=1'b1; ADDI<=1'b0;BNE<=1'b0;BEQ<=1'b0;SW<=1'b0;LW<=1'b0;
ADD<=1'b0;SLT<=1'b1;SysCall<=1'b0;
end
8'h0c:
begin
R<=1'b0; ADDI<=1'b0;BNE<=1'b0;BEQ<=1'b0;SW<=1'b0;LW<=1'b0;
ADD<=1'b0;SLT<=1'b0;SysCall<=1'b1;
end
endcase
always@(*)
case((R)&(cu_Func==6'h2a))
1'b0:cu_AluOP<=4'h5;
1'b1:cu_AluOP<=4'hc;
endcase
assign cu_RegDst=ADD|SLT;
assign cu_RegWrite=LW|ADDI|(ADD|SLT);
assign cu_MemtoReg=LW;
assign cu_MemWrite=SW;
assign cu_AluSrcB=SW|LW|ADDI;
assign cu_Beq=BEQ;
assign cu_Bne=BNE;
assign cu_Halt=SysCall;
endmodule
8、顶层CPU
module CPU(
input sys_clk_in,
input sys_rst_n
);
reg [31:0]PC;
reg [4:0] RF_IN_WA;
reg [31:0]RF_IN_WD;
reg [31:0]ALU_IN_B;
wire [31:0]instruct;
wire [9:0]ir_in_a;
wire [31:0]ir_out_d;
wire [5:0]Op,Func;
wire Halt,MemtoReg,MemWrite,Beq,Bne,AluSrcB,RegWrite,RegDst;
wire [3:0]AluOP;
wire rf_in_wre;
wire [4:0] rf_in_ra1,rf_in_ra2;
wire [31:0]rf_out_rd1,rf_out_rd2;
wire[4:0]rf_in_wa;
wire[31:0]rf_in_wd;
wire [31:0]alu_in_a,alu_in_b;
wire [3:0]alu_in_contr;
wire alu_out_equ;
wire [31:0]alu_out_rl,alu_out_rh;
wire dm_in_wre;
wire [9:0] dm_in_rwa;
wire[31:0]dm_in_wd,dm_out_rd;
wire se_in_sign;
wire [31:0]se_out_data;
always @(posedge sys_clk_in,negedge sys_rst_n)
begin
$display($time,,"上次instruct=%h,PC=%h",instruct,PC);
if(! sys_rst_n)
PC<=32'h0000_0000;
else if( Halt==1'b0)
begin
if(( Beq&alu_out_equ)||(Bne&&!alu_out_equ))
begin
PC<=PC+32'h4+{se_out_data[13:0],instruct[15:0],2'b00};
end
else
PC<=PC+32'h4;
end
else
PC<=PC;
end
always@(*)
$monitor($time,,"本周期PC=%h",PC);
assign ir_in_a=PC[11:2];
Instruct_Memory IR(sys_rst_n,ir_in_a, instruct);
always @(*)
$display($time,,"本周期的指令:instruct=%h",instruct);
assign rf_in_ra1=instruct[25:21];
assign rf_in_ra2=instruct[20:16];
assign rf_in_wre=RegWrite;
always @(*)
if(RegDst)
RF_IN_WA<=instruct[15:11];
else
RF_IN_WA<=instruct[20:16];
assign rf_in_wa=RF_IN_WA;
always @(*)
if(MemtoReg)
RF_IN_WD<=dm_out_rd;
else
RF_IN_WD<=alu_out_rl;
assign rf_in_wd=RF_IN_WD;
Reg_File RF(
sys_clk_in,sys_rst_n,
rf_in_ra1,rf_in_ra2,
rf_in_wre,
rf_in_wa,rf_in_wd,
rf_out_rd1,rf_out_rd2);
always@(*)
$monitor($time,,"输出:进入寄存器组后 的各项数据RF_IN_WD=%h,rf_in_ra1=%h,rf_in_ra2=%h,rf_in_wre=%h,rf_in_wa=%h,rf_in_wd=%h,rf_out_rd1=%h,rf_out_rd2=%h\n\n",
RF_IN_WD,rf_in_ra1,rf_in_ra2,rf_in_wre,rf_in_wa,rf_in_wd,rf_out_rd1,rf_out_rd2);
assign se_in_sign=instruct[15];
Sign_Extender SE(se_in_sign,se_out_data);
always@(*)
$monitor($time,,"输出:进入符号扩展器后的 各项数据se_in_sign=%h,se_out_data=%h,instruct[15:0]=%h\n\n",
se_in_sign,se_out_data,instruct[15:0]);
assign alu_in_a=rf_out_rd1;
always@(*)
if(AluSrcB)
ALU_IN_B={se_out_data[15:0],instruct[15:0]};
else
ALU_IN_B=rf_out_rd2;
assign alu_in_b=ALU_IN_B;
assign alu_in_contr= AluOP;
Arith_Logic_Unit ALU(
sys_rst_n,
alu_in_a,alu_in_b,
alu_in_contr,
alu_out_equ,alu_out_rl,alu_out_rh);
always@(*)
$monitor($time,,"输出:进入ALU后 的各项数据ALU_IN_B=%h,alu_in_a=%h,alu_in_b=%h,alu_in_contr=%h,alu_out_equ=%h,alu_out_rl=%h,alu_out_rh=%h\n\n",ALU_IN_B,alu_in_a,alu_in_b,
alu_in_contr,alu_out_equ,alu_out_rl,alu_out_rh);
assign dm_in_wre=MemWrite;
assign dm_in_rwa=alu_out_rl[11:2];
assign dm_in_wd=rf_out_rd2;
Data_Memory DM(
sys_clk_in,sys_rst_n,
dm_in_wre,
dm_in_rwa,dm_in_wd,
dm_out_rd);
always@(*)
$monitor($time,,"输出:进入后数据存储器 各项数据dm_in_wre=%h,dm_in_rwa=%h,dm_in_wd=%h,dm_out_rd=%h\n\n",
dm_in_wre,dm_in_rwa,dm_in_wd,dm_out_rd);
always @(*)
$monitor($time,," Op=%h, Func=%h,Halt=%h, MemtoReg=%h,MemWrite=%h,Beq=%h,Bne=%h,AluOP=%h,AluSrcB=%h,RegWrite=%h,RegDst=%h",
Op, Func,Halt, MemtoReg,MemWrite,Beq,Bne,AluOP,AluSrcB,RegWrite,RegDst);
assign Op=instruct[31:26];
assign Func=instruct[5:0];
Controller_Uint CU(
Op,
Func,
Halt,
MemtoReg,
MemWrite,
Beq,
Bne,
AluOP,
AluSrcB,
RegWrite,
RegDst
);
endmodule
9:sim_CPU(总体的测试代码)
module sim_CPU(
);
reg clk,rst_l;
initial
begin
clk=1'b1;
rst_l=1'b0;
#1
rst_l=1'b1;
end
CPU T(clk,rst_l);
always #5
clk=~clk;
endmodule
|