Exemplo n.º 1
0
BOOL WriteToAccum (int Location, int PC) {
	DWORD value = WriteToAccum2(Location, PC, FALSE);

	if (value == HIT_BRANCH) {
		return TRUE; /* ??? */
	} else
		return value;
}
int32_t WriteToAccum(int32_t Location, int32_t PC)
{
    uint32_t value = WriteToAccum2(Location, PC, 0);

    if (value == HIT_BRANCH) {
	return 1;		/* ??? */
    } else
	return value;
}
Exemplo n.º 3
0
DWORD WriteToAccum2 (int Location, int PC, BOOL RecursiveCall) {
	OPCODE RspOp;
	DWORD BranchTarget = 0;
	signed int BranchImmed = 0;
	int Instruction_State = NextInstruction;

	if (Compiler.bAccum == FALSE) return TRUE;

	if (Instruction_State == DELAY_SLOT) { 
		return TRUE;
	}

	do {
		PC += 4;
		if (PC >= 0x1000) { return TRUE; }
		RSP_LW_IMEM(PC, &RspOp.Hex);

		switch (RspOp.op) {
 		case RSP_REGIMM:
			switch (RspOp.rt) {
			case RSP_REGIMM_BLTZ:
			case RSP_REGIMM_BGEZ:
			case RSP_REGIMM_BLTZAL:
			case RSP_REGIMM_BGEZAL:
				Instruction_State = DO_DELAY_SLOT;
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_SPECIAL:
			switch (RspOp.funct) {
			case RSP_SPECIAL_SLL:
			case RSP_SPECIAL_SRL:
			case RSP_SPECIAL_SRA:
			case RSP_SPECIAL_SLLV:
			case RSP_SPECIAL_SRLV:
			case RSP_SPECIAL_SRAV:
			case RSP_SPECIAL_ADD:
			case RSP_SPECIAL_ADDU:
			case RSP_SPECIAL_SUB:
			case RSP_SPECIAL_SUBU:
			case RSP_SPECIAL_AND:
			case RSP_SPECIAL_OR:
			case RSP_SPECIAL_XOR:
			case RSP_SPECIAL_NOR:
			case RSP_SPECIAL_SLT:
			case RSP_SPECIAL_SLTU:
			case RSP_SPECIAL_BREAK:
				break;
				
			case RSP_SPECIAL_JALR:
				return TRUE;

			case RSP_SPECIAL_JR:
				Instruction_State = DO_DELAY_SLOT;
				break;

			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_J:
			/* there is no way a loopback is going to use accumulator */
			if (Compiler.bAudioUcode && (((int)(RspOp.target << 2) & 0xFFC) < PC)) {
				return FALSE;
			}
			/* rarely occurs let them have their way */
			else {
				Instruction_State = DO_DELAY_SLOT;
				break;
			}

		case RSP_JAL:
			/* there is no way calling a subroutine is going to use accum */
			/* or come back and continue an existing calculation */
			if(Compiler.bAudioUcode) {
				break;
			} else {
				Instruction_State = DO_DELAY_SLOT;
				break;
			}

		case RSP_BEQ:
		case RSP_BNE:
		case RSP_BLEZ:
		case RSP_BGTZ:			
			BranchImmed = (short)RspOp.offset;
			if (Compiler.bAudioUcode) {
				OPCODE NextOp;

				/* ignore backward branches and pretend its a nop */
				if (BranchImmed <= 0) {
					break;
				}
				/* if the opcode 8 bytes before the dest is a J backward than ignore this */
				BranchImmed = (PC + ((short)RspOp.offset << 2) + 4) & 0xFFC;
				RSP_LW_IMEM(BranchImmed - 8, &NextOp.Hex);
				if (RspOp.op == RSP_J && (int)(RspOp.target << 2) < PC) {
					break;
				}
			}
			BranchTarget = (PC + ((short)RspOp.offset << 2) + 4) & 0xFFC;
			Instruction_State = DO_DELAY_SLOT;
			break;
		case RSP_ADDI:
		case RSP_ADDIU:
		case RSP_SLTI:
		case RSP_SLTIU:
		case RSP_ANDI:
		case RSP_ORI:
		case RSP_XORI:
		case RSP_LUI:
		case RSP_CP0:
			break;

		case RSP_CP2:
			if ((RspOp.rs & 0x10) != 0) {
				switch (RspOp.funct) {
				case RSP_VECTOR_VMULF:
				case RSP_VECTOR_VMULU:
				case RSP_VECTOR_VMUDL:
				case RSP_VECTOR_VMUDM:
				case RSP_VECTOR_VMUDN:
				case RSP_VECTOR_VMUDH:
					return FALSE;
				case RSP_VECTOR_VMACF:
				case RSP_VECTOR_VMACU:
				case RSP_VECTOR_VMADL:
				case RSP_VECTOR_VMADM:
				case RSP_VECTOR_VMADN:
					return TRUE;
				case RSP_VECTOR_VMADH:
					if (Location == Low16BitAccum) { break; }
					return TRUE;

				case RSP_VECTOR_VABS:
				case RSP_VECTOR_VADD:
				case RSP_VECTOR_VADDC:
				case RSP_VECTOR_VSUB:
				case RSP_VECTOR_VSUBC:
				case RSP_VECTOR_VAND:
				case RSP_VECTOR_VNAND:
				case RSP_VECTOR_VOR:
				case RSP_VECTOR_VNOR:
				case RSP_VECTOR_VXOR:
				case RSP_VECTOR_VNXOR:
					/* since these modify the accumulator lower-16 bits we can */
					/* safely assume these 'reset' the accumulator no matter what */
					//			return FALSE;
				case RSP_VECTOR_VCR:
				case RSP_VECTOR_VCH:
				case RSP_VECTOR_VCL:
				case RSP_VECTOR_VRCP:
				case RSP_VECTOR_VRCPL:
				case RSP_VECTOR_VRCPH:
				case RSP_VECTOR_VRSQL:
				case RSP_VECTOR_VRSQH:
				case RSP_VECTOR_VLT:
				case RSP_VECTOR_VEQ:
				case RSP_VECTOR_VGE:
				case RSP_VECTOR_VNE:
				case RSP_VECTOR_VMRG:
				case RSP_VECTOR_VMOV:
					if (Location == Low16BitAccum) { return FALSE; }
					break;

				case RSP_VECTOR_VSAW:
					return TRUE;
				default:
					CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
					return TRUE;
				}
			} else {
				switch (RspOp.rs) {				
				case RSP_COP2_CF:
				case RSP_COP2_CT:
				case RSP_COP2_MT:
				case RSP_COP2_MF:
					break;
				default:
					CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
					return TRUE;
				}
			}
			break;
		case RSP_LB:
		case RSP_LH:
		case RSP_LW:
		case RSP_LBU:
		case RSP_LHU:
		case RSP_SB:
		case RSP_SH:
		case RSP_SW:
			break;
		case RSP_LC2:
			switch (RspOp.rd) {
			case RSP_LSC2_BV:
			case RSP_LSC2_SV:
			case RSP_LSC2_DV:
			case RSP_LSC2_RV:
			case RSP_LSC2_QV:
			case RSP_LSC2_LV:
			case RSP_LSC2_UV:
			case RSP_LSC2_PV:
			case RSP_LSC2_TV:
			case RSP_LSC2_HV:
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_SC2:
			switch (RspOp.rd) {
			case RSP_LSC2_BV:
			case RSP_LSC2_SV:
			case RSP_LSC2_LV:
			case RSP_LSC2_DV:
			case RSP_LSC2_QV:
			case RSP_LSC2_RV:
			case RSP_LSC2_PV:
			case RSP_LSC2_UV:
			case RSP_LSC2_HV:
			case RSP_LSC2_FV:
			case RSP_LSC2_WV:
			case RSP_LSC2_TV:
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		default:
			CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
			return TRUE;
		}
		switch (Instruction_State) {
		case NORMAL: break;
		case DO_DELAY_SLOT: 
			Instruction_State = DELAY_SLOT;
			break;
		case DELAY_SLOT: 
			Instruction_State = FINISH_BLOCK;
			break;
		}
	} while (Instruction_State != FINISH_BLOCK);

	/*
	 * This is a tricky situation because most of the 
	 * microcode does loops, so looping back and checking
	 * can prove effective, but it's still a branch..
	 */

	if (BranchTarget != 0 && RecursiveCall == FALSE) {
		DWORD BranchTaken, BranchFall;

		/* analysis of branch taken */
		BranchTaken = WriteToAccum2(Location, BranchTarget - 4, TRUE);
		/* analysis of branch as nop */
		BranchFall = WriteToAccum2(Location, PC, TRUE);

		if (BranchImmed < 0) {
			if (BranchTaken != FALSE) {
				/*
				 * took this back branch and found a place
				 * that needs this vector as a source
				 */
				return TRUE;
			} else if (BranchFall == HIT_BRANCH) {
				return TRUE;
			}
			/* otherwise this is completely valid */
			return BranchFall;
		} else {	
			if (BranchFall != FALSE) {
				/*
				 * took this forward branch and found a place
				 * that needs this vector as a source
				 */
				return TRUE;
			} else if (BranchTaken == HIT_BRANCH) {
				return TRUE;
			}
			/* otherwise this is completely valid */
			return BranchTaken;
		} 
	}
	return TRUE;
}
DWORD WriteToAccum2 (int Location, int PC, BOOL RecursiveCall) {
	OPCODE RspOp;
	DWORD BranchTarget = 0;
	signed int BranchImmed = 0;
	DWORD JumpTarget = 0;
	BOOL JumpUncond = FALSE;

	int Instruction_State = NextInstruction;

	if (Compiler.bAccum == FALSE) return TRUE;

	if (Instruction_State == DELAY_SLOT) { 
		return TRUE; 
	}

	do {
		PC += 4;
		if (PC >= 0x1000) { return TRUE; }
		RSP_LW_IMEM(PC, &RspOp.Hex);

		switch (RspOp.op) {
 		case RSP_REGIMM:
			switch (RspOp.rt) {
			case RSP_REGIMM_BLTZ:
			case RSP_REGIMM_BGEZ:
			case RSP_REGIMM_BLTZAL:
			case RSP_REGIMM_BGEZAL:
				Instruction_State = DO_DELAY_SLOT;
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_SPECIAL:
			switch (RspOp.funct) {
			case RSP_SPECIAL_SLL:
			case RSP_SPECIAL_SRL:
			case RSP_SPECIAL_SRA:
			case RSP_SPECIAL_SLLV:
			case RSP_SPECIAL_SRLV:
			case RSP_SPECIAL_SRAV:
			case RSP_SPECIAL_ADD:
			case RSP_SPECIAL_ADDU:
			case RSP_SPECIAL_SUB:
			case RSP_SPECIAL_SUBU:
			case RSP_SPECIAL_AND:
			case RSP_SPECIAL_OR:
			case RSP_SPECIAL_XOR:
			case RSP_SPECIAL_NOR:
			case RSP_SPECIAL_SLT:
			case RSP_SPECIAL_SLTU:
			case RSP_SPECIAL_BREAK:
				break;

			case RSP_SPECIAL_JR:
				Instruction_State = DO_DELAY_SLOT;
				break;

			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_J:
		case RSP_JAL:
			if (!JumpTarget) {
				JumpUncond = TRUE;
				JumpTarget = (RspOp.target << 2) & 0xFFC;
			}
			Instruction_State = DO_DELAY_SLOT;
			break;

		case RSP_BEQ:
		case RSP_BNE:
		case RSP_BLEZ:
		case RSP_BGTZ:
			Instruction_State = DO_DELAY_SLOT;
			BranchTarget = (PC + ((short)RspOp.offset << 2) + 4) & 0xFFC;
			BranchImmed = (short)RspOp.offset;
			break;
		case RSP_ADDI:
		case RSP_ADDIU:
		case RSP_SLTI:
		case RSP_SLTIU:
		case RSP_ANDI:
		case RSP_ORI:
		case RSP_XORI:
		case RSP_LUI:
		case RSP_CP0:			
			break;

		case RSP_CP2:
			if ((RspOp.rs & 0x10) != 0) {
				switch (RspOp.funct) {
				case RSP_VECTOR_VMULF:
				case RSP_VECTOR_VMUDL:
				case RSP_VECTOR_VMUDM:
				case RSP_VECTOR_VMUDN:
				case RSP_VECTOR_VMUDH:
					return FALSE;
				case RSP_VECTOR_VMACF:
				case RSP_VECTOR_VMADL:
				case RSP_VECTOR_VMADM:
				case RSP_VECTOR_VMADN:
				case RSP_VECTOR_VMADH:
					return TRUE;
				case RSP_VECTOR_VABS: // hope this is ok
				case RSP_VECTOR_VADD:
				case RSP_VECTOR_VADDC:
				case RSP_VECTOR_VSUB:
				case RSP_VECTOR_VSUBC:
				case RSP_VECTOR_VAND:
				case RSP_VECTOR_VOR:
				case RSP_VECTOR_VXOR:
				case RSP_VECTOR_VNXOR:
				case RSP_VECTOR_VCR:
				case RSP_VECTOR_VCH:
				case RSP_VECTOR_VCL:
				case RSP_VECTOR_VRCP:
				case RSP_VECTOR_VRCPL: // hope this is ok
				case RSP_VECTOR_VRCPH:
				case RSP_VECTOR_VRSQL:
				case RSP_VECTOR_VRSQH: // hope this is ok
				case RSP_VECTOR_VLT:
				case RSP_VECTOR_VEQ:
				case RSP_VECTOR_VGE:
					if (Location == Low16BitAccum) { return FALSE; }
					break;

				case RSP_VECTOR_VMOV:
				case RSP_VECTOR_VMRG:
					break;
				case RSP_VECTOR_VSAW:
					return TRUE;
				default:
					CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC));
					return TRUE;
				}
			} else {
				switch (RspOp.rs) {				
				case RSP_COP2_CF:
				case RSP_COP2_CT:
				case RSP_COP2_MT:
				case RSP_COP2_MF:
					break;
				default:
					CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC));
					return TRUE;
				}
			}
			break;
		case RSP_LB:
		case RSP_LH:
		case RSP_LW:
		case RSP_LBU:
		case RSP_LHU:
		case RSP_SB:
		case RSP_SH:
		case RSP_SW:
			break;
		case RSP_LC2:
			switch (RspOp.rd) {
			case RSP_LSC2_SV:
			case RSP_LSC2_DV:
			case RSP_LSC2_RV:
			case RSP_LSC2_QV:
			case RSP_LSC2_LV:
			case RSP_LSC2_UV:
			case RSP_LSC2_PV:
			case RSP_LSC2_TV:
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_SC2:
			switch (RspOp.rd) {
			case RSP_LSC2_BV:
			case RSP_LSC2_SV:
			case RSP_LSC2_LV:
			case RSP_LSC2_DV:
			case RSP_LSC2_QV:
			case RSP_LSC2_RV:
			case RSP_LSC2_PV:
			case RSP_LSC2_UV:
			case RSP_LSC2_HV:
			case RSP_LSC2_FV:
			case RSP_LSC2_WV:
			case RSP_LSC2_TV:
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		default:
			CompilerWarning("Unkown opcode in WriteToAccum\n%s",RSPOpcodeName(RspOp.Hex,PC));
			return TRUE;
		}
		switch (Instruction_State) {
		case NORMAL: break;
		case DO_DELAY_SLOT: 
			Instruction_State = DELAY_SLOT;
			break;
		case DELAY_SLOT: 
			if (JumpUncond) {
				PC = JumpTarget - 0x04;
				Instruction_State = NORMAL;
			} else {
				Instruction_State = FINISH_BLOCK; 
			}
			JumpUncond = FALSE;
			break;
		}
	} while (Instruction_State != FINISH_BLOCK);

	/***
	** This is a tricky situation because most of the 
	** microcode does loops, so looping back and checking
	** can prove effective, but it's still a branch..
	***/

	if (BranchTarget != 0 && RecursiveCall == FALSE) {
		DWORD BranchTaken, BranchFall;

		/* analysis of branch taken */
		BranchTaken = WriteToAccum2(Location, BranchTarget - 4, TRUE);
		/* analysis of branch as nop */
		BranchFall = WriteToAccum2(Location, PC, TRUE);

		if (BranchImmed < 0) {
			if (BranchTaken != FALSE) {
				/*
				** took this back branch and couldnt find a place 
				** that resets the accum or hit a branch etc 
				**/
				return TRUE;
			} else if (BranchFall == HIT_BRANCH) {
				/* risky? the loop ended, hit another branch after loop-back */
			
#if !defined(RSP_SAFE_ANALYSIS)
				CPU_Message("WriteToDest: Backward branch hit, BranchFall = Hit branch (returning FALSE)");
				return FALSE;
#endif
				return TRUE;
			} else {
				/* otherwise this is completely valid */
				return BranchFall;
			}
		} else {	
			if (BranchFall != FALSE) {
				/*
				** took this forward branch and couldnt find a place 
				** that resets the accum or hit a branch etc 
				**/
				return TRUE;
			} else if (BranchTaken == HIT_BRANCH) {
				/* risky? jumped forward, hit another branch */
				
#if !defined(RSP_SAFE_ANALYSIS)
				CPU_Message("WriteToDest: Forward branch hit, BranchTaken = Hit branch (returning FALSE)");
				return FALSE;
#endif

				return TRUE;
			} else {
				/* otherwise this is completely valid */
				return BranchTaken;
			}
		}
	} else {
		return HIT_BRANCH;
	}
}