Commit 12ae533b authored by Yuchen Wu's avatar Yuchen Wu
Browse files

Merge branch 'master' of https://git.ustc.edu.cn/Colorful/ustc_ca2021_lab into master

parents 4a26387f 6519d3e6
......@@ -14,9 +14,9 @@
## 签到与补交
* 学生总数106人左右,每周六下午和晚上开两次实验课,内容完全一样,可选择参加
* 验收和报告补交在一周内扣除20%成绩,介于一周两周之内补交扣除40%成绩,超过两周不予验收。
* 为了照顾对流水线不熟悉的学生和鼓励实验课出勤,每堂课设置签到。(每次实验课开始15分钟后停止签到,实验课结束半小时前可以签离,每周两个实验时间段任选其一参加,有签到和签离就算当周满勤)。
* 学生总数106人左右,每周一晚上实验课
* 验收和报告补交在一周内扣除15%成绩,介于一周两周之内补交扣除30%成绩,超过两周不予验收。
* 为了照顾对流水线不熟悉的学生和鼓励实验课出勤,每堂课设置签到。(每次实验课开始20分钟后停止签到)。
* 上周和本周连续两次满勤可以申请本周实验晚交一周不做扣分处理。(比如Lab2阶段一验收是第6周,如果到了第6周实验课结束了实验还没做完,如果你第5周和第6周都满勤,可以在第6周签离时向助教申请晚交一周同时不扣分。)希望对流水线和verilog不熟悉的同学可以积极参与实验课,届时有问题多问问助教,助教可以一对一讲解或者统一指导。
* 签到记录不以其他方式影响成绩
......@@ -42,3 +42,16 @@
请提交CPU设计报告 截止日期:2021.4.18
提交至BB平台
提交格式:要求包括一份**pdf格式**实验报告(如果无法打开会影响最终成绩)
* **2021.4.14 Release Lab2**
阶段一课堂验收 截止日期:2021.4.26
阶段二课堂验收 截止日期:2021.5.10
阶段三课堂验收 截止日期:2021.5.10
实验报告 截止日期:2021.5.16
提交至BB平台
提交格式:Lab2-学号-姓名.rar(or .zip) 要求包括一份pdf格式实验报告和用到的源代码集合的文件夹
## 实验课安排
* **lab1答案分析+Lab2预先讲解**
2021.4.19晚(18:30-21:00 电三楼516)
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,为1的部分表示有效,对于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;