public static void EmitLoadRegister( GenerationContext context, byte reg, byte fmt ) { if( ( fmt == 0 ) || ( fmt == 4 ) ) { context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 ); context.ILGen.Emit( OpCodes.Ldfld, context.Cp1Registers ); context.ILGen.Emit( OpCodes.Ldc_I4, ( int )reg ); context.ILGen.Emit( OpCodes.Ldelem_R4 ); //if( fmt == 4 ) // context.ILGen.Emit( OpCodes.Conv_I4 ); } else { Debug.Assert( false ); } }
public static void EmitStoreRegister( GenerationContext context, byte reg, byte fmt ) { if( ( fmt == 0 ) || ( fmt == 4 ) ) { if( fmt == 4 ) { context.ILGen.Emit( OpCodes.Conv_I4 ); context.ILGen.Emit( OpCodes.Conv_R4 ); } context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalTempD1 ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 ); context.ILGen.Emit( OpCodes.Ldfld, context.Cp1Registers ); context.ILGen.Emit( OpCodes.Ldc_I4, ( int )reg ); context.ILGen.Emit( OpCodes.Ldloc_S, ( byte )Cpu.LocalTempD1 ); context.ILGen.Emit( OpCodes.Stelem_R4 ); } else { Debug.Assert( false ); } }
public static void EmitConvertFormat( GenerationContext context, byte originalFmt, byte targetFmt ) { if( originalFmt == targetFmt ) return; else if( targetFmt == 0 ) { context.ILGen.Emit( OpCodes.Conv_R4 ); } else if( targetFmt == 1 ) { Debug.Assert( false ); } else if( targetFmt == 4 ) { context.ILGen.Emit( OpCodes.Conv_I4 ); context.ILGen.Emit( OpCodes.Conv_R4 ); } else if( targetFmt == 5 ) { Debug.Assert( false ); } }
public static GenerationResult DIVU( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { context.ReadRegisters[ rs ] = true; context.ReadRegisters[ rt ] = true; context.UseCore = true; } else if( pass == 1 ) { EmitLoadRegister( context, rs ); context.ILGen.Emit( OpCodes.Stloc_0 ); EmitLoadRegister( context, rt ); context.ILGen.Emit( OpCodes.Stloc_1 ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Conv_U4 ); context.ILGen.Emit( OpCodes.Ldloc_1 ); context.ILGen.Emit( OpCodes.Conv_U4 ); context.ILGen.Emit( OpCodes.Div_Un ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Lo ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Conv_U4 ); context.ILGen.Emit( OpCodes.Ldloc_1 ); context.ILGen.Emit( OpCodes.Conv_U4 ); context.ILGen.Emit( OpCodes.Rem_Un ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Hi ); //long rem; //context.Lo.Value = Math.DivRem( rs, rt, out rem ); //context.Hi.Value = rem; } return GenerationResult.Success; }
public static GenerationResult MTLO( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { context.ReadRegisters[ rs ] = true; context.UseCore = true; } else if( pass == 1 ) { context.ILGen.Emit( OpCodes.Ldarg_0 ); EmitLoadRegister( context, rs ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Lo ); //context.Lo.Value = rs; } return GenerationResult.Success; }
public static void EmitSingleToWord( GenerationContext context ) { #if FASTSINGLEWORDCONVERT context.ILGen.Emit( OpCodes.Conv_R4 ); context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalTempF ); context.ILGen.Emit( OpCodes.Ldloca_S, ( byte )Cpu.LocalTempF ); context.ILGen.Emit( OpCodes.Conv_U ); context.ILGen.Emit( OpCodes.Ldind_I4 ); #else context.ILGen.Emit( OpCodes.Conv_R4 ); context.ILGen.Emit( OpCodes.Call, typeof( BitConverter ).GetMethod( "GetBytes", new Type[] { typeof( float ) } ) ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Call, typeof( BitConverter ).GetMethod( "ToInt32" ) ); #endif }
public static void DefineBranchTarget( GenerationContext context, int target ) { if( context.BranchLabels.ContainsKey( target ) == false ) { //Debug.WriteLine( string.Format( "Defining branch target {0:X8}", target ) ); LabelMarker lm = new LabelMarker( target ); context.BranchLabels.Add( target, lm ); } if( context.LastBranchTarget < target ) context.LastBranchTarget = target; }
public static void EmitDirectMemoryWrite( GenerationContext context ) { // If the address is within main memory bounds, we do a direct read on it // If it's not, pass to the normal one // Stack: Memory / Address / Value Label l1 = context.ILGen.DefineLabel(); Label l2 = context.ILGen.DefineLabel(); Label l3 = context.ILGen.DefineLabel(); context.ILGen.Emit( OpCodes.Stloc_1 ); //if( ( address >= 0x08000000 ) && ( address < 0x09FFFFFF ) ) context.ILGen.Emit( OpCodes.Dup ); context.ILGen.Emit( OpCodes.Dup ); context.ILGen.Emit( OpCodes.Ldc_I4, 0x08000000 ); context.ILGen.Emit( OpCodes.Blt, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4, 0x09FFFFFF ); context.ILGen.Emit( OpCodes.Bgt, l2 ); // Address is within main memory range // Stack: Memory / Translated address context.ILGen.Emit( OpCodes.Ldc_I4, 0x08000000 ); context.ILGen.Emit( OpCodes.Sub ); context.ILGen.Emit( OpCodes.Stloc_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.MemoryMainBuffer ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Ldelema, typeof( byte ) ); context.ILGen.Emit( OpCodes.Ldloc_1 ); context.ILGen.Emit( OpCodes.Stind_I4 ); context.ILGen.Emit( OpCodes.Br_S, l3 ); context.ILGen.MarkLabel( l1 ); context.ILGen.Emit( OpCodes.Pop ); context.ILGen.MarkLabel( l2 ); // Address is not within main memory range // Stack: Memory / Translated address context.ILGen.Emit( OpCodes.Ldc_I4_4 ); context.ILGen.Emit( OpCodes.Ldloc_1 ); context.ILGen.Emit( OpCodes.Callvirt, context.MemoryWriteWord ); context.ILGen.MarkLabel( l3 ); }
public static void EmitAddressTranslation( GenerationContext context ) { // This is here to check for crazy kernel addresses or other things // - technically we shouldn't have to do this (on a real PSP they // would cause crashes), but the pspdev stuff sometimes does weird // things - except for uncached reads/writes, etc //if( ( address & 0x80000000 ) != 0 ) // address = address & 0x7FFFFFFF; //if( ( address & 0x40000000 ) != 0 ) // address = address & 0x3FFFFFFF; context.ILGen.Emit( OpCodes.Ldc_I4, 0x3FFFFFFF ); context.ILGen.Emit( OpCodes.And ); }
public static GenerationResult BREAK( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { } else if( pass == 1 ) { context.ILGen.Emit( OpCodes.Call, typeof( Debugger ).GetMethod( "Break" ) ); } return GenerationResult.Success; }
public static GenerationResult SYSCALL( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { // We could probably save a register write by properly obeying the // hasReturn flag, but I'm not confident the functions all have that // filled properly and I'd hate to introduce bugs like that // FUTURE: Ensure BIOS methods all have proper HasReturn and enable selective return storage int syscall = ( int )( ( code >> 6 ) & 0xFFFFF ); BiosFunction biosFunction = context.Cpu._syscalls[ syscall ]; bool willCall; bool hasReturn; int paramCount; if( biosFunction != null ) { willCall = biosFunction.IsImplemented; hasReturn = biosFunction.HasReturn; paramCount = biosFunction.ParameterCount; if( biosFunction.IsImplemented == false ) { if( pass == 0 ) { Debug.WriteLine( string.Format( "DynRec: NID 0x{0:X8} {1} is not implemented", biosFunction.NID, biosFunction.Name ) ); } } } else { willCall = false; hasReturn = false; paramCount = 0; if( pass == 0 ) Debug.WriteLine( "DynRec: unregistered syscall attempt" ); } if( pass == 0 ) { context.UseMemory = true; context.UseSyscalls = true; if( willCall == true ) { if( paramCount > 0 ) { context.ReadRegisters[ 4 ] = true; if( paramCount > 1 ) { context.ReadRegisters[ 5 ] = true; if( paramCount > 2 ) { context.ReadRegisters[ 6 ] = true; if( paramCount > 3 ) { context.ReadRegisters[ 7 ] = true; if( paramCount > 4 ) { // Maybe this should always go? context.ReadRegisters[ 29 ] = true; } } } } } if( hasReturn == true ) { context.WriteRegisters[ 2 ] = true; } } } else if( pass == 1 ) { // It's important that we save what we think is the current PC // If we had an UpdatePc, it means a branch has updated it before us // and we need to save it - otherwise, save the PC following us context.ILGen.Emit( OpCodes.Ldarg_0 ); if( context.UpdatePc == true ) context.ILGen.Emit( OpCodes.Ldloc_2 ); else context.ILGen.Emit( OpCodes.Ldc_I4, address + 4 ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Pc ); #if VERBOSESYSCALLS context.ILGen.Emit( OpCodes.Ldarg_3 ); context.ILGen.Emit( OpCodes.Ldc_I4, syscall ); context.ILGen.Emit( OpCodes.Ldelem, typeof( BiosFunction ) ); context.ILGen.Emit( OpCodes.Call, typeof( Special ).GetMethod( "SyscallDebugThunk" ) ); #endif if( willCall == true ) { // Lame, but we need the object this gets called on and // there is no way to communicate what we know now to the final IL //context.Cpu._syscalls[ syscall ].Target.Target; context.ILGen.Emit( OpCodes.Ldarg_3 ); context.ILGen.Emit( OpCodes.Ldc_I4, syscall ); context.ILGen.Emit( OpCodes.Ldelem, typeof( BiosFunction ) ); context.ILGen.Emit( OpCodes.Ldfld, context.BiosFunctionTarget ); context.ILGen.Emit( OpCodes.Call, context.DelegateTargetGet ); // Memory context.ILGen.Emit( OpCodes.Ldarg_1 ); if( paramCount > 0 ) { EmitLoadRegister( context, 4 ); if( paramCount > 1 ) { EmitLoadRegister( context, 5 ); if( paramCount > 2 ) { EmitLoadRegister( context, 6 ); if( paramCount > 3 ) { EmitLoadRegister( context, 7 ); if( paramCount > 4 ) { // Maybe this should always go? EmitLoadRegister( context, 29 ); } else context.ILGen.Emit( OpCodes.Ldc_I4_0 ); } else { context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); } } else { context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); } } else { context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); } } else { context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); } if( biosFunction.Target.Method.IsFinal == true ) context.ILGen.Emit( OpCodes.Call, biosFunction.Target.Method ); else context.ILGen.Emit( OpCodes.Callvirt, biosFunction.Target.Method ); // Function returns a value - may need to ignore if( hasReturn == true ) EmitStoreRegister( context, 2 ); else context.ILGen.Emit( OpCodes.Pop ); } else { // When we fail, we need to make sure to handle the cases where // the method has a return or else things could get even worse! if( biosFunction != null ) { if( hasReturn == true ) { context.ILGen.Emit( OpCodes.Ldc_I4, -1 ); EmitStoreRegister( context, 2 ); } } } } return GenerationResult.Syscall; }
public static GenerationResult NOP( GenerationContext context, int pass, int address, uint code, byte rs, byte rt, byte rd ) { EmitNop( context ); return GenerationResult.Success; }
public static GenerationResult BGEZALL( GenerationContext context, int pass, int address, uint code, byte opcode, uint imm ) { int target = ( address + AddressOffset ) + ( ( int )( short )imm << 2 ); int rs = ( int )( ( code >> 21 ) & 0x1F ); if( pass == 0 ) { context.UpdatePc = true; context.ReadRegisters[ rs ] = true; context.WriteRegisters[ 31 ] = true; DefineBranchTarget( context, target ); } else if( pass == 1 ) { LabelMarker targetLabel = context.BranchLabels[ target ]; //Debug.Assert( targetLabel != default( Label ) ); context.BranchTarget = targetLabel; Label l1 = context.ILGen.DefineLabel(); Label l2 = context.ILGen.DefineLabel(); EmitLoadRegister( context, rs ); //context.ILGen.Emit( OpCodes.Ldc_I4_0 ); //context.ILGen.Emit( OpCodes.Blt, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4, 31 ); context.ILGen.Emit( OpCodes.Shr ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Bne_Un, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4, address + 4 ); EmitStoreRegister( context, 31 ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Stloc_3 ); context.ILGen.Emit( OpCodes.Br_S, l2 ); context.ILGen.MarkLabel( l1 ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalNullifyDelay ); context.ILGen.MarkLabel( l2 ); } //if( rs.Value >= 0 ) //{ // context.Registers[ 31 ].Value = context.PC + 4; // context.PC.Value = context.PC + ( imm << 2 ); //} //else // null = true; return GenerationResult.BranchAndNullifyDelay; }
public static void EmitStoreRegister( GenerationContext context, int reg ) { Debug.Assert( ( reg >= 0 ) && ( reg <= 31 ) ); if( reg != 0 ) { //int map = context.Registers[ reg ]; //context.ILGen.Emit( OpCodes.Stloc_S, ( byte )map ); context.ILGen.Emit( OpCodes.Stloc_1 ); context.ILGen.Emit( OpCodes.Ldarg_2 ); context.ILGen.Emit( OpCodes.Ldc_I4, reg ); context.ILGen.Emit( OpCodes.Ldloc_1 ); context.ILGen.Emit( OpCodes.Stelem_I4 ); } else context.ILGen.Emit( OpCodes.Pop ); }
public static GenerationResult BLTZ( GenerationContext context, int pass, int address, uint code, byte opcode, uint imm ) { int target = ( address + AddressOffset ) + ( ( int )( short )imm << 2 ); int rs = ( int )( ( code >> 21 ) & 0x1F ); if( pass == 0 ) { context.UpdatePc = true; context.ReadRegisters[ rs ] = true; DefineBranchTarget( context, target ); } else if( pass == 1 ) { LabelMarker targetLabel = context.BranchLabels[ target ]; //Debug.Assert( targetLabel != default( Label ) ); context.BranchTarget = targetLabel; Label l1 = context.ILGen.DefineLabel(); EmitLoadRegister( context, rs ); //context.ILGen.Emit( OpCodes.Ldc_I4_0 ); //context.ILGen.Emit( OpCodes.Bge, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4, 31 ); context.ILGen.Emit( OpCodes.Shr ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Bne_Un, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Stloc_3 ); context.ILGen.MarkLabel( l1 ); } //if( rs.Value < 0 ) // context.PC.Value = context.PC + ( imm << 2 ); return GenerationResult.Branch; }
public static GenerationResult CTCz( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm ) { return GenerationResult.Invalid; //if( pass == 0 ) //{ // context.ReadRegisters[ rs ] = true; // context.WriteRegisters[ rt ] = true; //} //else if( pass == 1 ) //{ // EmitLoadRegister( context, rs ); // context.ILGen.Emit( OpCodes.Ldc_I4, ( int )( uint )imm ); // context.ILGen.Emit( OpCodes.And ); // EmitStoreRegister( context, rt ); // //rt.Value = rs & imm; //} //return GenerationResult.Success; }
public static void EmitStoreCopConditionBit( GenerationContext context, int cop ) { Debug.Assert( cop == 1 ); context.ILGen.Emit( OpCodes.Stloc_0 ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Conv_U1 ); context.ILGen.Emit( OpCodes.Call, context.Cp1ConditionBitSet ); }
public static GenerationResult COP2( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm ) { if( pass == 0 ) { } else if( pass == 1 ) { } return GenerationResult.Invalid; }
public static void EmitDirectMemoryRead( GenerationContext context ) { // If the address is within main memory bounds, we do a direct read on it // If it's not, pass to the nromal one // Stack: Memory / Address Label l1 = context.ILGen.DefineLabel(); Label l2 = context.ILGen.DefineLabel(); Label l3 = context.ILGen.DefineLabel(); //if( ( address >= 0x08000000 ) && ( address < 0x09FFFFFF ) ) context.ILGen.Emit( OpCodes.Dup ); context.ILGen.Emit( OpCodes.Dup ); context.ILGen.Emit( OpCodes.Ldc_I4, 0x08000000 ); context.ILGen.Emit( OpCodes.Blt, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4, 0x09FFFFFF ); context.ILGen.Emit( OpCodes.Bgt, l2 ); // Address is within main memory range // Stack: Memory / Translated address context.ILGen.Emit( OpCodes.Ldc_I4, 0x08000000 ); context.ILGen.Emit( OpCodes.Sub ); context.ILGen.Emit( OpCodes.Stloc_0 ); //context.ILGen.Emit( OpCodes.Ldstr, "read inline 0x{0:X8}" ); //context.ILGen.Emit( OpCodes.Ldloc_0 ); //context.ILGen.Emit( OpCodes.Ldc_I4, 0x08000000 ); //context.ILGen.Emit( OpCodes.Add ); //context.ILGen.Emit( OpCodes.Box, typeof( int ) ); //context.ILGen.Emit( OpCodes.Call, context.StringFormat1 ); //context.ILGen.Emit( OpCodes.Call, context.DebugWriteLine ); context.ILGen.Emit( OpCodes.Ldfld, context.MemoryMainBuffer ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Ldelema, typeof( byte ) ); context.ILGen.Emit( OpCodes.Ldind_I4 ); context.ILGen.Emit( OpCodes.Br_S, l3 ); context.ILGen.MarkLabel( l1 ); context.ILGen.Emit( OpCodes.Pop ); context.ILGen.MarkLabel( l2 ); // Address is not within main memory range // Stack: Memory / Translated address context.ILGen.Emit( OpCodes.Callvirt, context.MemoryReadWord ); context.ILGen.MarkLabel( l3 ); }
// TODO: Allegrex mtic public static GenerationResult MTIC( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { } else if( pass == 1 ) { } return GenerationResult.Success; }
public static void EmitNop( GenerationContext context ) { }
public static GenerationResult HandleInstruction( GenerationContext context, int pass, int address, uint code ) { uint copop = code >> 28; byte cop = ( byte )( ( code >> 26 ) & 0x3 ); // cop0, cop1, or cop2 byte rs = ( byte )( ( code >> 21 ) & 0x1F ); byte rt = ( byte )( ( code >> 16 ) & 0x1F ); byte rd = ( byte )( ( code >> 11 ) & 0x1F ); ushort imm = ( ushort )( code & 0xFFFF ); // rs = bc sub-opcode // rt = branch condition switch( copop ) { case 0x4: if( ( ( code >> 25 ) & 0x1 ) == 1 ) // COPz { uint cofun = code & 0x1FFFFFF; if( cop == 1 ) { byte fmt = ( byte )( ( cofun >> 21 ) & 0x1F ); // 0 = S = single binary fp // 1 = D = double binary fp // 4 = W = single 32 binary fixed point // 5 = L = longword 64 binary fixed point Debug.Assert( ( fmt != 1 ) && ( fmt != 5 ) ); byte ft = rt; // source 2 byte fs = rd; // source 1 byte fd = ( byte )( ( code >> 6 ) & 0x1F ); // dest byte func = ( byte )( code & 0x3F ); GenerateInstructionFpu instr = FpuInstructions.TableFpu[ func ]; if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, instr.Method.Name, string.Format( "fmt:{0} fs:{1} ft:{2} fd:{3}", fmt, fs, ft, fd ) ); return instr( context, pass, address + 4, code, fmt, fs, ft, fd, func ); } else { Debug.WriteLine( string.Format( "Cpu: attempted COP{0} function {1:X8}", cop, cofun ) ); return GenerationResult.Invalid; } } else { switch( rs ) { case 0x00: // mfcz rt, rd if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "MFCz", string.Format( "cop:{3} rd:{0} rt:{1} imm:{2}", cop, rd, rt, ( int )( short )imm ) ); return Cop.MFCz( context, pass, address, code, cop, rd, rt, imm ); case 0x04: // mtcz rt, rd if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "MTCz", string.Format( "cop:{3} rd:{0} rt:{1} imm:{2}", cop, rd, rt, ( int )( short )imm ) ); return Cop.MTCz( context, pass, address, code, cop, rd, rt, imm ); case 0x02: // cfcz rt, rd if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "CFCz", string.Format( "cop:{3} rd:{0} rt:{1} imm:{2}", cop, rd, rt, ( int )( short )imm ) ); return Cop.CFCz( context, pass, address, code, cop, rd, rt, imm ); case 0x06: // ctcz rt, rd if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "CTCz", string.Format( "cop:{3} rd:{0} rt:{1} imm:{2}", cop, rd, rt, ( int )( short )imm ) ); return Cop.CTCz( context, pass, address, code, cop, rd, rt, imm ); case 0x08: { switch( rt ) { case 0x0: // BCzF if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "BCzF", string.Format( "cop:{3} rs:{0} rt:{1} imm:{2}", cop, rs, rt, ( int )( short )imm ) ); return Cop.BCzF( context, pass, address, code, cop, rs, rt, imm ); case 0x2: // BCzFL if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "BCzFL", string.Format( "cop:{3} rs:{0} rt:{1} imm:{2}", cop, rs, rt, ( int )( short )imm ) ); return Cop.BCzFL( context, pass, address, code, cop, rs, rt, imm ); case 0x1: // BCzT if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "BCzT", string.Format( "cop:{3} rs:{0} rt:{1} imm:{2}", cop, rs, rt, ( int )( short )imm ) ); return Cop.BCzT( context, pass, address, code, cop, rs, rt, imm ); case 0x3: // BCzTL if( pass == 1 ) context.Cpu.EmitTrace( context, address, code, "BCzTL", string.Format( "cop:{3} rs:{0} rt:{1} imm:{2}", cop, rs, rt, ( int )( short )imm ) ); return Cop.BCzTL( context, pass, address, code, cop, rs, rt, imm ); } if( cop == 1 ) { // Hand off to COP1 to do it's thing //_cp1->Process( instruction ); Debug.Assert( false ); return GenerationResult.Invalid; } } return GenerationResult.Invalid; } } return GenerationResult.Invalid; } return GenerationResult.Invalid; }
public static void EmitWordToSingle( GenerationContext context ) { #if FASTSINGLEWORDCONVERT context.ILGen.Emit( OpCodes.Stloc_0 ); context.ILGen.Emit( OpCodes.Ldloca_S, 0 ); context.ILGen.Emit( OpCodes.Conv_U ); context.ILGen.Emit( OpCodes.Ldind_R4 ); #else context.ILGen.Emit( OpCodes.Conv_I4 ); context.ILGen.Emit( OpCodes.Call, typeof( BitConverter ).GetMethod( "GetBytes", new Type[] { typeof( int ) } ) ); context.ILGen.Emit( OpCodes.Ldc_I4_0 ); context.ILGen.Emit( OpCodes.Call, typeof( BitConverter ).GetMethod( "ToSingle" ) ); #endif }
public static void EmitStoreCopRegister( GenerationContext context, int cop, int reg ) { Debug.Assert( ( reg >= 0 ) && ( reg <= 31 ) ); switch( cop ) { case 0: { // Cop1 stuff not done Debug.Assert( false ); } break; case 1: { context.ILGen.Emit( OpCodes.Conv_R4 ); context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalTempD1 ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 ); context.ILGen.Emit( OpCodes.Ldfld, context.Cp1Registers ); context.ILGen.Emit( OpCodes.Ldc_I4, ( int )reg ); context.ILGen.Emit( OpCodes.Ldloc_S, ( byte )Cpu.LocalTempD1 ); context.ILGen.Emit( OpCodes.Stelem_R4 ); } break; case 2: { // Cop2 not implemented Debug.Assert( false ); } break; } }
public static GenerationResult MFLO( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { context.WriteRegisters[ rd ] = true; context.UseCore = true; } else if( pass == 1 ) { context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldfld, context.Core0Lo ); EmitStoreRegister( context, rd ); //rd.Value = context.Lo; } return GenerationResult.Success; }
public static GenerationResult BCzTL( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm ) { int target = ( address + AddressOffset ) + ( ( int )( short )imm << 2 ); //targetPcValid = condition; //nullifyDelay = !targetPcValid; if( pass == 0 ) { context.UpdatePc = true; DefineBranchTarget( context, target ); } else if( pass == 1 ) { LabelMarker targetLabel = context.BranchLabels[ target ]; //Debug.Assert( targetLabel != default( Label ) ); context.BranchTarget = targetLabel; Label l1 = context.ILGen.DefineLabel(); Label l2 = context.ILGen.DefineLabel(); EmitLoadCopConditionBit( context, opcode ); context.ILGen.Emit( OpCodes.Brfalse_S, l1 ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Stloc_3 ); context.ILGen.Emit( OpCodes.Br_S, l2 ); context.ILGen.MarkLabel( l1 ); context.ILGen.Emit( OpCodes.Ldc_I4_1 ); context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalNullifyDelay ); context.ILGen.MarkLabel( l2 ); } return GenerationResult.BranchAndNullifyDelay; }
public static GenerationResult MULTU( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { context.ReadRegisters[ rs ] = true; context.ReadRegisters[ rt ] = true; context.UseCore = true; } else if( pass == 1 ) { context.ILGen.Emit( OpCodes.Ldarg_0 ); EmitLoadRegister( context, rs ); context.ILGen.Emit( OpCodes.Conv_U8 ); EmitLoadRegister( context, rt ); context.ILGen.Emit( OpCodes.Conv_U8 ); context.ILGen.Emit( OpCodes.Mul_Ovf_Un ); context.ILGen.Emit( OpCodes.Dup ); context.ILGen.Emit( OpCodes.Conv_I4 ); context.ILGen.Emit( OpCodes.Stloc_0 ); context.ILGen.Emit( OpCodes.Ldc_I4, 32 ); context.ILGen.Emit( OpCodes.Shr_Un ); context.ILGen.Emit( OpCodes.Conv_I4 ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Hi ); context.ILGen.Emit( OpCodes.Ldarg_0 ); context.ILGen.Emit( OpCodes.Ldloc_0 ); context.ILGen.Emit( OpCodes.Stfld, context.Core0Lo ); //long res = rs * rt; //context.Hi.Value = ( int )( res >> 32 ); //context.Lo.Value = ( int )res; } return GenerationResult.Success; }
public static GenerationResult MFCz( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm ) { if( pass == 0 ) { context.WriteRegisters[ rt ] = true; } else if( pass == 1 ) { EmitLoadCopRegister( context, opcode, rs ); if( opcode == 1 ) EmitSingleToWord( context ); EmitStoreRegister( context, rt ); } return GenerationResult.Success; }
public static GenerationResult OR( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function ) { if( pass == 0 ) { context.ReadRegisters[ rs ] = true; context.ReadRegisters[ rt ] = true; context.WriteRegisters[ rd ] = true; } else if( pass == 1 ) { EmitLoadRegister( context, rs ); EmitLoadRegister( context, rt ); context.ILGen.Emit( OpCodes.Or ); EmitStoreRegister( context, rd ); //rd.Value = rs | rt; } return GenerationResult.Success; }
public static GenerationResult MTCz( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm ) { if( pass == 0 ) { context.ReadRegisters[ rs ] = true; } else if( pass == 1 ) { EmitLoadRegister( context, rt ); if( opcode == 1 ) EmitWordToSingle( context ); //context.ILGen.Emit( OpCodes.Stloc_S, ( byte )Cpu.LocalTempD1 ); //context.ILGen.Emit( OpCodes.Ldstr, string.Format( "{0:X8}: mtcz {{0}}", address - 4 ) ); //context.ILGen.Emit( OpCodes.Ldloc_S, ( byte )Cpu.LocalTempD1 ); //context.ILGen.Emit( OpCodes.Box, typeof( float ) ); //context.ILGen.Emit( OpCodes.Call, context.StringFormat1 ); //context.ILGen.Emit( OpCodes.Call, context.DebugWriteLine ); //context.ILGen.Emit( OpCodes.Ldloc_S, ( byte )Cpu.LocalTempD1 ); EmitStoreCopRegister( context, opcode, rs ); } return GenerationResult.Success; }