int32_t DelaySlotAffectBranch(uint32_t PC)
{
    RSPOPCODE Branch, Delay;
    OPCODE_INFO infoBranch, infoDelay;

    if (IsOpcodeNop(PC + 4) == 1) {
	return 0;
    }

    RSP_LW_IMEM(PC, &Branch.Hex);
    RSP_LW_IMEM(PC + 4, &Delay.Hex);

    memset(&infoDelay, 0, sizeof(infoDelay));
    memset(&infoBranch, 0, sizeof(infoBranch));

    GetInstructionInfo(PC, &Branch, &infoBranch);
    GetInstructionInfo(PC + 4, &Delay, &infoDelay);

    if ((infoDelay.flags & Instruction_Mask) == VEC_Instruction) {
	return 0;
    }

    if (infoBranch.SourceReg0 == infoDelay.DestReg) {
	return 1;
    }
    if (infoBranch.SourceReg1 == infoDelay.DestReg) {
	return 1;
    }

    return 0;
}
BOOL DelaySlotAffectBranch(DWORD PC) {
	OPCODE Branch, Delay;
	OPCODE_INFO infoBranch, infoDelay;

	if (IsOpcodeNop(PC + 4) == TRUE) { 
		return FALSE;
	}

	RSP_LW_IMEM(PC, &Branch.Hex);
	RSP_LW_IMEM(PC+4, &Delay.Hex);

	memset(&infoDelay,0,sizeof(infoDelay));
	memset(&infoBranch,0,sizeof(infoBranch));
	
	GetInstructionInfo(PC, &Branch, &infoBranch);
	GetInstructionInfo(PC+4, &Delay, &infoDelay);

	if ((infoDelay.flags & COPO_MF_Instruction) == COPO_MF_Instruction) {
		return TRUE;
	}

	if ((infoDelay.flags & Instruction_Mask) == VEC_Instruction) {
		return FALSE;
	}

	if (infoBranch.SourceReg0 == infoDelay.DestReg) { return TRUE; }
	if (infoBranch.SourceReg1 == infoDelay.DestReg) { return TRUE; }

	return FALSE;
}
Beispiel #3
0
void DumpRSPCode (void) {
	char string[100], LogFileName[255], *p ;
	DWORD location, OpCode, dwWritten;
	HANDLE hLogFile = NULL;

	strcpy(LogFileName,GetCommandLine() + 1);
	
	if (strchr(LogFileName,'\"')) {
		p = strchr(LogFileName,'\"');
		*p = '\0';
	}
	
	if (strchr(LogFileName,'\\')) {
		p = LogFileName;
		while (strchr(p,'\\')) {
			p = strchr(p,'\\');
			p++;
		}
		p -= 1;
		*p = '\0';
	}

	strcat(LogFileName,"\\RSP code.txt");

	hLogFile = CreateFile(LogFileName,GENERIC_WRITE, FILE_SHARE_READ,NULL,CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	SetFilePointer(hLogFile,0,NULL,FILE_BEGIN);

	for (location = 0; location < 0x1000; location += 4) {
		RSP_LW_IMEM(location, &OpCode);
		sprintf(string," 0x%03X\t%s\r\n",location, RSPOpcodeName ( OpCode, location ));
		WriteFile( hLogFile,string,strlen(string),&dwWritten,NULL );
	}
	CloseHandle(hLogFile);
}
Beispiel #4
0
int DisplayRSPCommand (DWORD location, int InsertPos)
{
	uint32_t OpCode;
	DWORD LinesUsed = 1, status;
	BOOL Redraw = FALSE;

	RSP_LW_IMEM(location, &OpCode);

	status = 0;
	if (location == *PrgCount) {status = RSP_Status_PC; }
	if (CheckForRSPBPoint(location)) { status |= RSP_Status_BP; }
	if (RSPCommandLine[InsertPos].opcode != OpCode) { Redraw = TRUE; }
	if (RSPCommandLine[InsertPos].Location != location) { Redraw = TRUE; }
	if (RSPCommandLine[InsertPos].status != status) { Redraw = TRUE; }
	if (Redraw)
	{
		RSPCommandLine[InsertPos].Location = location;
		RSPCommandLine[InsertPos].status = status;
		RSPCommandLine[InsertPos].opcode = OpCode;
		sprintf(RSPCommandLine[InsertPos].String," 0x%03X\t%s",location, 
			RSPOpcodeName ( OpCode, location ));
		if ( SendMessage(hList,LB_GETCOUNT,0,0) <= InsertPos)
		{
			SendMessage(hList,LB_INSERTSTRING,(WPARAM)InsertPos, (LPARAM)location);
		}
		else
		{
			RECT ItemRC;
			SendMessage(hList,LB_GETITEMRECT,(WPARAM)InsertPos, (LPARAM)&ItemRC);
			RedrawWindow(hList,&ItemRC,NULL, RDW_INVALIDATE );
		}
	}
	return LinesUsed;
}
int32_t IsNextInstructionMmx(uint32_t PC)
{
    RSPOPCODE RspOp;

    if (IsMmxEnabled == 0)
	return 0;

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

    if (RspOp.op != RSP_CP2)
	return 0;

    if ((RspOp.rs & 0x10) != 0) {
	switch (RspOp.funct) {
	case RSP_VECTOR_VMULF:
	case RSP_VECTOR_VMUDL:	/* Warning: Not all handled? */
	case RSP_VECTOR_VMUDM:
	case RSP_VECTOR_VMUDN:
	case RSP_VECTOR_VMUDH:
	    if (1 == WriteToAccum(7, PC)) {
		return 0;
	    } else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7
		       && IsMmx2Enabled == 0) {
		return 0;
	    } else
		return 1;

	case RSP_VECTOR_VAND:
	case RSP_VECTOR_VOR:
	case RSP_VECTOR_VXOR:
	    if (1 == WriteToAccum(Low16BitAccum, PC)) {
		return 0;
	    } else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7
		       && IsMmx2Enabled == 0) {
		return 0;
	    } else
		return 1;

	case RSP_VECTOR_VADD:
	    /* Requires no accumulator write! & No flags! */
	    if (WriteToAccum(Low16BitAccum, RSPCompilePC) == 1) {
		return 0;
	    } else if (UseRspFlags(RSPCompilePC) == 1) {
		return 0;
	    } else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7
		       && IsMmx2Enabled == 0) {
		return 0;
	    } else
		return 1;

	default:
	    return 0;
	}
    } else
	return 0;
}
BOOL IsNextInstructionMmx(DWORD PC) {
	OPCODE RspOp;
	
	if (IsMmxEnabled == FALSE)
		return FALSE;

	PC += 4;
	if (PC >= 0x1000) return FALSE;
	RSP_LW_IMEM(PC, &RspOp.Hex);

	if (RspOp.op != RSP_CP2)
		return FALSE;

	if ((RspOp.rs & 0x10) != 0) {
		switch (RspOp.funct) {
		case RSP_VECTOR_VMULF:
		case RSP_VECTOR_VMUDL: /* Warning: Not all handled? */
		case RSP_VECTOR_VMUDM:
		case RSP_VECTOR_VMUDN:
		case RSP_VECTOR_VMUDH:
			if (TRUE == WriteToAccum(7, PC)) {
				return FALSE;
			} else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7 && IsMmx2Enabled == FALSE) {
				return FALSE;
			} else 
				return TRUE;

		case RSP_VECTOR_VABS:
		case RSP_VECTOR_VAND:
		case RSP_VECTOR_VOR:
		case RSP_VECTOR_VXOR:
		case RSP_VECTOR_VNAND:
		case RSP_VECTOR_VNOR:
		case RSP_VECTOR_VNXOR:
			if (TRUE == WriteToAccum(Low16BitAccum, PC)) {
				return FALSE;
			} else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7 && IsMmx2Enabled == FALSE) {
				return FALSE;
			} else
				return TRUE;

		case RSP_VECTOR_VADD:
		case RSP_VECTOR_VSUB:
			/* Requires no accumulator write! & No flags! */
			if (WriteToAccum(Low16BitAccum, PC) == TRUE) {
				return FALSE;
			} else if (UseRspFlags(PC) == TRUE) {
				return FALSE;
			} else if ((RspOp.rs & 0x0f) >= 2 && (RspOp.rs & 0x0f) <= 7 && IsMmx2Enabled == FALSE) {
				return FALSE;
			} else
				return TRUE;

		default:
			return FALSE;
		}
	} else 
		return FALSE;
}
DWORD RunInterpreterCPU(DWORD Cycles) {
	DWORD CycleCount;
	RSP_Running = TRUE;
	Enable_RSP_Commands_Window();
	CycleCount = 0;

	while (RSP_Running) {
		if (NoOfBpoints != 0) {
			if (CheckForRSPBPoint(*PrgCount)) {
				if (InRSPCommandsWindow) {
					Enter_RSP_Commands_Window();
					if (Stepping_Commands) {
						DisplayError ( "Encounted a R4300i Breakpoint" );
					} else {
						DisplayError ( "Encounted a R4300i Breakpoint\n\nNow Stepping" );
						SetRSPCommandViewto( *PrgCount );
						SetRSPCommandToStepping();
					}
				} else {
					DisplayError ( "Encounted a RSP Breakpoint\n\nEntering Command Window" );
					Enter_RSP_Commands_Window();
				}
			}
		}
		
		if (Stepping_Commands) {
			WaitingForStep = TRUE;
			SetRSPCommandViewto( *PrgCount );
			UpdateRSPRegistersScreen();
			while ( WaitingForStep == TRUE ){ 
				Sleep(20);						
				if (!Stepping_Commands) {
					WaitingForStep = FALSE;
				}
			}
		}

		RSP_LW_IMEM(*PrgCount, &RSPOpC.Hex);
		((void (*)()) RSP_Opcode[ RSPOpC.op ])();

		switch (RSP_NextInstruction) {
		case NORMAL: 
			*PrgCount = (*PrgCount + 4) & 0xFFC; 
			break;
		case DELAY_SLOT:
			RSP_NextInstruction = JUMP;
			*PrgCount = (*PrgCount + 4) & 0xFFC; 
			break;
		case JUMP:
			RSP_NextInstruction = NORMAL;
			*PrgCount  = RSP_JumpTo;
			break;
		}
	}
	*PrgCount -= 4;

	return Cycles;
}
BOOL IsOpcodeNop(DWORD PC) {
	OPCODE RspOp;
	RSP_LW_IMEM(PC, &RspOp.Hex);

	if (RspOp.op == RSP_SPECIAL && RspOp.funct == RSP_SPECIAL_SLL) {
		return (RspOp.rd == 0) ? TRUE : FALSE;
	}

	return FALSE;
}
Beispiel #9
0
void DumpRSPCode (void)
{
	char string[100], LogFileName[255], *p ;
	uint32_t OpCode;
	DWORD location, dwWritten;
	HANDLE hLogFile = NULL;

	strcpy(LogFileName,GetCommandLine() + 1);
	
	if (strchr(LogFileName,'\"'))
	{
		p = strchr(LogFileName,'\"');
		*p = '\0';
	}
	
	if (strchr(LogFileName,'\\'))
	{
		p = LogFileName;
		while (strchr(p,'\\'))
		{
			p = strchr(p,'\\');
			p++;
		}
		p -= 1;
		*p = '\0';
	}

	strcat(LogFileName,"\\RSP code.txt");

	hLogFile = CreateFile(LogFileName,GENERIC_WRITE, FILE_SHARE_READ,NULL,CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	SetFilePointer(hLogFile,0,NULL,FILE_BEGIN);

	for (location = 0; location < 0x1000; location += 4) {
		unsigned int characters_to_write;
		int characters_converted;

		RSP_LW_IMEM(location, &OpCode);
		characters_converted = sprintf(
			&string[0],
			" 0x%03X\t%s\r\n",
			location,
			RSPOpcodeName(OpCode, location)
		);

		if (characters_converted < 0) {
			DisplayError("Failed to sprintf IMEM from 0x%03X.", location);
			break;
		}
		characters_to_write = (unsigned)characters_converted;
		WriteFile(hLogFile, string, characters_to_write, &dwWritten, NULL);
	}
	CloseHandle(hLogFile);
}
int32_t IsOpcodeNop(uint32_t PC)
{
    RSPOPCODE RspOp;
    RSP_LW_IMEM(PC, &RspOp.Hex);

    if (RspOp.op == RSP_SPECIAL && RspOp.funct == RSP_SPECIAL_SLL) {
	return (RspOp.rd == 0) ? 1 : 0;
    }

    return 0;
}
Beispiel #11
0
BOOL WriteToVectorDest2 (DWORD DestReg, int PC, BOOL RecursiveCall) {
	OPCODE RspOp;
	DWORD BranchTarget = 0;
	signed int BranchImmed = 0;

	int Instruction_State = NextInstruction;

	if (Compiler.bDest == 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 WriteToVectorDest\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 WriteToVectorDest\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) < PC) {
				return FALSE;
			}
			/* rarely occurs let them have their way */
			return TRUE;

		case RSP_JAL:
			/* Assume reg is being passed to function or used after the function call */
			return TRUE;

		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:
				case RSP_VECTOR_VMACF:
				case RSP_VECTOR_VMACU:
				case RSP_VECTOR_VMADL:
				case RSP_VECTOR_VMADM:
				case RSP_VECTOR_VMADN:
				case RSP_VECTOR_VMADH:
				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:
				case RSP_VECTOR_VABS:
					if (DestReg == RspOp.rd) { return TRUE; }
					if (DestReg == RspOp.rt) { return TRUE; }
					if (DestReg == RspOp.sa) { return FALSE; }
					break;

				case RSP_VECTOR_VMOV:
				case RSP_VECTOR_VRCP:
				case RSP_VECTOR_VRCPL:
				case RSP_VECTOR_VRCPH:
				case RSP_VECTOR_VRSQL:
				case RSP_VECTOR_VRSQH:
					if (DestReg == RspOp.rt) { return TRUE; }
					break;

				case RSP_VECTOR_VCH:
				case RSP_VECTOR_VCL:
				case RSP_VECTOR_VCR:
				case RSP_VECTOR_VMRG:
				case RSP_VECTOR_VLT:
				case RSP_VECTOR_VEQ:
				case RSP_VECTOR_VGE:
				case RSP_VECTOR_VNE:
					if (DestReg == RspOp.rd) { return TRUE; }
					if (DestReg == RspOp.rt) { return TRUE; }
					if (DestReg == RspOp.sa) { return FALSE; }
					break;
				case RSP_VECTOR_VSAW:
					if (DestReg == RspOp.sa) { return FALSE; }
					break;
				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:
					break;
				case RSP_COP2_MT:
				/*	if (DestReg == RspOp.rd) { return FALSE; } */
					break;
				case RSP_COP2_MF:
					if (DestReg == RspOp.rd) { return TRUE; }
					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:
				break;

			case RSP_LSC2_QV:
			case RSP_LSC2_BV:
			case RSP_LSC2_LV:
			case RSP_LSC2_TV:			
				break;
				
			case RSP_LSC2_PV:
			case RSP_LSC2_UV:
			case RSP_LSC2_HV:
				if (DestReg == RspOp.rt) { return FALSE; }
				break;

			default:
				CompilerWarning("Unkown opcode in WriteToVectorDest\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:
				if (DestReg == RspOp.rt) { return TRUE; }
				break;
				
			case RSP_LSC2_TV:
				if (8 <= 32 - RspOp.rt) {
					if (DestReg >= RspOp.rt && DestReg <= RspOp.rt + 7) {
						return TRUE;
					}
				} else {
					int length = 32 - RspOp.rt, count, del = RspOp.del >> 1, vect = RspOp.rt;
					for (count = 0; count < length; count++) {
						if (DestReg == vect + del) {
							return TRUE;
						}
						del = (del + 1) & 7;
					}
				}
				break;
				
			default:
				CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		default:
			CompilerWarning("Unkown opcode in WriteToVectorDest\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 = WriteToVectorDest2(DestReg, BranchTarget - 4, TRUE);
		/* analysis of branch as nop */
		BranchFall = WriteToVectorDest2(DestReg, 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;
}
Beispiel #12
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;
}
Beispiel #13
0
BOOL IsRegisterConstant (DWORD Reg, DWORD * Constant) {
	DWORD PC = 0;
	DWORD References = 0;
	DWORD Const = 0;
	OPCODE RspOp;

	if (Compiler.bGPRConstants == FALSE) 
		return FALSE;

	while (PC < 0x1000) {
		
		RSP_LW_IMEM(PC, &RspOp.Hex);
		
		/* resample command in microcode likes S7 */
	/*	if (PC == 0xFBC) {
			PC += 4;
			continue;
		}*/

		PC += 4;

		switch (RspOp.op) {
		case RSP_REGIMM:
			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:
				if (RspOp.rd == Reg) { return FALSE; }
				break;

			case RSP_SPECIAL_BREAK:
			case RSP_SPECIAL_JR:
				break;

			default:
			//	CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
			//	return FALSE;
				break;
			}
			break;

		case RSP_J:
		case RSP_JAL:
		case RSP_BEQ:
		case RSP_BNE:
		case RSP_BLEZ:
		case RSP_BGTZ:
			break;
		
		case RSP_ADDI:
		case RSP_ADDIU:
			if (RspOp.rt == Reg) {
				if (RspOp.rs == 0) {
					if (References > 0) {
						return FALSE;
					}
					Const = (short)RspOp.immediate;
					References++;
				} else {
					return FALSE;
				}
			}
			break;
		case RSP_ORI:
			if (RspOp.rt == Reg) {
				if (!RspOp.rs) {
					if (References > 0) { return FALSE; }
					Const = (WORD)RspOp.immediate;
					References++;
				} else
					return FALSE;
			}
			break;

		case RSP_LUI:
			if (RspOp.rt == Reg) {
				if (References > 0) { return FALSE; }
				Const = (short)RspOp.offset << 16;
				References++;
			}
			break;

		case RSP_ANDI:
		case RSP_XORI:
		case RSP_SLTI:
		case RSP_SLTIU:
			if (RspOp.rt == Reg) { return FALSE; }
			break;

		case RSP_CP0:
			switch (RspOp.rs) {
			case RSP_COP0_MF:
				if (RspOp.rt == Reg) { return FALSE; }
			case RSP_COP0_MT:
				break;
			}			
			break;

		case RSP_CP2:
			if ((RspOp.rs & 0x10) == 0) {
				switch (RspOp.rs) {
				case RSP_COP2_CT:
				case RSP_COP2_MT:
					break;

				case RSP_COP2_CF:
				case RSP_COP2_MF:
					if (RspOp.rt == Reg) { return FALSE; }
					break;

				default:
				//	CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
				//	return FALSE;
					break;
				}
			}
			break;

		case RSP_LB:
		case RSP_LH:
		case RSP_LW:
		case RSP_LBU:
		case RSP_LHU:
			if (RspOp.rt == Reg) { return FALSE; }
			break;

		case RSP_SB:
		case RSP_SH:
		case RSP_SW:
			break;
		case RSP_LC2:
			break;
		case RSP_SC2:
			break;
		default:
		//	CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
		//	return FALSE;
			break;
		}
	}

	if (References > 0) {
		*Constant = Const;
		return TRUE;
	} else {
		*Constant = 0;
		return FALSE;
	}
}
uint32_t WriteToAccum2(int32_t Location, int32_t PC, int32_t RecursiveCall)
{
    RSPOPCODE RspOp;
    uint32_t BranchTarget = 0;
    int32_t BranchImmed = 0;
    uint32_t JumpTarget = 0;
    int32_t JumpUncond = 0;

    int32_t Instruction_State = RSPNextInstruction;

    if (Compiler.bAccum == 0)
	return 1;

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

    do {
	PC += 4;
	if (PC >= 0x1000) {
	    return 1;
	}
	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 1;
	    }
	    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 1;
	    }
	    break;
	case RSP_J:
	case RSP_JAL:
	    if (!JumpTarget) {
		JumpUncond = 1;
		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 + ((int16_t) RspOp.offset << 2) + 4) & 0xFFC;
	    BranchImmed = (int16_t) 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 0;
		case RSP_VECTOR_VMACF:
		case RSP_VECTOR_VMADL:
		case RSP_VECTOR_VMADM:
		case RSP_VECTOR_VMADN:
		case RSP_VECTOR_VMADH:
		    return 1;
		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 0;
		    }
		    break;

		case RSP_VECTOR_VMOV:
		case RSP_VECTOR_VMRG:
		    break;
		case RSP_VECTOR_VSAW:
		    return 1;
		default:
		    CompilerWarning
			("Unkown opcode in WriteToVectorDest\n%s",
			 RSPOpcodeName(RspOp.Hex, PC));
		    return 1;
		}
	    } 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 1;
		}
	    }
	    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 1;
	    }
	    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 1;
	    }
	    break;
	default:
	    CompilerWarning("Unkown opcode in WriteToAccum\n%s",
			    RSPOpcodeName(RspOp.Hex, PC));
	    return 1;
	}
	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 = 0;
	    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 == 0) {
	uint32_t BranchTaken, BranchFall;

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

	if (BranchImmed < 0) {
	    if (BranchTaken != 0) {
		/*
		 ** took this back branch and couldnt find a place
		 ** that resets the accum or hit a branch etc
		 **/
		return 1;
	    } 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 0)");
		return 0;
#endif
		return 1;
	    } else {
		/* otherwise this is completely valid */
		return BranchFall;
	    }
	} else {
	    if (BranchFall != 0) {
		/*
		 ** took this forward branch and couldnt find a place
		 ** that resets the accum or hit a branch etc
		 **/
		return 1;
	    } 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 0)");
		return 0;
#endif

		return 1;
	    } else {
		/* otherwise this is completely valid */
		return BranchTaken;
	    }
	}
    } else {
	return HIT_BRANCH;
    }
}
BOOL WriteToVectorDest2 (DWORD DestReg, 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.bDest == 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 WriteToVectorDest\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 WriteToVectorDest\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:
				case RSP_VECTOR_VMACF:
				case RSP_VECTOR_VMADL:
				case RSP_VECTOR_VMADM:
				case RSP_VECTOR_VMADN:
				case RSP_VECTOR_VMADH:
				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_VABS:
					if (DestReg == RspOp.rd) { return TRUE; }
					if (DestReg == RspOp.rt) { return TRUE; }
					if (DestReg == RspOp.sa) { return FALSE; }
					break;

				case RSP_VECTOR_VMOV:
					if (DestReg == RspOp.rt) { return TRUE; }
					break;

				case RSP_VECTOR_VCR:
				case RSP_VECTOR_VRCP:
				case RSP_VECTOR_VRCPH:
				case RSP_VECTOR_VRSQH:
				case RSP_VECTOR_VCH:
				case RSP_VECTOR_VCL:
					return TRUE;

				case RSP_VECTOR_VMRG:
				case RSP_VECTOR_VLT:
				case RSP_VECTOR_VEQ:
				case RSP_VECTOR_VGE:
					if (DestReg == RspOp.rd) { return TRUE; }
					if (DestReg == RspOp.rt) { return TRUE; }
					if (DestReg == RspOp.sa) { return FALSE; }
					break;
				case RSP_VECTOR_VSAW:
					if (DestReg == RspOp.sa) { return FALSE; }
					break;
				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:
					break;
				case RSP_COP2_MT:
				/*	if (DestReg == RspOp.rd) { return FALSE; } */
					break;
				case RSP_COP2_MF:
					if (DestReg == RspOp.rd) { return TRUE; }
					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:
				break;

			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 WriteToVectorDest\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:
				if (DestReg == RspOp.rt) { return TRUE; }
				break;
			default:
				CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		default:
			CompilerWarning("Unkown opcode in WriteToVectorDest\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 = WriteToVectorDest2(DestReg, BranchTarget - 4, TRUE);
		/* analysis of branch as nop */
		BranchFall = WriteToVectorDest2(DestReg, 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) {
				/* (dlist) 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 found a place
				** that needs this vector as a source
				**/
				return TRUE;
			} else if (BranchTaken == HIT_BRANCH) {
				/* (dlist) 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;
	}
}
Beispiel #16
0
/* TODO: consider delay slots and such in a branch? */
BOOL UseRspFlags (int PC) {
	OPCODE RspOp;
	int Instruction_State = NextInstruction;

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

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

	do {
		PC -= 4;
		if (PC < 0) { 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 UseRspFlags\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 WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		case RSP_J:
		case RSP_JAL:
		case RSP_BEQ:
		case RSP_BNE:
		case RSP_BLEZ:
		case RSP_BGTZ:
			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:
					break;
				case RSP_VECTOR_VMACF:
				case RSP_VECTOR_VMACU:
				case RSP_VECTOR_VMADL:
				case RSP_VECTOR_VMADM:
				case RSP_VECTOR_VMADN:
				case RSP_VECTOR_VMADH:
					break;

				case RSP_VECTOR_VSUB:
				case RSP_VECTOR_VADD:
					return FALSE;
				case RSP_VECTOR_VSUBC:
				case RSP_VECTOR_VADDC:
					return TRUE;

				case RSP_VECTOR_VABS:				
				case RSP_VECTOR_VAND:
				case RSP_VECTOR_VOR:
				case RSP_VECTOR_VXOR:
				case RSP_VECTOR_VNAND:
				case RSP_VECTOR_VNOR:
				case RSP_VECTOR_VNXOR:
				case RSP_VECTOR_VRCPH:
				case RSP_VECTOR_VRSQL:
				case RSP_VECTOR_VRSQH:
				case RSP_VECTOR_VRCPL:
				case RSP_VECTOR_VRCP:
					break;

				case RSP_VECTOR_VCR:
				case RSP_VECTOR_VCH:
				case RSP_VECTOR_VCL:				
				case RSP_VECTOR_VLT:
				case RSP_VECTOR_VEQ:
				case RSP_VECTOR_VGE:
				case RSP_VECTOR_VNE:
				case RSP_VECTOR_VMRG:
					return TRUE;

				case RSP_VECTOR_VSAW:
				case RSP_VECTOR_VMOV:				
					break;

				default:
					CompilerWarning("Unkown opcode in UseRspFlags\n%s",RSPOpcodeName(RspOp.Hex,PC));
					return TRUE;
				}
			} else {
				switch (RspOp.rs) {
				case RSP_COP2_CT:
					return TRUE;

				case RSP_COP2_CF:
				case RSP_COP2_MT:
				case RSP_COP2_MF:
					break;
				default:
					CompilerWarning("Unkown opcode in UseRspFlags\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 UseRspFlags\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 UseRspFlags\n%s",RSPOpcodeName(RspOp.Hex,PC));
				return TRUE;
			}
			break;
		default:
			CompilerWarning("Unkown opcode in UseRspFlags\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);
	return TRUE;
}
int32_t IsRegisterConstant(uint32_t Reg, uint32_t * Constant)
{
    uint32_t PC = 0;
    uint32_t References = 0;
    uint32_t Const = 0;
    RSPOPCODE RspOp;

    if (Compiler.bGPRConstants == 0)
	return 0;

    while (PC < 0x1000) {

	RSP_LW_IMEM(PC, &RspOp.Hex);
	PC += 4;

	switch (RspOp.op) {
	case RSP_REGIMM:
	    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:
		if (RspOp.rd == Reg) {
		    return 0;
		}
		break;

	    case RSP_SPECIAL_BREAK:
	    case RSP_SPECIAL_JR:
		break;

	    default:
		//      CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
		//      return 0;
		break;
	    }
	    break;

	case RSP_J:
	case RSP_JAL:
	case RSP_BEQ:
	case RSP_BNE:
	case RSP_BLEZ:
	case RSP_BGTZ:
	    break;

	case RSP_ADDI:
	case RSP_ADDIU:
	    if (RspOp.rt == Reg) {
		if (!RspOp.rs) {
		    if (References > 0) {
			return 0;
		    }
		    Const = (int16_t) RspOp.immediate;
		    References++;
		} else
		    return 0;
	    }
	    break;
	case RSP_ORI:
	    if (RspOp.rt == Reg) {
		if (!RspOp.rs) {
		    if (References > 0) {
			return 0;
		    }
		    Const = (uint16_t) RspOp.immediate;
		    References++;
		} else
		    return 0;
	    }
	    break;

	case RSP_LUI:
	    if (RspOp.rt == Reg) {
		if (References > 0) {
		    return 0;
		}
		Const = (int16_t) RspOp.offset << 16;
		References++;
	    }
	    break;

	case RSP_ANDI:
	case RSP_XORI:
	case RSP_SLTI:
	case RSP_SLTIU:
	    if (RspOp.rt == Reg) {
		return 0;
	    }
	    break;

	case RSP_CP0:
	    switch (RspOp.rs) {
	    case RSP_COP0_MF:
		if (RspOp.rt == Reg) {
		    return 0;
		}
	    case RSP_COP0_MT:
		break;
	    }
	    break;

	case RSP_CP2:
	    if ((RspOp.rs & 0x10) == 0) {
		switch (RspOp.rs) {
		case RSP_COP2_CT:
		case RSP_COP2_MT:
		    break;

		case RSP_COP2_CF:
		case RSP_COP2_MF:
		    if (RspOp.rt == Reg) {
			return 0;
		    }
		    break;

		default:
		    //      CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
		    //      return 0;
		    break;
		}
	    }
	    break;

	case RSP_LB:
	case RSP_LH:
	case RSP_LW:
	case RSP_LBU:
	case RSP_LHU:
	    if (RspOp.rt == Reg) {
		return 0;
	    }
	    break;

	case RSP_SB:
	case RSP_SH:
	case RSP_SW:
	    break;
	case RSP_LC2:
	    break;
	case RSP_SC2:
	    break;
	default:
	    //      CompilerWarning("Unkown opcode in IsRegisterConstant\n%s",RSPOpcodeName(RspOp.Hex,PC));
	    //      return 0;
	    break;
	}
    }

    if (References > 0) {
	*Constant = Const;
	return 1;
    } else {
	*Constant = 0;
	return 0;
    }
}