CPU之路——逻辑、移位、空指令

译码模块
/***************************************译码模块**********************************************************/
`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];	//指令操作码
	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_SPECIAL_INST:	SPECIAL指令码
				begin
					case(op2)
						5'b00000:
						begin
							case(op3)	//功能码
								`EXE_AND:	//AND指令码
								begin
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									aluop_o		<= `EXE_AND_OP;		//逻辑运算中的“与”运算	
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//and读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//and读第二个寄存器的值
								end
								`EXE_OR:	//OR指令码
								begin
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									aluop_o		<= `EXE_OR_OP;		//逻辑运算中的“或”运算	
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		
									reg2_read_o	<= `ReadEnable;		
								end
								`EXE_XOR:	//XOR指令码
								begin
									aluop_o		<= `EXE_XOR_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//第二个寄存器的值
								end
								`EXE_NOR:	//NOR指令码
								begin
									aluop_o		<= `EXE_NOR_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//读第二个寄存器的值
								end
								`EXE_SLLV:	//SLLV指令码
								begin
									aluop_o		<= `EXE_SLLV_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//读第二个寄存器的值
								end
								`EXE_SRLV:	//SRLV指令码
								begin
									aluop_o		<= `EXE_SRLV_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//读第二个寄存器的值
								end
								`EXE_SRAV:	//SRAV指令码
								begin
									aluop_o		<= `EXE_SRAV_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadEnable;		//OR读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//OR读第二个寄存器的值
								end
								`EXE_SYNC:	//SYNC指令码
								begin
									aluop_o		<= `EXE_SYNC_OP;		//逻辑运算中的“或”运算	
									alusel_o	<= `EXE_RES_LOGIC;	//逻辑运算
									wreg_o		<= `WriteEnable;	//写寄存器使能有效
									instvalid	<= `InstValid;		//有效指令
									reg1_read_o	<= `ReadDisable;	//OR读第一个寄存器的值
									reg2_read_o	<= `ReadEnable;		//OR读第二个寄存器的值
								end
								default:
								begin
								end
						end
						default:
						begin
						end
				end
				
				`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
				`EXE_ANDI:	//andi指令
				begin
					aluop_o		<= `EXE_AND_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
				`EXE_XORI:	//xori指令
				begin
					aluop_o		<= `EXE_XOR_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
				`EXE_LUI:	//lui指令
				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
				`EXE_PREF:	//pref指令
				begin
					aluop_o		<= `EXE_NOP_OP;		//逻辑运算中的“或”运算	
					alusel_o	<= `EXE_RES_NOP;	//逻辑运算
					wreg_o		<= `WriteDisable;	//ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
					instvalid	<= `InstValid;		//有效指令
					reg1_read_o	<= `ReadDisable;		//ORI指令需要读第一个寄存器的值
					reg2_read_o	<= `ReadDisable;	//ORI指令无需读第二个寄存器的值
					imm			<= {16'h0,inst_i[15:0]};	//立即数扩展为32bit
				end
				default:
				begin	
				end
			endcase
			if(op3 == `EXE_SLL)
			begin
				aluop_o		<= `EXE_SLL_OP;		//逻辑运算中的“或”运算	
				alusel_o	<= `EXE_RES_SHIFT;	//逻辑运算
				wreg_o		<= `WriteEnable;	//ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
				instvalid	<= `InstValid;		//有效指令
				reg1_read_o	<= `ReadDisable;	//ORI指令需要读第一个寄存器的值
				reg2_read_o	<= `ReadEnable;		//ORI指令无需读第二个寄存器的值
				imm[4:0]	<= inst_i[10:6];	//立即数扩展为32bit
			end
			else if(op3 == `EXE_SRL)
			begin
				aluop_o		<= `EXE_SRL_OP;		//逻辑运算中的“或”运算	
				alusel_o	<= `EXE_RES_SHIFT;	//逻辑运算
				wreg_o		<= `WriteEnable;	//ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
				instvalid	<= `InstValid;		//有效指令
				reg1_read_o	<= `ReadDisable;	//ORI指令需要读第一个寄存器的值
				reg2_read_o	<= `ReadEnable;		//ORI指令无需读第二个寄存器的值
				imm[4:0]	<= inst_i[10:6];	//立即数扩展为32bit
			end
			else if(op3 == `EXE_SRA)
			begin
				aluop_o		<= `EXE_SRA_OP;		//逻辑运算中的“或”运算	
				alusel_o	<= `EXE_RES_SHIFT;	//逻辑运算
				wreg_o		<= `WriteEnable;	//ORI指令要将运算结果写入目的寄存器,故写寄存器使能有效
				instvalid	<= `InstValid;		//有效指令
				reg1_read_o	<= `ReadDisable;	//ORI指令需要读第一个寄存器的值
				reg2_read_o	<= `ReadEnable;		//ORI指令无需读第二个寄存器的值
				imm[4:0]	<= inst_i[10:6];	//立即数扩展为32bit
			end
		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 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;	//保存逻辑运算的结果
	reg[`RegBus] shiftout;	//保存移位运算的结果
	/******************根据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
				`EXE_AND_OP: 	//逻辑与运算
				begin
					logicout <= reg1_i & reg2_i;
				end
				`EXE_NOR_OP: 	//逻辑或非运算
				begin
					logicout <= ~(reg1_i | reg2_i);
				end
				`EXE_XOR_OP: 	//逻辑异或运算
				begin
					logicout <= reg1_i ^ reg2_i;
				end
				default:
				begin
					logicout <= `ZeroWord;
				end	
			endcase
		end
	end
	//移位运算
	always @(*)
	begin
		if(rst == `RstEnable)
		begin
			shiftout <= `ZeroWord;
		end
		else
		begin
			case(aluop_i)
				`EXE_SLL_OP: 	//逻辑/算数左移
				begin
					shiftout <= reg2_i << reg1_i[4:0];
				end
				`EXE_SRL_OP: 	//逻辑右移
				begin
					shiftout <= reg2_i >> reg1_i[4:0];
				end
				`EXE_SRA_OP: 	//算数右移
				begin
					shiftout <= ($signed (reg2_i) )>>> reg1_i[4:0];
					//shiftout <= ({32{reg2_i[31]}}<<(6'd32-{1'b0,reg1_i[4:0]})) | reg2_i >> reg1_i[4:0];
				end
				default:
				begin
					shiftout <= `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
			`EXE_RES_SHIFT:
			begin
				wdata_o <= shiftout;
			end
			default:
			begin
				wdata_o <= `ZeroWord;
			end	
		endcase
	end
endmodule
宏定义
//AluOp
`define EXE_OR_OP		8'b00100101		//OR指令
`define EXE_NOP_OP		8'b00000000		//空指令
`define EXE_NOP_OP		6'b000000		//空指令指令码
`define EXE_AND_OP		6'b100100		//AND的指令码
`define EXE_OR_OP		6'b100101		//OR指令码
`define EXE_XOR_OP		6'b100110		//XOR指令码
`define EXE_NOR_OP		6'b100111		//NOR指令码
`define EXE_ANDI_OP		6'b001100		//ANDI指令码
`define EXE_ORI_OP		6'b001101		//ORI指令码
`define EXE_XORI_OP		6'b001110		//XORI指令码
`define EXE_LUI_OP		6'b001111		//LUI指令码
`define EXE_SLL_OP		6'b000000		//SLL指令码
`define EXE_SLLV_OP		6'b000100		//SLLV指令码
`define EXE_SRL_OP		6'b000010		//SRL指令码
`define EXE_SRLV_OP		6'b000110		//SRLV指令码
`define EXE_SRA_OP		6'b000011		//SRA指令码
`define EXE_SRAV_OP		6'b000111		//SRAV指令码
`define EXE_SYNC_OP		6'b001111		//SYNC指令码
`define EXE_PREF_OP		6'b110011		//PREF指令码
`define EXE_SPECIAL_INST_OP		6'b000000			//SPECIAL指令码



//AluSe
`define EXE_RES_LOGIC	3'b001			//逻辑运算类型
`define EXE_RES_NOP		3'b000			//
`define EXE_RES_SHIFT	3'b010
测试指令
指令字		汇编指令			    解释说明								执行后的结果(寄存器值)
34011100	ori $1,$0,0x1100	$0 or imm -> $1							$1 = 0x00001100
34210020	ori $1,$1,0x0020											$1 = 0x00001120
34214400	ori $1,$1,0x4400											$1 = 0x00005520
34210044	ori $1,$1,0x0044											$1 = 0x00005564
3c010101	lui $1,0x0101		imm -> $1 (high 16bit) low 16bit == 0  	$1 = 0x01010000
34221010	ori $2,$1,0x1010											$2 = 0x01011010
00221825	or $3,$1,$2			$1 or $2 -> $3							$3 = 0x01011010
00431824	and $3,$3,$2		$2 and $3 -> $3							$3 = 0x01011010
3041ffff	andi $1,$2,ffff												$1 = 0x00001010
00231026	xor $2,$1,$3												$2 = 0x01010000
3843ff00	xori $3,$2,ff00												$3 = 0x0101ff00
000218c0	sll $3,$2,3													$3 = 0x08080000
00020882	srl $1,$2,2													$1 = 0x00404000
00611027	nor $2,$3,$1												$2 = 0xf7d7dfff
执行效果

仿真波形
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值