Remove dynamic usage from Ryujinx.HLE (will come back to make this not generic explode)

This commit is contained in:
Aaron Robinson
2025-11-19 00:33:17 -06:00
parent 4f5eea3417
commit 00021121ea
31 changed files with 198 additions and 106 deletions

View File

@@ -1,7 +1,5 @@
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
{ {
@@ -71,53 +69,42 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid right-hand side switch {rightHandSideIsImmediate} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid right-hand side switch {rightHandSideIsImmediate} in Atmosphere cheat");
} }
void Emit(Type operationType, IOperand rhs = null) void EmitCore<TOp>(IOperand rhs = null) where TOp : IOperation
{ {
List<IOperand> operandList = InstructionHelper.Emit<TOp>(operationWidth, context, destinationRegister, leftHandSideRegister, rhs);
[
destinationRegister,
leftHandSideRegister
];
if (rhs != null)
{
operandList.Add(rhs);
}
InstructionHelper.Emit(operationType, operationWidth, context, operandList.ToArray());
} }
switch (operation) switch (operation)
{ {
case Add: case Add:
Emit(typeof(OpAdd<>), rightHandSideOperand); EmitCore<OpAdd<byte>>(rightHandSideOperand);
break; break;
case Sub: case Sub:
Emit(typeof(OpSub<>), rightHandSideOperand); EmitCore<OpSub<byte>>(rightHandSideOperand);
break; break;
case Mul: case Mul:
Emit(typeof(OpMul<>), rightHandSideOperand); EmitCore<OpMul<byte>>(rightHandSideOperand);
break; break;
case Lsh: case Lsh:
Emit(typeof(OpLsh<>), rightHandSideOperand); EmitCore<OpLsh<byte>>(rightHandSideOperand);
break; break;
case Rsh: case Rsh:
Emit(typeof(OpRsh<>), rightHandSideOperand); EmitCore<OpRsh<byte>>(rightHandSideOperand);
break; break;
case And: case And:
Emit(typeof(OpAnd<>), rightHandSideOperand); EmitCore<OpAnd<byte>>(rightHandSideOperand);
break; break;
case Or: case Or:
Emit(typeof(OpOr<>), rightHandSideOperand); EmitCore<OpOr<byte>>(rightHandSideOperand);
break; break;
case Not: case Not:
Emit(typeof(OpNot<>)); EmitCore<OpNot<byte>>();
break; break;
case Xor: case Xor:
Emit(typeof(OpXor<>), rightHandSideOperand); EmitCore<OpXor<byte>>(rightHandSideOperand);
break; break;
case Mov: case Mov:
Emit(typeof(OpMov<>)); EmitCore<OpMov<byte>>();
break; break;
default: default:
throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat");

View File

@@ -1,5 +1,6 @@
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System;
namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
{ {
@@ -81,7 +82,15 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid operand type {operandType} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid operand type {operandType} in Atmosphere cheat");
} }
InstructionHelper.Emit(typeof(OpLog<>), operationWidth, context, logId, sourceOperand); IOperation op = operationWidth switch
{
1 => new OpLog<byte>(logId, sourceOperand),
2 => new OpLog<ushort>(logId, sourceOperand),
4 => new OpLog<uint>(logId, sourceOperand),
8 => new OpLog<ulong>(logId, sourceOperand),
_ => throw new NotSupportedException(),
};
InstructionHelper.Emit(op, context);
} }
} }
} }

View File

@@ -37,27 +37,27 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
ulong immediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize); ulong immediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize);
Value<ulong> rightHandSideValue = new(immediate); Value<ulong> rightHandSideValue = new(immediate);
void Emit(Type operationType) void EmitCore<TOp>() where TOp : IOperation
{ {
InstructionHelper.Emit(operationType, operationWidth, context, register, register, rightHandSideValue); InstructionHelper.Emit<TOp>(operationWidth, context, register, register, rightHandSideValue);
} }
switch (operation) switch (operation)
{ {
case Add: case Add:
Emit(typeof(OpAdd<>)); EmitCore<OpAdd<byte>>();
break; break;
case Sub: case Sub:
Emit(typeof(OpSub<>)); EmitCore<OpAdd<byte>>();
break; break;
case Mul: case Mul:
Emit(typeof(OpMul<>)); EmitCore<OpMul<byte>>();
break; break;
case Lsh: case Lsh:
Emit(typeof(OpLsh<>)); EmitCore<OpLsh<byte>>();
break; break;
case Rsh: case Rsh:
Emit(typeof(OpRsh<>)); EmitCore<OpRsh<byte>>();
break; break;
default: default:
throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat");

View File

@@ -1,4 +1,5 @@
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Tamper.Operations;
namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
{ {
@@ -52,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid source mode {useDestinationAsSourceIndex} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid source mode {useDestinationAsSourceIndex} in Atmosphere cheat");
} }
InstructionHelper.EmitMov(operationWidth, context, destinationRegister, sourceMemory); InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationRegister, sourceMemory, null);
} }
} }
} }

View File

@@ -1,3 +1,5 @@
using Ryujinx.HLE.HOS.Tamper.Operations;
namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
{ {
/// <summary> /// <summary>
@@ -35,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
ulong valueImmediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, valueImmediateSize); ulong valueImmediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, valueImmediateSize);
Value<ulong> storeValue = new(valueImmediate); Value<ulong> storeValue = new(valueImmediate);
InstructionHelper.EmitMov(operationWidth, context, dstMem, storeValue); InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, dstMem, storeValue, null);
} }
} }
} }

View File

@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid offset mode {useOffsetRegister} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid offset mode {useOffsetRegister} in Atmosphere cheat");
} }
InstructionHelper.EmitMov(operationWidth, context, destinationMemory, storeValue); InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationMemory, storeValue, null);
switch (incrementAddressRegister) switch (incrementAddressRegister)
{ {

View File

@@ -79,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
throw new TamperCompilationException($"Invalid offset type {offsetType} in Atmosphere cheat"); throw new TamperCompilationException($"Invalid offset type {offsetType} in Atmosphere cheat");
} }
InstructionHelper.EmitMov(operationWidth, context, destinationMemory, sourceRegister); InstructionHelper.Emit<OpMov<byte>>(operationWidth, context, destinationMemory, sourceRegister, null);
switch (incrementAddressRegister) switch (incrementAddressRegister)
{ {

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondEQ<T> : ICondition where T : unmanaged class CondEQ<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() == (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() == _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondEQ<T>(lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondGE<T> : ICondition where T : unmanaged class CondGE<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() >= (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() >= _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondGE<T>(lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondGT<T> : ICondition where T : unmanaged class CondGT<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() > (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() > _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondGT<T>(lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondLE<T> : ICondition where T : unmanaged class CondLE<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() <= (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() <= _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondLE<T>(lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondLT<T> : ICondition where T : unmanaged class CondLT<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() < (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() < _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondLT<T>(lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
class CondNE<T> : ICondition where T : unmanaged class CondNE<T> : ICondition where T : unmanaged, INumber<T>
{ {
private readonly IOperand _lhs; private readonly IOperand _lhs;
private readonly IOperand _rhs; private readonly IOperand _rhs;
@@ -15,7 +16,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Conditions
public bool Evaluate() public bool Evaluate()
{ {
return (dynamic)_lhs.Get<T>() != (dynamic)_rhs.Get<T>(); return _lhs.Get<T>() != _rhs.Get<T>();
} }
public static ICondition CreateFor<T1>(IOperand lhs, IOperand rhs) where T1 : INumber<T1>
=> new CondNE<T>(lhs, rhs);
} }
} }

View File

@@ -1,7 +1,13 @@
using Ryujinx.HLE.HOS.Tamper.Operations;
using System;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Conditions namespace Ryujinx.HLE.HOS.Tamper.Conditions
{ {
interface ICondition interface ICondition
{ {
bool Evaluate(); bool Evaluate();
static virtual ICondition CreateFor<T>(IOperand lhs, IOperand rhs) where T : INumber<T> => throw new NotImplementedException();
} }
} }

View File

@@ -15,46 +15,47 @@ namespace Ryujinx.HLE.HOS.Tamper
context.CurrentOperations.Add(operation); context.CurrentOperations.Add(operation);
} }
public static void Emit(Type instruction, byte width, CompilationContext context, params Object[] operands) public static void Emit<TOp>(byte width, CompilationContext context, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperation
{ {
Emit((IOperation)Create(instruction, width, operands), context); Emit(Create<TOp>(width, destination, lhs, rhs), context);
}
public static void EmitMov(byte width, CompilationContext context, IOperand destination, IOperand source)
{
Emit(typeof(OpMov<>), width, context, destination, source);
} }
public static ICondition CreateCondition(Comparison comparison, byte width, IOperand lhs, IOperand rhs) public static ICondition CreateCondition(Comparison comparison, byte width, IOperand lhs, IOperand rhs)
{ {
ICondition Create(Type conditionType) ICondition CreateCore<TOp>() where TOp : ICondition
{ {
return (ICondition)InstructionHelper.Create(conditionType, width, lhs, rhs); return width switch
{
1 => TOp.CreateFor<byte>(lhs, rhs),
2 => TOp.CreateFor<ushort>(lhs, rhs),
4 => TOp.CreateFor<uint>(lhs, rhs),
8 => TOp.CreateFor<ulong>(lhs, rhs),
_ => throw new NotSupportedException(),
};
} }
return comparison switch return comparison switch
{ {
Comparison.Greater => Create(typeof(CondGT<>)), Comparison.Greater => CreateCore<CondGT<byte>>(),
Comparison.GreaterOrEqual => Create(typeof(CondGE<>)), Comparison.GreaterOrEqual => CreateCore<CondGE<byte>>(),
Comparison.Less => Create(typeof(CondLT<>)), Comparison.Less => CreateCore<CondLT<byte>>(),
Comparison.LessOrEqual => Create(typeof(CondLE<>)), Comparison.LessOrEqual => CreateCore<CondLE<byte>>(),
Comparison.Equal => Create(typeof(CondEQ<>)), Comparison.Equal => CreateCore<CondEQ<byte>>(),
Comparison.NotEqual => Create(typeof(CondNE<>)), Comparison.NotEqual => CreateCore<CondNE<byte>>(),
_ => throw new TamperCompilationException($"Invalid comparison {comparison} in Atmosphere cheat"), _ => throw new TamperCompilationException($"Invalid comparison {comparison} in Atmosphere cheat"),
}; };
} }
public static Object Create(Type instruction, byte width, params Object[] operands) public static IOperation Create<TOp>(byte width, IOperand destination, IOperand lhs, IOperand rhs) where TOp : IOperation
{ {
Type realType = width switch return width switch
{ {
1 => instruction.MakeGenericType(typeof(byte)), 1 => TOp.CreateFor<byte>(destination, lhs, rhs),
2 => instruction.MakeGenericType(typeof(ushort)), 2 => TOp.CreateFor<ushort>(destination, lhs, rhs),
4 => instruction.MakeGenericType(typeof(uint)), 4 => TOp.CreateFor<uint>(destination, lhs, rhs),
8 => instruction.MakeGenericType(typeof(ulong)), 8 => TOp.CreateFor<ulong>(destination, lhs, rhs),
_ => throw new TamperCompilationException($"Invalid instruction width {width} in Atmosphere cheat"), _ => throw new NotSupportedException(),
}; };
return Activator.CreateInstance(realType, operands);
} }
public static ulong GetImmediate(byte[] instruction, int index, int nybbleCount) public static ulong GetImmediate(byte[] instruction, int index, int nybbleCount)

View File

@@ -1,8 +1,10 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
interface IOperand interface IOperand
{ {
public T Get<T>() where T : unmanaged; public T Get<T>() where T : unmanaged, INumber<T>;
public void Set<T>(T value) where T : unmanaged; public void Set<T>(T value) where T : unmanaged, INumber<T>;
} }
} }

View File

@@ -1,7 +1,13 @@
using System;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
interface IOperation interface IOperation
{ {
void Execute(); void Execute();
static virtual IOperation CreateFor<T>(IOperand destination, IOperand lhs, IOperand rhs) where T : unmanaged, IBinaryInteger<T>
=> throw new NotImplementedException();
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpAdd<T> : IOperation where T : unmanaged class OpAdd<T> : IOperation where T : unmanaged, INumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() + (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() + _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpAdd<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpAnd<T> : IOperation where T : unmanaged class OpAnd<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() & (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() & _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpAnd<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpLog<T> : IOperation where T : unmanaged class OpLog<T> : IOperation where T : unmanaged, INumber<T>
{ {
readonly int _logId; readonly int _logId;
readonly IOperand _source; readonly IOperand _source;
@@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
Logger.Debug?.Print(LogClass.TamperMachine, $"Tamper debug log id={_logId} value={(dynamic)_source.Get<T>():X}"); Logger.Debug?.Print(LogClass.TamperMachine, $"Tamper debug log id={_logId} value={_source.Get<T>():X}");
} }
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpLsh<T> : IOperation where T : unmanaged class OpLsh<T> : IOperation where T : unmanaged, IBinaryInteger<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() << (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() << int.CreateTruncating(_rhs.Get<T>()));
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpLsh<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpMov<T> : IOperation where T : unmanaged class OpMov<T> : IOperation where T : unmanaged, INumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _source; readonly IOperand _source;
@@ -15,5 +17,8 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
_destination.Set(_source.Get<T>()); _destination.Set(_source.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpMov<T1>(destination, lhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpMul<T> : IOperation where T : unmanaged class OpMul<T> : IOperation where T : unmanaged, INumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() * (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() * _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpMul<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpNot<T> : IOperation where T : unmanaged class OpNot<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _source; readonly IOperand _source;
@@ -13,7 +15,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)(~(dynamic)_source.Get<T>())); _destination.Set(~_source.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpNot<T1>(destination, lhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpOr<T> : IOperation where T : unmanaged class OpOr<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() | (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() | _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpOr<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpRsh<T> : IOperation where T : unmanaged class OpRsh<T> : IOperation where T : unmanaged, IBinaryInteger<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() >> (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() >> int.CreateTruncating(_rhs.Get<T>()));
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpRsh<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpSub<T> : IOperation where T : unmanaged class OpSub<T> : IOperation where T : unmanaged, INumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() - (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() - _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpSub<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper.Operations namespace Ryujinx.HLE.HOS.Tamper.Operations
{ {
class OpXor<T> : IOperation where T : unmanaged class OpXor<T> : IOperation where T : unmanaged, IBinaryNumber<T>
{ {
readonly IOperand _destination; readonly IOperand _destination;
readonly IOperand _lhs; readonly IOperand _lhs;
@@ -15,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
public void Execute() public void Execute()
{ {
_destination.Set((T)((dynamic)_lhs.Get<T>() ^ (dynamic)_rhs.Get<T>())); _destination.Set(_lhs.Get<T>() ^ _rhs.Get<T>());
} }
public static IOperation CreateFor<T1>(IOperand destination, IOperand lhs, IOperand rhs) where T1 : unmanaged, IBinaryInteger<T1>
=> new OpXor<T1>(destination, lhs, rhs);
} }
} }

View File

@@ -1,5 +1,6 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ryujinx.HLE.HOS.Tamper namespace Ryujinx.HLE.HOS.Tamper
@@ -15,12 +16,12 @@ namespace Ryujinx.HLE.HOS.Tamper
_process = process; _process = process;
} }
public T Get<T>() where T : unmanaged public T Get<T>() where T : unmanaged, INumber<T>
{ {
return _process.ReadMemory<T>(_position.Get<ulong>()); return _process.ReadMemory<T>(_position.Get<ulong>());
} }
public void Set<T>(T value) where T : unmanaged public void Set<T>(T value) where T : unmanaged, INumber<T>
{ {
ulong position = _position.Get<ulong>(); ulong position = _position.Get<ulong>();

View File

@@ -1,5 +1,6 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper namespace Ryujinx.HLE.HOS.Tamper
{ {
@@ -13,16 +14,16 @@ namespace Ryujinx.HLE.HOS.Tamper
_alias = alias; _alias = alias;
} }
public T Get<T>() where T : unmanaged public T Get<T>() where T : unmanaged, INumber<T>
{ {
return (T)(dynamic)_register; return T.CreateTruncating(_register);
} }
public void Set<T>(T value) where T : unmanaged public void Set<T>(T value) where T : unmanaged, INumber<T>
{ {
Logger.Debug?.Print(LogClass.TamperMachine, $"{_alias}: {value}"); Logger.Debug?.Print(LogClass.TamperMachine, $"{_alias}: {value}");
_register = (ulong)(dynamic)value; _register = ulong.CreateTruncating(value);
} }
} }
} }

View File

@@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.HLE.HOS.Tamper.Operations;
using System.Numerics;
namespace Ryujinx.HLE.HOS.Tamper namespace Ryujinx.HLE.HOS.Tamper
{ {
class Value<TP> : IOperand where TP : unmanaged class Value<TP> : IOperand where TP : unmanaged, INumber<TP>
{ {
private TP _value; private TP _value;
@@ -11,14 +12,14 @@ namespace Ryujinx.HLE.HOS.Tamper
_value = value; _value = value;
} }
public T Get<T>() where T : unmanaged public T Get<T>() where T : unmanaged, INumber<T>
{ {
return (T)(dynamic)_value; return T.CreateTruncating(_value);
} }
public void Set<T>(T value) where T : unmanaged public void Set<T>(T value) where T : unmanaged, INumber<T>
{ {
_value = (TP)(dynamic)value; _value = TP.CreateTruncating(value);
} }
} }
} }