第一条指令ori的实现

为什么加4:因为MIPS按照字节寻址,32bit是4个字节,所以每次加4。
译码阶段,会涉及到读2个寄存器以及立即数扩展,并最终通过两个mux确定两个立即数输出
在这里插入图片描述
这其实就是一个帧格式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
instvalid手动改为了1’b1
在这里插入图片描述
在这里插入图片描述
PC:给出指令地址
在这里插入图片描述

`include "defines.v"

module pc_reg(

	input  wire					clk,
	input  wire					rst,
	
	output reg [`InstAddrBus]	pc,	//InstAddrBus为宏定义 31:0 代表ROM的地址总线宽度 输出给ROM的addr
	output reg                 ce		//给到ROM的使能
	
);
	//如果复位,则使能信号ce拉0,否则置1
	always @ (posedge clk) begin
		if (rst == `RstEnable) begin	//复位信号有效 1'b1
			ce <= `ChipDisable;
		end 
		else begin
			ce <= `ChipEnable;
		end
	end
	
	//如果使能信号为低,则指令地址拉0;使能有效,则指令地址自加4'h4
	always @ (posedge clk) begin
		if (ce == `ChipDisable) begin	//芯片禁止宏定义 1'b0
			pc <= 32'h00000000;
		end 
		else begin
	 		pc <= pc + 4'h4;	//自加4 字节寻址
		end
	end
	
endmodule

if/id:保存取的指令,下一拍传给译码阶段,此处为寄存器
实际上,中间还有指令存储器,即pc模块的指令地址要给到存储器ROM中作为地址,ce作为ROM读使能,ROM的输出才给到IF/ID的if_inst
在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module if_id(
	input wire clk,
	input wire rst,
	input wire [`InstBus] 		if_inst,	//InstBus为ROM数据宽度,同样为31:0
	
	output reg [`InstBus] 		id_inst,
	output reg [`InstAddrBus]   id_pc  
	
);

	//复位有效 输出为32位的0;否则则寄存传递来的取指指令地址和指令
	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			id_pc   <= `ZeroWord;	//32位的数值0
			id_inst <= `ZeroWord;   //32位的数值0
	    end 
		else begin
		  id_pc   <= if_pc  ;
		  id_inst <= if_inst;
		end
	end
			
endmodule

重点:实现32个32位通用整数寄存器;同时可进行两个寄存器的读操作和一个寄存器的写操作
在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module regfile(
	input wire clk,
	input wire rst,
	
	input wire re1,	//1读使能
	input wire [`RegAddrBus] raddr1,	//寄存器地址,32个只需要4:0
	
	input wire re2,	//1读使能
	input wire [`RegAddrBus] raddr2,	//寄存器地址,32个只需要4:0

	input wire we,		//写使能
	input wire [`RegAddrBus] waddr,
	input wire [`RegBus]		 wdata,	//写数据
	
	output reg [`RegBus]		 rdata1,	//读出数据1
	output reg [`RegBus]		 rdata2	//读出数据1
);
	//定义32个通用寄存器
	reg [`RegBus] regs [0:`RegNum - 1];	
	
	//写操作,用时序描述;地址不能为寄存器0,MIPS规定寄存器0值只能为0
	always@(posedge clk)
		if(rst == `RstDisable) begin
			if((we == `WriteEnable)&&(waddr != `RegNumLog2'h0))
				regs[waddr] <= wdata;
		end
	
	//读操作 复位和寄存器0两种 写读同地址 普通读 其他时候为0
	//组合逻辑
	always@(*)
		if(rst == `RstEnable)
			rdata1 <= `ZeroWord;
		else if(raddr1 == `RegNumLog2'h0)
			rdata1 <= `ZeroWord;
		else if((re1 == `ReadEnable)&&(we == `WriteEnable)&&(waddr == raddr1))
			rdata1 <= wdata;
		else if(re1 == `ReadEnable)
			rdata1 <= regs[raddr1];
		else
			rdata1 <= `ZeroWord;
		
	always@(*)
		if(rst == `RstEnable)
			rdata2 <= `ZeroWord;
		else if(raddr2 == `RegNumLog2'h0)
			rdata2 <= `ZeroWord;
		else if((re2 == `ReadEnable)&&(we == `WriteEnable)&&(waddr == raddr2))
			rdata2 <= wdata;
		else if(re1 == `ReadEnable)
			rdata2 <= regs[raddr2];
		else
			rdata2 <= `ZeroWord;	
	
endmodule

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

module id(
	input wire					      rst,
	input wire[`InstAddrBus]	   pc_i,			//[31:0]
	input wire[`InstBus]          inst_i,		//[31:0] 接收IF/ID模块给的指令
	
	//从regfile里输入的
	input wire[`RegBus]           reg1_data_i,	//[31:0]
	input wire[`RegBus]           reg2_data_i,	//[31:0]

	//送到regfile的信息
	output reg                    reg1_read_o,	//使能
	output reg                    reg2_read_o,   //使能  	
	output reg[`RegAddrBus]       reg1_addr_o,	//[4:0]
	output reg[`RegAddrBus]       reg2_addr_o,	//[4:0] 	      
	
	//送到执行阶段的信息
	output reg[`AluOpBus]         aluop_o,		//译码阶段的输出aluop_o的宽度  7:0 运算子类型
	output reg[`AluSelBus]        alusel_o,	//译码阶段的输出alusel_o的宽度 2:0 运算类型
	
	//结果写入寄存器
	output reg[`RegAddrBus]       wd_o,			//[4:0]  要写入的目的寄存器地址
	output reg                    wreg_o,		//是否有要写入的目的寄存器
	
	//这两个是最终输出的操作数
	output reg[`RegBus]           reg1_o,		//[31:0] 源操作数1
	output reg[`RegBus]           reg2_o		//[31:0] 源操作数2
);
	
	//取得指令的指令码,功能码 即分解帧格式
	//对于ori指令只需通过判断第26-31bit的值,即可判断是否是ori指令;对应I类型指令
    wire[5:0] op  = inst_i[31:26];	//op指令段
    wire[4:0] op2 = inst_i[10:6];
    wire[5:0] op3 = inst_i[5:0];
    wire[4:0] op4 = inst_i[20:16];
	 
	//保存指令执行需要的立即数[31:0]
    reg[`RegBus]	imm;
	 
	//指示指令是否有效
    reg instvalid;

	//译码操作 组合逻辑实时译码
	always @ (*) begin	
		if (rst == `RstEnable) begin
			aluop_o  <= `EXE_NOP_OP;	//8'b0000_0000
			alusel_o <= `EXE_RES_NOP;	//3'b000
			wd_o   <= `NOPRegAddr;		//5'b00000
			wreg_o <= `WriteDisable;
			instvalid   <= `InstValid;	//指令有效 
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			reg1_addr_o <= `NOPRegAddr; //5'b00000
			reg2_addr_o <= `NOPRegAddr; //5'b00000
			imm <= `ZeroWord;			
	  end 
	  else begin
			//以下是非复位且无法判断指令时的默认情况
			aluop_o  <= `EXE_NOP_OP;	//8'b0000_0000
			alusel_o <= `EXE_RES_NOP;	//3'b000
			wd_o   <= inst_i[15:11];	
			wreg_o <= `WriteDisable;
			instvalid   <= `InstInvalid;	//指令无效  
			reg1_read_o <= 1'b0;
			reg2_read_o <= 1'b0;
			//默认
			reg1_addr_o <= inst_i[25:21];	//rs寄存器	
			reg2_addr_o <= inst_i[20:16];	//rt寄存器
			imm <= `ZeroWord;		
		  case (op)
				`EXE_ORI:	begin           //ORI指令 用立即数和rs计算后写入rt
					alusel_o    <= `EXE_RES_LOGIC;
					aluop_o 	   <= `EXE_OR_OP;
					wreg_o      <= `WriteEnable;
					wd_o        <= inst_i[20:16];	//立即数与rs的结果写入rt
					imm         <= {16'h0,inst_i[15:0]};
					reg1_read_o <= 1'b1;				//要去读一个rs
					reg2_read_o <= 1'b0;
					instvalid 	<= `InstValid;
				end 							 
				default:;			
		  endcase
		end       
	end       
	
	//确定2个源操作数
	always@(*)
		if(rst == `RstEnable)
			reg1_o <= `ZeroWord;
		else if(reg1_read_o == 1'b1)
			reg1_o <= reg1_data_i;
		else if(reg1_read_o == 1'b0)
			reg1_o <= imm;
		else
			reg1_o <= `ZeroWord;
		
	always@(*)
		if(rst == `RstEnable)
			reg2_o <= `ZeroWord;
		else if(reg2_read_o == 1'b1)
			reg2_o <= reg2_data_i;
		else if(reg2_read_o == 1'b0)
			reg2_o <= imm;
		else
			reg2_o <= `ZeroWord;

endmodule

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module id_ex(

	input wire					  clk,
	input wire					  rst,

	
	//从译码阶段传递的信息
	input wire[`AluOpBus]         id_aluop,		//[7:0]
	input wire[`AluSelBus]        id_alusel,	//[2:0]
	input wire[`RegBus]           id_reg1,
	input wire[`RegBus]           id_reg2,
	input wire[`RegAddrBus]       id_wd,
	input wire                    id_wreg,	
	
	//传递到执行阶段的信息
	output reg[`AluOpBus]         ex_aluop,
	output reg[`AluSelBus]        ex_alusel,
	output reg[`RegBus]           ex_reg1,
	output reg[`RegBus]           ex_reg2,
	output reg[`RegAddrBus]       ex_wd,
	output reg                    ex_wreg
	
);
	//打一拍传过去
	always @ (posedge clk) begin
		if (rst == `RstEnable) begin
			ex_aluop  <= `EXE_NOP_OP;
			ex_alusel <= `EXE_RES_NOP;
			ex_reg1   <= `ZeroWord;
			ex_reg2   <= `ZeroWord;
			ex_wd     <= `NOPRegAddr;
			ex_wreg   <= `WriteDisable;
		end 
		else begin		
			ex_aluop  <= id_aluop;
			ex_alusel <= id_alusel;
			ex_reg1   <= id_reg1;
			ex_reg2   <= id_reg2;
			ex_wd 	  <= id_wd;
			ex_wreg   <= 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,
	input wire[`RegBus]           reg2_i,
	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;

	//根据大类型判断输出
   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	
	
	//根据小类型作具体运算
	always@(*)
		if(rst == `RstEnable)
			logicout <= 0;
		else begin
			case(aluop_i)
				`EXE_OR_OP:	
					logicout <= reg1_i | reg2_i;
				default: wdata_o <= 0;
			endcase
		end
	
endmodule

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module ex_mem(

	input wire					  clk,
	input wire					  rst,
	
	
	//来自执行阶段的信息	
	input wire[`RegAddrBus]       ex_wd,
	input wire                    ex_wreg,
	input wire[`RegBus]			  ex_wdata, 	
	
	//送到访存阶段的信息
	output reg[`RegAddrBus]       mem_wd,
	output reg                    mem_wreg,
	output reg[`RegBus]			  mem_wdata
	
	
);


	always @ (posedge clk) begin
		if(rst == `RstEnable) begin
			mem_wd    <= `NOPRegAddr;
			mem_wreg  <= `WriteDisable;
		    mem_wdata <= `ZeroWord;	
		end else begin
			mem_wd    <= ex_wd;
			mem_wreg  <= ex_wreg;
			mem_wdata <= ex_wdata;			
		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

在这里插入图片描述
在这里插入图片描述

module mem_wb(

	input	wire										clk,
	input wire										rst,
	

	//来自访存阶段的信息	
	input wire[`RegAddrBus]       mem_wd,
	input wire                    mem_wreg,
	input wire[`RegBus]					 mem_wdata,

	//送到回写阶段的信息
	output reg[`RegAddrBus]      wb_wd,
	output reg                   wb_wreg,
	output reg[`RegBus]					 wb_wdata	       
	
);


	always @ (posedge clk) begin
		if(rst == `RstEnable) begin
			wb_wd 	 <= `NOPRegAddr;
			wb_wreg  <= `WriteDisable;
		    wb_wdata <= `ZeroWord;	
		end 
		else begin
			wb_wd	 <= mem_wd;
			wb_wreg  <= mem_wreg;
			wb_wdata <= mem_wdata;
		end    
	end      
			

endmodule

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module openmips(

	input  wire					   clk,
	input  wire					   rst,
	
 
	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;
	
	//连接译码阶段ID模块的输出与ID/EX模块的输入
	wire[`AluOpBus] id_aluop_o;
	wire[`AluSelBus] id_alusel_o;
	wire[`RegBus] id_reg1_o;
	wire[`RegBus] id_reg2_o;
	wire id_wreg_o;
	wire[`RegAddrBus] id_wd_o;
	
	//连接ID/EX模块的输出与执行阶段EX模块的输入
	wire[`AluOpBus] ex_aluop_i;
	wire[`AluSelBus] ex_alusel_i;
	wire[`RegBus] ex_reg1_i;
	wire[`RegBus] ex_reg2_i;
	wire ex_wreg_i;
	wire[`RegAddrBus] ex_wd_i;
	
	//连接执行阶段EX模块的输出与EX/MEM模块的输入
	wire ex_wreg_o;
	wire[`RegAddrBus] ex_wd_o;
	wire[`RegBus] ex_wdata_o;

	//连接EX/MEM模块的输出与访存阶段MEM模块的输入
	wire mem_wreg_i;
	wire[`RegAddrBus] mem_wd_i;
	wire[`RegBus] mem_wdata_i;

	//连接访存阶段MEM模块的输出与MEM/WB模块的输入
	wire mem_wreg_o;
	wire[`RegAddrBus] mem_wd_o;
	wire[`RegBus] mem_wdata_o;
	
	//连接MEM/WB模块的输出与回写阶段的输入	
	wire wb_wreg_i;
	wire[`RegAddrBus] wb_wd_i;
	wire[`RegBus] wb_wdata_i;
	
	//连接译码阶段ID模块与通用寄存器Regfile模块
    wire reg1_read;
    wire reg2_read;
    wire[`RegBus] reg1_data;
    wire[`RegBus] reg2_data;
    wire[`RegAddrBus] reg1_addr;
    wire[`RegAddrBus] reg2_addr;
  
  //pc_reg例化
	pc_reg pc_reg0(
		.clk(clk),
		.rst(rst),
		.pc(pc),
		.ce(rom_ce_o)	
			
	);
	
  assign rom_addr_o = pc;	//指令存储器的输入地址就是pc的值

  //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),
		.reg2_data_i(reg2_data),

		//送到regfile的信息
		.reg1_read_o(reg1_read),
		.reg2_read_o(reg2_read), 	  

		.reg1_addr_o(reg1_addr),
		.reg2_addr_o(reg2_addr), 
	  
		//送到ID/EX模块的信息
		.aluop_o(id_aluop_o),
		.alusel_o(id_alusel_o),
		.reg1_o(id_reg1_o),
		.reg2_o(id_reg2_o),
		.wd_o(id_wd_o),
		.wreg_o(id_wreg_o)
	);

  //通用寄存器Regfile例化
	regfile regfile1(
		.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),
		.re2 (reg2_read),
		.raddr2 (reg2_addr),
		.rdata2 (reg2_data)
	);

	//ID/EX模块
	id_ex id_ex0(
		.clk(clk),
		.rst(rst),
		
		//从译码阶段ID模块传递的信息
		.id_aluop(id_aluop_o),
		.id_alusel(id_alusel_o),
		.id_reg1(id_reg1_o),
		.id_reg2(id_reg2_o),
		.id_wd(id_wd_o),
		.id_wreg(id_wreg_o),
	
		//传递到执行阶段EX模块的信息
		.ex_aluop(ex_aluop_i),
		.ex_alusel(ex_alusel_i),
		.ex_reg1(ex_reg1_i),
		.ex_reg2(ex_reg2_i),
		.ex_wd(ex_wd_i),
		.ex_wreg(ex_wreg_i)
	);		
	
	//EX模块
	ex ex0(
		.rst(rst),
	
		//送到执行阶段EX模块的信息
		.aluop_i(ex_aluop_i),
		.alusel_i(ex_alusel_i),
		.reg1_i(ex_reg1_i),
		.reg2_i(ex_reg2_i),
		.wd_i(ex_wd_i),
		.wreg_i(ex_wreg_i),
	  
	  //EX模块的输出到EX/MEM模块信息
		.wd_o(ex_wd_o),
		.wreg_o(ex_wreg_o),
		.wdata_o(ex_wdata_o)
		
	);

  //EX/MEM模块
  ex_mem ex_mem0(
		.clk(clk),
		.rst(rst),
	  
		//来自执行阶段EX模块的信息	
		.ex_wd(ex_wd_o),
		.ex_wreg(ex_wreg_o),
		.ex_wdata(ex_wdata_o),
	

		//送到访存阶段MEM模块的信息
		.mem_wd(mem_wd_i),
		.mem_wreg(mem_wreg_i),
		.mem_wdata(mem_wdata_i)

						       	
	);
	
  //MEM模块例化
	mem mem0(
		.rst(rst),
	
		//来自EX/MEM模块的信息	
		.wd_i(mem_wd_i),
		.wreg_i(mem_wreg_i),
		.wdata_i(mem_wdata_i),
	  
		//送到MEM/WB模块的信息
		.wd_o(mem_wd_o),
		.wreg_o(mem_wreg_o),
		.wdata_o(mem_wdata_o)
	);

  //MEM/WB模块
	mem_wb mem_wb0(
		.clk(clk),
		.rst(rst),

		//来自访存阶段MEM模块的信息	
		.mem_wd(mem_wd_o),
		.mem_wreg(mem_wreg_o),
		.mem_wdata(mem_wdata_o),
	
		//送到回写阶段的信息
		.wb_wd(wb_wd_i),
		.wb_wreg(wb_wreg_i),
		.wb_wdata(wb_wdata_i)
									       	
	);

endmodule

在这里插入图片描述

`include "defines.v"

module inst_rom(

	input wire                    ce,
	input wire[`InstAddrBus]	  addr,
	output reg[`InstBus]		  inst
	
);
	//InstMemNum=131071 ROM实际大小为128KB,这儿扩充了4倍
	//因为OpenMIPS按字节寻址,实际使用时需要/4,131071 是按8bit字个数看的
	reg[`InstBus]  inst_mem[0:`InstMemNum-1];	

	initial $readmemh ( "inst_rom.data", inst_mem );

	always @ (*) begin
		if (ce == `ChipDisable) begin
			inst <= `ZeroWord;
	  end 
	  else begin
			//131071即是17bit,/4再右移2位,才是实际读的
		    inst <= inst_mem[ addr[`InstMemNumLog2+1:2] ];	
		end
	end

endmodule

在这里插入图片描述
在这里插入图片描述

`include "defines.v"

module openmips_min_sopc(

	input wire					clk,
	input wire					rst
	
);

  //连接指令存储器
  wire[`InstAddrBus] inst_addr;
  wire[`InstBus] 	 inst;
  wire 				 rom_ce;
 

 openmips openmips0(
		.clk(clk),
		.rst(rst),
	
		.rom_addr_o(inst_addr),
		.rom_data_i(inst),
		.rom_ce_o(rom_ce)
	
	);
	
	inst_rom inst_rom0(
		.addr(inst_addr),
		.inst(inst),
		.ce(rom_ce)	
	);


endmodule

测试过程见书。至此完成了第一条指令与基础五级流水的搭建

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值