哈工大体系结构lab3 —— 流水线处理器的verilog实现-FPGA常见问题社区-FPGA CPLD-ChipDebug

哈工大体系结构lab3 —— 流水线处理器的verilog实现

 

 

流水线处理器的verilog实现

是的我刚刚验收完最后一个实验,所以怀着激动的心情,把当时其中一个留档的代码发出来,还算较为清晰,仅供没有思路的同学参考。造完cache,我的生活终于可以恢复正轨了,这几天折磨的寝食不安呀~~ 另外最近感悟颇多呀,美好的假期真正开始了!!

先讲一个鬼故事,我花了一天造出基本框架后跑了一下就PASS了,但是波形完全不对。。(但是感谢这个PASS给我调下去的勇气)

然后就开始修锅,修了将近10个大bug,着实的锻炼了观察波形调试的能力,咱就是说我是干了多少负负得正的事儿PASS的啊!(还是这个测试环境本身就有点问题)

学弟学妹们请慎重参考,相信你们做完非流水的这个都能做出来,另外不出意外的话,你们会遇见我们班规格严格的ywy学长(验收建议找老师哦哈哈就俩人一起笑着笑着就完事儿了),人肉查重哦~

个人认为我码风还算可以,如果我的代码有写的错误/值得改进之处,欢迎指出!!

base 版本

设计图如下,WB阶段有一个MUX没画,因为没地方了(懒了)哈哈

image-20221206200020897

最后版本跟我最开始写出来的框架有些许变化,如果你看到了让你不知所以然的代码,大概率是修锅的时候造的。。

CPU.v

`timescale 1ns / 1ps // // Company:  // Engineer:  //  // Create Date: 2022/11/08 19:26:40 // Design Name:  // Module Name: cpu // Project Name:  // Target Devices:  // Tool Versions:  // Description:  //  // Dependencies:  //  // Revision: // Revision 0.01 - File Created // Additional Comments: //  //   module cpu(     input            clk             ,  // clock, 100MHz     input            resetn             ,  // active low, board switch 0 (SW0)      // debug signals     output [31:0]    debug_wb_pc     ,	// 当前正在执行指令的PC     output           debug_wb_rf_wen ,	// 当前通用寄存器组的写使能信号     output [4 :0]    debug_wb_rf_addr,	// 当前通用寄存器组写回的寄存器编号     output [31:0]    debug_wb_rf_wdata	// 当前指令需要写回的数据     );      	     //IF     wire [31:0] IF_PC;  //output_new_address; //PC output     wire [31:0] next_PC;            //PC+4     wire [31:0] IF_NPC;         //PC input以下是段寄存器输入输出     wire [31:0] IF_IR;          //IR的指令            //ID     wire [31:0] ID_PC;     wire [31:0] ID_NPC;     wire [31:0] ID_A;     wire [31:0] ID_B;     wire [31:0] ID_Imm;     wire [31:0] ID_IR;          //EX     wire [31:0] EX_PC;     wire [31:0] EX_NPC;     wire [31:0] EX_A;     wire [31:0] EX_B;     wire [31:0] EX_Imm;     wire [31:0] EX_IR;          wire        EX_Cond;     wire [31:0] EX_ALU_output;          wire [31:0] alu_data_1;     wire [31:0] alu_data_2;          //MEM     wire [31:0] MEM_PC; //    wire        MEM_Cond;     wire [31:0] MEM_ALU_output;     wire [31:0] MEM_B;     wire [31:0] MEM_IR;     wire [31:0] MEM_LMD;          //WB     wire [31:0] WB_PC;     wire [31:0] WB_LMD;     wire [31:0] WB_ALU_output;     wire [31:0] WB_IR;          wire reg_write_enable;     wire [4:0]  WB_address;//WB_mux output     wire [31:0] WB_data;//MUX3 output        	assign debug_wb_pc = WB_PC; 	assign debug_wb_rf_wen = reg_write_enable; 	assign debug_wb_rf_addr = WB_address; 	assign debug_wb_rf_wdata = WB_data; 	     //IF      PC pc(         .clk            (clk),         .reset_n        (resetn),         .new_address    (IF_NPC),         .output_address (IF_PC)     );          ADD PC_plus4( 		.data1          (IF_PC),  		.data2          (32'h00000004),  		.result         (next_PC) 	); 	 	IMEM inst_mem( 	   .address        (IF_PC), 	   .output_instruction(IF_IR) 	);      MUX PC_mux(         .data0          (MEM_ALU_output),         .data1          (next_PC),         .select         (EX_Cond),         .result         (IF_NPC)     );          IF_ID_registers IF_ID_reg(         .clk            (clk),         .reset_n        (resetn),         .NPC_i          (IF_NPC),         .IR_i           (IF_IR),         .PC_i           (IF_PC),         .NPC_o          (ID_NPC),         .IR_o           (ID_IR),         .PC_o           (ID_PC)     );          //ID     Extender extender(         .opcode         (ID_IR[31:26]),         .input_26bImm   (ID_IR[25:0]),         .output_32bImm  (ID_Imm)     );          Registers Registers_set(         .clk            (clk),         .reset_n        (resetn),         .write_enable   (reg_write_enable),         .rs             (ID_IR[25:21]),         .rt             (ID_IR[20:16]),         .writeback_address(WB_address),         .writeback_data (WB_data),         .output_data_A  (ID_A),         .output_data_B  (ID_B)     );          ID_EX_registers ID_EX_reg(         .clk            (clk),         .reset_n        (resetn),         .NPC_i          (ID_NPC),         .A_i            (ID_A),         .B_i            (ID_B),         .Imm32_i        (ID_Imm),         .IR_i           (ID_IR),         .PC_i           (ID_PC),         .NPC_o          (EX_NPC),         .A_o            (EX_A),         .B_o            (EX_B),         .Imm32_o        (EX_Imm),         .IR_o           (EX_IR),         .PC_o           (EX_PC)     );          //EX     MUX1 mux1(         .opcode         (EX_IR[31:26]),         .data0          (EX_NPC),         .data1          (EX_A),         .result         (alu_data_1)     );          MUX2 mux2(         .opcode         (EX_IR[31:26]),         .data0          (EX_B),         .data1          (EX_Imm),         .result         (alu_data_2)     );          Equal equal(         .opcode         (IF_IR[31:26]),         .data_A         (EX_A),         .data_B         (EX_B),         .equal          (EX_Cond)     );          ALU alu(         .opcode         (EX_IR[31:26]),         .alu_op         (EX_IR[5:0]),         .input_data1    (alu_data_1),         .input_data2    (alu_data_2),         .result         (EX_ALU_output)     );          EX_MEM_registers EX_MEM_reg(         .clk            (clk),         .reset_n        (resetn),          .ALU_output_i   (EX_ALU_output),         .B_i            (EX_B),         .IR_i           (EX_IR),         .PC_i           (EX_PC),         .ALU_output_o   (MEM_ALU_output),         .B_o            (MEM_B),         .IR_o           (MEM_IR),         .PC_o           (MEM_PC)     );          //MEM     DMEM data_mem(         .clk            (clk),         .reset_n        (resetn),         .opcode         (MEM_IR[31:26]),         .alu_address    (MEM_ALU_output),         .WD             (MEM_B),         .RD             (MEM_LMD)     );      MEM_WB_registers MEM_WB_reg(         .clk            (clk),         .reset_n        (resetn),         .LMD_i          (MEM_LMD),         .ALU_output_i   (MEM_ALU_output),           .IR_i           (MEM_IR),         .PC_i           (MEM_PC),         .LMD_o          (WB_LMD),         .ALU_output_o   (WB_ALU_output),         .IR_o           (WB_IR),         .PC_o           (WB_PC),         .write_enable   (reg_write_enable)     );          //WB     Writeback_aMUX Writeback_aMUX_inst( //写回寄存器编号选择         .opcode         (WB_IR[31:26]),         .rt_address     (WB_IR[20:16]),         .rd_address     (WB_IR[15:11]),         .writeback_address(WB_address)     );          Writeback_dMUX Writeback_dMUX_inst(         .opcode         (WB_IR[31:26]),         .data0          (WB_LMD),         .data1          (WB_ALU_output),         .writeback_data (WB_data)     );      endmodule  

PC.v

module PC(     input       clk,     input		reset_n,     input [31:0] new_address,  // 下一个地址 	      output reg [31:0] output_address	// 当前PC内容 ); 	always@(posedge clk) begin 		if(reset_n == 1'b0)  			output_address <= 0; 		else  			output_address <= new_address; 	end  endmodule  

ADD.v

`timescale 1ns / 1ps  module ADD(     input	[31:0] 	data1, 	input	[31:0]	data2, 	     output	[31:0] 	result );  	assign result = data1 + data2; 	 endmodule  

IMEM.v

//组合逻辑 module IMEM(     input  [31:0] address,	// 指令的地址     output [31:0] output_instruction	// 取出的指令 );  	reg [31:0] instruction [255:0];	// 32位*256大小的指令存储缓冲器 	 	initial begin 	    // 读取文件内容并进行初始化 		$readmemh("E:/FPGA_code/CPU_pipeline/CPU_pipeline.sim/sim_1/behav/xsim/base_inst_data", instruction);  	end 	 	assign output_instruction = instruction[address / 4];   endmodule                                                                                                 

MUX.v

module MUX(     input  [31:0] data0, //跳转地址     input  [31:0] data1, //顺序执行的地址     input         select,	 	      output [31:0] result ); 	 	assign result = (select == 1)? data0 : data1; //cond == 1则跳转  endmodule  

IF_ID_registers.v

`timescale 1ns / 1ps  module IF_ID_registers(     input clk,     input reset_n,     input [31:0] NPC_i,     input [31:0] IR_i,     input [31:0] PC_i,          output reg [31:0] NPC_o,     output reg [31:0] IR_o,     output reg [31:0] PC_o     );          always@(posedge clk)     if(reset_n == 1'b0) begin         NPC_o <= 0;         IR_o <= 0;         PC_o <= 0;     end     else begin         NPC_o <= NPC_i;         IR_o <= IR_i;         PC_o <= PC_i;      end             endmodule  

Extender.v

`timescale 1ns / 1ps   `define JMP 6'b000010  module Extender(     input  [ 5:0] opcode,	// 指令的操作码     input  [25:0] input_26bImm,	// 待扩展的数据 	      output [31:0] output_32bImm	// 扩展到32位后的数据 ); 	 	assign output_32bImm[31:0] = (opcode == `JMP)? { {6{input_26bImm[25]}}, input_26bImm[25:0]}	// JMP将后25位符号扩展为32位 										: { {16{input_26bImm[15]}}, input_26bImm[15:0]};//其他的指令如 SW/LW将后16位符号扩展为32位   endmodule   

Registers.v

`timescale 1ns / 1ps  module Registers(     input         clk,     input         reset_n,     input       write_enable,     input [4:0] rs,	// rt的值     input [4:0] rt,	// rd的值 	input [4:0] writeback_address,	// 要写的寄存器的地址 	input [31:0] writeback_data,	// 要写入的内容 	      output  [31:0] output_data_A,		// Reg[rt]     output  [31:0] output_data_B		// Reg[rd] );  	reg [31:0] registers [31:0];	// 32个32位寄存器 	 	assign output_data_A = registers[rs]; 	assign output_data_B = registers[rt]; 	 	 	//  使用本地文件初始化寄存器组 	initial begin 		$readmemb("E:/FPGA_code/lab2/lab2.sim/sim_1/behav/xsim/reg_data.txt" , registers); 	end 	 	always@(posedge clk) begin 		if(reset_n == 0) begin 			//output_data_1 = 32'h00000000; 			//output_data_2 = 32'h00000000; 		end 		else begin  			if(write_enable == 1) begin 				registers[writeback_address] <= writeback_data; //WB写回寄存器 			end 		end 	end endmodule  

ID_EX_registers.v

module ID_EX_registers(     input clk,     input reset_n,     input [31:0] NPC_i,     input [31:0] A_i,     input [31:0] B_i,     input [31:0] Imm32_i,     input [31:0] IR_i,     input [31:0] PC_i,          output reg [31:0] NPC_o,     output reg [31:0] A_o,     output reg [31:0] B_o,     output reg [31:0] Imm32_o,     output reg [31:0] IR_o,     output reg [31:0] PC_o     );          always@(posedge clk)     if(reset_n == 1'b0) begin         NPC_o <= 0;         A_o <= 0;         B_o <= 0;         Imm32_o <= 0;         IR_o <= 0;         PC_o <= 0;     end     else begin         NPC_o <= NPC_i;         A_o <= A_i;         B_o <= B_i;         Imm32_o <= Imm32_i;         IR_o <= IR_i;          PC_o <= PC_i;     end      endmodule 

MUX1.v

`timescale 1ns / 1ps  `define JMP 6'b000010 `define BEQ 6'b000100  module MUX1(     input [5:0]  opcode,     input [31:0] data0,     input [31:0] data1,          output [31:0] result     );     //JMP BEQ     assign result = (opcode == `JMP || opcode == `BEQ) ? data0 : data1; //NPC:A endmodule  

MUX2.v

`define JMP 6'b000010 `define BEQ 6'b000100 `define LW 6'b100011 `define SW 6'b101011  module MUX2(     input [5:0]  opcode,     input [31:0] data0,     input [31:0] data1,          output [31:0] result ); 	assign result = (opcode == `JMP || opcode == `BEQ || opcode == `LW || opcode == `SW) ? data1 : data0; //Imm:B      endmodule 

Equal.v

`define JMP 6'b000010 `define BEQ 6'b000100  module Equal(     input [5:0] opcode,     input [31:0] data_A,     input [31:0] data_B,          output equal     );          assign equal = (opcode == `JMP || (opcode == `BEQ && data_A == data_B)) ? 1:0; endmodule 

ALU.v

`define ALU 6'b000000 `define BEQ 6'b000100 `define JMP 6'b000010 `define MOVZ 6'b001010 `define SW 6'b101011 `define LW 6'b100011  module ALU(     input [5:0] opcode, 	input [5:0] alu_op,		//执行哪种运算     input [31:0] input_data1,     input [31:0] input_data2, 	      output wire [31:0] result );  	wire [31:0] temp;     //若为JMP指令,将其中的26位形式地址instr_index左移2位作为低28位,放于temp 	assign temp = (alu_op == 6'b110000) ? input_data2 << 2 : 32'b0; //JMP (NPC[31:28]) ## (instr_index << 2), 	 	assign result = ({32{alu_op == 6'b101000 && opcode == `BEQ}} & ((input_data2 << 2) + input_data1)) |    //BEQ:sign_extend(offset) << 2 + NPC 	                       ({32{alu_op == 6'b100000 && opcode == `ALU}} & (input_data1 + input_data2)) |           //ADD 	                       ({32{alu_op == 6'b100010 && opcode == `ALU}} & (input_data1 - input_data2)) |           //SUB 	                       ({32{alu_op == 6'b100100 && opcode == `ALU}} & (input_data1 & input_data2)) |           //AND 	                       ({32{alu_op == 6'b100101 && opcode == `ALU}} & (input_data1 | input_data2)) |           //OR 	                       ({32{alu_op == 6'b100110 && opcode == `ALU}} & (input_data1 ^ input_data2)) |           //XOR 	                       ({32{alu_op == 6'b101010 && opcode == `ALU}} & (input_data1 < input_data2)? 32'h000000001 : 32'h00000000) | //SLT:[rd] <- [rs] < [rt] ? 1 : 0 	                       ({32{alu_op == 6'b001010 && opcode == `MOVZ}} & (input_data2 == 0)? input_data1 : 32'h00000000) |  // MOVZ:if([rt] == 0)then[rd] ← [rs] else 不做任何 	                       ({32{alu_op == 6'b110000 && opcode == `JMP}} & {input_data1[31:26], temp[25:0]} ) | //JMP 	                       ({32{opcode == `LW}} & (input_data1 + input_data2)) |   //LW 	                       ({32{opcode == `SW}} & (input_data1 + input_data2));    //SW              endmodule 

EX_MEM_registers.v

module EX_MEM_registers(     input clk,     input reset_n, //    input Cond_i,     input [31:0] ALU_output_i,     input [31:0] B_i,     input [31:0] IR_i,     input [31:0] PC_i,      //    output reg        Cond_o,     output reg [31:0] ALU_output_o,     output reg [31:0] B_o,     output reg [31:0] IR_o,     output reg [31:0] PC_o     );          always@(posedge clk)     if(reset_n == 1'b0) begin //        Cond_o <= 0;         ALU_output_o <= 0;         B_o <= 0;         IR_o <= 0;         PC_o <= 0;     end     else begin  //        Cond_o <= Cond_i;         ALU_output_o <= ALU_output_i;         B_o <= B_i;         IR_o <= IR_i;         PC_o <= PC_i;     end endmodule 

DMEM.v

`timescale 1ns / 1ps  module DMEM(     input         clk,     input         reset_n,     input [5:0]   opcode,     input [31:0]  alu_address,	// 要访问或写入的地址     input [31:0]  WD,		    // 要写入的数据 	      output [31:0] RD            // 读出的数据 );  	reg [31:0] memory [255:0];		// 256*32的数据存储缓冲器 	 	//  用本地文件初始化存储器 	initial begin 		$readmemh("E:/FPGA_code/CPU_pipeline/CPU_pipeline.sim/sim_1/behav/xsim/base_data_data", memory); 	end 	 	assign RD = memory[alu_address / 4]; 		 	always@(negedge clk) begin 		if(reset_n == 0) begin 		end 		else begin 			if(opcode == 6'b101011) //SW 				memory[alu_address / 4] <= WD; 		end 	end   endmodule 

注意,如果你reset_n == 0重置的时候啥也不干,仿真并不会出错,但是上板后就“不符合要求”了,所以在此提供颜神的简单又靠谱的DMEM初始化方式,不好使他女装!

image-20221206200240968

(看见了吗,颜牛字里行间都写着“贴心”二字)

MEM_WB_registers.v

`define ALU 6'b000000 `define MOVZ 6'b001010 `define LW 6'b100011  module MEM_WB_registers(     input clk,     input reset_n,     input [31:0] LMD_i,     input [31:0] ALU_output_i,     input [31:0] IR_i,     input [31:0] PC_i,          output reg [31:0] LMD_o,     output reg [31:0] ALU_output_o,     output reg [31:0] IR_o,     output reg [31:0] PC_o,     output reg write_enable );     wire [5:0] opcode;     wire [5:0] ALUfunc;     wire [4:0] rt;          assign opcode = IR_i[31:26];     assign ALUfunc = IR_i[5:0];     assign rt = IR_i[20:16];               always@(posedge clk)      if(reset_n == 1'b0) begin         LMD_o <= 0;         ALU_output_o <= 0;         IR_o <= 0;         PC_o <= 0;         write_enable <= 0;     end      else begin         LMD_o <= LMD_i;         ALU_output_o <= ALU_output_i;         IR_o <= IR_i;         PC_o <= PC_i;         write_enable <= (opcode == `LW || (opcode == `ALU && !(ALUfunc == `MOVZ && rt != 0))) && IR_i != 32'h00000000? 1 : 0;     end endmodule 

Writeback_aMUX.v

`timescale 1ns / 1ps  `define LW 6'b100011  module Writeback_aMUX(     input  [5:0] opcode,     input  [4:0] rt_address,     input  [4:0] rd_address, 	      output [4:0] writeback_address     );         assign writeback_address = (opcode == `LW)? rt_address : rd_address; //Load-rt:其他-rd endmodule  

Writeback_dMUX.v

`define LW 6'b100011  module Writeback_dMUX(     input [5:0] opcode,     input [31:0] data0,     input [31:0] data1,          output [31:0] writeback_data     );         assign writeback_data = (opcode == `LW)? data0 : data1; //LMD:ALU_output endmodule  

 

请登录后发表评论

    没有回复内容