CPU之路——五级流水线与第一条ORI指令

经过几天的打造,流水线终于竣工了。。。     

一、ORI指令 

二、状态机与流水线

三、五级流水线模型

四、流水线验证

五、处理数据相关问题

六、MIPS编译环境建立——GNU工具链


一、ORI指令 

CPU之路——五级流水线与第一条ORI指令_第1张图片

  • 31~26为ORI指令的指令码
  • 25~21为源寄存器(取出源操作数)——MIPS有32个寄存器,所以5位即可全部表示
  • 20~16为目的寄存器(保存运算结果)
  • 15~0为立即数
  • ORI指令:将immediate进行无符号数扩展(高位补0)至32位,与rs,结果保存至rt

二、状态机与流水线

CPU之路——五级流水线与第一条ORI指令_第2张图片

三、五级流水线模型

CPU之路——五级流水线与第一条ORI指令_第3张图片

CPU之路——五级流水线与第一条ORI指令_第4张图片

  • 以下模块全都基于此结构框图,“心中有电路,手下有代码”果然不只是说说。

  • 取指、译码、执行、访存、回写各阶段内部模块均采用组合逻辑电路,即:只要有数据变化,电路就开始工作,然后将执行结果保存至各传递模块,在下一时钟上升沿到来时,将数据传入下一阶段。故各传递模块采用时序逻辑电路

宏定义

//******************************************全局宏定义******************************************************
`define RstEnable		1'b1			//复位信号有效
`define RstDisable		1'b0			//复位信号无效
`define ZeroWord		32'h00000000	//32位的数值0
`define WriteEnable		1'b1			//使能写
`define WriteDisable	1'b0			//禁止写
`define ReadEnable		1'b1			//使能读
`define ReadDisable		1'b0			//禁止读
`define AluOpBus		7:0				//译码阶段的输出aluop_o的宽度
`define AluSelBus		2:0				//译码阶段的输出alusel_o的宽度
`define InstValid		1'b1			//指令有效
`define InstInvalid		1'b0			//指令无效
`define True_v			1'b1			//逻辑“真”
`define False_v			1'b0			//逻辑“假”
`define ChipEnable		1'b1			//芯片使能
`define ChipDisable		1'b0			//芯片禁止


//**************************************与具体指令有关的宏定义***********************************************
`define EXE_ORI		6'b001101			//指令ori的指令码
`define EXE_NOP		6'b000000			//空指令指令码

//AluOp
`define EXE_OR_OP		8'b00100101		//OR指令
`define EXE_NOP_OP		8'b00000000		//空指令

//AluSe
`define EXE_RES_LOGIC	3'b001			//逻辑运算类型
`define EXE_RES_NOP		3'b000			//


//************************************与指令存储器ROM有关的宏定义********************************************
`define InstAddrBus			31:0		//ROM地址总线宽度
`define InstBus				31:0		//ROM数据总线宽度
`define InstMemNum			131071		//ROM的实际大小为128KB = 2^17
`define InstMemNumLog2		17			//ROM实际使用的地址线宽度


//**********************************与通用寄存器Regfile有关的宏定义******************************************
`define RegAddrBus		4:0			//Regfile模块的地址线宽度
`define RegBus			31:0		//Regfile模块的数据线宽度
`define RegWidth		32			//通用寄存器的宽度
`define DoubleRegWidth	64			//两倍的通用寄存器的宽度
`define DoubleRegBus	63:0		//两倍的通用寄存器的数据线宽度
`define RegNum			32			//通用寄存器的数量
`define RegNumLog2		5			//寻址通用寄存器使用的地址位数
`define NOPRegAddr		5'b00000	

通用寄存器模块

/***************************************寄存器读写配置模块*********************************************/
`include "defines.v"
module regfile( input wire clk, input wire rst, 	//时钟 复位
				input wire we,  input wire[`RegAddrBus] waddr, input wire[`RegBus] wdata,	//写端口
				input wire re1, input wire[`RegAddrBus] raddr1,output reg[`RegBus] rdata1,	//读端口1
				input wire re2, input wire[`RegAddrBus] raddr2,output reg[`RegBus] rdata2	//读端口2
				);
	
/**************************************32个32位寄存器********************************************/
	reg [`RegBus] regs [`RegNum-1:0];

/***************************************寄存器写操作*********************************************/
	always @( posedge clk )
	begin
		if(rst == `RstDisable)	//复位时钟无效时
		begin
			if( (waddr != `RegNumLog2'h0) && we == `WriteEnable)	
			//若当前寄存器不为0(MIPS规定$0为32bit0 不允许写入) 并且写使能有效 则将数据写入其中
			begin
				regs[waddr] <= wdata;
			end
		end
	end
/***************************************寄存器读操作1*********************************************/	
	always @(*)
	begin
		if(rst == `RstEnable)	//复位有效
		begin
			rdata1 <= `ZeroWord;
		end
		//复位无效
		else if(raddr1 == `RegNumLog2'h0)	//所读寄存器为$0
				rdata1 <= `ZeroWord;
		else if( (raddr1 == waddr) && (we ==`WriteEnable)  && (re1 == `ReadEnable) )
			rdata1 <= wdata;		//读写为同一寄存器
		else if( re1 == `ReadEnable )	//正常读取
			rdata1 <= regs[raddr1];
		else
			rdata1 <= `ZeroWord;	//无法使用
	end
/***************************************寄存器读操作2*********************************************/	
	always @(*)
	begin
		if(rst == `RstEnable)	//复位有效
		begin
			rdata2 <= `ZeroWord;
		end
		else	//复位无效
		begin
			if(raddr2 == `RegNumLog2'h0)	//
				rdata2 <= `ZeroWord;
			else if( (raddr2 == waddr) && (we ==`WriteEnable)  && (re2 == `ReadEnable) )
				rdata2 <= wdata;
			else if( re2 == `ReadEnable )
				rdata2 <= regs[raddr2];
			else
				rdata2 <= `ZeroWord;
		end
	end

endmodule

取值模块

/***********************************取指模块**************************************/
`include "defines.v"
module pc_reg( input wire rst, input wire clk, output reg[`InstAddrBus] pc, output reg ce );

	always @(posedge clk)
	begin 
		if(rst == `RstEnable)	//复位开始,指令存储器禁用
			ce <= `ChipDisable;
		else 
			ce <= `ChipEnable;	//复位结束,指令存储器使能
	end
	
	always @(posedge clk)
	begin 
		if(ce == `ChipDisable)	//指令寄存器禁用
			pc <= `ZeroWord;	//PC始终为0 32位
		else 	
			pc <= pc + 4'h4;	//指令寄存器使能,PC值每时钟周期+4
	end

endmodule

取值-译码模块

/*************************************取值-译码模块****************************************/
`include "defines.v"
module if_id( 	input wire clk, input wire rst, 
				input wire[`InstAddrBus] if_pc,
				input wire[`InstBus] if_inst,
			
				output reg[`InstAddrBus] id_pc,
				output reg[`InstBus] id_inst	);

	always @(posedge clk)
	begin 
		if(rst == `RstEnable)	//复位开始
		begin
			id_pc <= `ZeroWord;
			id_inst <= `ZeroWord;
		end
		else 
		begin
			id_pc <= if_pc;
			id_inst <= if_inst;
		end
	end

endmodule

译码模块

/***************************************译码模块**********************************************************/
`include "defines.v"
module id(	input wire rst, 					//复位		
			input wire[`InstAddrBus] pc_i, 		//程序计数器
			input wire[`InstBus] inst_i,		//指令
			//读取的regfile的值
			input wire[`RegBus] reg1_data_i, 	//寄存器堆中寄存器1数据	
			input wire[`RegBus] reg2_data_i,	//寄存器堆中寄存器2数据	
			//输出到regfile的信息
			output reg reg1_read_o, 			//
			output reg reg2_read_o,
			output reg[`RegAddrBus] reg1_addr_o, 	
			output reg[`RegAddrBus] reg2_addr_o,
			//送到执行阶段的信息
			output reg[`AluOpBus] aluop_o, 		//具体运算:或、与...
			output reg[`AluSelBus] alusel_o,	//运算类型:算数、逻辑、移位...	
			output reg[`RegBus] reg1_o, 		//操作数1
			output reg[`RegBus] reg2_o,			//操作数2
			output reg[`RegAddrBus] wd_o,		//写入目的寄存器的地址
 			output reg wreg_o					//写目的寄存器使能
		);

	//取得指令的指令码和功能码
	wire[5:0] op  = inst_i[31:26];	//ORI指令操作码
	wire[4:0] op2 = inst_i[10:6];	/*暂时好像没用*/
	wire[5:0] op3 = inst_i[5:0];	/*暂时好像没用*/
	wire[4:0] op4 = inst_i[20:16];	/*暂时好像没用*/
	
	//保存指令执行需要的立即数
	reg[`RegBus] imm;
	//指令指针是否有效
	reg instvalid;
	
	/***************************************对指令译码*****************************************/
	always @(*)
	begin
		if(rst == `RstEnable)	//复位
		begin		
			aluop_o		<= `EXE_NOP_OP;			//初始化
			alusel_o	<= `EXE_RES_NOP;
			wd_o		<= `NOPRegAddr;
			wreg_o		<= `WriteDisable;
			instvalid	<= `InstInvalid;
			reg1_read_o	<= `ReadDisable;
			reg2_read_o	<= `ReadDisable;
			reg1_addr_o	<= `NOPRegAddr;
			reg2_addr_o	<= `NOPRegAddr;
			imm			<= `ZeroWord;
		end
		else	//复位无效
		begin		
			aluop_o		<= `EXE_NOP_OP;			//初始化
			alusel_o	<= `EXE_RES_NOP;
			wd_o		<= inst_i[15:11];
			wreg_o		<= `WriteDisable;
			instvalid	<= `InstValid;
			reg1_read_o	<= `ReadDisable;
			reg2_read_o	<= `ReadDisable;
			reg1_addr_o	<= inst_i[25:21];	//寄存器1地址
			reg2_addr_o	<= inst_i[20:16];	//寄存器2地址
			imm			<= `ZeroWord;
			
			case(op)	//指令译码
				`EXE_ORI:	//ori指令
				begin
					aluop_o		<= `EXE_OR_OP;		//逻辑运算中的“或”运算	
					alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
					wd_o		<= inst_i[20:16];	//目的寄存器地址
					wreg_o		<= `WriteEnable;	//ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
					instvalid	<= `InstValid;		//有效指令
					reg1_read_o	<= `ReadEnable;		//ORI指令需要读第一个寄存器的值
					reg2_read_o	<= `ReadDisable;	//ORI指令无需读第二个寄存器的值
					imm			<= {16'h0,inst_i[15:0]};	//立即数扩展为32bit
				end
				default:
				begin
					
				end
			endcase
		end
	end
	
	/***************************************确定源操作数1*****************************************/
	always @(*) 
	begin
		if(rst == `RstEnable)	//复位有效
			reg1_o <= `ZeroWord;
		else if(reg1_read_o ==`ReadEnable)	//读使能
			reg1_o <= reg1_data_i;
		else if(reg1_read_o ==`ReadDisable)	//读无效时,将立即数放到操作数中,传给执行部分
			reg1_o <= imm;
		else
			reg1_o <= `ZeroWord;
	end
	
	/***************************************确定源操作数2*****************************************/
	always @(*) 
	begin
		if(rst == `RstEnable)
			reg2_o <= `ZeroWord;
		else if(reg2_read_o ==`ReadEnable)
			reg2_o <= reg2_data_i;
		else if(reg2_read_o ==`ReadDisable)
			reg2_o <= imm;
		else
			reg2_o <= `ZeroWord;
	end
	
endmodule

译码-执行模块

/****************************************译码-执行模块***********************************************/
/***********************作用:在时钟上升沿,将译码模块输出传递给执行模块*****************************/
`include "defines.v"
module id_ex(	input wire clk,
				input wire rst,
				input wire[`AluOpBus] id_aluop, 	//具体运算:或、与...
				input wire[`AluSelBus] id_alusel,	//运算类型:算数、逻辑、移位...	
				input wire[`RegBus] id_reg1, 		//操作数1
				input wire[`RegBus] id_reg2,		//操作数2
				input wire[`RegAddrBus] id_wd,		//写入目的寄存器的地址
				input wire id_wreg,				//写目的寄存器使能
				
				output reg[`AluOpBus] ex_aluop_o, 	//具体运算:或、与...
				output reg[`AluSelBus] ex_alusel_o,	//运算类型:算数、逻辑、移位...	
				output reg[`RegBus] ex_reg1_o, 		//操作数1
				output reg[`RegBus] ex_reg2_o,		//操作数2
				output reg[`RegAddrBus] ex_wd_o,	//写入目的寄存器的地址
				output reg ex_wreg_o				//写目的寄存器使能
			);

	always @(posedge clk)
	begin
		if(rst == `RstEnable)
		begin
			ex_aluop_o  <= `EXE_NOP_OP; 	//具体运算:或、与...
			ex_alusel_o <= `EXE_RES_NOP;	//运算类型:算数、逻辑、移位...	
			ex_reg1_o   <= `ZeroWord; 		//操作数1
			ex_reg2_o   <= `ZeroWord;		//操作数2
			ex_wd_o	 	<= `NOPRegAddr;
			ex_wreg_o   <= `WriteDisable;
		end
		else
		begin
			ex_aluop_o	<= id_aluop; 	//具体运算:或、与...
			ex_alusel_o	<= id_alusel;	//运算类型:算数、逻辑、移位...	
			ex_reg1_o	<= id_reg1; 	//操作数1
			ex_reg2_o	<= id_reg2;		//操作数2
			ex_wd_o		<= id_wd;
			ex_wreg_o	<= id_wreg;
		end
	end

endmodule

执行模块

/**************************************执行模块***************************************************/
`include "defines.v"
module ex(	input wire rst,					//复位
			input wire[`AluOpBus] aluop_i, 	//具体运算:或、与...
			input wire[`AluSelBus] alusel_i,//运算类型:算数、逻辑、移位...	
			input wire[`RegBus] reg1_i, 	//操作数1
			input wire[`RegBus] reg2_i,		//操作数2
			input wire[`RegAddrBus] wd_i,	//写入目的寄存器的地址
			input wire wreg_i,				//写目的寄存器使能
			output reg[`RegAddrBus] wd_o,
			output reg wreg_o,
			output reg[`RegBus] wdata_o   );
			
	reg[`RegBus] logicout;	//保存逻辑运算的结果
	
	/******************根据aluop_i指示的运算子类型进行运算,结果保存至logicout*****************/
	always @(*)
	begin
		if(rst == `RstEnable)
		begin
			logicout <= `ZeroWord;
		end
		else
		begin
			case(aluop_i)
				`EXE_OR_OP: 	//逻辑或运算
				begin
					logicout <= reg1_i | reg2_i;
				end
				//后续可添加其余运算
				default:
				begin
					logicout <= `ZeroWord;
				end	
			endcase
		end
	end
	/*****************根据alusel_i指示的运算子类型进行运算,将logicout输出******************/
	always @(*)
	begin
		wd_o <= wd_i;		//来自上一级模块的输入。写目的寄存器地址和写寄存器使能
		wreg_o <= wreg_i;
		case(alusel_i)
			`EXE_RES_LOGIC:
			begin
				wdata_o <= logicout;
			end
			//后续可添加其余运算
			default:
			begin
				wdata_o <= `ZeroWord;
			end	
		endcase
	end
endmodule

执行-访存模块

/******************************************执行-访存模块*********************************************/
/***********************作用:在时钟上升沿,将执行模块输出传递给访存模块*****************************/
`include "defines.v"
module ex_mem(	input wire clk,
				input wire rst,
				input wire[`RegAddrBus] ex_wd_i,
				input wire ex_wreg_i,
				input wire[`RegBus] ex_wdata_i,
				output reg[`RegAddrBus] mem_wd_o,
				output reg mem_wreg_o,
				output reg[`RegBus] mem_wdata_o 
			);
		
	always @(posedge clk)
	begin
		if(rst == `RstEnable)	//复位
		begin
			mem_wd_o	<=	`NOPRegAddr;
			mem_wreg_o	<=	`WriteDisable;
			mem_wdata_o	<=	`ZeroWord;
		end
		else	//传递
		begin
			mem_wd_o	<=	ex_wd_i;
			mem_wreg_o	<=	ex_wreg_i;
			mem_wdata_o	<=	ex_wdata_i;
		end
	end
	
endmodule

访存模块

/***************************************访存模块*********************************************/
`include "defines.v"
module mem(	input wire rst,
			input wire[`RegAddrBus] wd_i,
			input wire wreg_i,
			input wire[`RegBus] wdata_i,
			output reg[`RegAddrBus] wd_o,
			output reg wreg_o,
			output reg[`RegBus] wdata_o 
			);
	
	always @(*)
	begin
		if(rst == `RstEnable)	//复位
		begin
			wd_o	<=	`NOPRegAddr;
			wreg_o	<=	`WriteDisable;
			wdata_o	<=	`ZeroWord;
		end
		else	//传递
		begin
			wd_o	<=	wd_i;
			wreg_o	<=	wreg_i;
			wdata_o	<=	wdata_i;
		end
	end
	
endmodule

访存-回写模块

/******************************************访存-回写模块*********************************************/
/***********************作用:在时钟上升沿,将访存模块输出传递给回写模块*****************************/
`include "defines.v"
module mem_wb(	input wire clk,
				input wire rst,
				input wire[`RegAddrBus] mem_wd_i,
				input wire mem_wreg_i,
				input wire[`RegBus] mem_wdata_i,
				output reg[`RegAddrBus] wb_wd_o,
				output reg wb_wreg_o,
				output reg[`RegBus] wb_wdata_o 
			);
		
	always @(posedge clk)
	begin
		if(rst == `RstEnable)	//复位
		begin
			wb_wd_o		<=	`NOPRegAddr;
			wb_wreg_o	<=	`WriteDisable;
			wb_wdata_o	<=	`ZeroWord;
		end
		else	//传递
		begin
			wb_wd_o		<=	mem_wd_i;
			wb_wreg_o	<=	mem_wreg_i;
			wb_wdata_o	<=	mem_wdata_i;
		end
	end
	
endmodule

顶层模块(将各模块连接起来)

/*************************************MIPS五级流水线顶层*****************************************/
`include "defines.v"
`include "pc_reg.v"
`include "if_id.v"
`include "id.v"
`include "regfile.v"
`include "ex.v"
`include "ex_mem.v"
`include "mem.v"
`include "mem_wb.v"
module openmips(	input wire rst,
					input wire clk,
					input wire[`RegBus] rom_data_i,
					output wire[`RegBus] rom_addr_o,
					output wire rom_ce_o
				);
	/*** 取值-译码模块输出 && 译码模块输入 ***/
	wire[`InstAddrBus] pc;
	wire[`InstAddrBus] id_pc_i;
	wire[`InstBus] id_inst_i;
	/*** 译码模块输出 && 译码-执行模块输入 ***/
	wire[`AluOpBus] id_aluop_o;		//具体运算:或、与...
	wire[`AluSelBus] id_alusel_o;	//运算类型:算数、逻辑、移位...	
	wire[`RegBus] id_reg1_o;		//操作数1
	wire[`RegBus] id_reg2_o;		//操作数2
	wire[`RegAddrBus] id_wd_o;		//写入目的寄存器的地址
	wire id_wreg_o;					//写目的寄存器使能
	/*** 译码-执行模块输出 && 执行模块输入 ***/
	wire[`AluOpBus] ex_aluop_i;
	wire[`AluSelBus] ex_alusel_i;
	wire[`RegBus] ex_reg1_i;
	wire[`RegBus] ex_reg2_i;
	wire[`RegAddrBus] ex_wd_i;
	wire ex_wreg_i;
	/*** 执行模块输出 && 执行-访存模块输入 ***/
	wire[`RegAddrBus] ex_wd_o;
	wire ex_wreg_o;
	wire[`RegBus] ex_wdata_o;
	/*** 执行-访存模块输出 && 访存模块输入 ***/
	wire[`RegAddrBus] mem_wd_i;
	wire mem_wreg_i;
	wire[`RegBus] mem_wdata_i;
	/*** 访存模块输出 && 回写模块输入 ***/
	wire[`RegAddrBus] mem_wd_o;
	wire mem_wreg_o;
	wire[`RegBus] mem_wdata_o;
	/*** 回写模块输出 && 寄存器模块输入 ***/
	wire[`RegAddrBus] wb_wd_i;
	wire wb_wreg_i;
	wire[`RegBus] wb_wdata_i;
	/*** 连接译码模块与通用寄存器模块 ***/
	wire reg1_read;
	wire[`RegAddrBus] reg1_addr;
	wire[`RegBus] reg1_data;	//读端口1
	wire reg2_read;
	wire[`RegAddrBus] reg2_addr;
	wire[`RegBus] reg2_data;	//读端口2
	
	/***********************************各模块实例化************************************/
	//实例化pc_reg模块
	pc_reg	pc_reg0( .rst(rst), .clk(clk), .pc(pc), .ce(rom_ce_o) );
	assign rom_addr_o = pc;	//指令存储器的输入地址就是pc
	//实例化regfile模块
	regfile	regfile0( 	.clk(clk), 			.rst(rst), 	//时钟 复位
						.we(wb_wreg_i),		.waddr(wb_wd_i),		.wdata(wb_wdata_i),	//写端口
						.re1(reg1_read),	.raddr1(reg1_addr),		.rdata1(reg1_data),	//读端口1
						.re2(reg2_read),	.raddr2(reg2_addr),		.rdata2(reg2_data)	//读端口2
					);
	//实例化if_id模块				
	if_id	if_id0( .clk(clk), .rst(rst), .if_pc(pc), .if_inst(rom_data_i), 
					.id_pc(id_pc_i), .id_inst(id_inst_i) );
	//实例化id模块
	id	id0(	.rst(rst), 				//复位		
				.pc_i(id_pc_i), 		//程序计数器
				.inst_i(id_inst_i),		//指令
				//读取的regfile的值
				.reg1_data_i(reg1_data), 	//寄存器堆中寄存器1数据	
				.reg2_data_i(reg2_data),		//寄存器堆中寄存器2数据	
				//输出到regfile的信息
				.reg1_read_o(reg1_read), 
				.reg2_read_o(reg2_read),
				.reg1_addr_o(reg1_addr), 	
				.reg2_addr_o(reg2_addr),
				//送到执行阶段的信息
				.aluop_o(id_aluop_o), 	//具体运算:或、与...
				.alusel_o(id_alusel_o),	//运算类型:算数、逻辑、移位...	
				.reg1_o(id_reg1_o), 	//操作数1
				.reg2_o(id_reg2_o),		//操作数2
				.wd_o(id_wd_o),			//写入目的寄存器的地址
				.wreg_o(id_wreg_o)		//写目的寄存器使能
			);
	id_ex	id_ex0	(	.clk(clk),
						.rst(rst),
						.id_aluop(id_aluop_o), 	//具体运算:或、与...
						.id_alusel(id_alusel_o),//运算类型:算数、逻辑、移位...	
						.id_reg1(id_reg1_o), 	//操作数1
						.id_reg2(id_reg2_o),	//操作数2
						.id_wd(id_wd_o),		//写入目的寄存器的地址
						.id_wreg(id_wreg_o),		//写目的寄存器使能
						
						.ex_aluop_o(ex_aluop_i), 	//具体运算:或、与...
						.ex_alusel_o(ex_alusel_i),	//运算类型:算数、逻辑、移位...	
						.ex_reg1_o(ex_reg1_i), 		//操作数1
						.ex_reg2_o(ex_reg2_i),		//操作数2
						.ex_wd_o(ex_wd_i),	//写入目的寄存器的地址
						.ex_wreg_o(ex_wreg_i)				//写目的寄存器使能
					);
	ex	ex0(	.rst(rst),					//复位
				.aluop_i(ex_aluop_i), 	//具体运算:或、与...
				.alusel_i(ex_alusel_i),//运算类型:算数、逻辑、移位...	
				.reg1_i(ex_reg1_i), 	//操作数1
				.reg2_i(ex_reg2_i),		//操作数2
				.wd_i(ex_wd_i),	//写入目的寄存器的地址
				.wreg_i(ex_wreg_i),				//写目的寄存器使能
				.wd_o(ex_wd_o),
				.wreg_o(ex_wreg_o),
				.wdata_o(ex_wdata_o)   
			);
	ex_mem	ex_mem0(	.clk(clk),
						.rst(rst),
						.ex_wd_i(ex_wd_o),
						.ex_wreg_i(ex_wreg_o),
						.ex_wdata_i(ex_wdata_o),
						.mem_wd_o(mem_wd_i),
						.mem_wreg_o(mem_wreg_i),
						.mem_wdata_o(mem_wdata_i) 
					);
	mem	mem0(	.rst(rst),
				.wd_i(mem_wd_i),
				.wreg_i(mem_wreg_i),
				.wdata_i(mem_wdata_i),
				.wd_o(mem_wd_o),
				.wreg_o(mem_wreg_o),
				.wdata_o(mem_wdata_o) 
			);
	mem_wb	mem_wb0(	.clk(clk),
						.rst(rst),
						.mem_wd_i(mem_wd_o),
						.mem_wreg_i(mem_wreg_o),
						.mem_wdata_i(mem_wdata_o),
						.wb_wd_o(wb_wd_i),
						.wb_wreg_o(wb_wreg_i),
						.wb_wdata_o(wb_wdata_i) 
					);

endmodule

四、流水线验证

CPU之路——五级流水线与第一条ORI指令_第5张图片

CPU之路——五级流水线与第一条ORI指令_第6张图片

CPU之路——五级流水线与第一条ORI指令_第7张图片

CPU之路——五级流水线与第一条ORI指令_第8张图片

  • 可以观察到:regs[1]最终值为0X1100
  • regs[2]最终值为0X0020
  • regs[3]最终值为0Xff00
  • regs[4]最终值为0Xffff
  • 流水线工作正常
  • 分析第一条指令的执行过程:

CPU之路——五级流水线与第一条ORI指令_第9张图片

五、处理数据相关问题

CPU之路——五级流水线与第一条ORI指令_第10张图片

六、MIPS编译环境建立——GNU工具链

  • 【总结】得到bin文件需要以下四步:
  • 编译:     mips-sde-elf-as -mips32 inst_rom.S -o inst_rom.o
    链接:     mips-sde-elf-ld -T ram.ld inst_rom.o -o inst_rom.om
    bin:     mips-sde-elf-objcopy -O binary inst_rom.om inst_rom.bin
    格式转化: .Bin2Mem.exe -f inst_rom.bin -o inst_rom.data

    makefile:2: *** 遗漏分隔符 。 停止

你可能感兴趣的:(Verilog,HDL)