哈工大计算机体系与结构课程实验lab1个人实验代码分享,欢迎参考,如有不足或错误欢迎指正。
学校的实验以后做完大概会挑一些困难的、重要的分享出来,比如计算机体系与结构课程实验大概会把lab都分享出来,因为一方面我在自己做实验的时候发现网上的教程确实不多 ,所以准备发上来作为“火炬”以供其他同学参考,另一方面是因为博客搭建完成之后确实太久没有发文章了,也因为这件事被朋友多次diss,所以就来水一水文章 ;
总体构思
做完之后转过头来看,其实这个实验算不上特别难,不过确实花了我很多时间,大致思路还是比较清晰的,在课本上也已经画出来了流水线处理器的图,根据这个图基本可以搞清楚需要哪些模块了。
不过在具体实现的时候还是有一些部分与课本的图不完全相同,所以我在做完之后又草草地画了一下,也放在这里供大家参考。
实现方法
在实现的时候想怎样通过verilog代码确实花费了一段时间,因为不知道该怎么让用代码实现指令一条一条向前走。
刚开始考虑的是定义好各个模块之后在cpu.v文件里面定义一些操作,每个阶段都根据时钟信号的操作执行,不过最后没有采用,因为我在看课本以及上网搜索相关实验分享的时候发现还是在cpu.v中定义线路,再连起来而不定义操作这样比较合理简洁一点,不过我估计我工刚开始的实现方法也是可以的。
代码实现思路就是PC像水泵一样不断向外面输出值,推动流水线不断前进,而每两个阶段之间的寄存器存储着正在执行指令的信息,使得在每一个时钟周期不同的模块可以执行不同的指令操作,赢 !
实现代码
那么话不多说,直接把代码摆上来好了,再参考的过程中注意指令译码方法可能不同,注意辨别就好。
cpu.v
`timescale 1ns / 1ps
module cpu(
input clk,
input resetn,
output [31:0] debug_wb_pc ,
output debug_wb_rf_wen ,
output [4 :0] debug_wb_rf_addr,
output [31:0] debug_wb_rf_wdata
);
/**********************************Start defining the connection lines********************************/
/**********************************IF Part********************************/
wire [31:0]IF_NPC;
wire [31:0]IF_PC;
wire [31:0]IF_INS;
wire [31:0]IF_ADDNPC;
/**********************************ID Part********************************/
wire [31:0]ID_NPC;
wire [31:0]ID_INS;
wire [31:0]ID_IMM;
wire [31:0]ID_RS;
wire [31:0]ID_RT;
wire [31:0]ID_PC;
/**********************************EX Part********************************/
wire [31:0]EX_NPC;
wire [31:0]EX_INS;
wire [31:0]EX_RS;
wire [31:0]EX_RT;
wire [31:0]EX_A;
wire [31:0]EX_B;
wire [31:0]EX_IMM;
wire EX_JUDG;
wire [31:0]EX_ALUOUT;
wire [31:0]EX_PC;
/**********************************MEM Part********************************/
wire [31:0]MEM_INS;
wire MEM_JUDG;
wire [31:0]MEM_ALUOUT;
wire [31:0]MEM_RT;
wire [31:0]MEM_MEMOUT;
wire [31:0]MEM_PC;
/**********************************WB Part********************************/
wire [31:0]WB_INS;
wire [31:0]WB_MEMOUT;
wire [31:0]WB_ALUOUT;
wire [31:0]WB_DATA;
wire [31:0]WB_PC;
wire [4:0]WB_ADDR;
wire WB_ABLE;
/**********************************Start link module**************************************/
assign debug_wb_pc=WB_PC;
assign debug_wb_rf_wen=WB_ABLE;
assign debug_wb_rf_addr=WB_ADDR;
assign debug_wb_rf_wdata=WB_DATA;
/**********************************IF Part********************************/
PC PC(
.clk(clk),
.resetn(resetn),
.next_pc(IF_NPC),
.pc(IF_PC)
);
ADD ADD(
.pc(IF_PC),
.add_result(IF_ADDNPC)
);
Ins_reg Ins_reg(
.ins_addr(IF_PC),
.ins_out(IF_INS)
);
NPC_MUX NPC_MUX(
.ori_npc(IF_ADDNPC),
.jmp_npc(MEM_ALUOUT),
.select(MEM_JUDG),
.npc(IF_NPC)
);
IF_ID IF_ID(
.clk(clk),
.resetn(resetn),
.wdata_1_1(IF_NPC),
.wdata_1_2(IF_INS),
.wdata_1_3(IF_PC),
.rdata_1_1(ID_NPC),
.rdata_1_2(ID_INS),
.rdata_1_3(ID_PC)
);
/**********************************ID Part********************************/
Regs Regs(
.clk(clk),
.we(WB_ABLE),
.raddr1(ID_INS[25:21]),
.raddr2(ID_INS[20:16]),
.rdata1(ID_RS),
.rdata2(ID_RT),
.waddr(WB_ADDR),
.wdata(WB_DATA)
);
Extender Extender(
.imm(ID_INS[25:0]),
.opcode(ID_INS[31:26]),
.extend_result(ID_IMM)
);
ID_EX ID_EX(
.clk(clk),
.resetn(resetn),
.wdata_2_1(ID_NPC),
.wdata_2_2(ID_RS),
.wdata_2_3(ID_RT),
.wdata_2_4(ID_IMM),
.wdata_2_5(ID_INS),
.wdata_2_6(ID_PC),
.rdata_2_1(EX_NPC),
.rdata_2_2(EX_RS),
.rdata_2_3(EX_RT),
.rdata_2_4(EX_IMM),
.rdata_2_5(EX_INS),
.rdata_2_6(EX_PC)
);
/**********************************EX Part********************************/
zero zero(
.a(EX_RS),
.b(EX_RT),
.opcode(EX_INS[31:26]),
.judge(EX_JUDG)
);
MUX_1 MUX_1(
.d0(EX_NPC),
.d1(EX_RS),
.select(EX_INS[31:26]),
.out(EX_A)
);
MUX_2 MUX_2(
.d0(EX_IMM),
.d1(EX_RT),
.select(EX_INS[31:26]),
.out(EX_B)
);
ALU ALU(
.A(EX_A),
.B(EX_B),
.sll(EX_INS[10:6]),
.Card(EX_INS[5:0]),
.opcode(EX_INS[31:26]),
.F(EX_ALUOUT)
);
EX_MEM EX_MEM(
.clk(clk),
.resetn(resetn),
.wdata_3_1(EX_JUDG),
.wdata_3_2(EX_ALUOUT),
.wdata_3_3(EX_RT),
.wdata_3_4(EX_INS),
.wdata_3_5(EX_PC),
.rdata_3_1(MEM_JUDG),
.rdata_3_2(MEM_ALUOUT),
.rdata_3_3(MEM_RT),
.rdata_3_4(MEM_INS),
.rdata_3_5(MEM_PC)
);
/**********************************MEM Part********************************/
Data_reg Data_reg(
.clk(clk),
.opcode(MEM_INS[31:26]),
.data_reg_wdata(MEM_RT),
.data_reg_addr(MEM_ALUOUT),
.data_reg_rdata(MEM_MEMOUT)
);
MEM_WB MEM_WB(
.clk(clk),
.resetn(resetn),
.wdata_4_1(MEM_MEMOUT),
.wdata_4_2(MEM_ALUOUT),
.wdata_4_3(MEM_INS),
.wdata_4_4(MEM_PC),
.rdata_4_1(WB_MEMOUT),
.rdata_4_2(WB_ALUOUT),
.rdata_4_3(WB_INS),
.rdata_4_4(WB_PC),
.wb_enable(WB_ABLE)
);
/**********************************WB Part********************************/
WB_MUX WB_MUX(
.d0(WB_MEMOUT),
.d1(WB_ALUOUT),
.select(WB_INS[31:26]),
.out(WB_DATA)
);
WB_MUX_2 WB_MUX_2(
.a(WB_INS[20:16]),
.b(WB_INS[15:11]),
.opcode(WB_INS[31:26]),
.result(WB_ADDR)
);
endmodule
下面是一些模块的代码,我直接折叠了,需要的话展开看就可以,因为我感觉最主要的还是cpu.v。
`timescale 1ns / 1ps
module PC(
input clk,
input resetn,
input [31:0]next_pc,
output reg [31:0]pc
);
always @(posedge clk)
if(resetn==1'b0) begin
pc<=0;
end
else begin
pc<=next_pc;
end
endmodule
`timescale 1ns / 1ps
module ADD(
input [31:0]pc,
output [31:0]add_result
);
reg [31:0]count;
initial begin
count=32'd4;
end
assign add_result=pc+count;
endmodule
`timescale 1ns / 1ps
module Ins_reg(
input [31:0]ins_addr,
output [31:0]ins_out
);
reg [31:0]regs[255:0];
initial begin
$readmemh("F:/OneDrive/Pang/vivado/computer_structure/lab1_env_new/lab_1/lab_1.data/base_inst_data",regs);
end
assign ins_out=regs[ins_addr/4];
endmodule
`timescale 1ns / 1ps
module NPC_MUX(
input [31:0]ori_npc,
input [31:0]jmp_npc,
input select,
output [31:0]npc
);
assign npc=select?jmp_npc:ori_npc;
endmodule
`timescale 1ns / 1ps
module IF_ID(
input clk,
input resetn,
input [31:0]wdata_1_1,
input [31:0]wdata_1_2,
input [31:0]wdata_1_3,
output reg [31:0]rdata_1_1,
output reg [31:0]rdata_1_2,
output reg [31:0]rdata_1_3
);
always @(posedge clk)
if(resetn==0) begin
rdata_1_1<=0;
rdata_1_2<=0;
rdata_1_3<=0;
end
else begin
rdata_1_1<=wdata_1_1;
rdata_1_2<=wdata_1_2;
rdata_1_3<=wdata_1_3;
end
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module Regs(
input clk,
input [4:0]raddr1,
output [31:0]rdata1,
input [4:0]raddr2,
output [31:0]rdata2,
input we,
input [4:0]waddr,
input [31:0]wdata
);
reg [31:0] rf[31:0];
initial begin
$readmemh("F:/OneDrive/Pang/vivado/computer_structure/lab1_env_new/lab_1/lab_1.data/base_reg_data",rf);
end
assign rdata1 = rf[raddr1];
assign rdata2 = rf[raddr2];
always @(posedge clk)
if(we)
begin
if(waddr!=0) begin
rf[waddr]<=wdata;
end
end
endmodule
`timescale 1ns / 1ps
module Extender(
input [25:0]imm,
input [5:0]opcode,
output [31:0]extend_result
);
assign extend_result=(opcode==6'b000010)?{{6{imm[25]}},imm[25:0]}: {{16{imm[15]}},imm[15:0]};
endmodule
`timescale 1ns / 1ps
module ID_EX(
input clk,
input resetn,
input [31:0]wdata_2_1,
input [31:0]wdata_2_2,
input [31:0]wdata_2_3,
input [31:0]wdata_2_4,
input [31:0]wdata_2_5,
input [31:0]wdata_2_6,
output reg [31:0]rdata_2_1,
output reg [31:0]rdata_2_2,
output reg [31:0]rdata_2_3,
output reg [31:0]rdata_2_4,
output reg [31:0]rdata_2_5,
output reg [31:0]rdata_2_6
);
always @(posedge clk)
if(resetn==0) begin
rdata_2_1<=0;
rdata_2_2<=0;
rdata_2_3<=0;
rdata_2_4<=0;
rdata_2_5<=0;
rdata_2_6<=0;
end
else begin
rdata_2_1<=wdata_2_1;
rdata_2_2<=wdata_2_2;
rdata_2_3<=wdata_2_3;
rdata_2_4<=wdata_2_4;
rdata_2_5<=wdata_2_5;
rdata_2_6<=wdata_2_6;
end
endmodule
`timescale 1ns / 1ps
module zero(
input [31:0]a,
input [31:0]b,
input [5:0]opcode,
output judge
);
assign judge=(opcode==6'b000000||opcode==6'b101011||opcode==6'b100011||a==b)?0:1;
endmodule
`timescale 1ns / 1ps
module MUX_1(
input [31:0]d0,
input [31:0]d1,
output [31:0]out,
input [5:0]select
);
assign out = (select==6'b000000||6'b101011||6'b100011)? d1 : d0;
endmodule
`timescale 1ns / 1ps
module MUX_2(
input [31:0]d0,
input [31:0]d1,
output [31:0]out,
input [5:0]select
);
assign out = (select==6'b000000)? d1 : d0;
endmodule
`timescale 1ns / 1ps
`define ADD 6'b100000
`define SUB 6'b100010
`define OR 6'b100101
`define AND 6'b100100
`define XOR 6'b100110
`define SLT 6'b101010 //比较,A<B则返回1,否则返回0
`define MOVZ 6'b001010 //MOVZ指令,B为0则返回A
`define SLL 6'b000000
module ALU(
input [31:0]A,
input [31:0]B,
input [4:0]sll,
input [5:0]Card,
input [5:0]opcode,
output [31:0]F
);
reg [31:0] add_result;
reg [31:0] sub_result;
reg [31:0] or_result;
reg [31:0] and_result;
reg [31:0] xor_result;
reg [31:0] slt_result;
reg [31:0] movz_result;
reg [31:0] lw_result;
reg [31:0] sw_result;
reg [31:0] bne_result;
reg [31:0] jmp_result;
reg [31:0] sll_result;
always @ (*)
case(opcode)
6'b000000:
begin
case(Card)
`ADD:
begin
assign add_result= A+B;
end
`SUB:
begin
assign sub_result= A-B;
end
`OR:
begin
assign or_result=A|B;
end
`AND:
begin
assign and_result=A&B;
end
`XOR:
begin
assign xor_result=A^B;
end
`SLT:
begin
assign slt_result=(A<B)?1:0;
end
`MOVZ:
begin
assign movz_result=(B==0)?A:0;
end
`SLL:
begin
assign sll_result=B<<sll;
end
endcase
end
6'b101011:
begin
assign sw_result=A+B;
end
6'b100011:
begin
assign lw_result=A+B;
end
6'b000101:
begin
assign bne_result=A+(B<<2);
end
6'b000010:
begin
assign jmp_result={A[31:28],B[25:0]<<2};
end
endcase
assign F = ({32{opcode==6'b000000&&Card == `ADD}} & add_result) |
({32{opcode==6'b000000&&Card == `SUB}} & sub_result) |
({32{opcode==6'b000000&&Card == `OR}} & or_result) |
({32{opcode==6'b000000&&Card == `AND}} & and_result) |
({32{opcode==6'b000000&&Card == `XOR}} & xor_result) |
({32{opcode==6'b000000&&Card == `SLT}} & slt_result) |
({32{opcode==6'b000000&&Card == `MOVZ}} & movz_result)|
({32{opcode==6'b000000&&Card == `SLL}} & sll_result)|
({32{opcode==6'b101011}}&sw_result)|
({32{opcode==6'b100011}}&lw_result)|
({32{opcode==6'b000101}}&bne_result)|
({32{opcode==6'b000010}}&jmp_result);
endmodule
`timescale 1ns / 1ps
module EX_MEM(
input clk,
input resetn,
input wdata_3_1,
input [31:0]wdata_3_2,
input [31:0]wdata_3_3,
input [31:0]wdata_3_4,
input [31:0]wdata_3_5,
output reg rdata_3_1,
output reg [31:0]rdata_3_2,
output reg [31:0]rdata_3_3,
output reg [31:0]rdata_3_4,
output reg [31:0]rdata_3_5
);
always @(posedge clk)
if(resetn==0) begin
rdata_3_1<=0;
rdata_3_2<=0;
rdata_3_3<=0;
rdata_3_4<=0;
rdata_3_5<=0;
end
else begin
rdata_3_1<=wdata_3_1;
rdata_3_2<=wdata_3_2;
rdata_3_3<=wdata_3_3;
rdata_3_4<=wdata_3_4;
rdata_3_5<=wdata_3_5;
end
endmodule
`timescale 1ns / 1ps
module Data_reg(
input clk,
input [5:0]opcode,
input [31:0]data_reg_wdata,
input [31:0]data_reg_addr,
output [31:0]data_reg_rdata
);
reg [31:0]regs[255:0];
initial begin
$readmemh("F:/OneDrive/Pang/vivado/computer_structure/lab1_env_new/lab_1/lab_1.data/base_data_data",regs);
end
assign data_reg_rdata=regs[data_reg_addr/4];
always @(posedge clk)
if(opcode==6'b101011) begin
regs[data_reg_addr/4]<=data_reg_wdata;
end
endmodule
`timescale 1ns / 1ps
`define ALU 6'b000000
`define LW 6'b100011
module MEM_WB(
input clk,
input resetn,
input [31:0]wdata_4_1,
input [31:0]wdata_4_2,
input [31:0]wdata_4_3,
input [31:0]wdata_4_4,
output reg [31:0]rdata_4_1,
output reg [31:0]rdata_4_2,
output reg [31:0]rdata_4_3,
output reg wb_enable,
output reg [31:0]rdata_4_4
);
wire [5:0]opcode;
wire [5:0]ALUfunc;
wire [5:0]rt;
assign opcode = wdata_4_3[31:26];
assign ALUfunc = wdata_4_3[5:0];
assign rt = wdata_4_3[20:16];
always @(posedge clk)
if(resetn==0) begin
rdata_4_1<=0;
rdata_4_2<=0;
rdata_4_3<=0;
rdata_4_4<=0;
wb_enable<=0;
end
else begin
rdata_4_1<=wdata_4_1;
rdata_4_2<=wdata_4_2;
rdata_4_3<=wdata_4_3;
rdata_4_4<=wdata_4_4;
wb_enable <= (opcode == `LW || (opcode == `ALU && !(ALUfunc == `MOVZ && rt != 0))|| (opcode == `ALU && (ALUfunc == `MOVZ && wdata_4_2!=0))) && wdata_4_3!= 32'h00000000 ? 1 : 0;
end
endmodule
`timescale 1ns / 1ps
module WB_MUX(
input [31:0]d0,
input [31:0]d1,
output [31:0]out,
input [5:0]select
);
assign out = (select==6'b100011)? d0 : d1;
endmodule
`timescale 1ns / 1ps
module WB_MUX_2(
input [4:0]a,
input [4:0]b,
input [5:0]opcode,
output [4:0]result
);
assign result=(opcode==6'b100011)?a:b;
endmodule
结尾
以上就是实验的全部内容,欢迎参考。
本次实验还有附加部分:数据冲突,包括暂停与重定向的实现,不过我没有放在这篇文章,链接在下面:
理性借鉴,欢迎交流!
2 条评论
(╯°A°)╯︵○○○