哈工大计算机体系与结构课程实验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。

PC

`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

ADD

`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

NPC_MUX

`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

IF_ID

`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

Regs

`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

Extender

`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

ID_EX

`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

zero

`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

MUX_1

`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

MUX_2

`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

ALU

`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

EX_MEM

`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

MEM_WB

`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

WB_MUX

`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

WB_MUX_2

`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

结尾

以上就是实验的全部内容,欢迎参考。

本次实验还有附加部分:数据冲突,包括暂停与重定向的实现,不过我没有放在这篇文章,链接在下面:

因为作者也比较菜,所以讲的东西或者代码难免有不合理的地方,欢迎下方评论区留言,我会在收到通知后尽快回复!
理性借鉴,欢迎交流!

最后修改:2023 年 10 月 20 日
如果觉得我的文章对你有用,请随意赞赏