MIPS: Emulate the new MIPS R6 B{L,G}Ε{Z,}{AL,}C instructions
MIPS R6 added the following four instructions which share the BLEZ and BLEZL opcodes: BLEZALC: Compact branch-and-link if GPR rt is <= to zero BGEZALC: Compact branch-and-link if GPR rt is >= to zero BLEZC : Compact branch if GPR rt is <= to zero BGEZC : Compact branch if GPR rt is >= to zero BGEC : Compact branch if GPR rs is less than or equal to GPR rt BGEUC : Similar to BGEC but unsigned. Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
This commit is contained in:
		
					parent
					
						
							
								c8a34581ec
							
						
					
				
			
			
				commit
				
					
						a8ff66f52d
					
				
			
		
					 2 changed files with 55 additions and 0 deletions
				
			
		|  | @ -399,6 +399,16 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs) | ||||||
|  * @returns:	-EFAULT on error and forces SIGBUS, and on success |  * @returns:	-EFAULT on error and forces SIGBUS, and on success | ||||||
|  *		returns 0 or BRANCH_LIKELY_TAKEN as appropriate after |  *		returns 0 or BRANCH_LIKELY_TAKEN as appropriate after | ||||||
|  *		evaluating the branch. |  *		evaluating the branch. | ||||||
|  |  * | ||||||
|  |  * MIPS R6 Compact branches and forbidden slots: | ||||||
|  |  *	Compact branches do not throw exceptions because they do | ||||||
|  |  *	not have delay slots. The forbidden slot instruction ($PC+4) | ||||||
|  |  *	is only executed if the branch was not taken. Otherwise the | ||||||
|  |  *	forbidden slot is skipped entirely. This means that the | ||||||
|  |  *	only possible reason to be here because of a MIPS R6 compact | ||||||
|  |  *	branch instruction is that the forbidden slot has thrown one. | ||||||
|  |  *	In that case the branch was not taken, so the EPC can be safely | ||||||
|  |  *	set to EPC + 8. | ||||||
|  */ |  */ | ||||||
| int __compute_return_epc_for_insn(struct pt_regs *regs, | int __compute_return_epc_for_insn(struct pt_regs *regs, | ||||||
| 				   union mips_instruction insn) | 				   union mips_instruction insn) | ||||||
|  | @ -590,6 +600,27 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, | ||||||
| 		if (NO_R6EMU) | 		if (NO_R6EMU) | ||||||
| 			goto sigill_r6; | 			goto sigill_r6; | ||||||
| 	case blez_op: | 	case blez_op: | ||||||
|  | 		/*
 | ||||||
|  | 		 * Compact branches for R6 for the | ||||||
|  | 		 * blez and blezl opcodes. | ||||||
|  | 		 * BLEZ  | rs = 0 | rt != 0  == BLEZALC | ||||||
|  | 		 * BLEZ  | rs = rt != 0      == BGEZALC | ||||||
|  | 		 * BLEZ  | rs != 0 | rt != 0 == BGEUC | ||||||
|  | 		 * BLEZL | rs = 0 | rt != 0  == BLEZC | ||||||
|  | 		 * BLEZL | rs = rt != 0      == BGEZC | ||||||
|  | 		 * BLEZL | rs != 0 | rt != 0 == BGEC | ||||||
|  | 		 * | ||||||
|  | 		 * For real BLEZ{,L}, rt is always 0. | ||||||
|  | 		 */ | ||||||
|  | 
 | ||||||
|  | 		if (cpu_has_mips_r6 && insn.i_format.rt) { | ||||||
|  | 			if ((insn.i_format.opcode == blez_op) && | ||||||
|  | 			    ((!insn.i_format.rs && insn.i_format.rt) || | ||||||
|  | 			     (insn.i_format.rs == insn.i_format.rt))) | ||||||
|  | 				regs->regs[31] = epc + 4; | ||||||
|  | 			regs->cp0_epc += 8; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
| 		/* rt field assumed to be zero */ | 		/* rt field assumed to be zero */ | ||||||
| 		if ((long)regs->regs[insn.i_format.rs] <= 0) { | 		if ((long)regs->regs[insn.i_format.rs] <= 0) { | ||||||
| 			epc = epc + 4 + (insn.i_format.simmediate << 2); | 			epc = epc + 4 + (insn.i_format.simmediate << 2); | ||||||
|  |  | ||||||
|  | @ -552,6 +552,30 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||||||
| 		if (NO_R6EMU) | 		if (NO_R6EMU) | ||||||
| 			break; | 			break; | ||||||
| 	case blez_op: | 	case blez_op: | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Compact branches for R6 for the | ||||||
|  | 		 * blez and blezl opcodes. | ||||||
|  | 		 * BLEZ  | rs = 0 | rt != 0  == BLEZALC | ||||||
|  | 		 * BLEZ  | rs = rt != 0      == BGEZALC | ||||||
|  | 		 * BLEZ  | rs != 0 | rt != 0 == BGEUC | ||||||
|  | 		 * BLEZL | rs = 0 | rt != 0  == BLEZC | ||||||
|  | 		 * BLEZL | rs = rt != 0      == BGEZC | ||||||
|  | 		 * BLEZL | rs != 0 | rt != 0 == BGEC | ||||||
|  | 		 * | ||||||
|  | 		 * For real BLEZ{,L}, rt is always 0. | ||||||
|  | 		 */ | ||||||
|  | 		if (cpu_has_mips_r6 && insn.i_format.rt) { | ||||||
|  | 			if ((insn.i_format.opcode == blez_op) && | ||||||
|  | 			    ((!insn.i_format.rs && insn.i_format.rt) || | ||||||
|  | 			     (insn.i_format.rs == insn.i_format.rt))) | ||||||
|  | 				regs->regs[31] = regs->cp0_epc + | ||||||
|  | 					dec_insn.pc_inc; | ||||||
|  | 			*contpc = regs->cp0_epc + dec_insn.pc_inc + | ||||||
|  | 				dec_insn.next_pc_inc; | ||||||
|  | 
 | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
| 		if ((long)regs->regs[insn.i_format.rs] <= 0) | 		if ((long)regs->regs[insn.i_format.rs] <= 0) | ||||||
| 			*contpc = regs->cp0_epc + | 			*contpc = regs->cp0_epc + | ||||||
| 				dec_insn.pc_inc + | 				dec_insn.pc_inc + | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Markos Chandras
				Markos Chandras