Commit f21931bc authored by yz w's avatar yz w
Browse files

add lab2

parent 8aae704b
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: testBench
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: This testBench Help users to initial the bram content, by loading .data file and .inst file.
// Then give signals to start the execution of our cpu
// When all instructions finish their executions, this testBench will dump the Instruction Bram and Data Bram's content to .txt files
// !!! ALL YOU NEED TO CHANGE IS 4 FILE PATH BELOW !!!
// (they are all optional, you can run cpu without change paths here,if files are failed to open, we will not dump the content to .txt and will not try to initial your bram)
//////////////////////////////////////////////////////////////////////////////////
`define DataRamContentLoadPath "D:\\Vivado\\CA_lab\\testbench\\1testAll.data" //修改此处为测试数据路径
`define InstRamContentLoadPath "D:\\Vivado\\CA_lab\\testbench\\1testAll.inst" //修改此处为测试数据路径
`define DataRamContentSavePath "D:\\Vivado\\CA_lab\\testbench\\DataRamContent.txt" //修改此处为测试数据路径
`define InstRamContentSavePath "D:\\Vivado\\CA_lab\\testbench\\InstRamContent.txt" //修改此处为测试数据路径
`define BRAMWORDS 4096 //a word is 32bit, so our bram is 4096*32bit
module testBench(
);
//
reg CPU_CLK;
reg CPU_RST;
reg [31:0] CPU_Debug_DataRAM_A2;
reg [31:0] CPU_Debug_DataRAM_WD2;
reg [3:0] CPU_Debug_DataRAM_WE2;
wire [31:0] CPU_Debug_DataRAM_RD2;
reg [31:0] CPU_Debug_InstRAM_A2;
reg [31:0] CPU_Debug_InstRAM_WD2;
reg [3:0] CPU_Debug_InstRAM_WE2;
wire [31:0] CPU_Debug_InstRAM_RD2;
//generate clock signal
always #1 CPU_CLK = ~CPU_CLK;
// Connect the CPU core
RV32Core RV32Core1(
.CPU_CLK(CPU_CLK),
.CPU_RST(CPU_RST),
.CPU_Debug_DataRAM_A2(CPU_Debug_DataRAM_A2),
.CPU_Debug_DataRAM_WD2(CPU_Debug_DataRAM_WD2),
.CPU_Debug_DataRAM_WE2(CPU_Debug_DataRAM_WE2),
.CPU_Debug_DataRAM_RD2(CPU_Debug_DataRAM_RD2),
.CPU_Debug_InstRAM_A2(CPU_Debug_InstRAM_A2),
.CPU_Debug_InstRAM_WD2(CPU_Debug_InstRAM_WD2),
.CPU_Debug_InstRAM_WE2(CPU_Debug_InstRAM_WE2),
.CPU_Debug_InstRAM_RD2(CPU_Debug_InstRAM_RD2)
);
//define file handles
integer LoadDataRamFile;
integer LoadInstRamFile;
integer SaveDataRamFile;
integer SaveInstRamFile;
//
integer i;
//
initial
begin
$display("Initialing reg values...");
CPU_Debug_DataRAM_WD2 = 32'b0;
CPU_Debug_DataRAM_WE2 = 4'b0;
CPU_Debug_InstRAM_WD2 = 32'b0;
CPU_Debug_InstRAM_WE2 = 4'b0;
CPU_Debug_DataRAM_A2 = 32'b0;
CPU_Debug_InstRAM_A2 = 32'b0;
CPU_CLK=1'b0;
CPU_RST = 1'b0;
#10
$display("Loading DataRam Content from file...");
LoadDataRamFile = $fopen(`DataRamContentLoadPath,"r");
if(LoadDataRamFile==0)
$display("Failed to Open %s, Do Not Load DataRam values from file!",`DataRamContentLoadPath);
else begin
CPU_Debug_DataRAM_A2 = 32'h0;
$fscanf(LoadDataRamFile,"%h",CPU_Debug_DataRAM_WD2);
if($feof(LoadDataRamFile))
CPU_Debug_DataRAM_WE2 = 4'b0;
else
CPU_Debug_DataRAM_WE2 = 4'b1111;
#10
for(i=0;i<`BRAMWORDS;i=i+1)
begin
if($feof(LoadDataRamFile))
CPU_Debug_DataRAM_WE2 = 4'b0;
else
CPU_Debug_DataRAM_WE2 = 4'b1111;
@(negedge CPU_CLK);
CPU_Debug_DataRAM_A2 = CPU_Debug_DataRAM_A2+4;
$fscanf(LoadDataRamFile,"%h",CPU_Debug_DataRAM_WD2);
end
$fclose(LoadDataRamFile);
end
$display("Loading InstRam Content from file...");
LoadInstRamFile = $fopen(`InstRamContentLoadPath,"r");
if(LoadInstRamFile==0)
$display("Failed to Open %s, Do Not Load InstRam values from file!",`InstRamContentLoadPath);
else begin
CPU_Debug_InstRAM_A2 = 32'h0;
$fscanf(LoadInstRamFile,"%h",CPU_Debug_InstRAM_WD2);
if($feof(LoadInstRamFile))
CPU_Debug_InstRAM_WE2 = 4'b0;
else
CPU_Debug_InstRAM_WE2 = 4'b1111;
#10
for(i=0;i<`BRAMWORDS;i=i+1)
begin
if($feof(LoadInstRamFile))
CPU_Debug_InstRAM_WE2 = 4'b0;
else
CPU_Debug_InstRAM_WE2 = 4'b1111;
@(negedge CPU_CLK);
CPU_Debug_InstRAM_A2 = CPU_Debug_InstRAM_A2+4;
$fscanf(LoadInstRamFile,"%h",CPU_Debug_InstRAM_WD2);
end
$fclose(LoadInstRamFile);
end
$display("Start Instruction Execution!");
#10;
CPU_RST = 1'b1;
#10;
CPU_RST = 1'b0;
#400000 // waiting for instruction Execution to End
$display("Finish Instruction Execution!");
$display("Saving DataRam Content to file...");
CPU_Debug_DataRAM_A2 = 32'hfffffffc;
#10
SaveDataRamFile = $fopen(`DataRamContentSavePath,"w");
if(SaveDataRamFile==0)
$display("Failed to Open %s, Do Not Save DataRam values to file!",`DataRamContentSavePath);
else
begin
$fwrite(SaveDataRamFile,"i\tAddr\tAddr\tData\tData\n");
#10
for(i=0;i<`BRAMWORDS;i=i+1)
begin
@(posedge CPU_CLK);
CPU_Debug_DataRAM_A2 = CPU_Debug_DataRAM_A2+4;
@(posedge CPU_CLK);
@(negedge CPU_CLK);
$fwrite(SaveDataRamFile,"%4d\t%8h\t%4d\t%8h\t%4d\n",i,CPU_Debug_DataRAM_A2,CPU_Debug_DataRAM_A2,CPU_Debug_DataRAM_RD2,CPU_Debug_DataRAM_RD2);
end
$fclose(SaveDataRamFile);
end
$display("Saving InstRam Content to file...");
SaveInstRamFile = $fopen(`InstRamContentSavePath,"w");
if(SaveInstRamFile==0)
$display("Failed to Open %s, Do Not Save InstRam values to file!",`InstRamContentSavePath);
else
begin
CPU_Debug_InstRAM_A2 = 32'hfffffffc;
#10
$fwrite(SaveInstRamFile,"i\tAddr\tAddr\tData\tData\n");
#10
for(i=0;i<`BRAMWORDS;i=i+1)
begin
@(posedge CPU_CLK);
CPU_Debug_InstRAM_A2 = CPU_Debug_InstRAM_A2+4;
@(posedge CPU_CLK);
@(negedge CPU_CLK);
$fwrite(SaveInstRamFile,"%4d\t%8h\t%4d\t%8h\t%4d\n",i,CPU_Debug_InstRAM_A2,CPU_Debug_InstRAM_A2,CPU_Debug_InstRAM_RD2,CPU_Debug_InstRAM_RD2);
end
$fclose(SaveInstRamFile);
end
$display("Simulation Ended!");
$stop();
end
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: ALU
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: ALU unit of RISCV CPU
//////////////////////////////////////////////////////////////////////////////////
//功能和接口说明
//ALU接受两个操作数,根据AluContrl的不同,进行不同的计算操作,将计算结果输出到AluOut
//AluContrl的类型定义在Parameters.v中
//推荐格式:
//case()
// `ADD: AluOut<=Operand1 + Operand2;
// .......
// default: AluOut <= 32'hxxxxxxxx;
//endcase
//实验要求
//补全模块
`include "Parameters.v"
module ALU(
input wire [31:0] Operand1,
input wire [31:0] Operand2,
input wire [3:0] AluContrl,
output reg [31:0] AluOut
);
// 请补全此处代码
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: DataRamWrapper
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: a Verilog-based ram which can be systhesis as BRAM
//
//////////////////////////////////////////////////////////////////////////////////
//功能说明
//同步读写bram,a、b双口可读写,a口用于CPU访问dataRam,b口用于外接debug_module进行读写
//写使能为4bit,支持byte write
//输入
//clk 输入时钟
//addra a口读写地址
//dina a口写输入数据
//wea a口写使能
//addrb b口读写地址
//dinb b口写输入数据
//web b口写使能
//输出
//douta a口读数据
//doutb b口读数据
//实验要求
//无需修改
module DataRam(
input clk,
input [ 3:0] wea, web,
input [31:2] addra, addrb,
input [31:0] dina , dinb,
output reg [31:0] douta, doutb
);
initial begin douta=0; doutb=0; end
wire addra_valid = ( addra[31:14]==18'h0 );
wire addrb_valid = ( addrb[31:14]==18'h0 );
wire [11:0] addral = addra[13:2];
wire [11:0] addrbl = addrb[13:2];
reg [31:0] ram_cell [0:4095];
initial begin // 可以把测试数据手动输入此处
ram_cell[0] = 32'h00000000;
// ......
end
always @ (posedge clk)
douta <= addra_valid ? ram_cell[addral] : 0;
always @ (posedge clk)
doutb <= addrb_valid ? ram_cell[addrbl] : 0;
always @ (posedge clk)
if(wea[0] & addra_valid)
ram_cell[addral][ 7: 0] <= dina[ 7: 0];
always @ (posedge clk)
if(wea[1] & addra_valid)
ram_cell[addral][15: 8] <= dina[15: 8];
always @ (posedge clk)
if(wea[2] & addra_valid)
ram_cell[addral][23:16] <= dina[23:16];
always @ (posedge clk)
if(wea[3] & addra_valid)
ram_cell[addral][31:24] <= dina[31:24];
always @ (posedge clk)
if(web[0] & addrb_valid)
ram_cell[addrbl][ 7: 0] <= dinb[ 7: 0];
always @ (posedge clk)
if(web[1] & addrb_valid)
ram_cell[addrbl][15: 8] <= dinb[15: 8];
always @ (posedge clk)
if(web[2] & addrb_valid)
ram_cell[addrbl][23:16] <= dinb[23:16];
always @ (posedge clk)
if(web[3] & addrb_valid)
ram_cell[addrbl][31:24] <= dinb[31:24];
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: InstructionRamWrapper
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: a Verilog-based ram which can be systhesis as BRAM
//
//////////////////////////////////////////////////////////////////////////////////
//功能说明
//同步读写bram,a口只读,用于取指,b口可读写,用于外接debug_module进行读写
//写使能为1bit,不支持byte write
//输入
//clk 输入时钟
//addra a口读地址
//addrb b口读写地址
//dinb b口写输入数据
//web b口写使能
//输出
//douta a口读数据
//doutb b口读数据
//实验要求
//无需修改
module InstructionRam(
input clk,
input web,
input [31:2] addra, addrb,
input [31:0] dinb,
output reg [31:0] douta, doutb
);
initial begin douta=0; doutb=0; end
wire addra_valid = ( addra[31:14]==18'h0 );
wire addrb_valid = ( addrb[31:14]==18'h0 );
wire [11:0] addral = addra[13:2];
wire [11:0] addrbl = addrb[13:2];
reg [31:0] ram_cell [0:4095];
initial begin // 可以把测试指令手动输入此处
ram_cell[0] = 32'h00000000;
// ......
end
always @ (posedge clk)
douta <= addra_valid ? ram_cell[addral] : 0;
always @ (posedge clk)
doutb <= addrb_valid ? ram_cell[addrbl] : 0;
always @ (posedge clk)
if(web & addrb_valid)
ram_cell[addrbl] <= dinb;
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: BranchDecisionMaking
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: Decide whether to branch
//////////////////////////////////////////////////////////////////////////////////
//功能和接口说明
//BranchDecisionMaking接受两个操作数,根据BranchTypeE的不同,进行不同的判断,当分支应该taken时,令BranchE=1'b1
//BranchTypeE的类型定义在Parameters.v中
//推荐格式:
//case()
// `BEQ: ???
// .......
// default: BranchE<=1'b0; //NOBRANCH
//endcase
//实验要求
//补全模块
`include "Parameters.v"
module BranchDecisionMaking(
input wire [2:0] BranchTypeE,
input wire [31:0] Operand1,Operand2,
output reg BranchE
);
// 请补全此处代码
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: ControlUnit
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: RISC-V Instruction Decoder
//////////////////////////////////////////////////////////////////////////////////
//功能和接口说明
//ControlUnit 是本CPU的指令译码器,组合逻辑电路
//输入
// Op 是指令的操作码部分
// Fn3 是指令的func3部分
// Fn7 是指令的func7部分
//输出
// JalD==1 表示Jal指令到达ID译码阶段
// JalrD==1 表示Jalr指令到达ID译码阶段
// RegWriteD 表示ID阶段的指令对应的寄存器写入模式
// MemToRegD==1 表示ID阶段的指令需要将data memory读取的值写入寄存器,
// MemWriteD 共4bit,采用独热码格式,对于data memory的32bit字按byte进行写入,MemWriteD=0001表示只写入最低1个byte,和xilinx bram的接口类似
// LoadNpcD==1 表示将NextPC输出到ResultM
// RegReadD 表示A1和A2对应的寄存器值是否被使用到了,用于forward的处理
// BranchTypeD 表示不同的分支类型,所有类型定义在Parameters.v中
// AluContrlD 表示不同的ALU计算功能,所有类型定义在Parameters.v中
// AluSrc2D 表示Alu输入源2的选择
// AluSrc1D 表示Alu输入源1的选择
// ImmType 表示指令的立即数格式
//实验要求
//补全模块
`include "Parameters.v"
module ControlUnit(
input wire [6:0] Op,
input wire [2:0] Fn3,
input wire [6:0] Fn7,
output wire JalD,
output wire JalrD,
output reg [2:0] RegWriteD,
output wire MemToRegD,
output reg [3:0] MemWriteD,
output wire LoadNpcD,
output reg [1:0] RegReadD,
output reg [2:0] BranchTypeD,
output reg [3:0] AluContrlD,
output wire [1:0] AluSrc2D,
output wire AluSrc1D,
output reg [2:0] ImmType
);
// 请补全此处代码
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: DataExt
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: Data Extension module
//////////////////////////////////////////////////////////////////////////////////
//功能说明
//DataExt是用来处理非字对齐load的情形,同时根据load的不同模式对Data Mem中load的数进行符号或者无符号拓展,组合逻辑电路
//输入
//IN 是从Data Memory中load的32bit字
//LoadedBytesSelect 等价于AluOutM[1:0],是读Data Memory地址的低两位,
//因为DataMemory是按字(32bit)进行访问的,所以需要把字节地址转化为字地址传给DataMem
//DataMem一次返回一个字,低两位地址用来从32bit字中挑选出我们需要的字节
//RegWriteW 表示不同的 寄存器写入模式 ,所有模式定义在Parameters.v中
//输出
//OUT表示要写入寄存器的最终值
//实验要求
//补全模块
`include "Parameters.v"
module DataExt(
input wire [31:0] IN,
input wire [1:0] LoadedBytesSelect,
input wire [2:0] RegWriteW,
output reg [31:0] OUT
);
// 请补全此处代码
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: USTC ESLAB
// Engineer: Wu Yuzhang
//
// Design Name: RISCV-Pipline CPU
// Module Name: EXSegReg
// Target Devices: Nexys4
// Tool Versions: Vivado 2017.4.1
// Description: ID-EX Segment Register
//////////////////////////////////////////////////////////////////////////////////
//功能说明
//本模块是支持同步清零的段寄存器,当EN==0时寄存器状态保持不变(也不会执行清零)
//实验要求
//无需修改
module EXSegReg(
input wire clk,
input wire en,
input wire clear,
//Data Signals
input wire [31:0] PCD,
output reg [31:0] PCE,
input wire [31:0] JalNPC,
output reg [31:0] BrNPC,
input wire [31:0] ImmD,
output reg [31:0] ImmE,
input wire [4:0] RdD,
output reg [4:0] RdE,
input wire [4:0] Rs1D,
output reg [4:0] Rs1E,
input wire [4:0] Rs2D,
output reg [4:0] Rs2E,
input wire [31:0] RegOut1D,
output reg [31:0] RegOut1E,
input wire [31:0] RegOut2D,
output reg [31:0] RegOut2E,
//Control Signals
input wire JalrD,
output reg JalrE,
input wire [2:0] RegWriteD,
output reg [2:0] RegWriteE,
input wire MemToRegD,
output reg MemToRegE,
input wire [3:0] MemWriteD,
output reg [3:0] MemWriteE,
input wire LoadNpcD,
output reg LoadNpcE,
input wire [1:0] RegReadD,
output reg [1:0] RegReadE,
input wire [2:0] BranchTypeD,
output reg [2:0] BranchTypeE,
input wire [4:0] AluContrlD,
output reg [4:0] AluContrlE,
input wire AluSrc1D,
output reg AluSrc1E,
input wire [1:0] AluSrc2D,
output reg [1:0] AluSrc2E
);
initial begin
PCE = 32'b0;
BrNPC = 32'b0;
ImmE = 32'b0;
RdE = 32'b0;
Rs1E = 5'b0;
Rs2E = 5'b0;
RegOut1E = 32'b0;
RegOut2E = 32'b0;
JalrE = 1'b0;
RegWriteE = 1'b0;
MemToRegE = 1'b0;
MemWriteE = 1'b0;
LoadNpcE = 1'b0;
RegReadE = 2'b00;
BranchTypeE = 3'b0;
AluContrlE = 5'b0;
AluSrc1E = 1'b0;
AluSrc2E = 2'b0;
end
//
always@(posedge clk) begin
if(en)
if(clear)
begin
PCE<=32'b0;
BrNPC<=32'b0;
ImmE<=32'b0;
RdE<=32'b0;
Rs1E<=5'b0;
Rs2E<=5'b0;
RegOut1E<=32'b0;
RegOut2E<=32'b0;
JalrE<=1'b0;
RegWriteE<=1'b0;
MemToRegE<=1'b0;
MemWriteE<=1'b0;
LoadNpcE<=1'b0;
RegReadE<=2'b00;