Risc-v架构简易CPU实现(不包括ROM,RAM)

之前看到很多人都用mips架构写了cpu(挺常见的计组大作业),所以我跟着学完以后照猫画虎写了riscv的。屑作,不足请斧正。

module pc_reg(
	input wire 		 clk,
	input wire 		 rst,
	input wire[31:0] jump_addr_i,//跳转到哪个指令(地址)
	input wire 		 jump_en,//决定是否跳转
	output reg[31:0] pc_o
);

	always @(posedge clk) begin
		if(rst == 1'b0)
			pc_o <= 32'b0;
		else if(jump_en)
			pc_o <= jump_addr_i;
		else
			pc_o <= pc_o + 3'd4;
	end

endmodule
module ifetch(
	//从pc来的地址
	input  wire[31:0] pc_addr_i,
	//指令,从rom
	input  wire[31:0] rom_inst_i,
	//to rom
	output wire[31:0] to_rom_addr_o, 
	//查找完,该译码了
	output wire[31:0] inst_addr_o, 
	output wire[31:0] inst_o
	);


	assign to_rom_addr_o = pc_addr_i;
	
	assign inst_addr_o  = pc_addr_i;
	
	assign inst_o = rom_inst_i;



endmodule

`include "defines.v"

module if_id(
	input wire clk,
	input wire rst,
	input wire hold_flag_i,
	input wire [31:0]  inst_i, 
	input wire [31:0]  inst_addr_i,
	output wire[31:0]  inst_addr_o, 
	output wire[31:0]  inst_o
);
//复位
	dff_set #(32) dff1(clk,rst,hold_flag_i,`INST_NOP,inst_i,inst_o);
	
	dff_set #(32) dff2(clk,rst,hold_flag_i,32'b0,inst_addr_i,inst_addr_o);



endmodule


`include "defines.v"

module id(
	//from if_id
	input wire[31:0] inst_i			,
	input wire[31:0] inst_addr_i	,
		
	// to regs 
	output reg[4:0] rs1_addr_o		,
	output reg[4:0] rs2_addr_o		,
	// from regs
	input wire[31:0] rs1_data_i		,
	input wire[31:0] rs2_data_i		,
	
	//to id_ex
	output reg[31:0] inst_o			,
	output reg[31:0] inst_addr_o	,
	output reg[31:0] op1_o			,	
	output reg[31:0] op2_o			,
	output reg[4:0]  rd_addr_o		,	
	output reg 		 reg_wen		,
	output reg[31:0] base_addr_o	,
	output reg[31:0] addr_offset_o		
);

	wire[6:0] opcode; 
	wire[4:0] rd; 
	wire[2:0] func3; 
	wire[4:0] rs1;
	wire[4:0] rs2;
	wire[6:0] func7;
	wire[11:0]imm;
	wire[4:0] shamt;
	
	assign opcode = inst_i[6:0];
	assign rd 	  = inst_i[11:7];
	assign func3  = inst_i[14:12];
	assign rs1 	  = inst_i[19:15];
	assign rs2 	  = inst_i[24:20];
	assign func7  = inst_i[31:25];
	assign imm    = inst_i[31:20];
	assign shamt  = inst_i[24:20];
	

	
	
	
	always @(*)begin
		inst_o  	= inst_i;
		inst_addr_o = inst_addr_i;  
		
		case(opcode)
			`INST_TYPE_I:begin
				base_addr_o		= 32'b0;
				addr_offset_o	= 32'b0;		
				case(func3)
					`INST_ADDI,`INST_SLTI,`INST_SLTIU,`INST_XORI,`INST_ORI,`INST_ANDI:begin
						rs1_addr_o = rs1;
						rs2_addr_o = 5'b0;
						op1_o 	   = rs1_data_i;
						op2_o      = {{20{imm[11]}},imm};
						rd_addr_o  = rd;
						reg_wen    = 1'b1;
					end
					`INST_SLLI,`INST_SRI:begin
						rs1_addr_o = rs1;
						rs2_addr_o = 5'b0;
						op1_o 	   = rs1_data_i;
						op2_o      = {27'b0,shamt};
						rd_addr_o  = rd;
						reg_wen    = 1'b1;					
					end
					default:begin
						rs1_addr_o = 5'b0;
						rs2_addr_o = 5'b0;
						op1_o 	   = 32'b0;
						op2_o      = 32'b0;
						rd_addr_o  = 5'b0;
						reg_wen    = 1'b0;						
					end
				endcase	
			end
			`INST_TYPE_R_M:begin
				base_addr_o		= 32'b0;
				addr_offset_o	= 32'b0;			
				case(func3)
					`INST_ADD_SUB,`INST_SLT,`INST_SLTU,`INST_XOR,`INST_OR,`INST_AND:begin
						rs1_addr_o = rs1;
						rs2_addr_o = rs2;
						op1_o 	   = rs1_data_i;
						op2_o      = rs2_data_i;
						rd_addr_o  = rd;
						reg_wen    = 1'b1;
					end
					`INST_SLL,`INST_SR:begin
						rs1_addr_o = rs1;
						rs2_addr_o = rs2;
						op1_o 	   = rs1_data_i;
						op2_o      = {27'b0,rs2_data_i[4:0]};
						rd_addr_o  = rd;
						reg_wen    = 1'b1;					
					end
					default:begin
						rs1_addr_o = 5'b0;
						rs2_addr_o = 5'b0;
						op1_o 	   = 32'b0;
						op2_o      = 32'b0;
						rd_addr_o  = 5'b0;
						reg_wen    = 1'b0;						
					end
				endcase				
			end
			`INST_TYPE_B:begin
				case(func3)
					`INST_BNE,`INST_BEQ,`INST_BLT,`INST_BGE,`INST_BLTU,`INST_BGEU:begin
						rs1_addr_o = rs1;
						rs2_addr_o = rs2;
						op1_o 	   = rs1_data_i;
						op2_o      = rs2_data_i;
						rd_addr_o  = 5'b0;
						reg_wen    = 1'b0;
						base_addr_o		= inst_addr_i;
						addr_offset_o	= {{19{inst_i[31]}},inst_i[31],inst_i[7],inst_i[30:25],inst_i[11:8],1'b0};						
					end	
					default:begin
						rs1_addr_o = 5'b0;
						rs2_addr_o = 5'b0;
						op1_o 	   = 32'b0;
						op2_o      = 32'b0;
						rd_addr_o  = 5'b0;
						reg_wen    = 1'b0;
						base_addr_o		= 32'b0;
						addr_offset_o	= 32'b0;						
					end
				endcase
			end
			`INST_JAL:begin
				rs1_addr_o = 5'b0;
				rs2_addr_o = 5'b0;
				op1_o 	   = inst_addr_i;
				op2_o      = 32'h4;
				rd_addr_o  = rd;
				reg_wen    = 1'b1;
				base_addr_o		= inst_addr_i;
				addr_offset_o	= {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};				
			end
			`INST_LUI:begin
				rs1_addr_o = 5'b0;
				rs2_addr_o = 5'b0;
				op1_o 	   = {inst_i[31:12],12'b0};
				op2_o      = 32'b0;
				rd_addr_o  = rd;
				reg_wen    = 1'b1;
				base_addr_o		= 32'b0;
				addr_offset_o	= 32'b0;				
			end	
			`INST_JALR:begin
				rs1_addr_o = rs1;
				rs2_addr_o = 5'b0;
				op1_o 	   = inst_addr_i;
				op2_o      = 32'h4;
				rd_addr_o  = rd;
				reg_wen    = 1'b1;	
				base_addr_o		= rs1_data_i;
				addr_offset_o	= {{20{imm[11]}},imm};				
			end
			`INST_AUIPC:begin
				rs1_addr_o = 5'b0;
				rs2_addr_o = 5'b0;
				op1_o 	   = {inst_i[31:12],12'b0};
				op2_o      = inst_addr_i;
				rd_addr_o  = rd;
				reg_wen    = 1'b1;	
				base_addr_o		= 32'b0;
				addr_offset_o	= 32'b0;				
			end
			default:begin
				rs1_addr_o = 5'b0;
				rs2_addr_o = 5'b0;
				op1_o 	   = 32'b0;
				op2_o      = 32'b0;
				rd_addr_o  = 5'b0;
				reg_wen    = 1'b0;	
				base_addr_o		= 32'b0;
				addr_offset_o	= 32'b0;				
			end
		endcase
	end

	


endmodule
`include "defines.v"

module id_ex(
	input wire clk					,
	input wire rst					,
	//from ctrl
	input wire hold_flag_i			,
	//from id
	input wire[31:0] inst_i			,
	input wire[31:0] inst_addr_i	,
	input wire[31:0] op1_i			,	
	input wire[31:0] op2_i			,
	input wire[4:0]  rd_addr_i		,	
	input wire 		 reg_wen_i		,
	input wire[31:0] base_addr_i	,
	input wire[31:0] addr_offset_i	,	
	//to ex
	output wire[31:0] inst_o		,
	output wire[31:0] inst_addr_o	,
	output wire[31:0] op1_o			,	
	output wire[31:0] op2_o			,
	output wire[4:0]  rd_addr_o		,	
	output wire 	  reg_wen_o		,	
	output wire[31:0] base_addr_o	,
	output wire[31:0] addr_offset_o		
);

	dff_set #(32) dff1(clk,rst,hold_flag_i,`INST_NOP,inst_i,inst_o);
	
	dff_set #(32) dff2(clk,rst,hold_flag_i,32'b0,inst_addr_i,inst_addr_o);
	
	dff_set #(32) dff3(clk,rst,hold_flag_i,32'b0,op1_i,op1_o);
	
	dff_set #(32) dff4(clk,rst,hold_flag_i,32'b0,op2_i,op2_o);
	
	dff_set #(5) dff5(clk,rst,hold_flag_i,5'b0,rd_addr_i,rd_addr_o);
	
	dff_set #(1) dff6(clk,rst,hold_flag_i,1'b0,reg_wen_i,reg_wen_o);
	
	dff_set #(32) dff7(clk,rst,hold_flag_i,32'b0,base_addr_i,base_addr_o);
	
	dff_set #(32) dff8(clk,rst,hold_flag_i,32'b0,addr_offset_i,addr_offset_o);





endmodule
`include "defines.v"

module ex(
	//from id_ex
	input wire[31:0] inst_i			,	
	input wire[31:0] inst_addr_i	,
	input wire[31:0] op1_i			,
	input wire[31:0] op2_i			,
	input wire[4:0]  rd_addr_i		,
	input wire 		 rd_wen_i		,
	input wire[31:0] base_addr_i	,
	input wire[31:0] addr_offset_i	,
	//to regs
	output reg[4:0] rd_addr_o		,
	output reg[31:0]rd_data_o		,
	output reg 	    rd_wen_o		,
	
	//to ctrl
	output reg[31:0]jump_addr_o		,
	output reg   	jump_en_o		,
	output reg  	hold_flag_o		,

);

	wire[6:0] opcode; 
	wire[4:0] rd; 
	wire[2:0] func3; 
	wire[4:0] rs1;
	wire[4:0] rs2;
	wire[6:0] func7;
	wire[11:0]imm;
	wire[4:0] shamt;
	
	assign opcode = inst_i[6:0];
	assign rd 	  = inst_i[11:7];
	assign func3  = inst_i[14:12];
	assign rs1 	  = inst_i[19:15];
	assign rs2 	  = inst_i[24:20];
	assign func7  = inst_i[31:25];
	assign imm    = inst_i[31:20];
	assign shamt  = inst_i[24:20];
	
	
	// tpye branch
	//wire[31:0] jump_imm = {{19{inst_i[31]}},inst_i[31],inst_i[7],inst_i[30:25],inst_i[11:8],1'b0}; //改 21+6+4+1
	wire  	   op1_i_equal_op2_i;
	wire       op1_i_less_op2_i_signed;
	wire       op1_i_less_op2_i_unsigned;
	
	assign	   op1_i_less_op2_i_signed 	 = ($signed(op1_i) < $signed(op2_i))?1'b1:1'b0;
	assign	   op1_i_less_op2_i_unsigned = (op1_i < op2_i)  ? 1'b1:1'b0;
	assign	   op1_i_equal_op2_i 		 = (op1_i == op2_i) ? 1'b1:1'b0;
	


	//ALU 
	wire[31:0] op1_i_add_op2_i			;//加法器
	wire[31:0] op1_i_and_op2_i			;//与
	wire[31:0] op1_i_xor_op2_i			;//异或
	wire[31:0] op1_i_or_op2_i			;//或
	wire[31:0] op1_i_shift_left_op2_i	;//左移
	wire[31:0] op1_i_shift_right_op2_i	;//右移
	wire[31:0] base_addr_add_addr_offset;//计算地址单元
	
	assign op1_i_add_op2_i = op1_i + op2_i;
	assign op1_i_and_op2_i = op1_i & op2_i;
	assign op1_i_xor_op2_i = op1_i ^ op2_i;
	assign op1_i_or_op2_i  = op1_i | op2_i;
	assign op1_i_shift_left_op2_i 		= op1_i << op2_i;
	assign op1_i_shift_right_op2_i 		= op1_i >> op2_i;
	assign base_addr_add_addr_offset 	= base_addr_i + addr_offset_i;
	
	// tpye I
	wire[31:0] SRA_mask;
	assign 	   SRA_mask = (32'hffff_ffff) >> op2_i[4:0];
	
	
	//wire[31:0] store_offset_addr = {{20{inst_i[31]}},inst_i[31:25],inst_i[11:7]};
	// tpye store && load index
	wire[1:0]  store_index 	= base_addr_add_addr_offset[1:0];
	wire[1:0]  load_index 	= base_addr_add_addr_offset[1:0];
	
	
	always @(*)begin
		
		case(opcode)		
			`INST_TYPE_I:begin
				jump_addr_o   = 32'b0;
				jump_en_o	  = 1'b0;
				hold_flag_o   = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
				case(func3)				
					`INST_ADDI:begin
						rd_data_o = op1_i_add_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end
					`INST_SLTI:begin
						rd_data_o = {30'b0,op1_i_less_op2_i_signed};
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end					
					`INST_SLTIU:begin
						rd_data_o = {30'b0,op1_i_less_op2_i_unsigned};
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end					
					`INST_XORI:begin
						rd_data_o = op1_i_xor_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end					
					`INST_ORI:begin
						rd_data_o = op1_i_or_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end					
					`INST_ANDI:begin
						rd_data_o = op1_i_and_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
					end	
					`INST_SLLI:begin
						rd_data_o = op1_i_shift_left_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;					
					end
					`INST_SRI:begin
						if(func7[5] == 1'b1) begin //SRAI
							rd_data_o = ((op1_i_shift_right_op2_i) & SRA_mask) | ({32{op1_i[31]}} & (~SRA_mask));
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;							
						end
						else begin //SRLI
							rd_data_o = op1_i_shift_right_op2_i;
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;							
						end
					end					
					default:begin
						rd_data_o = 32'b0;
						rd_addr_o = 5'b0;
						rd_wen_o  = 1'b0;
					end						
				endcase
			end				
			`INST_TYPE_R_M:begin			
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;	
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
				case(func3)				
					`INST_ADD_SUB:begin
						if(func7[5] == 1'b0)begin//add
							rd_data_o = op1_i_add_op2_i;
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;
						end
						else begin
							rd_data_o = op1_i - op2_i;
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1; 								
						end
					end
					`INST_SLL:begin
						rd_data_o = op1_i_shift_left_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end
					`INST_SLT:begin
						rd_data_o = {30'b0,op1_i_less_op2_i_signed};
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end
					`INST_SLTU:begin
						rd_data_o = {30'b0,op1_i_less_op2_i_unsigned};
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end
					`INST_XOR:begin
						rd_data_o = op1_i_xor_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end	
					`INST_OR:begin
						rd_data_o = op1_i_or_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end
					`INST_AND:begin
						rd_data_o = op1_i_and_op2_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;	
					end	
					`INST_SR:begin
						if(func7[5] == 1'b1) begin //SRA
							rd_data_o = ((op1_i_shift_right_op2_i) & SRA_mask) | ({32{op1_i[31]}} & (~SRA_mask));
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;							
						end
						else begin //SRL
							rd_data_o = op1_i_shift_right_op2_i;
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;							
						end	
					end						
					default:begin
						rd_data_o = 32'b0;
						rd_addr_o = 5'b0;
						rd_wen_o  = 1'b0;					
					end
				endcase
			end			
			`INST_TYPE_B:begin
				rd_data_o = 32'b0; 
				rd_addr_o = 5'b0;
				rd_wen_o  = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
				case(func3)
					`INST_BEQ:begin
						jump_addr_o = base_addr_add_addr_offset; 
						jump_en_o	= op1_i_equal_op2_i;
						hold_flag_o = 1'b0;					
					end					
					`INST_BNE:begin
						jump_addr_o = base_addr_add_addr_offset;
						jump_en_o	= ~op1_i_equal_op2_i;
						hold_flag_o = 1'b0;					
					end	
					`INST_BLT:begin
						jump_addr_o = base_addr_add_addr_offset;
						jump_en_o	= op1_i_less_op2_i_signed;
						hold_flag_o = 1'b0;					
					end	
					`INST_BGE:begin
						jump_addr_o = base_addr_add_addr_offset;
						jump_en_o	= ~op1_i_less_op2_i_signed;
						hold_flag_o = 1'b0;					
					end
					`INST_BLTU:begin
						jump_addr_o = base_addr_add_addr_offset;
						jump_en_o	= op1_i_less_op2_i_unsigned;
						hold_flag_o = 1'b0;					
					end
					`INST_BGEU:begin
						jump_addr_o = base_addr_add_addr_offset;
						jump_en_o	= ~op1_i_less_op2_i_unsigned;
						hold_flag_o = 1'b0;					
					end					
					default:begin
						jump_addr_o = 32'b0;
						jump_en_o	= 1'b0;
						hold_flag_o = 1'b0;					
					end
				endcase
			end
			`INST_TYPE_L:begin
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
				case(func3)
					`INST_LW:begin
						rd_data_o = mem_rd_data_i;
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;						
					end
					`INST_LH:begin			
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
						case(load_index[1])
							1'b0:begin
								rd_data_o = {{16{mem_rd_data_i[15]}},mem_rd_data_i[15:0]};	
							end
							1'b1:begin
								rd_data_o = {{16{mem_rd_data_i[31]}},mem_rd_data_i[31:16]};
							end
							default:begin
								rd_data_o = 32'b0;
							end
						endcase
					end						
					`INST_LB:begin			
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
						case(load_index)
							2'b00:begin
								rd_data_o = {{24{mem_rd_data_i[7]}},mem_rd_data_i[7:0]};	
							end
							2'b01:begin
								rd_data_o = {{24{mem_rd_data_i[15]}},mem_rd_data_i[15:8]};
							end
							2'b10:begin
								rd_data_o = {{24{mem_rd_data_i[23]}},mem_rd_data_i[23:16]};
							end
							2'b11:begin
								rd_data_o = {{24{mem_rd_data_i[31]}},mem_rd_data_i[31:24]};
							end
							default:begin
								rd_data_o = 32'b0;
							end
						endcase
					end
					`INST_LHU:begin			
						rd_addr_o = rd_addr_i;
						rd_wen_o  = 1'b1;
						case(load_index[1]) //二字节对齐 所以是第 1 位,第零位默认为0的,其实这里要做处理,
							1'b0:begin		//如果发现最低为不为零要进行硬件报异常(说明你程序员的代码没有二字节对齐,16位对齐)
								rd_data_o = {16'b0,mem_rd_data_i[15:0]};	
							end
							1'b1:begin
								rd_data_o = {16'b0,mem_rd_data_i[31:16]};
							end
							default:begin
								rd_data_o = 32'b0;
							end
						endcase
					end	
					`INST_LBU:begin			
							rd_addr_o = rd_addr_i;
							rd_wen_o  = 1'b1;
							case(load_index)
								2'b00:begin
									rd_data_o = {24'b0,mem_rd_data_i[7:0]};	
								end
								2'b01:begin
									rd_data_o = {24'b0,mem_rd_data_i[15:8]};
								end
								2'b10:begin
									rd_data_o = {24'b0,mem_rd_data_i[23:16]};
								end
								2'b11:begin
									rd_data_o = {24'b0,mem_rd_data_i[31:24]};
								end
								default:begin
									rd_data_o = 32'b0;
								end
							endcase
					end				
					default:begin
						rd_data_o = 32'b0;
						rd_addr_o = 5'b0;
						rd_wen_o  = 1'b0;						
					end
				endcase
			end
			`INST_TYPE_S:begin
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;
				rd_data_o   = 32'b0;
				rd_addr_o   = 5'b0;
				rd_wen_o    = 1'b0;				
				case(func3)
					`INST_SW:begin
						mem_wr_req_o  = 1'b1;
						mem_wr_sel_o  = 4'b1111;
						mem_wr_addr_o = base_addr_add_addr_offset;
						mem_wr_data_o = op2_i;						
					end
					`INST_SH:begin			
						mem_wr_req_o  = 1'b1;
						mem_wr_addr_o = base_addr_add_addr_offset;
						case(store_index)
							1'b0:begin
								mem_wr_data_o = {16'b0,op2_i[15:0]};
								mem_wr_sel_o  = 4'b0011;	
							end
							1'b1:begin
								mem_wr_data_o = {op2_i[15:0],16'b0};
								mem_wr_sel_o  = 4'b1100;	
							end
							default:begin
								mem_wr_data_o = 32'b0;
								mem_wr_sel_o  = 4'b0000;	
							end
						endcase
					end					
					`INST_SB:begin			
						mem_wr_req_o  = 1'b1;
						mem_wr_addr_o = base_addr_add_addr_offset;
						case(store_index)
							2'b00:begin
								mem_wr_data_o = {24'b0,op2_i[7:0]};
								mem_wr_sel_o  = 4'b0001;	
							end
							2'b01:begin
								mem_wr_data_o = {16'b0,op2_i[7:0],8'b0};
								mem_wr_sel_o  = 4'b0010;	
							end
							2'b10:begin
								mem_wr_data_o = {8'b0,op2_i[7:0],16'b0};
								mem_wr_sel_o  = 4'b0100;	
							end
							2'b11:begin
								mem_wr_data_o = {op2_i[7:0],24'b0};
								mem_wr_sel_o  = 4'b1000;	
							end
							default:begin
								mem_wr_data_o = 32'b0;
								mem_wr_sel_o  = 4'b0000;	
							end
						endcase
					end						
					default:begin
						mem_wr_req_o  = 1'b0;
						mem_wr_sel_o  = 4'b0;
						mem_wr_addr_o = 32'b0;
						mem_wr_data_o = 32'b0;						
					end
				endcase
			end			
			`INST_JAL:begin
				rd_data_o = op1_i_add_op2_i;
				rd_addr_o = rd_addr_i;
				rd_wen_o  = 1'b1;
				jump_addr_o = base_addr_add_addr_offset;
				jump_en_o	= 1'b1;
				hold_flag_o = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
			end
			`INST_JALR:begin
				rd_data_o     = op1_i_add_op2_i;
				rd_addr_o     = rd_addr_i;
				rd_wen_o      = 1'b1;
				jump_addr_o   = base_addr_add_addr_offset;
				jump_en_o	  = 1'b1;
				hold_flag_o   = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
			end				
			`INST_LUI:begin
				rd_data_o = op1_i;
				rd_addr_o = rd_addr_i;
				rd_wen_o  = 1'b1;
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;	
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
			end	
			`INST_AUIPC:begin
				rd_data_o = op1_i_add_op2_i;
				rd_addr_o = rd_addr_i;
				rd_wen_o  = 1'b1;
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
			end
			default:begin
				rd_data_o = 32'b0;
				rd_addr_o = 5'b0;
				rd_wen_o  = 1'b0;
				jump_addr_o = 32'b0;
				jump_en_o	= 1'b0;
				hold_flag_o = 1'b0;
				mem_wr_req_o  = 1'b0;
				mem_wr_sel_o  = 4'b0;
				mem_wr_addr_o = 32'b0;
				mem_wr_data_o = 32'b0;				
			end
		endcase
	end

	
	
	
endmodule
module open_cpu(
	input  wire 		  clk   		,
	input  wire 		  rst		    , 
	input  wire [31:0]    inst_i		,
	output wire [31:0]    inst_addr_o
);
	//pc to if
	wire[31:0] pc_reg_pc_o;
	
	//if to if_id
	wire[31:0] if_inst_addr_o;
	wire[31:0] if_inst_o;	
	
	// if_id to id
	wire[31:0] if_id_inst_addr_o;
	wire[31:0] if_id_inst_o;	
	
	//ex to regs
	wire[4:0]  ex_rd_addr_o;
	wire[31:0] ex_rd_data_o;
	wire       ex_reg_wen_o;

	//id to regs
	wire[4:0] id_rs1_addr_o;
	wire[4:0] id_rs2_addr_o;
	
	//id to id_ex
	wire[31:0] id_inst_o;
	wire[31:0] id_inst_addr_o;
	wire[31:0] id_op1_o;
	wire[31:0] id_op2_o;
	wire[4:0]  id_rd_addr_o;
	wire       id_reg_wen;
	wire[31:0] id_base_addr_o;	
	wire[31:0] id_addr_offset_o;	

	//regs to id
	wire[31:0] regs_reg1_rdata_o;
	wire[31:0] regs_reg2_rdata_o;
	
	
	//id_ex to ex
	wire[31:0] id_ex_inst_o;
	wire[31:0] id_ex_inst_addr_o;
	wire[31:0] id_ex_op1_o;
	wire[31:0] id_ex_op2_o;
	wire[4:0]  id_ex_rd_addr_o;
	wire       id_ex_reg_wen;
	wire[31:0] id_ex_base_addr_o;	
	wire[31:0] id_ex_addr_offset_o;
	
	//ex  to ctrl
	wire[31:0] ex_jump_addr_o;
	wire  	   ex_jump_en_o;
	wire 	   ex_hold_flag_o;
	//ctrl to pc_reg
	wire[31:0] ctrl_jump_addr_o;
	wire  	   ctrl_jump_en_o;
	//ctrl to if_id id_ex
	wire 	   ctrl_hold_flag_o;		
	
	
	pc_reg pc_reg_inst(
		.clk			(clk),
		.rst			(rst),
		.jump_addr_i	(ctrl_jump_addr_o), //&
		.jump_en		(ctrl_jump_en_o),		
		.pc_o   		(pc_reg_pc_o)
	);
	
	
	ifetch ifetch_inst(
		.pc_addr_i		(pc_reg_pc_o),
		.rom_inst_i		(inst_i),
		.if2rom_addr_o	(inst_addr_o), 
		.inst_addr_o	(if_inst_addr_o), 
		.inst_o         (if_inst_o)
	);


	if_id if_id_inst(
		.clk			(clk		      ),
		.rst			(rst		      ),
		.hold_flag_i	(ctrl_hold_flag_o ),
		.inst_i			(if_inst_o        ),  
		.inst_addr_i	(if_inst_addr_o   ),  
		.inst_addr_o	(if_id_inst_addr_o), 
		.inst_o         (if_id_inst_o	  )
	);
	

	
	id id_inst(
		.inst_i			(if_id_inst_o		),
		.inst_addr_i	(if_id_inst_addr_o	),
		.rs1_addr_o		(id_rs1_addr_o		),
		.rs2_addr_o		(id_rs2_addr_o		),
		.rs1_data_i		(regs_reg1_rdata_o	),
		.rs2_data_i		(regs_reg2_rdata_o	),
		.inst_o			(id_inst_o			),
		.inst_addr_o	(id_inst_addr_o		),	
		.op1_o			(id_op1_o			),	
		.op2_o			(id_op2_o			),
		.rd_addr_o		(id_rd_addr_o		),	
		.reg_wen        (id_reg_wen			),
		.base_addr_o	(id_base_addr_o		),
		.addr_offset_o	(id_addr_offset_o	)	
		);


	
	regs regs_inst(
		.clk			(clk					),
		.rst			(rst					),
		.reg1_raddr_i	(id_rs1_addr_o			),
		.reg2_raddr_i	(id_rs2_addr_o			), 
		.reg1_rdata_o	(regs_reg1_rdata_o		),
		.reg2_rdata_o	(regs_reg2_rdata_o		),
		.reg_waddr_i	(ex_rd_addr_o			),
		.reg_wdata_i	(ex_rd_data_o			),
		.reg_wen        (ex_reg_wen_o			)
	);
	

	id_ex id_ex_inst(
		.clk			(clk					),
		.rst			(rst					),
		.hold_flag_i	(ctrl_hold_flag_o 		),
		.inst_i			(id_inst_o				),
		.inst_addr_i	(id_inst_addr_o			),
		.op1_i			(id_op1_o				),
		.op2_i			(id_op2_o				),
		.rd_addr_i		(id_rd_addr_o			),
		.reg_wen_i		(id_reg_wen				),
		.base_addr_i	(id_base_addr_o			),
		.addr_offset_i	(id_addr_offset_o		),		
		.inst_o			(id_ex_inst_o			),
		.inst_addr_o    (id_ex_inst_addr_o		),
		.op1_o			(id_ex_op1_o			),
		.op2_o			(id_ex_op2_o			),
		.rd_addr_o		(id_ex_rd_addr_o		),
		.reg_wen_o		(id_ex_reg_wen			),
		.base_addr_o	(id_ex_base_addr_o		),
		.addr_offset_o	(id_ex_addr_offset_o	)		
		);
	


	ex ex_inst(
		.inst_i			(id_ex_inst_o			),	
		.inst_addr_i	(id_ex_inst_addr_o		),
		.op1_i			(id_ex_op1_o			),
		.op2_i			(id_ex_op2_o			),
		.rd_addr_i		(id_ex_rd_addr_o		),
		.rd_wen_i		(id_ex_reg_wen			),
		.base_addr_i	(id_ex_base_addr_o		),
		.addr_offset_i	(id_ex_addr_offset_o	),		
		.rd_addr_o		(ex_rd_addr_o			),
		.rd_data_o		(ex_rd_data_o			),	
		.rd_wen_o       (ex_reg_wen_o			),
		.jump_addr_o	(ex_jump_addr_o			),		
		.jump_en_o		(ex_jump_en_o			),		
		.hold_flag_o	(ex_hold_flag_o			)		
		
	);
	
	
	
	
	ctrl ctrl_inst(
		.jump_addr_i	(ex_jump_addr_o),
		.jump_en_i		(ex_jump_en_o),
		.hold_flag_ex_i	(ex_hold_flag_o),
		.jump_addr_o	(ctrl_jump_addr_o),
		.jump_en_o		(ctrl_jump_en_o),
		.hold_flag_o	(ctrl_hold_flag_o)	
	);

endmodule
module dff_set #(
	parameter DW  = 32
)
(
	input wire clk,
	input wire rst,
	input wire hold_flag_i,
	input wire [DW-1:0]  set_data, 
	input wire [DW-1:0]  data_i, 
	output reg [DW-1:0]  data_o	
);
	always @(posedge clk)begin
		if(rst == 1'b0 || hold_flag_i == 1'b1)
			data_o <= set_data;
		else
			data_o <= data_i;
	end	

endmodule
module ctrl(
	input wire [31:0]jump_addr_i,
	input wire    	 jump_en_i,
	input wire   	 hold_flag_ex_i,
	
	output reg [31:0]jump_addr_o,
	output reg    	 jump_en_o,
	output reg   	 hold_flag_o	
);

	always @(*)begin
		jump_addr_o = jump_addr_i;
		jump_en_o   = jump_en_i; 
		if( jump_en_i || hold_flag_ex_i)begin 
			hold_flag_o = 1'b1;
		end
		else begin
			hold_flag_o = 1'b0;
		end
	end




endmodule

全部评论
这里defines.v是我define了一下常用指令,这样写代码的时候写INST_ADDI什么的,好辨识
点赞 回复 分享
发布于 2022-12-27 23:16 山东
其实十一月就想写了,但当时只是写完了几个模块,依托答辩,不算个cpu
点赞 回复 分享
发布于 2022-12-27 23:12 山东

相关推荐

点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务