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; }
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); }
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; }
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; }
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; }
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; }
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; } }
/* 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; } }