自己动手写CPU(8)——简单算术操作指令的实现

1. 代码模块

1.1 宏定义defines

新增关于具体指令的宏定义

  • 需要注意的是EXE_ADD = EXE_CLZ、EXE_ADDU = EXE_CLO,但由于指令码不同,他们在译码阶段是可区分的,但在执行阶段是靠译码阶段给的aluop子类型区分具体操作,所以不能简单把6位的功能码补0扩展到8位
`define	EXE_ADD					6'b100000			
`define	EXE_ADDU				6'b100001	
`define	EXE_CLZ					6'b100000			
`define	EXE_CLO					6'b100001		

`define	EXE_ADD_OP			8'b00100000
`define	EXE_ADDU_OP			8'b00100001
`define	EXE_CLZ_OP			8'b10100000
`define	EXE_CLO_OP			8'b10100001
// 与具体指令有关宏定义
`define	EXE_SLTI				6'b001010			// op_slti		compare_signed
`define	EXE_SLTIU				6'b001011			// op_sltiu		compare_unsigned
`define	EXE_ADDI				6'b001000			// op_addi		add_overflow_check
`define	EXE_ADDIU				6'b001001			// op_addiu		add_no_overflow_check

`define EXE_NOP         6'b000000
`define EXE_SPECIAL_INST 	6'b000000		// instruction code of SPECIAL
`define	EXE_SPECIAL2_INST	6'b011100		// instruction code of SPECIAL2

`define	EXE_SLT					6'b101010			// func_slt		compare_signed
`define	EXE_SLTU				6'b101011			// func_sltu	compare_unsigned
`define	EXE_ADD					6'b100000			// func_add		add_overflow_check
`define	EXE_ADDU				6'b100001			// func_addu	add_no_overflow_check
`define	EXE_SUB					6'b100010			// func_sub		sub_overflow_check
`define	EXE_SUBU				6'b100011			// func_subu	sub__no_overflow_check
`define	EXE_CLZ					6'b100000			// func_clz		count_0
`define	EXE_CLO					6'b100001			// func_clo		count_0
`define	EXE_MULT				6'b011000			// func_mult	mul_signed_result_in_hilo
`define	EXE_MULTU				6'b011001			// func_multu	mul_unsigned_result_in_hilo
`define	EXE_MUL					6'b000010			// func_mul		mul_signed_result_in_rd

// AluOp 子类型
`define	EXE_SLT_OP			8'b00101010
`define	EXE_SLTU_OP			8'b00101011
`define	EXE_ADD_OP			8'b00100000
`define	EXE_ADDU_OP			8'b00100001
`define	EXE_ADDI_OP			8'b00001000
`define	EXE_ADDIU_OP		8'b00001001
`define	EXE_SUB_OP			8'b00100010
`define	EXE_SUBU_OP			8'b00100011
`define	EXE_CLZ_OP			8'b10100000
`define	EXE_CLO_OP			8'b10100001
`define	EXE_MULT_OP			8'b00011000
`define	EXE_MULTU_OP		8'b00011001
`define	EXE_MUL_OP			8'b00000010

// AluSel 类型
`define EXE_RES_NOP     		3'b000
`define EXE_RES_LOGIC   		3'b001      // logic operation
`define EXE_RES_SHIFT   		3'b010      // shift operation
`define EXE_RES_MOVE    		3'b011      // move operation
`define	EXE_RES_ARITHMETIC		3'b100		// arithmetc operation
`define	EXE_RES_MUL				3'b101		// mul_signed_result_in_rd

1.2 译码id

添加新的算术指令add、addu、sub、subu、slt、sltu、addi、addiu、slti、sltiu、clz、clo、mul、mult、multu的case分支

  • slti、sltiu、addi、addiu都是立即数符号扩展
  • mult、multu写入HILO寄存器,所以wreg_o = `WriteDisable
  • mul是需要特殊对待的乘法乘法运算
case (op)
        `EXE_SPECIAL_INST:  begin
          case  (op2)                 // [10:6]sa为0
            5'b00000: begin
              case (op3)              // [5:0]func
 					... ... 
                `EXE_SLT:		begin								// slt	compare_signed
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_SLT_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_SLTU:	begin									// sltu	compare_unsigned
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_SLTU_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_ADD:		begin								// add	add_overflow_check
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_ADD_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_ADDU:	begin									// addu	add_no_overflow_check
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_ADDU_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_SUB:		begin								// sub	sub_overflow_check
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_SUB_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_SUBU:	begin									// subu	sub_no_overflow_check
                	wreg_o			<=	`WriteEnable;
                	aluop_o			<=	`EXE_SUBU_OP;
                	alusel_o		<=	`EXE_RES_ARITHMETIC;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_MULT:	begin									// mult		mul_signed_result_in_hilo
                	wreg_o			<=	`WriteDisable;
                	aluop_o			<=	`EXE_MULT_OP;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end
                `EXE_MULTU:	begin									// multu	mul_unsigned_result_in_hilo
                	wreg_o			<=	`WriteDisable;
                	aluop_o			<=	`EXE_MULTU_OP;
                	reg1_read_o	<=	1'b1;
                	reg2_read_o	<=	1'b1;
                	instvalid		<=	`InstValid;
                end                               
                default:    begin
                end    
              endcase   // case (op3)
            end
            default:  begin
            end
          endcase   // case(op2)
        end  
        	... ... 
        `EXE_SLTI:	begin													// slti		compare_signed
        	wreg_o			<=	`WriteEnable;
        	aluop_o			<=	`EXE_SLT_OP;
        	alusel_o		<=	`EXE_RES_ARITHMETIC;
        	reg1_read_o	<=	1'b1;
        	reg2_read_o	<=	1'b0;
        	imm					<=	{ {16{inst_i[15]}}, inst_i[15:0] };
        	wd_o				<=	inst_i[20:16];
        	instvalid		<=	`InstValid;
        end
        `EXE_SLTIU:	begin													// sltiu	compare_unsigned
        	wreg_o			<=	`WriteEnable;
        	aluop_o			<=	`EXE_SLTU_OP;
        	alusel_o		<=	`EXE_RES_ARITHMETIC;
        	reg1_read_o	<=	1'b1;
        	reg2_read_o	<=	1'b0;
        	imm					<=	{ {16{inst_i[15]}}, inst_i[15:0] };
        	wd_o				<=	inst_i[20:16];
        	instvalid		<=	`InstValid;
        end
        `EXE_ADDI:	begin													// addi		add_singned
        	wreg_o			<=	`WriteEnable;
        	aluop_o			<=	`EXE_ADDI_OP;
        	alusel_o		<=	`EXE_RES_ARITHMETIC;
        	reg1_read_o	<=	1'b1;
        	reg2_read_o	<=	1'b0;
        	imm					<=	{ {16{inst_i[15]}}, inst_i[15:0] };
        	wd_o				<=	inst_i[20:16];
        	instvalid		<=	`InstValid;
        end
        `EXE_ADDIU:	begin													// addiu	add_unsigned
        	wreg_o			<=	`WriteEnable;
        	aluop_o			<=	`EXE_ADDIU_OP;
        	alusel_o		<=	`EXE_RES_ARITHMETIC;
        	reg1_read_o	<=	1'b1;
        	reg2_read_o	<=	1'b0;
        	imm					<=	{ {16{inst_i[15]}}, inst_i[15:0] };
        	wd_o				<=	inst_i[20:16];
        	instvalid		<=	`InstValid;
        end
        `EXE_SPECIAL2_INST:	begin
        	case (op3)
       			`EXE_CLZ:		begin										// clz		count_0
        			wreg_o			<=	`WriteEnable;
        			aluop_o			<=	`EXE_CLZ_OP;
        			alusel_o		<=	`EXE_RES_ARITHMETIC;
        			reg1_read_o	<=	1'b1;
        			reg2_read_o	<=	1'b0;
        			instvalid		<=	`InstValid;
        		end
        		`EXE_CLO:		begin										// clo		count_1
        			wreg_o			<=	`WriteEnable;
        			aluop_o			<=	`EXE_CLO_OP;
        			alusel_o		<=	`EXE_RES_ARITHMETIC;
        			reg1_read_o	<=	1'b1;
        			reg2_read_o	<=	1'b0;
        			instvalid		<=	`InstValid;
        		end
        		`EXE_MUL:		begin										// mul		mul_signed_result_in_rd
        			wreg_o			<=	`WriteEnable;
        			aluop_o			<=	`EXE_MUL_OP;
        			alusel_o		<=	`EXE_RES_MUL;
        			reg1_read_o	<=	1'b1;
        			reg2_read_o	<=	1'b1;
        			instvalid		<=	`InstValid;
        		end
        		default:    begin
        		end
        	endcase		// EXE_SPECIAL2_INST	case
        end
      endcase // case(op)

1.3 执行ex

1.3.1. 添加一些新的变量
  • arithmeticres保存算术运算类型的运算结果
  reg	[`RegBus]		arithmeticres;		//	save the result of arithmetic operation
  
  // new variables for arithmetic
  wire					ov_sum;					// save overflow
  wire					reg1_eq_reg2;			// if operand1 = operand2
  wire					reg1_lt_reg2;			// if operand1 < operand2
  wire	[`RegBus]		reg2_i_mux;				// the complement of reg2_i
  wire	[`RegBus]		reg1_i_not;				// the not of reg1_i
  wire	[`RegBus]		result_sum;				// the result of add operation
  wire	[`RegBus]		opdata1_mult;			// save the multiplier1
  wire	[`RegBus]		opdata2_mult;			// save the multiplier2
  wire	[`DoubleRegBus]			hilo_temp;		// save the result of multiplcation 64bits temporary
  reg	[`DoubleRegBus]			mulres;			// save the result of multiplication
1.3.2. 计算五个变量的值
  • (1) 如果是减法运算或者有符号比较运算,那么reg2_i_mux等于第二个操作数reg2_i的补码,否则等于第二个操作数
  • (2) 分三种情况:
         A. 如果是加法运算,reg2_i_mux就是第二个操作数reg2_i,
             所以result_sum就是加法运算的结果
         B. 如果是减法运算,reg2_i_mux就是第二个操作数reg2_i的补码,
             所以result_sum就是减法运算的结果
         C. 如果是有符号比较运算,reg2_i_mux就是第二个操作数reg2_i的补码,
             所以result_sum也是减法运算的结果,
             可以通过判断减法的结果是否小于0,进而判断第一个操作数reg1_i是否小于第二个操作数reg2_i
  • (3) 计算是否溢出,加法指令(add和addi)、减法指令(sub)执行的时候,需要判断溢出
         满足以下情况之一,有溢出:
         A. reg1_i是正数,reg2_i_mux是正数,两者之和为负数
         B. reg1_i是负数,reg2_i_mux是负数,两者之和为正数
  • (4) 计算操作数1是否小于操作数2,分两种情况:
         A. aluop_i为EXE_SLT_OP表示有符号比较运算,分三种情况:
             A1. reg1_i为负数,reg2_i为正数,显然reg1_i小于reg2_i
             A2. reg1_i为正数,reg2_i为正数,并且reg1_i减去reg2_i小于0
                    即result_sum为负,此时也有reg1_i小于reg2_i
             A3. reg1_i为负数,reg2_i为负数,并且reg1_i减去reg2_i小于0
                    即result_sum为负,此时也有reg1_i小于reg2_i
         B. 无符号数比较的时候,世界使用比较运算符比较reg1_i和reg2_i
  • (5) 对操作数1逐位取反,赋给reg1_i_not
	// (1)	if (sub or comp_signed)		reg2_i_mux = reg2_i's complement
	assign reg2_i_mux = ( (aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) || (aluop_i == `EXE_SLT_OP) ) ? ( ~reg2_i+1 ) : reg2_i;
	
	// (2)	A. if (add)						reg2_i_mux = reg2_i
	//					so result_sum = add's result
	//			B. if (sun)						reg2_i_mux = reg2_i's complement
	//					so result_sum = sub's result
	//			C. if (comp_signed)		reg2_i_mux = reg2_i's complement
	//					so result_sum = sub's result
	//					the result can be utilized for judging the size of values' relationship
	assign  result_sum = reg1_i + reg2_i_mux;
	
	// (3)	if (add or addi or sub)		need to judge overflow
	//			A. reg1_i is positive, reg2_i_mux is positive, the result_sum is negative
	//			B. reg1_i is negative, reg2_i_mux is negative, the result_sum is positive
	assign ov_sum = ( !reg1_i[31] && !reg2_i_mux[31] && result_sum[31] ) || ( reg1_i[31] && reg2_i_mux[31] && !result_sum[31] );
	
	// (4)	judge operand1 < operand2
	//			A. aluop_i == EXE_SLT_OP		(comp_signed)
	//				A1. reg1_i is negative, reg2_i is positive
	//						so reg1_i < reg2_i(negative < positive)
	//				A2. reg1_i is positive, reg2_i is positvie,		reg1_i-reg2_i < 0(result_sum < 0)
	//						so reg1_i < reg2_i(positive < positive)
	//				A3. reg1_i is negative, reg2_i is negative,		reg1_i-reg2_i < 0(result_sum < 0)
	//						so reg1_i < reg2_i(negative < negative)							
	//			B. aluop_i == EXE_SLTU_OP		(comp_unsigned)
	//				use comparison operator
	assign reg1_lt_reg2 = ( (aluop_i == `EXE_SLT_OP) ) ?
												( (reg1_i[31] && !reg2_i[31]) || (!reg1_i[31] && !reg2_i[31] && result_sum) || (reg1_i[31] && reg2_i[31] && result_sum)  ) :
												( reg1_i < reg2_i );
												
	// (5)	reverse the operand1
	assign reg1_i_not = ~reg1_i;
1.3.3. 依据aluop_i,给arithmeticres赋值
  // ********** arithmetic operation **********  
  always @ (*) begin
  	if (rst == `RstEnable) begin
  		arithmeticres		<=	`ZeroWord;
  	end else begin
  		case (aluop_i)
  			`EXE_SLT_OP, `EXE_SLTU:	begin											// compare operation
  				arithmeticres	<=	reg1_lt_reg2;
  			end
  			`EXE_ADD_OP, `EXE_ADDU_OP, `EXE_ADDI_OP, `EXE_ADDIU_OP:	begin			// add operation
  				arithmeticres	<=	result_sum;
  			end
  			`EXE_SUB_OP, `EXE_SUBU_OP:	begin										// sub operation
  				arithmeticres	<=	result_sum;
  			end
  			`EXE_CLZ_OP:	beg														// clz count_0
      		arithmeticres <= reg1_i[31] ? 0 : reg1_i[30] ? 1 :
                          reg1_i[29] ? 2 : reg1_i[28] ? 3 :
                          reg1_i[27] ? 4 : reg1_i[26] ? 5 :
                          reg1_i[25] ? 6 : reg1_i[24] ? 7 :
                          reg1_i[23] ? 8 : reg1_i[22] ? 9 :
                          reg1_i[21] ? 10 : reg1_i[20] ? 11 :
                          reg1_i[19] ? 12 : reg1_i[18] ? 13 :
                          reg1_i[17] ? 14 : reg1_i[16] ? 15 :
                          reg1_i[15] ? 16 : reg1_i[14] ? 17 :
                          reg1_i[13] ? 18 : reg1_i[12] ? 19 :
                          reg1_i[11] ? 20 : reg1_i[10] ? 21 :
                          reg1_i[9]  ? 22 : reg1_i[8]  ? 23 :
                          reg1_i[7]  ? 24 : reg1_i[6]  ? 25 :
                          reg1_i[5]  ? 26 : reg1_i[4]  ? 27 :
                          reg1_i[3]  ? 28 : reg1_i[2]  ? 29 :
                          reg1_i[1]  ? 30 : reg1_i[0]  ? 31 : 32 ;
      	end
     		`EXE_CLO_OP:  begin       												// clo count_1
        arithmeticres <= (reg1_i_not[31] ? 0 : reg1_i_not[30] ? 1 :
                          reg1_i_not[29] ? 2 : reg1_i_not[28] ? 3 : 
                          reg1_i_not[27] ? 4 : reg1_i_not[26] ? 5 :
                          reg1_i_not[25] ? 6 : reg1_i_not[24] ? 7 : 
                          reg1_i_not[23] ? 8 : reg1_i_not[22] ? 9 : 
                          reg1_i_not[21] ? 10 : reg1_i_not[20] ? 11 :
                          reg1_i_not[19] ? 12 : reg1_i_not[18] ? 13 : 
                          reg1_i_not[17] ? 14 : reg1_i_not[16] ? 15 : 
                          reg1_i_not[15] ? 16 : reg1_i_not[14] ? 17 : 
                          reg1_i_not[13] ? 18 : reg1_i_not[12] ? 19 : 
                          reg1_i_not[11] ? 20 :reg1_i_not[10] ? 21 : 
                          reg1_i_not[9] ? 22 : reg1_i_not[8] ? 23 : 
                          reg1_i_not[7] ? 24 : reg1_i_not[6] ? 25 : 
                          reg1_i_not[5] ? 26 : reg1_i_not[4] ? 27 : 
                          reg1_i_not[3] ? 28 : reg1_i_not[2] ? 29 : 
                          reg1_i_not[1] ? 30 : reg1_i_not[0] ? 31 : 32) ;
       	end 
      endcase
    end		// else
  end		// always 
1.3.4. 进行乘法运算
  • (1) 取得乘法运算的被乘数,如果是有符号乘法并且被乘数是负数,那么取补码
  • (2) 取得乘法运算的乘数,如果是有符号乘法并且乘数是负数,那么取补码
  • (3) 得到临时的乘法结果,保存在变量hilo_temp中
  • (4) 对临时乘法结果进行修正,最终的乘法结果保存在变量mulres中
         A. 如果是有符号乘法指令mul、mult,那么需要修正临时乘法结果,如下:
             A1. 如果被乘数和乘数一正一负,
                   需要对临时乘法结果hilo_temp求补码,作为最终的乘法结果,赋给变量mulres
             A2. 如果被乘数和乘数同号,
                   hilo_temp的值就作为最终乘法结果,赋给变量mulres
         B. 如果是无符号乘法指令multu,那么hilo_temp的值就作为最终乘法结果,赋给变量mulres
  	// ********** multiplicative operation **********  
  	// (1)	acquire operand1
  	//			if ( (mul_signed || mult_signed) && reg1_i is negative)		complement reg1_i
  	assign opdata1_mult = ( ( (aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ) && (reg1_i[31] == 1'b1) ) ? ( ~reg1_i + 1 ) : reg1_i;
  
  	// (2)	acquire operand2
  	//			if ( (mul_signed || mult_signed) && reg2_i is negative)		complement reg2_i
  	assign opdata2_mult = ( ( (aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ) && (reg2_i[31] == 1'b1) ) ? ( ~reg2_i + 1 ) : reg2_i;
      
	// (3)	acquire	the result of multiplication temporary
	assign	hilo_temp = opdata1_mult * opdata2_mult;
	
	// (4)	modify the result of multiplication temporary, the final value is stored in mulres
	//			A. if (mul_signed || mult_signed)				need to modify
	//				A1.	if (two operands have different sign)
	//						take the complement of temporary value as the final value
	//				A2.	if (two operands have same sign)	no need to modify
	//						the temporary value is the final value
	//			B. if (multu_unsigned)
	//					the temporary value is the final value
	always @ (*) begin
		if (rst == `RstEnable) begin
			mulres		<=	{`ZeroWord, `ZeroWord};
		end else if ( (aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ) begin
								if ( reg1_i[31] ^ reg2_i[31] == 1'b1 ) begin
									mulres	<=	~hilo_temp + 1;
								end else begin
									mulres	<=	hilo_temp;
								end
		end else begin
			mulres	<=	hilo_temp;
		end
	end
1.3.5. 依据alusel_i确定最终要写入目的寄存器的值
  • 如果是add、addi、sub、subi指令,且发生了溢出,那么设置wreg_o为WriteDisable,表示不写入目的寄存器
  always @ (*) begin
    wd_o    <=  wd_i;     // destination register address
    // if ( (add || addi || sub || subi) && overflow )		WriteDisable
    if ( ( (aluop_i == `EXE_ADD_OP) || (aluop_i == `EXE_ADDI_OP) || (aluop_i == `EXE_SUB_OP) ) && (ov_sum == 1'b1) ) begin
    	wreg_o	<=	`WriteDisable;
    end else begin
    	wreg_o	<=	`WriteEnable;
    end
    case (alusel_i)
      	... ... 
      `EXE_RES_ARITHMETIC:	begin		// simple arithmetic operation but multiplication
      	wdata_o	<=	arithmeticres;
      end
      `EXE_RES_MUL:	begin						// store the result of multiplication
      	wdata_o	<=	mulres;
      end
      default:        begin
        wdata_o <=  `ZeroWord;
      end
    endcase // case
  end // always 
1.3.6. 确定对HILO寄存器的操作信息
  • mult、multu分别是有符号数相乘和无符号数相乘,结果低32bit存在LO寄存器中,高32bit存在HI寄存器中
  always @ (*) begin
    if (rst == `RstEnable) begin
      whilo_o   <=  `WriteEnable;
      hi_o      <=  `ZeroWord;
      lo_o      <=  `ZeroWord;
    end else if ( (aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MULTU_OP) ) begin
    	whilo_o		<=	`WriteEnable;
    	hi_o			<=	mulres[63:32];
    	lo_o			<=	mulres[31:0];
    end else if (aluop_i == `EXE_MTHI_OP) begin       // hi <- rs
      whilo_o   <=  `WriteEnable;
      hi_o      <=  reg1_i;
      lo_o      <=  LO;
    end else if (aluop_i == `EXE_MTLO_OP) begin       // lo <- rs
      whilo_o   <=  `WriteEnable;
      hi_o      <=  HI;
      lo_o      <=  reg1_i;
    end
  end 

结构框图
在这里插入图片描述

2. 测试模块

2.1 第一段 add addi addiu addu sub subu

1
在这里插入图片描述

2.2 第二段 slt sltu slti sltiu

在这里插入图片描述

在这里插入图片描述

2.3 第三段 clo clz

1
在这里插入图片描述

2.4 第四段 mul、mult、multu

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

 
 
 
 
 
 
 
 
 
先照着书上的写了一遍,暂时发布,后面再完善
希望等回头的时候,一切都明白了

从第一条ori指令写到现在的简单算数指令,已经开始看不明白代码了
书上有个别错误已经修改,但是关于简单算术的取补、判断溢出已经迷惑了

关于slti有符号数比较指令
reg1 = 0xffff_0000
reg2 = 0xffff_8000
进行有符号数比较,实际是reg1 > reg2,reg1_lt_reg2 = 0,wdata_o = 0
但是仿真结果是1
根据reg2_i_mux、result_sum、ov_sum,三者判断reg1_lt_reg2的逻辑关系还需要改进一点

在对reg2进行求补运算的时候,应该是reg2_mux = { reg2[31], ~reg2[30:0]+1 }

对reg2求补要分别考虑正数(补码就是源码)和负数(除符号位的其他位按位取反末位加1),确定reg2_i_mux的分支情况需要增加新的分支

自己想推理一下add和addu指令结果的由来,推着推着就不懂了

给寄存器中写入数据的形式应该是源码,否则在进行减法运算的时候就不需要对reg2判断求补
reg1 $1 = 32’h 8000_0001
reg2 $2 = 32’h 8000_0010
ADDU: 无符号加法,不进行溢出检查,直接写入结果
不用对reg2求补,result_sum = reg1+reg2 = 32’h 0000_0011
最高位都是1,相加结果最高位为0,结果有溢出
ADD: 有符号加法,进行溢出检查,结果溢出不写入
不用对reg2求补,负数在寄存器存储时是以补码形式存放的
[reg1]补 = 32’h 8000_0001 reg1 = [[reg1]补]补 = 32’h ffff_ffff
[reg2]补 = 32’h 8000_0010 reg2 = [[reg2]补]补 = 32’h ffff_fff0
result_sum = reg1+reg2 = 32’h 0000_0011
负 + 负 = 正 有溢出,结果不写入(满足ov_sum分支的条件)

数据已经写入寄存器,
进行无符号数操作就直接操作,没有符号位
进行有符号数操作就把它当成有符号数操作,最高位是1就是负数,最高位是0就是正数
但是作者博客下的评论又说“负数在寄存器存储时,以补码形式存放”,“指令中就是补码,不需要自己转”,啥意思啊这是

12.27 好像明白了一点,关于“负数在寄存器存储时,以补码形式存放”

第四段测试:
ori $1, $1, 0xfffb          # $1 = -5
该指令进行完后,$1 = oxffff_fffb     作者提示这是-5
如果最高位是1的话,直接默认这个数是负数,符号为没有表示在这个32位数中,实际是这样的 1_1111_1111_1111_1011
而在regs存储器中直接以补码形式存放,并且默认省略掉符号位“1”,1111_1111_1111_1011
对她求原码,1_0000_0000_0000_0101,刚好就是-5

流水线的乘累加、乘累减可以了

12.29 除法指令好难啊 想给dividend赋值,一直写不进去
12.30 除法指令测试通过了,奈斯,谢谢奥姐给我检查

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值