From 62b827f474f0aa2152dd339fcc7cf31084e16a0b Mon Sep 17 00:00:00 2001 From: emmauss Date: Tue, 20 Feb 2018 22:09:23 +0200 Subject: Split main project into core,graphics and chocolarm4 subproject (#29) --- ChocolArm64/ABitUtils.cs | 57 ++ ChocolArm64/AOpCodeTable.cs | 408 ++++++++++++++ ChocolArm64/AOptimizations.cs | 4 + ChocolArm64/AThread.cs | 72 +++ ChocolArm64/ATranslatedSub.cs | 104 ++++ ChocolArm64/ATranslator.cs | 106 ++++ ChocolArm64/ChocolArm64.csproj | 15 + ChocolArm64/Decoder/ABlock.cs | 35 ++ ChocolArm64/Decoder/ACond.cs | 22 + ChocolArm64/Decoder/ADataOp.cs | 10 + ChocolArm64/Decoder/ADecoder.cs | 207 +++++++ ChocolArm64/Decoder/ADecoderHelper.cs | 107 ++++ ChocolArm64/Decoder/AIntType.cs | 14 + ChocolArm64/Decoder/AOpCode.cs | 38 ++ ChocolArm64/Decoder/AOpCodeAdr.cs | 18 + ChocolArm64/Decoder/AOpCodeAlu.cs | 24 + ChocolArm64/Decoder/AOpCodeAluImm.cs | 39 ++ ChocolArm64/Decoder/AOpCodeAluRs.cs | 29 + ChocolArm64/Decoder/AOpCodeAluRx.cs | 19 + ChocolArm64/Decoder/AOpCodeBImm.cs | 11 + ChocolArm64/Decoder/AOpCodeBImmAl.cs | 12 + ChocolArm64/Decoder/AOpCodeBImmCmp.cs | 16 + ChocolArm64/Decoder/AOpCodeBImmCond.cs | 25 + ChocolArm64/Decoder/AOpCodeBImmTest.cs | 20 + ChocolArm64/Decoder/AOpCodeBReg.cs | 24 + ChocolArm64/Decoder/AOpCodeBfm.cs | 29 + ChocolArm64/Decoder/AOpCodeCcmp.cs | 31 ++ ChocolArm64/Decoder/AOpCodeCcmpImm.cs | 11 + ChocolArm64/Decoder/AOpCodeCcmpReg.cs | 15 + ChocolArm64/Decoder/AOpCodeCsel.cs | 17 + ChocolArm64/Decoder/AOpCodeException.cs | 14 + ChocolArm64/Decoder/AOpCodeMem.cs | 19 + ChocolArm64/Decoder/AOpCodeMemEx.cs | 16 + ChocolArm64/Decoder/AOpCodeMemImm.cs | 53 ++ ChocolArm64/Decoder/AOpCodeMemLit.cs | 28 + ChocolArm64/Decoder/AOpCodeMemPair.cs | 25 + ChocolArm64/Decoder/AOpCodeMemReg.cs | 20 + ChocolArm64/Decoder/AOpCodeMov.cs | 36 ++ ChocolArm64/Decoder/AOpCodeMul.cs | 16 + ChocolArm64/Decoder/AOpCodeSimd.cs | 27 + ChocolArm64/Decoder/AOpCodeSimdCvt.cs | 31 ++ ChocolArm64/Decoder/AOpCodeSimdFcond.cs | 17 + ChocolArm64/Decoder/AOpCodeSimdFmov.cs | 33 ++ ChocolArm64/Decoder/AOpCodeSimdImm.cs | 94 ++++ ChocolArm64/Decoder/AOpCodeSimdIns.cs | 36 ++ ChocolArm64/Decoder/AOpCodeSimdMemImm.cs | 19 + ChocolArm64/Decoder/AOpCodeSimdMemLit.cs | 31 ++ ChocolArm64/Decoder/AOpCodeSimdMemMs.cs | 49 ++ ChocolArm64/Decoder/AOpCodeSimdMemPair.cs | 16 + ChocolArm64/Decoder/AOpCodeSimdMemReg.cs | 14 + ChocolArm64/Decoder/AOpCodeSimdMemSs.cs | 97 ++++ ChocolArm64/Decoder/AOpCodeSimdReg.cs | 18 + ChocolArm64/Decoder/AOpCodeSimdRegElem.cs | 22 + ChocolArm64/Decoder/AOpCodeSimdShImm.cs | 16 + ChocolArm64/Decoder/AOpCodeSimdTbl.cs | 12 + ChocolArm64/Decoder/AOpCodeSystem.cs | 24 + ChocolArm64/Decoder/AShiftType.cs | 10 + ChocolArm64/Decoder/IAOpCode.cs | 13 + ChocolArm64/Decoder/IAOpCodeAlu.cs | 10 + ChocolArm64/Decoder/IAOpCodeAluImm.cs | 7 + ChocolArm64/Decoder/IAOpCodeAluRs.cs | 10 + ChocolArm64/Decoder/IAOpCodeAluRx.cs | 10 + ChocolArm64/Decoder/IAOpCodeCond.cs | 7 + ChocolArm64/Decoder/IAOpCodeLit.cs | 11 + ChocolArm64/Decoder/IAOpCodeSimd.cs | 7 + .../Exceptions/VmmAccessViolationException.cs | 14 + ChocolArm64/Exceptions/VmmOutOfMemoryException.cs | 13 + ChocolArm64/Exceptions/VmmPageFaultException.cs | 13 + ChocolArm64/Instruction/AInst.cs | 18 + ChocolArm64/Instruction/AInstEmitAlu.cs | 364 ++++++++++++ ChocolArm64/Instruction/AInstEmitAluHelper.cs | 168 ++++++ ChocolArm64/Instruction/AInstEmitBfm.cs | 217 ++++++++ ChocolArm64/Instruction/AInstEmitCcmp.cs | 81 +++ ChocolArm64/Instruction/AInstEmitCsel.cs | 59 ++ ChocolArm64/Instruction/AInstEmitException.cs | 65 +++ ChocolArm64/Instruction/AInstEmitFlow.cs | 124 +++++ ChocolArm64/Instruction/AInstEmitMemory.cs | 252 +++++++++ ChocolArm64/Instruction/AInstEmitMemoryEx.cs | 180 ++++++ ChocolArm64/Instruction/AInstEmitMemoryHelper.cs | 138 +++++ ChocolArm64/Instruction/AInstEmitMove.cs | 41 ++ ChocolArm64/Instruction/AInstEmitMul.cs | 80 +++ ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs | 367 ++++++++++++ ChocolArm64/Instruction/AInstEmitSimdCmp.cs | 233 ++++++++ ChocolArm64/Instruction/AInstEmitSimdCvt.cs | 444 +++++++++++++++ ChocolArm64/Instruction/AInstEmitSimdHelper.cs | 616 +++++++++++++++++++++ ChocolArm64/Instruction/AInstEmitSimdLogical.cs | 69 +++ ChocolArm64/Instruction/AInstEmitSimdMemory.cs | 184 ++++++ ChocolArm64/Instruction/AInstEmitSimdMove.cs | 333 +++++++++++ ChocolArm64/Instruction/AInstEmitSimdShift.cs | 297 ++++++++++ ChocolArm64/Instruction/AInstEmitSystem.cs | 122 ++++ ChocolArm64/Instruction/AInstEmitter.cs | 6 + ChocolArm64/Instruction/ASoftFallback.cs | 316 +++++++++++ ChocolArm64/Memory/AMemory.cs | 345 ++++++++++++ ChocolArm64/Memory/AMemoryAlloc.cs | 35 ++ ChocolArm64/Memory/AMemoryHelper.cs | 73 +++ ChocolArm64/Memory/AMemoryMapInfo.cs | 21 + ChocolArm64/Memory/AMemoryMgr.cs | 286 ++++++++++ ChocolArm64/Memory/AMemoryPerm.cs | 15 + ChocolArm64/State/AInstExceptEventArgs.cs | 14 + ChocolArm64/State/AInstUndEventArgs.cs | 16 + ChocolArm64/State/APState.cs | 23 + ChocolArm64/State/ARegister.cs | 142 +++++ ChocolArm64/State/ARegisterSize.cs | 10 + ChocolArm64/State/ARegisterType.cs | 9 + ChocolArm64/State/AThreadState.cs | 64 +++ ChocolArm64/State/AVec.cs | 243 ++++++++ ChocolArm64/Translation/AILBlock.cs | 65 +++ ChocolArm64/Translation/AILEmitter.cs | 187 +++++++ ChocolArm64/Translation/AILEmitterCtx.cs | 487 ++++++++++++++++ ChocolArm64/Translation/AILLabel.cs | 28 + ChocolArm64/Translation/AILOpCode.cs | 19 + ChocolArm64/Translation/AILOpCodeBranch.cs | 21 + ChocolArm64/Translation/AILOpCodeCall.cs | 20 + ChocolArm64/Translation/AILOpCodeConst.cs | 81 +++ ChocolArm64/Translation/AILOpCodeLoad.cs | 77 +++ ChocolArm64/Translation/AILOpCodeLog.cs | 17 + ChocolArm64/Translation/AILOpCodeStore.cs | 75 +++ ChocolArm64/Translation/AIoType.cs | 15 + ChocolArm64/Translation/ALocalAlloc.cs | 231 ++++++++ ChocolArm64/Translation/IAILEmit.cs | 7 + ChocolArm64/Translation/ILGeneratorEx.cs | 129 +++++ Ryujinx.Core/Config.cs | 95 ++++ Ryujinx.Core/Hid.cs | 185 +++++++ Ryujinx.Core/Hid/HidController.cs | 188 +++++++ Ryujinx.Core/Hid/HidKeyboard.cs | 33 ++ Ryujinx.Core/Hid/HidMouse.cs | 37 ++ Ryujinx.Core/Hid/HidTouchScreen.cs | 54 ++ Ryujinx.Core/Hid/HidUnknown.cs | 81 +++ Ryujinx.Core/Hid/JoyCon.cs | 66 +++ Ryujinx.Core/Loaders/Compression/Lz4.cs | 78 +++ Ryujinx.Core/Loaders/ElfDyn.cs | 15 + Ryujinx.Core/Loaders/ElfDynTag.cs | 72 +++ Ryujinx.Core/Loaders/ElfRel.cs | 19 + Ryujinx.Core/Loaders/ElfRelType.cs | 128 +++++ Ryujinx.Core/Loaders/ElfSym.cs | 43 ++ Ryujinx.Core/Loaders/ElfSymBinding.cs | 9 + Ryujinx.Core/Loaders/ElfSymType.cs | 13 + Ryujinx.Core/Loaders/ElfSymVisibility.cs | 10 + Ryujinx.Core/Loaders/Executable.cs | 149 +++++ Ryujinx.Core/Loaders/Executables/IExecutable.cs | 17 + Ryujinx.Core/Loaders/Executables/Nro.cs | 62 +++ Ryujinx.Core/Loaders/Executables/Nso.cs | 122 ++++ Ryujinx.Core/Logging.cs | 132 +++++ Ryujinx.Core/OsHle/CondVar.cs | 138 +++++ Ryujinx.Core/OsHle/Display.cs | 12 + .../Exceptions/GuestBrokeExecutionException.cs | 11 + .../Exceptions/UndefinedInstructionException.cs | 13 + Ryujinx.Core/OsHle/FileDesc.cs | 12 + Ryujinx.Core/OsHle/Handles/HDomain.cs | 58 ++ Ryujinx.Core/OsHle/Handles/HEvent.cs | 7 + Ryujinx.Core/OsHle/Handles/HNvMap.cs | 18 + Ryujinx.Core/OsHle/Handles/HSession.cs | 27 + Ryujinx.Core/OsHle/Handles/HSessionObj.cs | 30 + Ryujinx.Core/OsHle/Handles/HSharedMem.cs | 70 +++ Ryujinx.Core/OsHle/Handles/HThread.cs | 21 + Ryujinx.Core/OsHle/Handles/HTransferMem.cs | 21 + Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs | 334 +++++++++++ Ryujinx.Core/OsHle/Horizon.cs | 197 +++++++ Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs | 27 + Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs | 8 + Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs | 90 +++ Ryujinx.Core/OsHle/Ipc/IpcHandler.cs | 277 +++++++++ Ryujinx.Core/OsHle/Ipc/IpcMessage.cs | 231 ++++++++ Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs | 10 + Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs | 26 + Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs | 19 + Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs | 4 + Ryujinx.Core/OsHle/MemoryInfo.cs | 28 + Ryujinx.Core/OsHle/MemoryType.cs | 25 + Ryujinx.Core/OsHle/Mutex.cs | 122 ++++ .../OsHle/Objects/Acc/IManagerForApplication.cs | 33 ++ Ryujinx.Core/OsHle/Objects/Acc/IProfile.cs | 33 ++ .../OsHle/Objects/Am/IApplicationFunctions.cs | 80 +++ Ryujinx.Core/OsHle/Objects/Am/IApplicationProxy.cs | 85 +++ Ryujinx.Core/OsHle/Objects/Am/IAudioController.cs | 20 + .../OsHle/Objects/Am/ICommonStateGetter.cs | 74 +++ Ryujinx.Core/OsHle/Objects/Am/IDebugFunctions.cs | 20 + .../OsHle/Objects/Am/IDisplayController.cs | 20 + .../OsHle/Objects/Am/ILibraryAppletCreator.cs | 20 + .../OsHle/Objects/Am/IParentalControlService.cs | 20 + Ryujinx.Core/OsHle/Objects/Am/ISelfController.cs | 53 ++ Ryujinx.Core/OsHle/Objects/Am/IStorage.cs | 33 ++ Ryujinx.Core/OsHle/Objects/Am/IStorageAccessor.cs | 62 +++ Ryujinx.Core/OsHle/Objects/Am/IWindowController.cs | 33 ++ Ryujinx.Core/OsHle/Objects/Apm/ISession.cs | 28 + Ryujinx.Core/OsHle/Objects/Aud/IAudioOut.cs | 180 ++++++ Ryujinx.Core/OsHle/Objects/Aud/IAudioRenderer.cs | 66 +++ .../OsHle/Objects/Friend/IFriendService.cs | 20 + Ryujinx.Core/OsHle/Objects/FspSrv/IDirectory.cs | 133 +++++ Ryujinx.Core/OsHle/Objects/FspSrv/IFile.cs | 93 ++++ Ryujinx.Core/OsHle/Objects/FspSrv/IFileSystem.cs | 247 +++++++++ Ryujinx.Core/OsHle/Objects/FspSrv/IStorage.cs | 52 ++ Ryujinx.Core/OsHle/Objects/Hid/IAppletResource.cs | 32 ++ Ryujinx.Core/OsHle/Objects/IIpcInterface.cs | 10 + Ryujinx.Core/OsHle/Objects/ObjHelper.cs | 24 + Ryujinx.Core/OsHle/Objects/Parcel.cs | 58 ++ Ryujinx.Core/OsHle/Objects/Time/ISteadyClock.cs | 20 + Ryujinx.Core/OsHle/Objects/Time/ISystemClock.cs | 42 ++ .../OsHle/Objects/Time/ITimeZoneService.cs | 20 + Ryujinx.Core/OsHle/Objects/Time/SystemClockType.cs | 9 + .../OsHle/Objects/Vi/IApplicationDisplayService.cs | 176 ++++++ Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs | 214 +++++++ .../OsHle/Objects/Vi/IManagerDisplayService.cs | 33 ++ .../OsHle/Objects/Vi/ISystemDisplayService.cs | 25 + Ryujinx.Core/OsHle/Process.cs | 257 +++++++++ Ryujinx.Core/OsHle/ServiceCtx.cs | 36 ++ Ryujinx.Core/OsHle/Services/ServiceAcc.cs | 33 ++ Ryujinx.Core/OsHle/Services/ServiceApm.cs | 16 + Ryujinx.Core/OsHle/Services/ServiceAppletOE.cs | 16 + Ryujinx.Core/OsHle/Services/ServiceAud.cs | 71 +++ Ryujinx.Core/OsHle/Services/ServiceFriend.cs | 16 + Ryujinx.Core/OsHle/Services/ServiceFspSrv.cs | 49 ++ Ryujinx.Core/OsHle/Services/ServiceHid.cs | 56 ++ Ryujinx.Core/OsHle/Services/ServiceLm.cs | 12 + Ryujinx.Core/OsHle/Services/ServiceNvDrv.cs | 610 ++++++++++++++++++++ Ryujinx.Core/OsHle/Services/ServicePctl.cs | 16 + Ryujinx.Core/OsHle/Services/ServicePl.cs | 35 ++ Ryujinx.Core/OsHle/Services/ServiceSet.cs | 32 ++ Ryujinx.Core/OsHle/Services/ServiceSm.cs | 48 ++ Ryujinx.Core/OsHle/Services/ServiceTime.cs | 45 ++ Ryujinx.Core/OsHle/Services/ServiceVi.cs | 18 + Ryujinx.Core/OsHle/Svc/SvcHandler.cs | 80 +++ Ryujinx.Core/OsHle/Svc/SvcMemory.cs | 121 ++++ Ryujinx.Core/OsHle/Svc/SvcResult.cs | 11 + Ryujinx.Core/OsHle/Svc/SvcSystem.cs | 227 ++++++++ Ryujinx.Core/OsHle/Svc/SvcThread.cs | 85 +++ Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs | 78 +++ Ryujinx.Core/OsHle/Utilities/IdPool.cs | 53 ++ Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs | 78 +++ Ryujinx.Core/OsHle/Utilities/MemReader.cs | 44 ++ Ryujinx.Core/OsHle/Utilities/MemWriter.cs | 38 ++ Ryujinx.Core/Ryujinx.Core.csproj | 20 + Ryujinx.Core/Switch.cs | 75 +++ Ryujinx.Core/VirtualFs.cs | 70 +++ Ryujinx.Graphics/Gal/GalPrimitiveType.cs | 21 + Ryujinx.Graphics/Gal/GalVertexAttrib.cs | 33 ++ Ryujinx.Graphics/Gal/GalVertexAttribSize.cs | 20 + Ryujinx.Graphics/Gal/GalVertexAttribType.cs | 13 + Ryujinx.Graphics/Gal/IGalRenderer.cs | 17 + Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs | 282 ++++++++++ Ryujinx.Graphics/Gpu/BCn.cs | 468 ++++++++++++++++ Ryujinx.Graphics/Gpu/NsGpu.cs | 53 ++ Ryujinx.Graphics/Gpu/NsGpuEngine.cs | 13 + Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs | 204 +++++++ Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs | 79 +++ Ryujinx.Graphics/Gpu/NsGpuPGraph.cs | 276 +++++++++ Ryujinx.Graphics/Gpu/NsGpuRegister.cs | 93 ++++ Ryujinx.Graphics/Gpu/NsGpuTexture.cs | 10 + Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs | 9 + Ryujinx.Graphics/Gpu/SwizzleAddr.cs | 144 +++++ Ryujinx.Graphics/Ryujinx.Graphics.csproj | 15 + Ryujinx.sln | 24 +- Ryujinx/Config.cs | 95 ---- Ryujinx/Cpu/ABitUtils.cs | 57 -- Ryujinx/Cpu/AOpCodeTable.cs | 408 -------------- Ryujinx/Cpu/AOptimizations.cs | 4 - Ryujinx/Cpu/AThread.cs | 72 --- Ryujinx/Cpu/ATranslatedSub.cs | 104 ---- Ryujinx/Cpu/ATranslator.cs | 106 ---- Ryujinx/Cpu/Decoder/ABlock.cs | 35 -- Ryujinx/Cpu/Decoder/ACond.cs | 22 - Ryujinx/Cpu/Decoder/ADataOp.cs | 10 - Ryujinx/Cpu/Decoder/ADecoder.cs | 207 ------- Ryujinx/Cpu/Decoder/ADecoderHelper.cs | 107 ---- Ryujinx/Cpu/Decoder/AIntType.cs | 14 - Ryujinx/Cpu/Decoder/AOpCode.cs | 38 -- Ryujinx/Cpu/Decoder/AOpCodeAdr.cs | 18 - Ryujinx/Cpu/Decoder/AOpCodeAlu.cs | 24 - Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs | 39 -- Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs | 29 - Ryujinx/Cpu/Decoder/AOpCodeAluRx.cs | 19 - Ryujinx/Cpu/Decoder/AOpCodeBImm.cs | 11 - Ryujinx/Cpu/Decoder/AOpCodeBImmAl.cs | 12 - Ryujinx/Cpu/Decoder/AOpCodeBImmCmp.cs | 16 - Ryujinx/Cpu/Decoder/AOpCodeBImmCond.cs | 25 - Ryujinx/Cpu/Decoder/AOpCodeBImmTest.cs | 20 - Ryujinx/Cpu/Decoder/AOpCodeBReg.cs | 24 - Ryujinx/Cpu/Decoder/AOpCodeBfm.cs | 29 - Ryujinx/Cpu/Decoder/AOpCodeCcmp.cs | 31 -- Ryujinx/Cpu/Decoder/AOpCodeCcmpImm.cs | 11 - Ryujinx/Cpu/Decoder/AOpCodeCcmpReg.cs | 15 - Ryujinx/Cpu/Decoder/AOpCodeCsel.cs | 17 - Ryujinx/Cpu/Decoder/AOpCodeException.cs | 14 - Ryujinx/Cpu/Decoder/AOpCodeMem.cs | 19 - Ryujinx/Cpu/Decoder/AOpCodeMemEx.cs | 16 - Ryujinx/Cpu/Decoder/AOpCodeMemImm.cs | 53 -- Ryujinx/Cpu/Decoder/AOpCodeMemLit.cs | 28 - Ryujinx/Cpu/Decoder/AOpCodeMemPair.cs | 25 - Ryujinx/Cpu/Decoder/AOpCodeMemReg.cs | 20 - Ryujinx/Cpu/Decoder/AOpCodeMov.cs | 36 -- Ryujinx/Cpu/Decoder/AOpCodeMul.cs | 16 - Ryujinx/Cpu/Decoder/AOpCodeSimd.cs | 27 - Ryujinx/Cpu/Decoder/AOpCodeSimdCvt.cs | 31 -- Ryujinx/Cpu/Decoder/AOpCodeSimdFcond.cs | 17 - Ryujinx/Cpu/Decoder/AOpCodeSimdFmov.cs | 33 -- Ryujinx/Cpu/Decoder/AOpCodeSimdImm.cs | 94 ---- Ryujinx/Cpu/Decoder/AOpCodeSimdIns.cs | 36 -- Ryujinx/Cpu/Decoder/AOpCodeSimdMemImm.cs | 19 - Ryujinx/Cpu/Decoder/AOpCodeSimdMemLit.cs | 31 -- Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs | 49 -- Ryujinx/Cpu/Decoder/AOpCodeSimdMemPair.cs | 16 - Ryujinx/Cpu/Decoder/AOpCodeSimdMemReg.cs | 14 - Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs | 97 ---- Ryujinx/Cpu/Decoder/AOpCodeSimdReg.cs | 18 - Ryujinx/Cpu/Decoder/AOpCodeSimdRegElem.cs | 22 - Ryujinx/Cpu/Decoder/AOpCodeSimdShImm.cs | 16 - Ryujinx/Cpu/Decoder/AOpCodeSimdTbl.cs | 12 - Ryujinx/Cpu/Decoder/AOpCodeSystem.cs | 24 - Ryujinx/Cpu/Decoder/AShiftType.cs | 10 - Ryujinx/Cpu/Decoder/IAOpCode.cs | 13 - Ryujinx/Cpu/Decoder/IAOpCodeAlu.cs | 10 - Ryujinx/Cpu/Decoder/IAOpCodeAluImm.cs | 7 - Ryujinx/Cpu/Decoder/IAOpCodeAluRs.cs | 10 - Ryujinx/Cpu/Decoder/IAOpCodeAluRx.cs | 10 - Ryujinx/Cpu/Decoder/IAOpCodeCond.cs | 7 - Ryujinx/Cpu/Decoder/IAOpCodeLit.cs | 11 - Ryujinx/Cpu/Decoder/IAOpCodeSimd.cs | 7 - .../Cpu/Exceptions/VmmAccessViolationException.cs | 14 - Ryujinx/Cpu/Exceptions/VmmOutOfMemoryException.cs | 13 - Ryujinx/Cpu/Exceptions/VmmPageFaultException.cs | 13 - Ryujinx/Cpu/Instruction/AInst.cs | 18 - Ryujinx/Cpu/Instruction/AInstEmitAlu.cs | 364 ------------ Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs | 168 ------ Ryujinx/Cpu/Instruction/AInstEmitBfm.cs | 217 -------- Ryujinx/Cpu/Instruction/AInstEmitCcmp.cs | 81 --- Ryujinx/Cpu/Instruction/AInstEmitCsel.cs | 59 -- Ryujinx/Cpu/Instruction/AInstEmitException.cs | 65 --- Ryujinx/Cpu/Instruction/AInstEmitFlow.cs | 124 ----- Ryujinx/Cpu/Instruction/AInstEmitMemory.cs | 252 --------- Ryujinx/Cpu/Instruction/AInstEmitMemoryEx.cs | 180 ------ Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs | 138 ----- Ryujinx/Cpu/Instruction/AInstEmitMove.cs | 41 -- Ryujinx/Cpu/Instruction/AInstEmitMul.cs | 80 --- Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs | 367 ------------ Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs | 233 -------- Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs | 444 --------------- Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs | 616 --------------------- Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs | 69 --- Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs | 184 ------ Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs | 333 ----------- Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs | 297 ---------- Ryujinx/Cpu/Instruction/AInstEmitSystem.cs | 122 ---- Ryujinx/Cpu/Instruction/AInstEmitter.cs | 6 - Ryujinx/Cpu/Instruction/ASoftFallback.cs | 316 ----------- Ryujinx/Cpu/Memory/AMemory.cs | 345 ------------ Ryujinx/Cpu/Memory/AMemoryAlloc.cs | 35 -- Ryujinx/Cpu/Memory/AMemoryHelper.cs | 73 --- Ryujinx/Cpu/Memory/AMemoryMapInfo.cs | 21 - Ryujinx/Cpu/Memory/AMemoryMgr.cs | 286 ---------- Ryujinx/Cpu/Memory/AMemoryPerm.cs | 15 - Ryujinx/Cpu/State/AInstExceptEventArgs.cs | 14 - Ryujinx/Cpu/State/AInstUndEventArgs.cs | 16 - Ryujinx/Cpu/State/APState.cs | 23 - Ryujinx/Cpu/State/ARegister.cs | 142 ----- Ryujinx/Cpu/State/ARegisterSize.cs | 10 - Ryujinx/Cpu/State/ARegisterType.cs | 9 - Ryujinx/Cpu/State/AThreadState.cs | 64 --- Ryujinx/Cpu/State/AVec.cs | 243 -------- Ryujinx/Cpu/Translation/AILBlock.cs | 65 --- Ryujinx/Cpu/Translation/AILEmitter.cs | 187 ------- Ryujinx/Cpu/Translation/AILEmitterCtx.cs | 487 ---------------- Ryujinx/Cpu/Translation/AILLabel.cs | 28 - Ryujinx/Cpu/Translation/AILOpCode.cs | 19 - Ryujinx/Cpu/Translation/AILOpCodeBranch.cs | 21 - Ryujinx/Cpu/Translation/AILOpCodeCall.cs | 20 - Ryujinx/Cpu/Translation/AILOpCodeConst.cs | 81 --- Ryujinx/Cpu/Translation/AILOpCodeLoad.cs | 77 --- Ryujinx/Cpu/Translation/AILOpCodeLog.cs | 17 - Ryujinx/Cpu/Translation/AILOpCodeStore.cs | 75 --- Ryujinx/Cpu/Translation/AIoType.cs | 15 - Ryujinx/Cpu/Translation/ALocalAlloc.cs | 231 -------- Ryujinx/Cpu/Translation/IAILEmit.cs | 7 - Ryujinx/Cpu/Translation/ILGeneratorEx.cs | 129 ----- Ryujinx/Gal/GalPrimitiveType.cs | 21 - Ryujinx/Gal/GalVertexAttrib.cs | 33 -- Ryujinx/Gal/GalVertexAttribSize.cs | 20 - Ryujinx/Gal/GalVertexAttribType.cs | 13 - Ryujinx/Gal/IGalRenderer.cs | 17 - Ryujinx/Gal/OpenGL/OpenGLRenderer.cs | 282 ---------- Ryujinx/Gpu/BCn.cs | 468 ---------------- Ryujinx/Gpu/NsGpu.cs | 22 - Ryujinx/Gpu/NsGpuEngine.cs | 13 - Ryujinx/Gpu/NsGpuMemoryMgr.cs | 204 ------- Ryujinx/Gpu/NsGpuPBEntry.cs | 79 --- Ryujinx/Gpu/NsGpuPGraph.cs | 276 --------- Ryujinx/Gpu/NsGpuRegister.cs | 93 ---- Ryujinx/Gpu/NsGpuTexture.cs | 10 - Ryujinx/Gpu/NsGpuTextureFormat.cs | 9 - Ryujinx/Gpu/SwizzleAddr.cs | 144 ----- Ryujinx/Hid.cs | 185 ------- Ryujinx/Hid/HidController.cs | 188 ------- Ryujinx/Hid/HidKeyboard.cs | 33 -- Ryujinx/Hid/HidMouse.cs | 37 -- Ryujinx/Hid/HidTouchScreen.cs | 54 -- Ryujinx/Hid/HidUnknown.cs | 81 --- Ryujinx/Hid/JoyCon.cs | 66 --- Ryujinx/Loaders/Compression/Lz4.cs | 78 --- Ryujinx/Loaders/ElfDyn.cs | 15 - Ryujinx/Loaders/ElfDynTag.cs | 72 --- Ryujinx/Loaders/ElfRel.cs | 19 - Ryujinx/Loaders/ElfRelType.cs | 128 ----- Ryujinx/Loaders/ElfSym.cs | 43 -- Ryujinx/Loaders/ElfSymBinding.cs | 9 - Ryujinx/Loaders/ElfSymType.cs | 13 - Ryujinx/Loaders/ElfSymVisibility.cs | 10 - Ryujinx/Loaders/Executable.cs | 149 ----- Ryujinx/Loaders/Executables/IExecutable.cs | 17 - Ryujinx/Loaders/Executables/Nro.cs | 62 --- Ryujinx/Loaders/Executables/Nso.cs | 122 ---- Ryujinx/Logging.cs | 132 ----- Ryujinx/OsHle/CondVar.cs | 138 ----- Ryujinx/OsHle/Display.cs | 12 - .../Exceptions/GuestBrokeExecutionException.cs | 11 - .../Exceptions/UndefinedInstructionException.cs | 13 - Ryujinx/OsHle/FileDesc.cs | 12 - Ryujinx/OsHle/Handles/HDomain.cs | 58 -- Ryujinx/OsHle/Handles/HEvent.cs | 7 - Ryujinx/OsHle/Handles/HNvMap.cs | 18 - Ryujinx/OsHle/Handles/HSession.cs | 27 - Ryujinx/OsHle/Handles/HSessionObj.cs | 30 - Ryujinx/OsHle/Handles/HSharedMem.cs | 70 --- Ryujinx/OsHle/Handles/HThread.cs | 21 - Ryujinx/OsHle/Handles/HTransferMem.cs | 21 - Ryujinx/OsHle/Handles/KProcessScheduler.cs | 334 ----------- Ryujinx/OsHle/Horizon.cs | 197 ------- Ryujinx/OsHle/Ipc/IpcBuffDesc.cs | 27 - Ryujinx/OsHle/Ipc/IpcDomCmd.cs | 8 - Ryujinx/OsHle/Ipc/IpcHandleDesc.cs | 90 --- Ryujinx/OsHle/Ipc/IpcHandler.cs | 277 --------- Ryujinx/OsHle/Ipc/IpcMessage.cs | 231 -------- Ryujinx/OsHle/Ipc/IpcMessageType.cs | 10 - Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs | 26 - Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs | 19 - Ryujinx/OsHle/Ipc/ServiceProcessRequest.cs | 4 - Ryujinx/OsHle/MemoryInfo.cs | 28 - Ryujinx/OsHle/MemoryType.cs | 25 - Ryujinx/OsHle/Mutex.cs | 122 ---- .../OsHle/Objects/Acc/IManagerForApplication.cs | 33 -- Ryujinx/OsHle/Objects/Acc/IProfile.cs | 33 -- Ryujinx/OsHle/Objects/Am/IApplicationFunctions.cs | 80 --- Ryujinx/OsHle/Objects/Am/IApplicationProxy.cs | 85 --- Ryujinx/OsHle/Objects/Am/IAudioController.cs | 20 - Ryujinx/OsHle/Objects/Am/ICommonStateGetter.cs | 74 --- Ryujinx/OsHle/Objects/Am/IDebugFunctions.cs | 20 - Ryujinx/OsHle/Objects/Am/IDisplayController.cs | 20 - Ryujinx/OsHle/Objects/Am/ILibraryAppletCreator.cs | 20 - .../OsHle/Objects/Am/IParentalControlService.cs | 20 - Ryujinx/OsHle/Objects/Am/ISelfController.cs | 53 -- Ryujinx/OsHle/Objects/Am/IStorage.cs | 33 -- Ryujinx/OsHle/Objects/Am/IStorageAccessor.cs | 62 --- Ryujinx/OsHle/Objects/Am/IWindowController.cs | 33 -- Ryujinx/OsHle/Objects/Apm/ISession.cs | 28 - Ryujinx/OsHle/Objects/Aud/IAudioOut.cs | 180 ------ Ryujinx/OsHle/Objects/Aud/IAudioRenderer.cs | 66 --- Ryujinx/OsHle/Objects/Friend/IFriendService.cs | 20 - Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs | 133 ----- Ryujinx/OsHle/Objects/FspSrv/IFile.cs | 93 ---- Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs | 247 --------- Ryujinx/OsHle/Objects/FspSrv/IStorage.cs | 52 -- Ryujinx/OsHle/Objects/Hid/IAppletResource.cs | 32 -- Ryujinx/OsHle/Objects/IIpcInterface.cs | 10 - Ryujinx/OsHle/Objects/ObjHelper.cs | 24 - Ryujinx/OsHle/Objects/Parcel.cs | 58 -- Ryujinx/OsHle/Objects/Time/ISteadyClock.cs | 20 - Ryujinx/OsHle/Objects/Time/ISystemClock.cs | 42 -- Ryujinx/OsHle/Objects/Time/ITimeZoneService.cs | 20 - Ryujinx/OsHle/Objects/Time/SystemClockType.cs | 9 - .../OsHle/Objects/Vi/IApplicationDisplayService.cs | 176 ------ Ryujinx/OsHle/Objects/Vi/IHOSBinderDriver.cs | 214 ------- Ryujinx/OsHle/Objects/Vi/IManagerDisplayService.cs | 33 -- Ryujinx/OsHle/Objects/Vi/ISystemDisplayService.cs | 25 - Ryujinx/OsHle/Process.cs | 257 --------- Ryujinx/OsHle/ServiceCtx.cs | 36 -- Ryujinx/OsHle/Services/ServiceAcc.cs | 33 -- Ryujinx/OsHle/Services/ServiceApm.cs | 16 - Ryujinx/OsHle/Services/ServiceAppletOE.cs | 16 - Ryujinx/OsHle/Services/ServiceAud.cs | 71 --- Ryujinx/OsHle/Services/ServiceFriend.cs | 16 - Ryujinx/OsHle/Services/ServiceFspSrv.cs | 49 -- Ryujinx/OsHle/Services/ServiceHid.cs | 56 -- Ryujinx/OsHle/Services/ServiceLm.cs | 12 - Ryujinx/OsHle/Services/ServiceNvDrv.cs | 610 -------------------- Ryujinx/OsHle/Services/ServicePctl.cs | 16 - Ryujinx/OsHle/Services/ServicePl.cs | 35 -- Ryujinx/OsHle/Services/ServiceSet.cs | 32 -- Ryujinx/OsHle/Services/ServiceSm.cs | 48 -- Ryujinx/OsHle/Services/ServiceTime.cs | 45 -- Ryujinx/OsHle/Services/ServiceVi.cs | 18 - Ryujinx/OsHle/Svc/SvcHandler.cs | 80 --- Ryujinx/OsHle/Svc/SvcMemory.cs | 121 ---- Ryujinx/OsHle/Svc/SvcResult.cs | 11 - Ryujinx/OsHle/Svc/SvcSystem.cs | 227 -------- Ryujinx/OsHle/Svc/SvcThread.cs | 85 --- Ryujinx/OsHle/Svc/SvcThreadSync.cs | 78 --- Ryujinx/OsHle/Utilities/IdPool.cs | 53 -- Ryujinx/OsHle/Utilities/IdPoolWithObj.cs | 78 --- Ryujinx/OsHle/Utilities/MemReader.cs | 44 -- Ryujinx/OsHle/Utilities/MemWriter.cs | 38 -- Ryujinx/Ryujinx.csproj | 5 + Ryujinx/Switch.cs | 51 -- Ryujinx/Ui/GLScreen.cs | 5 +- Ryujinx/Ui/Program.cs | 13 +- Ryujinx/VirtualFs.cs | 70 --- 503 files changed, 19620 insertions(+), 19490 deletions(-) create mode 100644 ChocolArm64/ABitUtils.cs create mode 100644 ChocolArm64/AOpCodeTable.cs create mode 100644 ChocolArm64/AOptimizations.cs create mode 100644 ChocolArm64/AThread.cs create mode 100644 ChocolArm64/ATranslatedSub.cs create mode 100644 ChocolArm64/ATranslator.cs create mode 100644 ChocolArm64/ChocolArm64.csproj create mode 100644 ChocolArm64/Decoder/ABlock.cs create mode 100644 ChocolArm64/Decoder/ACond.cs create mode 100644 ChocolArm64/Decoder/ADataOp.cs create mode 100644 ChocolArm64/Decoder/ADecoder.cs create mode 100644 ChocolArm64/Decoder/ADecoderHelper.cs create mode 100644 ChocolArm64/Decoder/AIntType.cs create mode 100644 ChocolArm64/Decoder/AOpCode.cs create mode 100644 ChocolArm64/Decoder/AOpCodeAdr.cs create mode 100644 ChocolArm64/Decoder/AOpCodeAlu.cs create mode 100644 ChocolArm64/Decoder/AOpCodeAluImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeAluRs.cs create mode 100644 ChocolArm64/Decoder/AOpCodeAluRx.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBImmAl.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBImmCmp.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBImmCond.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBImmTest.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBReg.cs create mode 100644 ChocolArm64/Decoder/AOpCodeBfm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeCcmp.cs create mode 100644 ChocolArm64/Decoder/AOpCodeCcmpImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeCcmpReg.cs create mode 100644 ChocolArm64/Decoder/AOpCodeCsel.cs create mode 100644 ChocolArm64/Decoder/AOpCodeException.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMem.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMemEx.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMemImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMemLit.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMemPair.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMemReg.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMov.cs create mode 100644 ChocolArm64/Decoder/AOpCodeMul.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimd.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdCvt.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdFcond.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdFmov.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdIns.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemLit.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemMs.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemPair.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemReg.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdMemSs.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdReg.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdRegElem.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdShImm.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSimdTbl.cs create mode 100644 ChocolArm64/Decoder/AOpCodeSystem.cs create mode 100644 ChocolArm64/Decoder/AShiftType.cs create mode 100644 ChocolArm64/Decoder/IAOpCode.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeAlu.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeAluImm.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeAluRs.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeAluRx.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeCond.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeLit.cs create mode 100644 ChocolArm64/Decoder/IAOpCodeSimd.cs create mode 100644 ChocolArm64/Exceptions/VmmAccessViolationException.cs create mode 100644 ChocolArm64/Exceptions/VmmOutOfMemoryException.cs create mode 100644 ChocolArm64/Exceptions/VmmPageFaultException.cs create mode 100644 ChocolArm64/Instruction/AInst.cs create mode 100644 ChocolArm64/Instruction/AInstEmitAlu.cs create mode 100644 ChocolArm64/Instruction/AInstEmitAluHelper.cs create mode 100644 ChocolArm64/Instruction/AInstEmitBfm.cs create mode 100644 ChocolArm64/Instruction/AInstEmitCcmp.cs create mode 100644 ChocolArm64/Instruction/AInstEmitCsel.cs create mode 100644 ChocolArm64/Instruction/AInstEmitException.cs create mode 100644 ChocolArm64/Instruction/AInstEmitFlow.cs create mode 100644 ChocolArm64/Instruction/AInstEmitMemory.cs create mode 100644 ChocolArm64/Instruction/AInstEmitMemoryEx.cs create mode 100644 ChocolArm64/Instruction/AInstEmitMemoryHelper.cs create mode 100644 ChocolArm64/Instruction/AInstEmitMove.cs create mode 100644 ChocolArm64/Instruction/AInstEmitMul.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdCmp.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdCvt.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdHelper.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdLogical.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdMemory.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdMove.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSimdShift.cs create mode 100644 ChocolArm64/Instruction/AInstEmitSystem.cs create mode 100644 ChocolArm64/Instruction/AInstEmitter.cs create mode 100644 ChocolArm64/Instruction/ASoftFallback.cs create mode 100644 ChocolArm64/Memory/AMemory.cs create mode 100644 ChocolArm64/Memory/AMemoryAlloc.cs create mode 100644 ChocolArm64/Memory/AMemoryHelper.cs create mode 100644 ChocolArm64/Memory/AMemoryMapInfo.cs create mode 100644 ChocolArm64/Memory/AMemoryMgr.cs create mode 100644 ChocolArm64/Memory/AMemoryPerm.cs create mode 100644 ChocolArm64/State/AInstExceptEventArgs.cs create mode 100644 ChocolArm64/State/AInstUndEventArgs.cs create mode 100644 ChocolArm64/State/APState.cs create mode 100644 ChocolArm64/State/ARegister.cs create mode 100644 ChocolArm64/State/ARegisterSize.cs create mode 100644 ChocolArm64/State/ARegisterType.cs create mode 100644 ChocolArm64/State/AThreadState.cs create mode 100644 ChocolArm64/State/AVec.cs create mode 100644 ChocolArm64/Translation/AILBlock.cs create mode 100644 ChocolArm64/Translation/AILEmitter.cs create mode 100644 ChocolArm64/Translation/AILEmitterCtx.cs create mode 100644 ChocolArm64/Translation/AILLabel.cs create mode 100644 ChocolArm64/Translation/AILOpCode.cs create mode 100644 ChocolArm64/Translation/AILOpCodeBranch.cs create mode 100644 ChocolArm64/Translation/AILOpCodeCall.cs create mode 100644 ChocolArm64/Translation/AILOpCodeConst.cs create mode 100644 ChocolArm64/Translation/AILOpCodeLoad.cs create mode 100644 ChocolArm64/Translation/AILOpCodeLog.cs create mode 100644 ChocolArm64/Translation/AILOpCodeStore.cs create mode 100644 ChocolArm64/Translation/AIoType.cs create mode 100644 ChocolArm64/Translation/ALocalAlloc.cs create mode 100644 ChocolArm64/Translation/IAILEmit.cs create mode 100644 ChocolArm64/Translation/ILGeneratorEx.cs create mode 100644 Ryujinx.Core/Config.cs create mode 100644 Ryujinx.Core/Hid.cs create mode 100644 Ryujinx.Core/Hid/HidController.cs create mode 100644 Ryujinx.Core/Hid/HidKeyboard.cs create mode 100644 Ryujinx.Core/Hid/HidMouse.cs create mode 100644 Ryujinx.Core/Hid/HidTouchScreen.cs create mode 100644 Ryujinx.Core/Hid/HidUnknown.cs create mode 100644 Ryujinx.Core/Hid/JoyCon.cs create mode 100644 Ryujinx.Core/Loaders/Compression/Lz4.cs create mode 100644 Ryujinx.Core/Loaders/ElfDyn.cs create mode 100644 Ryujinx.Core/Loaders/ElfDynTag.cs create mode 100644 Ryujinx.Core/Loaders/ElfRel.cs create mode 100644 Ryujinx.Core/Loaders/ElfRelType.cs create mode 100644 Ryujinx.Core/Loaders/ElfSym.cs create mode 100644 Ryujinx.Core/Loaders/ElfSymBinding.cs create mode 100644 Ryujinx.Core/Loaders/ElfSymType.cs create mode 100644 Ryujinx.Core/Loaders/ElfSymVisibility.cs create mode 100644 Ryujinx.Core/Loaders/Executable.cs create mode 100644 Ryujinx.Core/Loaders/Executables/IExecutable.cs create mode 100644 Ryujinx.Core/Loaders/Executables/Nro.cs create mode 100644 Ryujinx.Core/Loaders/Executables/Nso.cs create mode 100644 Ryujinx.Core/Logging.cs create mode 100644 Ryujinx.Core/OsHle/CondVar.cs create mode 100644 Ryujinx.Core/OsHle/Display.cs create mode 100644 Ryujinx.Core/OsHle/Exceptions/GuestBrokeExecutionException.cs create mode 100644 Ryujinx.Core/OsHle/Exceptions/UndefinedInstructionException.cs create mode 100644 Ryujinx.Core/OsHle/FileDesc.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HDomain.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HEvent.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HNvMap.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HSession.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HSessionObj.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HSharedMem.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HThread.cs create mode 100644 Ryujinx.Core/OsHle/Handles/HTransferMem.cs create mode 100644 Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs create mode 100644 Ryujinx.Core/OsHle/Horizon.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcHandler.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcMessage.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs create mode 100644 Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs create mode 100644 Ryujinx.Core/OsHle/MemoryInfo.cs create mode 100644 Ryujinx.Core/OsHle/MemoryType.cs create mode 100644 Ryujinx.Core/OsHle/Mutex.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Acc/IManagerForApplication.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Acc/IProfile.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IApplicationFunctions.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IApplicationProxy.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IAudioController.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/ICommonStateGetter.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IDebugFunctions.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IDisplayController.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/ILibraryAppletCreator.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IParentalControlService.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/ISelfController.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IStorage.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IStorageAccessor.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Am/IWindowController.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Apm/ISession.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Aud/IAudioOut.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Aud/IAudioRenderer.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Friend/IFriendService.cs create mode 100644 Ryujinx.Core/OsHle/Objects/FspSrv/IDirectory.cs create mode 100644 Ryujinx.Core/OsHle/Objects/FspSrv/IFile.cs create mode 100644 Ryujinx.Core/OsHle/Objects/FspSrv/IFileSystem.cs create mode 100644 Ryujinx.Core/OsHle/Objects/FspSrv/IStorage.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Hid/IAppletResource.cs create mode 100644 Ryujinx.Core/OsHle/Objects/IIpcInterface.cs create mode 100644 Ryujinx.Core/OsHle/Objects/ObjHelper.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Parcel.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Time/ISteadyClock.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Time/ISystemClock.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Time/ITimeZoneService.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Time/SystemClockType.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Vi/IApplicationDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Vi/IManagerDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Objects/Vi/ISystemDisplayService.cs create mode 100644 Ryujinx.Core/OsHle/Process.cs create mode 100644 Ryujinx.Core/OsHle/ServiceCtx.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceAcc.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceApm.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceAppletOE.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceAud.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceFriend.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceFspSrv.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceHid.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceLm.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceNvDrv.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServicePctl.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServicePl.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceSet.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceSm.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceTime.cs create mode 100644 Ryujinx.Core/OsHle/Services/ServiceVi.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcHandler.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcMemory.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcResult.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcSystem.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcThread.cs create mode 100644 Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs create mode 100644 Ryujinx.Core/OsHle/Utilities/IdPool.cs create mode 100644 Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs create mode 100644 Ryujinx.Core/OsHle/Utilities/MemReader.cs create mode 100644 Ryujinx.Core/OsHle/Utilities/MemWriter.cs create mode 100644 Ryujinx.Core/Ryujinx.Core.csproj create mode 100644 Ryujinx.Core/Switch.cs create mode 100644 Ryujinx.Core/VirtualFs.cs create mode 100644 Ryujinx.Graphics/Gal/GalPrimitiveType.cs create mode 100644 Ryujinx.Graphics/Gal/GalVertexAttrib.cs create mode 100644 Ryujinx.Graphics/Gal/GalVertexAttribSize.cs create mode 100644 Ryujinx.Graphics/Gal/GalVertexAttribType.cs create mode 100644 Ryujinx.Graphics/Gal/IGalRenderer.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs create mode 100644 Ryujinx.Graphics/Gpu/BCn.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpu.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuEngine.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuPGraph.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuRegister.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuTexture.cs create mode 100644 Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs create mode 100644 Ryujinx.Graphics/Gpu/SwizzleAddr.cs create mode 100644 Ryujinx.Graphics/Ryujinx.Graphics.csproj delete mode 100644 Ryujinx/Config.cs delete mode 100644 Ryujinx/Cpu/ABitUtils.cs delete mode 100644 Ryujinx/Cpu/AOpCodeTable.cs delete mode 100644 Ryujinx/Cpu/AOptimizations.cs delete mode 100644 Ryujinx/Cpu/AThread.cs delete mode 100644 Ryujinx/Cpu/ATranslatedSub.cs delete mode 100644 Ryujinx/Cpu/ATranslator.cs delete mode 100644 Ryujinx/Cpu/Decoder/ABlock.cs delete mode 100644 Ryujinx/Cpu/Decoder/ACond.cs delete mode 100644 Ryujinx/Cpu/Decoder/ADataOp.cs delete mode 100644 Ryujinx/Cpu/Decoder/ADecoder.cs delete mode 100644 Ryujinx/Cpu/Decoder/ADecoderHelper.cs delete mode 100644 Ryujinx/Cpu/Decoder/AIntType.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCode.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeAdr.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeAlu.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeAluRx.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBImmAl.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBImmCmp.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBImmCond.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBImmTest.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBReg.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeBfm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeCcmp.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeCcmpImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeCcmpReg.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeCsel.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeException.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMem.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMemEx.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMemImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMemLit.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMemPair.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMemReg.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMov.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeMul.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimd.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdCvt.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdFcond.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdFmov.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdIns.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemLit.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemPair.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemReg.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdReg.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdRegElem.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdShImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSimdTbl.cs delete mode 100644 Ryujinx/Cpu/Decoder/AOpCodeSystem.cs delete mode 100644 Ryujinx/Cpu/Decoder/AShiftType.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCode.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeAlu.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeAluImm.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeAluRs.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeAluRx.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeCond.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeLit.cs delete mode 100644 Ryujinx/Cpu/Decoder/IAOpCodeSimd.cs delete mode 100644 Ryujinx/Cpu/Exceptions/VmmAccessViolationException.cs delete mode 100644 Ryujinx/Cpu/Exceptions/VmmOutOfMemoryException.cs delete mode 100644 Ryujinx/Cpu/Exceptions/VmmPageFaultException.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInst.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitAlu.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitBfm.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitCcmp.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitCsel.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitException.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitFlow.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitMemory.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitMemoryEx.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitMove.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitMul.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitSystem.cs delete mode 100644 Ryujinx/Cpu/Instruction/AInstEmitter.cs delete mode 100644 Ryujinx/Cpu/Instruction/ASoftFallback.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemory.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemoryAlloc.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemoryHelper.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemoryMapInfo.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemoryMgr.cs delete mode 100644 Ryujinx/Cpu/Memory/AMemoryPerm.cs delete mode 100644 Ryujinx/Cpu/State/AInstExceptEventArgs.cs delete mode 100644 Ryujinx/Cpu/State/AInstUndEventArgs.cs delete mode 100644 Ryujinx/Cpu/State/APState.cs delete mode 100644 Ryujinx/Cpu/State/ARegister.cs delete mode 100644 Ryujinx/Cpu/State/ARegisterSize.cs delete mode 100644 Ryujinx/Cpu/State/ARegisterType.cs delete mode 100644 Ryujinx/Cpu/State/AThreadState.cs delete mode 100644 Ryujinx/Cpu/State/AVec.cs delete mode 100644 Ryujinx/Cpu/Translation/AILBlock.cs delete mode 100644 Ryujinx/Cpu/Translation/AILEmitter.cs delete mode 100644 Ryujinx/Cpu/Translation/AILEmitterCtx.cs delete mode 100644 Ryujinx/Cpu/Translation/AILLabel.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCode.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeBranch.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeCall.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeConst.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeLoad.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeLog.cs delete mode 100644 Ryujinx/Cpu/Translation/AILOpCodeStore.cs delete mode 100644 Ryujinx/Cpu/Translation/AIoType.cs delete mode 100644 Ryujinx/Cpu/Translation/ALocalAlloc.cs delete mode 100644 Ryujinx/Cpu/Translation/IAILEmit.cs delete mode 100644 Ryujinx/Cpu/Translation/ILGeneratorEx.cs delete mode 100644 Ryujinx/Gal/GalPrimitiveType.cs delete mode 100644 Ryujinx/Gal/GalVertexAttrib.cs delete mode 100644 Ryujinx/Gal/GalVertexAttribSize.cs delete mode 100644 Ryujinx/Gal/GalVertexAttribType.cs delete mode 100644 Ryujinx/Gal/IGalRenderer.cs delete mode 100644 Ryujinx/Gal/OpenGL/OpenGLRenderer.cs delete mode 100644 Ryujinx/Gpu/BCn.cs delete mode 100644 Ryujinx/Gpu/NsGpu.cs delete mode 100644 Ryujinx/Gpu/NsGpuEngine.cs delete mode 100644 Ryujinx/Gpu/NsGpuMemoryMgr.cs delete mode 100644 Ryujinx/Gpu/NsGpuPBEntry.cs delete mode 100644 Ryujinx/Gpu/NsGpuPGraph.cs delete mode 100644 Ryujinx/Gpu/NsGpuRegister.cs delete mode 100644 Ryujinx/Gpu/NsGpuTexture.cs delete mode 100644 Ryujinx/Gpu/NsGpuTextureFormat.cs delete mode 100644 Ryujinx/Gpu/SwizzleAddr.cs delete mode 100644 Ryujinx/Hid.cs delete mode 100644 Ryujinx/Hid/HidController.cs delete mode 100644 Ryujinx/Hid/HidKeyboard.cs delete mode 100644 Ryujinx/Hid/HidMouse.cs delete mode 100644 Ryujinx/Hid/HidTouchScreen.cs delete mode 100644 Ryujinx/Hid/HidUnknown.cs delete mode 100644 Ryujinx/Hid/JoyCon.cs delete mode 100644 Ryujinx/Loaders/Compression/Lz4.cs delete mode 100644 Ryujinx/Loaders/ElfDyn.cs delete mode 100644 Ryujinx/Loaders/ElfDynTag.cs delete mode 100644 Ryujinx/Loaders/ElfRel.cs delete mode 100644 Ryujinx/Loaders/ElfRelType.cs delete mode 100644 Ryujinx/Loaders/ElfSym.cs delete mode 100644 Ryujinx/Loaders/ElfSymBinding.cs delete mode 100644 Ryujinx/Loaders/ElfSymType.cs delete mode 100644 Ryujinx/Loaders/ElfSymVisibility.cs delete mode 100644 Ryujinx/Loaders/Executable.cs delete mode 100644 Ryujinx/Loaders/Executables/IExecutable.cs delete mode 100644 Ryujinx/Loaders/Executables/Nro.cs delete mode 100644 Ryujinx/Loaders/Executables/Nso.cs delete mode 100644 Ryujinx/Logging.cs delete mode 100644 Ryujinx/OsHle/CondVar.cs delete mode 100644 Ryujinx/OsHle/Display.cs delete mode 100644 Ryujinx/OsHle/Exceptions/GuestBrokeExecutionException.cs delete mode 100644 Ryujinx/OsHle/Exceptions/UndefinedInstructionException.cs delete mode 100644 Ryujinx/OsHle/FileDesc.cs delete mode 100644 Ryujinx/OsHle/Handles/HDomain.cs delete mode 100644 Ryujinx/OsHle/Handles/HEvent.cs delete mode 100644 Ryujinx/OsHle/Handles/HNvMap.cs delete mode 100644 Ryujinx/OsHle/Handles/HSession.cs delete mode 100644 Ryujinx/OsHle/Handles/HSessionObj.cs delete mode 100644 Ryujinx/OsHle/Handles/HSharedMem.cs delete mode 100644 Ryujinx/OsHle/Handles/HThread.cs delete mode 100644 Ryujinx/OsHle/Handles/HTransferMem.cs delete mode 100644 Ryujinx/OsHle/Handles/KProcessScheduler.cs delete mode 100644 Ryujinx/OsHle/Horizon.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcBuffDesc.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcDomCmd.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcHandleDesc.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcHandler.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcMessage.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcMessageType.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs delete mode 100644 Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs delete mode 100644 Ryujinx/OsHle/Ipc/ServiceProcessRequest.cs delete mode 100644 Ryujinx/OsHle/MemoryInfo.cs delete mode 100644 Ryujinx/OsHle/MemoryType.cs delete mode 100644 Ryujinx/OsHle/Mutex.cs delete mode 100644 Ryujinx/OsHle/Objects/Acc/IManagerForApplication.cs delete mode 100644 Ryujinx/OsHle/Objects/Acc/IProfile.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IApplicationFunctions.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IApplicationProxy.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IAudioController.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/ICommonStateGetter.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IDebugFunctions.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IDisplayController.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/ILibraryAppletCreator.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IParentalControlService.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/ISelfController.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IStorage.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IStorageAccessor.cs delete mode 100644 Ryujinx/OsHle/Objects/Am/IWindowController.cs delete mode 100644 Ryujinx/OsHle/Objects/Apm/ISession.cs delete mode 100644 Ryujinx/OsHle/Objects/Aud/IAudioOut.cs delete mode 100644 Ryujinx/OsHle/Objects/Aud/IAudioRenderer.cs delete mode 100644 Ryujinx/OsHle/Objects/Friend/IFriendService.cs delete mode 100644 Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs delete mode 100644 Ryujinx/OsHle/Objects/FspSrv/IFile.cs delete mode 100644 Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs delete mode 100644 Ryujinx/OsHle/Objects/FspSrv/IStorage.cs delete mode 100644 Ryujinx/OsHle/Objects/Hid/IAppletResource.cs delete mode 100644 Ryujinx/OsHle/Objects/IIpcInterface.cs delete mode 100644 Ryujinx/OsHle/Objects/ObjHelper.cs delete mode 100644 Ryujinx/OsHle/Objects/Parcel.cs delete mode 100644 Ryujinx/OsHle/Objects/Time/ISteadyClock.cs delete mode 100644 Ryujinx/OsHle/Objects/Time/ISystemClock.cs delete mode 100644 Ryujinx/OsHle/Objects/Time/ITimeZoneService.cs delete mode 100644 Ryujinx/OsHle/Objects/Time/SystemClockType.cs delete mode 100644 Ryujinx/OsHle/Objects/Vi/IApplicationDisplayService.cs delete mode 100644 Ryujinx/OsHle/Objects/Vi/IHOSBinderDriver.cs delete mode 100644 Ryujinx/OsHle/Objects/Vi/IManagerDisplayService.cs delete mode 100644 Ryujinx/OsHle/Objects/Vi/ISystemDisplayService.cs delete mode 100644 Ryujinx/OsHle/Process.cs delete mode 100644 Ryujinx/OsHle/ServiceCtx.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceAcc.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceApm.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceAppletOE.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceAud.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceFriend.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceFspSrv.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceHid.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceLm.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceNvDrv.cs delete mode 100644 Ryujinx/OsHle/Services/ServicePctl.cs delete mode 100644 Ryujinx/OsHle/Services/ServicePl.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceSet.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceSm.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceTime.cs delete mode 100644 Ryujinx/OsHle/Services/ServiceVi.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcHandler.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcMemory.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcResult.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcSystem.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcThread.cs delete mode 100644 Ryujinx/OsHle/Svc/SvcThreadSync.cs delete mode 100644 Ryujinx/OsHle/Utilities/IdPool.cs delete mode 100644 Ryujinx/OsHle/Utilities/IdPoolWithObj.cs delete mode 100644 Ryujinx/OsHle/Utilities/MemReader.cs delete mode 100644 Ryujinx/OsHle/Utilities/MemWriter.cs delete mode 100644 Ryujinx/Switch.cs delete mode 100644 Ryujinx/VirtualFs.cs diff --git a/ChocolArm64/ABitUtils.cs b/ChocolArm64/ABitUtils.cs new file mode 100644 index 00000000..357dd45d --- /dev/null +++ b/ChocolArm64/ABitUtils.cs @@ -0,0 +1,57 @@ +namespace ChocolArm64 +{ + static class ABitUtils + { + public static int CountBitsSet(long Value) + { + int Count = 0; + + for (int Bit = 0; Bit < 64; Bit++) + { + Count += (int)(Value >> Bit) & 1; + } + + return Count; + } + + public static int HighestBitSet32(int Value) + { + for (int Bit = 31; Bit >= 0; Bit--) + { + if (((Value >> Bit) & 1) != 0) + { + return Bit; + } + } + + return -1; + } + + public static long Replicate(long Bits, int Size) + { + long Output = 0; + + for (int Bit = 0; Bit < 64; Bit += Size) + { + Output |= Bits << Bit; + } + + return Output; + } + + public static long FillWithOnes(int Bits) + { + return Bits == 64 ? -1L : (1L << Bits) - 1; + } + + public static long RotateRight(long Bits, int Shift, int Size) + { + return (Bits >> Shift) | (Bits << (Size - Shift)); + } + + public static bool IsPow2(int Value) + { + return Value != 0 && (Value & (Value - 1)) == 0; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs new file mode 100644 index 00000000..ff2796b8 --- /dev/null +++ b/ChocolArm64/AOpCodeTable.cs @@ -0,0 +1,408 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Instruction; +using System; + +namespace ChocolArm64 +{ + static class AOpCodeTable + { + static AOpCodeTable() + { + #region "OpCode Table" + //Integer + Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs)); + Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm)); + Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs)); + Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx)); + Set("x01100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluImm)); + Set("x0101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRs)); + Set("x0101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRx)); + Set("0xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adr, typeof(AOpCodeAdr)); + Set("1xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adrp, typeof(AOpCodeAdr)); + Set("x00100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.And, typeof(AOpCodeAluImm)); + Set("x0001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.And, typeof(AOpCodeAluRs)); + Set("x11100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ands, typeof(AOpCodeAluImm)); + Set("x1101010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ands, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx001010xxxxxxxxxx", AInstEmit.Asrv, typeof(AOpCodeAluRs)); + Set("000101xxxxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.B, typeof(AOpCodeBImmAl)); + Set("01010100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.B_Cond, typeof(AOpCodeBImmCond)); + Set("x01100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bfm, typeof(AOpCodeBfm)); + Set("x0001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bic, typeof(AOpCodeAluRs)); + Set("x1101010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bics, typeof(AOpCodeAluRs)); + Set("100101xxxxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bl, typeof(AOpCodeBImmAl)); + Set("11010110001xxxxx000000xxxxxxxxxx", AInstEmit.Blr, typeof(AOpCodeBReg)); + Set("11010110000xxxxx000000xxxxxxxxxx", AInstEmit.Br, typeof(AOpCodeBReg)); + Set("11010100001xxxxxxxxxxxxxxxx00000", AInstEmit.Brk, typeof(AOpCodeException)); + Set("x0110101xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Cbnz, typeof(AOpCodeBImmCmp)); + Set("x0110100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Cbz, typeof(AOpCodeBImmCmp)); + Set("x0111010010xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ccmn, typeof(AOpCodeCcmpImm)); + Set("x0111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmn, typeof(AOpCodeCcmpReg)); + Set("x1111010010xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpImm)); + Set("x1111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpReg)); + Set("11010101000000110011xxxx01011111", AInstEmit.Clrex, typeof(AOpCodeSystem)); + Set("x101101011000000000100xxxxxxxxxx", AInstEmit.Clz, typeof(AOpCodeAlu)); + Set("x0011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csel, typeof(AOpCodeCsel)); + Set("x0011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csinc, typeof(AOpCodeCsel)); + Set("x1011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csinv, typeof(AOpCodeCsel)); + Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel)); + Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem)); + Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem)); + Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs)); + Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm)); + Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs)); + Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs)); + Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx)); + Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx)); + Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx)); + Set("<<10100xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp, typeof(AOpCodeMemPair)); + Set("xx111000010xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm)); + Set("xx11100101xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm)); + Set("xx111000011xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemReg)); + Set("xx011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeMemLit)); + Set("0x1110001x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); + Set("0x1110011xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); + Set("10111000100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); + Set("1011100110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); + Set("0x1110001x1xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemReg)); + Set("10111000101xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemReg)); + Set("xx001000010xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Ldxr, typeof(AOpCodeMemEx)); + Set("1x001000011xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Ldxp, typeof(AOpCodeMemEx)); + Set("x0011010110xxxxx001000xxxxxxxxxx", AInstEmit.Lslv, typeof(AOpCodeAluRs)); + Set("x0011010110xxxxx001001xxxxxxxxxx", AInstEmit.Lsrv, typeof(AOpCodeAluRs)); + Set("x0011011000xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Madd, typeof(AOpCodeMul)); + Set("x11100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movk, typeof(AOpCodeMov)); + Set("x00100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movn, typeof(AOpCodeMov)); + Set("x10100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movz, typeof(AOpCodeMov)); + Set("110101010011xxxxxxxxxxxxxxxxxxxx", AInstEmit.Mrs, typeof(AOpCodeSystem)); + Set("110101010001xxxxxxxxxxxxxxxxxxxx", AInstEmit.Msr, typeof(AOpCodeSystem)); + Set("x0011011000xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Msub, typeof(AOpCodeMul)); + Set("11010101000000110010000000011111", AInstEmit.Nop, typeof(AOpCodeSystem)); + Set("x0101010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orn, typeof(AOpCodeAluRs)); + Set("x01100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluImm)); + Set("x0101010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluRs)); + Set("1111100110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemImm)); + Set("11011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemLit)); + Set("x101101011000000000000xxxxxxxxxx", AInstEmit.Rbit, typeof(AOpCodeAlu)); + Set("11010110010xxxxx000000xxxxxxxxxx", AInstEmit.Ret, typeof(AOpCodeBReg)); + Set("x101101011000000000001xxxxxxxxxx", AInstEmit.Rev16, typeof(AOpCodeAlu)); + Set("x101101011000000000010xxxxxxxxxx", AInstEmit.Rev32, typeof(AOpCodeAlu)); + Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu)); + Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs)); + Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs)); + Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm)); + Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs)); + Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul)); + Set("10011011001xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Smsubl, typeof(AOpCodeMul)); + Set("10011011010xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smulh, typeof(AOpCodeMul)); + Set("xx001000100xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlr, typeof(AOpCodeMemEx)); + Set("1x001000001xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlxp, typeof(AOpCodeMemEx)); + Set("xx001000000xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlxr, typeof(AOpCodeMemEx)); + Set("x010100xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeMemPair)); + Set("xx111000000xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemImm)); + Set("xx11100100xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemImm)); + Set("xx111000001xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemReg)); + Set("1x001000001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxp, typeof(AOpCodeMemEx)); + Set("xx001000000xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxr, typeof(AOpCodeMemEx)); + Set("x10100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluImm)); + Set("x1001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRs)); + Set("x1001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRx)); + Set("x11100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluImm)); + Set("x1101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRs)); + Set("x1101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRx)); + Set("11010100000xxxxxxxxxxxxxxxx00001", AInstEmit.Svc, typeof(AOpCodeException)); + Set("1101010100001xxxxxxxxxxxxxxxxxxx", AInstEmit.Sys, typeof(AOpCodeSystem)); + Set("x0110111xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Tbnz, typeof(AOpCodeBImmTest)); + Set("x0110110xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Tbz, typeof(AOpCodeBImmTest)); + Set("x10100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ubfm, typeof(AOpCodeBfm)); + Set("x0011010110xxxxx000010xxxxxxxxxx", AInstEmit.Udiv, typeof(AOpCodeAluRs)); + Set("10011011101xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Umaddl, typeof(AOpCodeMul)); + Set("10011011101xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Umsubl, typeof(AOpCodeMul)); + Set("10011011110xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Umulh, typeof(AOpCodeMul)); + + //Vector + Set("0>001110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Add_V, typeof(AOpCodeSimdReg)); + Set("01011110xx110001101110xxxxxxxxxx", AInstEmit.Addp_S, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg)); + Set("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); + Set("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); + Set("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg)); + Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg)); + Set("0x10111100000xxx<101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<100000100010xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimd)); + Set("0>001110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<100000100010xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimd)); + Set("0>101110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmhi_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg)); + Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd)); + Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd)); + Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd)); + Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns)); + Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns)); + Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns)); + Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg)); + Set("00011110xx100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd)); + Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg)); + Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond)); + Set("00011110xx1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond)); + Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond)); + Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd)); + Set("x0011110xx100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt)); + Set("0>0011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd)); + Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm)); + Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt)); + Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt)); + Set("0>1011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd)); + Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm)); + Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg)); + Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg)); + Set("00011111xx0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg)); + Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg)); + Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg)); + Set("0x0011111<1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg)); + Set("0x0011111<0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg)); + Set("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp, typeof(AOpCodeSimdIns)); + Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns)); + Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x001100110xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x00110101000000xx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs)); + Set("0x001101110xxxxxxx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs)); + Set("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp, typeof(AOpCodeSimdMemPair)); + Set("xx111100x10xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); + Set("xx111100x10xxxxxxxxx01xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); + Set("xx111100x10xxxxxxxxx11xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); + Set("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); + Set("xx111100x11xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemReg)); + Set("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeSimdMemLit)); + Set("0x001110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg)); + Set("0x101110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mls_V, typeof(AOpCodeSimdReg)); + Set("0x00111100000xxx0xx001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); + Set("0x00111100000xxx10x001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); + Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); + Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); + Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg)); + Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); + Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); + Set("0x10111100000xxx110x01xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); + Set("0>101110<<100000101110xxxxxxxxxx", AInstEmit.Neg_V, typeof(AOpCodeSimdReg)); + Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd)); + Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg)); + Set("0x00111100000xxx<>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm)); + Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm)); + Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm)); + Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg)); + Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg)); + Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm)); + Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm)); + Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm)); + Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); + Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); + Set("0x001101100xxxxxxx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); + Set("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeSimdMemPair)); + Set("xx111100x00xxxxxxxxx00xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); + Set("xx111100x00xxxxxxxxx01xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); + Set("xx111100x00xxxxxxxxx11xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); + Set("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); + Set("xx111100x01xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemReg)); + Set("01111110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_S, typeof(AOpCodeSimdReg)); + Set("0>101110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V, typeof(AOpCodeSimdReg)); + Set("0x001110000xxxxx0xx000xxxxxxxxxx", AInstEmit.Tbl_V, typeof(AOpCodeSimdTbl)); + Set("001011100x110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); + Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); + Set("0x101110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Uaddw_V, typeof(AOpCodeSimdReg)); + Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt)); + Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd)); + Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd)); + Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); + Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); + Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm)); + Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm)); + Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm)); + Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm)); + Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg)); + Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg)); + Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd)); + Set("0x001110xx0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg)); + Set("0x001110xx0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg)); +#endregion + } + + private class TreeNode + { + public int Mask; + public int Value; + + public TreeNode Next; + public TreeNode Child; + + public AInst Inst; + + public TreeNode(int Mask, int Value, AInst Inst) + { + this.Mask = Mask; + this.Value = Value; + this.Inst = Inst; + } + } + + private static TreeNode Root; + + private static void Set(string Encoding, AInstEmitter Emitter, Type Type) + { + Set(Encoding, new AInst(Emitter, Type)); + } + + private static void Set(string Encoding, AInst Inst) + { + int Bit = Encoding.Length - 1; + int Value = 0; + int XMask = 0; + int ZCount = 0; + int OCount = 0; + + int[] ZPos = new int[Encoding.Length]; + int[] OPos = new int[Encoding.Length]; + + for (int Index = 0; Index < Encoding.Length; Index++, Bit--) + { + //Note: < and > are used on special encodings. + //The < means that we should never have ALL bits with the '<' set. + //So, when the encoding has <<, it means that 00, 01, and 10 are valid, + //but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on... + //For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid, + //but 00 isn't. + switch (Encoding[Index]) + { + case '0': /* Do nothing. */ break; + case '1': Value |= 1 << Bit; break; + case 'x': XMask |= 1 << Bit; break; + + case '<': OPos[OCount++] = Bit; break; + case '>': ZPos[ZCount++] = Bit; break; + + default: throw new ArgumentException(nameof(Encoding)); + } + } + + if (ZCount + OCount == 0) + { + InsertTop(XMask, Value, Inst); + } + else if (ZCount != 0 && OCount != 0) + { + //When both the > and the < are used, then a value is blacklisted, + //with > indicating 0, and < indicating 1. So, for example, ><< + //blacklists the pattern 011, but 000, 001, 010, 100, 101, + //110 and 111 are valid. + for (int OCtr = 0; (uint)OCtr < (1 << OCount); OCtr++) + { + int OVal = Value; + + for (int O = 0; O < OCount; O++) + { + OVal |= ((OCtr >> O) & 1) << OPos[O]; + } + + int ZStart = OCtr == (1 << OCount) ? 1 : 0; + + InsertWithCtr(ZStart, 1 << ZCount, ZCount, ZPos, XMask, OVal, Inst); + } + } + else if (ZCount != 0) + { + InsertWithCtr(1, 1 << ZCount, ZCount, ZPos, XMask, Value, Inst); + } + else if (OCount != 0) + { + InsertWithCtr(0, (1 << OCount) - 1, OCount, OPos, XMask, Value, Inst); + } + } + + private static void InsertWithCtr( + int Start, + int End, + int Cnt, + int[] Pos, + int XMask, + int Value, + AInst Inst) + { + for (int Ctr = Start; (uint)Ctr < End; Ctr++) + { + int Val = Value; + + for (int Index = 0; Index < Cnt; Index++) + { + Val |= ((Ctr >> Index) & 1) << Pos[Index]; + } + + InsertTop(XMask, Val, Inst); + } + } + + private static void InsertTop(int XMask, int Value, AInst Inst) + { + TreeNode Next = Root; + + Root = new TreeNode(~XMask, Value, Inst); + + Root.Next = Next; + } + + public static AInst GetInst(int OpCode) + { + TreeNode Node = Root; + + do + { + if ((OpCode & Node.Mask) == Node.Value) + { + return Node.Inst; + } + } + while ((Node = Node.Next) != null); + + return AInst.Undefined; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/AOptimizations.cs b/ChocolArm64/AOptimizations.cs new file mode 100644 index 00000000..cbfd1ce5 --- /dev/null +++ b/ChocolArm64/AOptimizations.cs @@ -0,0 +1,4 @@ +public static class AOptimizations +{ + +} \ No newline at end of file diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs new file mode 100644 index 00000000..5c032289 --- /dev/null +++ b/ChocolArm64/AThread.cs @@ -0,0 +1,72 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using System; +using System.Threading; + +namespace ChocolArm64 +{ + public class AThread + { + public AThreadState ThreadState { get; private set; } + public AMemory Memory { get; private set; } + + public long EntryPoint { get; private set; } + + private ATranslator Translator; + + private ThreadPriority Priority; + + private Thread Work; + + public event EventHandler WorkFinished; + + public int ThreadId => ThreadState.ThreadId; + + public bool IsAlive => Work.IsAlive; + + private bool IsExecuting; + + private object ExecuteLock; + + public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint) + { + this.Memory = Memory; + this.Priority = Priority; + this.EntryPoint = EntryPoint; + + ThreadState = new AThreadState(); + Translator = new ATranslator(this); + ExecuteLock = new object(); + } + + public void StopExecution() => Translator.StopExecution(); + + public bool Execute() + { + lock (ExecuteLock) + { + if (IsExecuting) + { + return false; + } + + IsExecuting = true; + } + + Work = new Thread(delegate() + { + Translator.ExecuteSubroutine(EntryPoint); + + Memory.RemoveMonitor(ThreadId); + + WorkFinished?.Invoke(this, EventArgs.Empty); + }); + + Work.Priority = Priority; + + Work.Start(); + + return true; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/ATranslatedSub.cs b/ChocolArm64/ATranslatedSub.cs new file mode 100644 index 00000000..71a6793a --- /dev/null +++ b/ChocolArm64/ATranslatedSub.cs @@ -0,0 +1,104 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace ChocolArm64 +{ + class ATranslatedSub + { + private delegate long AA64Subroutine(AThreadState Register, AMemory Memory); + + private AA64Subroutine ExecDelegate; + + private bool HasDelegate; + + public static Type[] FixedArgTypes { get; private set; } + + public static int StateArgIdx { get; private set; } + public static int MemoryArgIdx { get; private set; } + + public DynamicMethod Method { get; private set; } + + public HashSet SubCalls { get; private set; } + + public List Params { get; private set; } + + public bool NeedsReJit { get; private set; } + + public ATranslatedSub() + { + SubCalls = new HashSet(); + } + + public ATranslatedSub(DynamicMethod Method, List Params) : this() + { + if (Params == null) + { + throw new ArgumentNullException(nameof(Params)); + } + + this.Method = Method; + this.Params = Params; + } + + static ATranslatedSub() + { + MethodInfo MthdInfo = typeof(AA64Subroutine).GetMethod("Invoke"); + + ParameterInfo[] Params = MthdInfo.GetParameters(); + + FixedArgTypes = new Type[Params.Length]; + + for (int Index = 0; Index < Params.Length; Index++) + { + Type ParamType = Params[Index].ParameterType; + + FixedArgTypes[Index] = ParamType; + + if (ParamType == typeof(AThreadState)) + { + StateArgIdx = Index; + } + else if (ParamType == typeof(AMemory)) + { + MemoryArgIdx = Index; + } + } + } + + public long Execute(AThreadState ThreadState, AMemory Memory) + { + if (!HasDelegate) + { + string Name = $"{Method.Name}_Dispatch"; + + DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes); + + ILGenerator Generator = Mthd.GetILGenerator(); + + Generator.EmitLdargSeq(FixedArgTypes.Length); + + foreach (ARegister Reg in Params) + { + Generator.EmitLdarg(StateArgIdx); + + Generator.Emit(OpCodes.Ldfld, Reg.GetField()); + } + + Generator.Emit(OpCodes.Call, Method); + Generator.Emit(OpCodes.Ret); + + ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine)); + + HasDelegate = true; + } + + return ExecDelegate(ThreadState, Memory); + } + + public void MarkForReJit() => NeedsReJit = true; + } +} \ No newline at end of file diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs new file mode 100644 index 00000000..96bbc89e --- /dev/null +++ b/ChocolArm64/ATranslator.cs @@ -0,0 +1,106 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Instruction; +using ChocolArm64.Translation; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace ChocolArm64 +{ + class ATranslator + { + public AThread Thread { get; private set; } + + private Dictionary CachedSubs; + + private bool KeepRunning; + + public ATranslator(AThread Parent) + { + this.Thread = Parent; + + CachedSubs = new Dictionary(); + + KeepRunning = true; + } + + public void StopExecution() => KeepRunning = false; + + public void ExecuteSubroutine(long Position) + { + do + { + if (CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) && !Sub.NeedsReJit) + { + Position = Sub.Execute(Thread.ThreadState, Thread.Memory); + } + else + { + Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory); + } + } + while (Position != 0 && KeepRunning); + } + + public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) + { + if (OpCode.Emitter != AInstEmit.Bl) + { + Sub = null; + + return false; + } + + return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub); + } + + public bool TryGetCachedSub(long Position, out ATranslatedSub Sub) + { + return CachedSubs.TryGetValue(Position, out Sub); + } + + public bool HasCachedSub(long Position) + { + return CachedSubs.ContainsKey(Position); + } + + private ATranslatedSub TranslateSubroutine(long Position) + { + (ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Position); + + AILEmitterCtx Context = new AILEmitterCtx( + this, + Cfg.Graph, + Cfg.Root); + + if (Context.CurrBlock.Position != Position) + { + Context.Emit(OpCodes.Br, Context.GetLabel(Position)); + } + + do + { + Context.EmitOpCode(); + } + while (Context.AdvanceOpCode()); + + //Mark all methods that calls this method for ReJiting, + //since we can now call it directly which is faster. + foreach (ATranslatedSub TS in CachedSubs.Values) + { + if (TS.SubCalls.Contains(Position)) + { + TS.MarkForReJit(); + } + } + + ATranslatedSub Subroutine = Context.GetSubroutine(); + + if (!CachedSubs.TryAdd(Position, Subroutine)) + { + CachedSubs[Position] = Subroutine; + } + + return Subroutine; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/ChocolArm64.csproj b/ChocolArm64/ChocolArm64.csproj new file mode 100644 index 00000000..47d66cf1 --- /dev/null +++ b/ChocolArm64/ChocolArm64.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.0 + + + + true + + + + true + + + diff --git a/ChocolArm64/Decoder/ABlock.cs b/ChocolArm64/Decoder/ABlock.cs new file mode 100644 index 00000000..32974c1a --- /dev/null +++ b/ChocolArm64/Decoder/ABlock.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace ChocolArm64.Decoder +{ + class ABlock + { + public long Position { get; set; } + public long EndPosition { get; set; } + + public ABlock Next { get; set; } + public ABlock Branch { get; set; } + + public List OpCodes { get; private set; } + + public ABlock() + { + OpCodes = new List(); + } + + public ABlock(long Position) : this() + { + this.Position = Position; + } + + public AOpCode GetLastOp() + { + if (OpCodes.Count > 0) + { + return OpCodes[OpCodes.Count - 1]; + } + + return null; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/ACond.cs b/ChocolArm64/Decoder/ACond.cs new file mode 100644 index 00000000..f2da8bd2 --- /dev/null +++ b/ChocolArm64/Decoder/ACond.cs @@ -0,0 +1,22 @@ +namespace ChocolArm64.Decoder +{ + enum ACond + { + Eq = 0, + Ne = 1, + Ge_Un = 2, + Lt_Un = 3, + Mi = 4, + Pl = 5, + Vs = 6, + Vc = 7, + Gt_Un = 8, + Le_Un = 9, + Ge = 10, + Lt = 11, + Gt = 12, + Le = 13, + Al = 14, + Nv = 15 + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/ADataOp.cs b/ChocolArm64/Decoder/ADataOp.cs new file mode 100644 index 00000000..a5601a3a --- /dev/null +++ b/ChocolArm64/Decoder/ADataOp.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoder +{ + enum ADataOp + { + Adr = 0, + Arithmetic = 1, + Logical = 2, + BitField = 3 + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs new file mode 100644 index 00000000..06a535c1 --- /dev/null +++ b/ChocolArm64/Decoder/ADecoder.cs @@ -0,0 +1,207 @@ +using ChocolArm64.Instruction; +using ChocolArm64.Memory; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace ChocolArm64.Decoder +{ + static class ADecoder + { + public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start) + { + Dictionary Visited = new Dictionary(); + Dictionary VisitedEnd = new Dictionary(); + + Queue Blocks = new Queue(); + + ABlock Enqueue(long Position) + { + if (!Visited.TryGetValue(Position, out ABlock Output)) + { + Output = new ABlock(Position); + + Blocks.Enqueue(Output); + + Visited.Add(Position, Output); + } + + return Output; + } + + ABlock Root = Enqueue(Start); + + while (Blocks.Count > 0) + { + ABlock Current = Blocks.Dequeue(); + + FillBlock(Translator.Thread.Memory, Current); + + //Set child blocks. "Branch" is the block the branch instruction + //points to (when taken), "Next" is the block at the next address, + //executed when the branch is not taken. For Unconditional Branches + //(except BL/BLR that are sub calls) or end of executable, Next is null. + if (Current.OpCodes.Count > 0) + { + bool HasCachedSub = false; + + AOpCode LastOp = Current.GetLastOp(); + + if (LastOp is AOpCodeBImm Op) + { + if (Op.Emitter == AInstEmit.Bl) + { + HasCachedSub = Translator.HasCachedSub(Op.Imm); + } + else + { + Current.Branch = Enqueue(Op.Imm); + } + } + + if ((!(LastOp is AOpCodeBImmAl) && + !(LastOp is AOpCodeBReg)) || HasCachedSub) + { + Current.Next = Enqueue(Current.EndPosition); + } + } + + //If we have on the tree two blocks with the same end position, + //then we need to split the bigger block and have two small blocks, + //the end position of the bigger "Current" block should then be == to + //the position of the "Smaller" block. + while (VisitedEnd.TryGetValue(Current.EndPosition, out ABlock Smaller)) + { + if (Current.Position > Smaller.Position) + { + ABlock Temp = Smaller; + + Smaller = Current; + Current = Temp; + } + + Current.EndPosition = Smaller.Position; + Current.Next = Smaller; + Current.Branch = null; + + Current.OpCodes.RemoveRange( + Current.OpCodes.Count - Smaller.OpCodes.Count, + Smaller.OpCodes.Count); + + VisitedEnd[Smaller.EndPosition] = Smaller; + } + + VisitedEnd.Add(Current.EndPosition, Current); + } + + //Make and sort Graph blocks array by position. + ABlock[] Graph = new ABlock[Visited.Count]; + + while (Visited.Count > 0) + { + ulong FirstPos = ulong.MaxValue; + + foreach (ABlock Block in Visited.Values) + { + if (FirstPos > (ulong)Block.Position) + FirstPos = (ulong)Block.Position; + } + + ABlock Current = Visited[(long)FirstPos]; + + do + { + Graph[Graph.Length - Visited.Count] = Current; + + Visited.Remove(Current.Position); + + Current = Current.Next; + } + while (Current != null); + } + + return (Graph, Root); + } + + private static void FillBlock(AMemory Memory, ABlock Block) + { + long Position = Block.Position; + + AOpCode OpCode; + + do + { + OpCode = DecodeOpCode(Memory, Position); + + Block.OpCodes.Add(OpCode); + + Position += 4; + } + while (!(IsBranch(OpCode) || IsException(OpCode))); + + Block.EndPosition = Position; + } + + private static bool IsBranch(AOpCode OpCode) + { + return OpCode is AOpCodeBImm || + OpCode is AOpCodeBReg; + } + + private static bool IsException(AOpCode OpCode) + { + return OpCode.Emitter == AInstEmit.Brk || + OpCode.Emitter == AInstEmit.Svc || + OpCode.Emitter == AInstEmit.Und; + } + + public static AOpCode DecodeOpCode(AMemory Memory, long Position) + { + int OpCode = Memory.ReadInt32(Position); + + AInst Inst = AOpCodeTable.GetInst(OpCode); + + AOpCode DecodedOpCode = new AOpCode(AInst.Undefined, Position, OpCode); + + if (Inst.Type != null) + { + DecodedOpCode = CreateOpCode(Inst.Type, Inst, Position, OpCode); + } + + return DecodedOpCode; + } + + private delegate object OpActivator(AInst Inst, long Position, int OpCode); + + private static Dictionary Activators = new Dictionary(); + + private static AOpCode CreateOpCode(Type Type, AInst Inst, long Position, int OpCode) + { + if (Type == null) + { + throw new ArgumentNullException(nameof(Type)); + } + + if (!Activators.TryGetValue(Type, out OpActivator CreateInstance)) + { + Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) }; + + DynamicMethod Mthd = new DynamicMethod($"{Type.Name}_Create", Type, ArgTypes); + + ILGenerator Generator = Mthd.GetILGenerator(); + + Generator.Emit(OpCodes.Ldarg_0); + Generator.Emit(OpCodes.Ldarg_1); + Generator.Emit(OpCodes.Ldarg_2); + Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes)); + Generator.Emit(OpCodes.Ret); + + CreateInstance = (OpActivator)Mthd.CreateDelegate(typeof(OpActivator)); + + Activators.Add(Type, CreateInstance); + } + + return (AOpCode)CreateInstance(Inst, Position, OpCode); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/ADecoderHelper.cs b/ChocolArm64/Decoder/ADecoderHelper.cs new file mode 100644 index 00000000..a2179f49 --- /dev/null +++ b/ChocolArm64/Decoder/ADecoderHelper.cs @@ -0,0 +1,107 @@ +using System; + +namespace ChocolArm64.Decoder +{ + static class ADecoderHelper + { + public struct BitMask + { + public long WMask; + public long TMask; + public int Pos; + public int Shift; + public bool IsUndefined; + + public static BitMask Invalid => new BitMask { IsUndefined = true }; + } + + public static BitMask DecodeBitMask(int OpCode, bool Immediate) + { + int ImmS = (OpCode >> 10) & 0x3f; + int ImmR = (OpCode >> 16) & 0x3f; + + int N = (OpCode >> 22) & 1; + int SF = (OpCode >> 31) & 1; + + int Length = ABitUtils.HighestBitSet32((~ImmS & 0x3f) | (N << 6)); + + if (Length < 1 || (SF == 0 && N != 0)) + { + return BitMask.Invalid; + } + + int Size = 1 << Length; + + int Levels = Size - 1; + + int S = ImmS & Levels; + int R = ImmR & Levels; + + if (Immediate && S == Levels) + { + return BitMask.Invalid; + } + + long WMask = ABitUtils.FillWithOnes(S + 1); + long TMask = ABitUtils.FillWithOnes(((S - R) & Levels) + 1); + + if (R > 0) + { + WMask = ABitUtils.RotateRight(WMask, R, Size); + WMask &= ABitUtils.FillWithOnes(Size); + } + + return new BitMask() + { + WMask = ABitUtils.Replicate(WMask, Size), + TMask = ABitUtils.Replicate(TMask, Size), + + Pos = ImmS, + Shift = ImmR + }; + } + + public static long DecodeImm8Float(long Imm, int Size) + { + int E = 0, F = 0; + + switch (Size) + { + case 0: E = 8; F = 23; break; + case 1: E = 11; F = 52; break; + + default: throw new ArgumentOutOfRangeException(nameof(Size)); + } + + long Value = (Imm & 0x3f) << F - 4; + + long EBit = (Imm >> 6) & 1; + long SBit = (Imm >> 7) & 1; + + if (EBit != 0) + { + Value |= (1L << E - 3) - 1 << F + 2; + } + + Value |= (EBit ^ 1) << F + E - 1; + Value |= SBit << F + E; + + return Value; + } + + public static long DecodeImm26_2(int OpCode) + { + return ((long)OpCode << 38) >> 36; + } + + public static long DecodeImmS19_2(int OpCode) + { + return (((long)OpCode << 40) >> 43) & ~3; + } + + public static long DecodeImmS14_2(int OpCode) + { + return (((long)OpCode << 45) >> 48) & ~3; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AIntType.cs b/ChocolArm64/Decoder/AIntType.cs new file mode 100644 index 00000000..242fdada --- /dev/null +++ b/ChocolArm64/Decoder/AIntType.cs @@ -0,0 +1,14 @@ +namespace ChocolArm64.Decoder +{ + enum AIntType + { + UInt8 = 0, + UInt16 = 1, + UInt32 = 2, + UInt64 = 3, + Int8 = 4, + Int16 = 5, + Int32 = 6, + Int64 = 7 + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCode.cs b/ChocolArm64/Decoder/AOpCode.cs new file mode 100644 index 00000000..5d127593 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCode.cs @@ -0,0 +1,38 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; +using System; + +namespace ChocolArm64.Decoder +{ + class AOpCode : IAOpCode + { + public long Position { get; private set; } + public int RawOpCode { get; private set; } + + public AInstEmitter Emitter { get; protected set; } + public ARegisterSize RegisterSize { get; protected set; } + + public AOpCode(AInst Inst, long Position, int OpCode) + { + this.Position = Position; + this.RawOpCode = OpCode; + + RegisterSize = ARegisterSize.Int64; + + Emitter = Inst.Emitter; + } + + public int GetBitsCount() + { + switch (RegisterSize) + { + case ARegisterSize.Int32: return 32; + case ARegisterSize.Int64: return 64; + case ARegisterSize.SIMD64: return 64; + case ARegisterSize.SIMD128: return 128; + } + + throw new InvalidOperationException(); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeAdr.cs b/ChocolArm64/Decoder/AOpCodeAdr.cs new file mode 100644 index 00000000..3396281f --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeAdr.cs @@ -0,0 +1,18 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeAdr : AOpCode + { + public int Rd { get; private set; } + public long Imm { get; private set; } + + public AOpCodeAdr(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rd = OpCode & 0x1f; + + Imm = ADecoderHelper.DecodeImmS19_2(OpCode); + Imm |= ((long)OpCode >> 29) & 3; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeAlu.cs b/ChocolArm64/Decoder/AOpCodeAlu.cs new file mode 100644 index 00000000..e1a44f04 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeAlu.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeAlu : AOpCode, IAOpCodeAlu + { + public int Rd { get; protected set; } + public int Rn { get; private set; } + + public ADataOp DataOp { get; private set; } + + public AOpCodeAlu(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rd = (OpCode >> 0) & 0x1f; + Rn = (OpCode >> 5) & 0x1f; + DataOp = (ADataOp)((OpCode >> 24) & 0x3); + + RegisterSize = (OpCode >> 31) != 0 + ? ARegisterSize.Int64 + : ARegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeAluImm.cs b/ChocolArm64/Decoder/AOpCodeAluImm.cs new file mode 100644 index 00000000..e913475a --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeAluImm.cs @@ -0,0 +1,39 @@ +using ChocolArm64.Instruction; +using System; + +namespace ChocolArm64.Decoder +{ + class AOpCodeAluImm : AOpCodeAlu, IAOpCodeAluImm + { + public long Imm { get; private set; } + + public AOpCodeAluImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + if (DataOp == ADataOp.Arithmetic) + { + Imm = (OpCode >> 10) & 0xfff; + + int Shift = (OpCode >> 22) & 3; + + Imm <<= Shift * 12; + } + else if (DataOp == ADataOp.Logical) + { + var BM = ADecoderHelper.DecodeBitMask(OpCode, true); + + if (BM.IsUndefined) + { + Emitter = AInstEmit.Und; + + return; + } + + Imm = BM.WMask; + } + else + { + throw new ArgumentException(nameof(OpCode)); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeAluRs.cs b/ChocolArm64/Decoder/AOpCodeAluRs.cs new file mode 100644 index 00000000..9c215be3 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeAluRs.cs @@ -0,0 +1,29 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeAluRs : AOpCodeAlu, IAOpCodeAluRs + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public AShiftType ShiftType { get; private set; } + + public AOpCodeAluRs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Shift = (OpCode >> 10) & 0x3f; + + if (Shift >= GetBitsCount()) + { + Emitter = AInstEmit.Und; + + return; + } + + this.Shift = Shift; + + Rm = (OpCode >> 16) & 0x1f; + ShiftType = (AShiftType)((OpCode >> 22) & 0x3); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeAluRx.cs b/ChocolArm64/Decoder/AOpCodeAluRx.cs new file mode 100644 index 00000000..7dd72a68 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeAluRx.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeAluRx : AOpCodeAlu, IAOpCodeAluRx + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public AIntType IntType { get; private set; } + + public AOpCodeAluRx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Shift = (OpCode >> 10) & 0x7; + IntType = (AIntType)((OpCode >> 13) & 0x7); + Rm = (OpCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBImm.cs b/ChocolArm64/Decoder/AOpCodeBImm.cs new file mode 100644 index 00000000..6519d281 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBImm.cs @@ -0,0 +1,11 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBImm : AOpCode + { + public long Imm { get; protected set; } + + public AOpCodeBImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBImmAl.cs b/ChocolArm64/Decoder/AOpCodeBImmAl.cs new file mode 100644 index 00000000..a4ff686d --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBImmAl.cs @@ -0,0 +1,12 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBImmAl : AOpCodeBImm + { + public AOpCodeBImmAl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Imm = Position + ADecoderHelper.DecodeImm26_2(OpCode); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBImmCmp.cs b/ChocolArm64/Decoder/AOpCodeBImmCmp.cs new file mode 100644 index 00000000..1b6185da --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBImmCmp.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBImmCmp : AOpCodeBImm + { + public int Rt { get; private set; } + + public AOpCodeBImmCmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt = OpCode & 0x1f; + + Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBImmCond.cs b/ChocolArm64/Decoder/AOpCodeBImmCond.cs new file mode 100644 index 00000000..1310feb8 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBImmCond.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBImmCond : AOpCodeBImm, IAOpCodeCond + { + public ACond Cond { get; private set; } + + public AOpCodeBImmCond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int O0 = (OpCode >> 4) & 1; + + if (O0 != 0) + { + Emitter = AInstEmit.Und; + + return; + } + + Cond = (ACond)(OpCode & 0xf); + + Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBImmTest.cs b/ChocolArm64/Decoder/AOpCodeBImmTest.cs new file mode 100644 index 00000000..73e57b7a --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBImmTest.cs @@ -0,0 +1,20 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBImmTest : AOpCodeBImm + { + public int Rt { get; private set; } + public int Pos { get; private set; } + + public AOpCodeBImmTest(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt = OpCode & 0x1f; + + Imm = Position + ADecoderHelper.DecodeImmS14_2(OpCode); + + Pos = (OpCode >> 19) & 0x1f; + Pos |= (OpCode >> 26) & 0x20; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBReg.cs b/ChocolArm64/Decoder/AOpCodeBReg.cs new file mode 100644 index 00000000..c9c600af --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBReg.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBReg : AOpCode + { + public int Rn { get; private set; } + + public AOpCodeBReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Op4 = (OpCode >> 0) & 0x1f; + int Op2 = (OpCode >> 16) & 0x1f; + + if (Op2 != 0b11111 || Op4 != 0b00000) + { + Emitter = AInstEmit.Und; + + return; + } + + Rn = (OpCode >> 5) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeBfm.cs b/ChocolArm64/Decoder/AOpCodeBfm.cs new file mode 100644 index 00000000..6498d8ec --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeBfm.cs @@ -0,0 +1,29 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeBfm : AOpCodeAlu + { + public long WMask { get; private set; } + public long TMask { get; private set; } + public int Pos { get; private set; } + public int Shift { get; private set; } + + public AOpCodeBfm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + var BM = ADecoderHelper.DecodeBitMask(OpCode, false); + + if (BM.IsUndefined) + { + Emitter = AInstEmit.Und; + + return; + } + + WMask = BM.WMask; + TMask = BM.TMask; + Pos = BM.Pos; + Shift = BM.Shift; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeCcmp.cs b/ChocolArm64/Decoder/AOpCodeCcmp.cs new file mode 100644 index 00000000..d0c7f779 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeCcmp.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeCcmp : AOpCodeAlu, IAOpCodeCond + { + public int NZCV { get; private set; } + protected int RmImm; + + public ACond Cond { get; private set; } + + public AOpCodeCcmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int O3 = (OpCode >> 4) & 1; + + if (O3 != 0) + { + Emitter = AInstEmit.Und; + + return; + } + + NZCV = (OpCode >> 0) & 0xf; + Cond = (ACond)((OpCode >> 12) & 0xf); + RmImm = (OpCode >> 16) & 0x1f; + + Rd = AThreadState.ZRIndex; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeCcmpImm.cs b/ChocolArm64/Decoder/AOpCodeCcmpImm.cs new file mode 100644 index 00000000..803eefc2 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeCcmpImm.cs @@ -0,0 +1,11 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeCcmpImm : AOpCodeCcmp, IAOpCodeAluImm + { + public long Imm => RmImm; + + public AOpCodeCcmpImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeCcmpReg.cs b/ChocolArm64/Decoder/AOpCodeCcmpReg.cs new file mode 100644 index 00000000..c364ae68 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeCcmpReg.cs @@ -0,0 +1,15 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeCcmpReg : AOpCodeCcmp, IAOpCodeAluRs + { + public int Rm => RmImm; + + public int Shift => 0; + + public AShiftType ShiftType => AShiftType.Lsl; + + public AOpCodeCcmpReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeCsel.cs b/ChocolArm64/Decoder/AOpCodeCsel.cs new file mode 100644 index 00000000..cdef3e74 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeCsel.cs @@ -0,0 +1,17 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeCsel : AOpCodeAlu, IAOpCodeCond + { + public int Rm { get; private set; } + + public ACond Cond { get; private set; } + + public AOpCodeCsel(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rm = (OpCode >> 16) & 0x1f; + Cond = (ACond)((OpCode >> 12) & 0xf); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeException.cs b/ChocolArm64/Decoder/AOpCodeException.cs new file mode 100644 index 00000000..4579c1a7 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeException.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeException : AOpCode + { + public int Id { get; private set; } + + public AOpCodeException(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Id = (OpCode >> 5) & 0xffff; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMem.cs b/ChocolArm64/Decoder/AOpCodeMem.cs new file mode 100644 index 00000000..be5367cf --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMem.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMem : AOpCode + { + public int Rt { get; protected set; } + public int Rn { get; protected set; } + public int Size { get; protected set; } + public bool Extend64 { get; protected set; } + + public AOpCodeMem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt = (OpCode >> 0) & 0x1f; + Rn = (OpCode >> 5) & 0x1f; + Size = (OpCode >> 30) & 0x3; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMemEx.cs b/ChocolArm64/Decoder/AOpCodeMemEx.cs new file mode 100644 index 00000000..3a28cfd7 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMemEx.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMemEx : AOpCodeMem + { + public int Rt2 { get; private set; } + public int Rs { get; private set; } + + public AOpCodeMemEx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt2 = (OpCode >> 10) & 0x1f; + Rs = (OpCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMemImm.cs b/ChocolArm64/Decoder/AOpCodeMemImm.cs new file mode 100644 index 00000000..14edc514 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMemImm.cs @@ -0,0 +1,53 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMemImm : AOpCodeMem + { + public long Imm { get; protected set; } + public bool WBack { get; protected set; } + public bool PostIdx { get; protected set; } + protected bool Unscaled { get; private set; } + + private enum MemOp + { + Unscaled = 0, + PostIndexed = 1, + Unprivileged = 2, + PreIndexed = 3, + Unsigned + } + + public AOpCodeMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Extend64 = ((OpCode >> 22) & 3) == 2; + WBack = ((OpCode >> 24) & 1) == 0; + + //The type is not valid for the Unsigned Immediate 12-bits encoding, + //because the bits 11:10 are used for the larger Immediate offset. + MemOp Type = WBack ? (MemOp)((OpCode >> 10) & 3) : MemOp.Unsigned; + + PostIdx = Type == MemOp.PostIndexed; + Unscaled = Type == MemOp.Unscaled || + Type == MemOp.Unprivileged; + + //Unscaled and Unprivileged doesn't write back, + //but they do use the 9-bits Signed Immediate. + if (Unscaled) + { + WBack = false; + } + + if (WBack || Unscaled) + { + //9-bits Signed Immediate. + Imm = (OpCode << 43) >> 55; + } + else + { + //12-bits Unsigned Immediate. + Imm = ((OpCode >> 10) & 0xfff) << Size; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMemLit.cs b/ChocolArm64/Decoder/AOpCodeMemLit.cs new file mode 100644 index 00000000..ad719a19 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMemLit.cs @@ -0,0 +1,28 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMemLit : AOpCode, IAOpCodeLit + { + public int Rt { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + public bool Signed { get; private set; } + public bool Prefetch { get; private set; } + + public AOpCodeMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt = OpCode & 0x1f; + + Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); + + switch ((OpCode >> 30) & 3) + { + case 0: Size = 2; Signed = false; Prefetch = false; break; + case 1: Size = 3; Signed = false; Prefetch = false; break; + case 2: Size = 2; Signed = true; Prefetch = false; break; + case 3: Size = 0; Signed = false; Prefetch = true; break; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMemPair.cs b/ChocolArm64/Decoder/AOpCodeMemPair.cs new file mode 100644 index 00000000..ec866c84 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMemPair.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMemPair : AOpCodeMemImm + { + public int Rt2 { get; private set; } + + public AOpCodeMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt2 = (OpCode >> 10) & 0x1f; + WBack = ((OpCode >> 23) & 0x1) != 0; + PostIdx = ((OpCode >> 23) & 0x3) == 1; + Extend64 = ((OpCode >> 30) & 0x3) == 1; + Size = ((OpCode >> 31) & 0x1) | 2; + + DecodeImm(OpCode); + } + + protected void DecodeImm(int OpCode) + { + Imm = ((long)(OpCode >> 15) << 57) >> (57 - Size); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMemReg.cs b/ChocolArm64/Decoder/AOpCodeMemReg.cs new file mode 100644 index 00000000..98927128 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMemReg.cs @@ -0,0 +1,20 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMemReg : AOpCodeMem + { + public bool Shift { get; private set; } + public int Rm { get; private set; } + + public AIntType IntType { get; private set; } + + public AOpCodeMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Shift = ((OpCode >> 12) & 0x1) != 0; + IntType = (AIntType)((OpCode >> 13) & 0x7); + Rm = (OpCode >> 16) & 0x1f; + Extend64 = ((OpCode >> 22) & 0x3) == 2; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMov.cs b/ChocolArm64/Decoder/AOpCodeMov.cs new file mode 100644 index 00000000..d5398646 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMov.cs @@ -0,0 +1,36 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMov : AOpCode + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Pos { get; private set; } + + public AOpCodeMov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int P1 = (OpCode >> 22) & 1; + int SF = (OpCode >> 31) & 1; + + if (SF == 0 && P1 != 0) + { + Emitter = AInstEmit.Und; + + return; + } + + Rd = (OpCode >> 0) & 0x1f; + Imm = (OpCode >> 5) & 0xffff; + Pos = (OpCode >> 21) & 0x3; + + Pos <<= 4; + Imm <<= Pos; + + RegisterSize = (OpCode >> 31) != 0 + ? ARegisterSize.Int64 + : ARegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeMul.cs b/ChocolArm64/Decoder/AOpCodeMul.cs new file mode 100644 index 00000000..ca2b0cdb --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeMul.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeMul : AOpCodeAlu + { + public int Rm { get; private set; } + public int Ra { get; private set; } + + public AOpCodeMul(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Ra = (OpCode >> 10) & 0x1f; + Rm = (OpCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimd.cs b/ChocolArm64/Decoder/AOpCodeSimd.cs new file mode 100644 index 00000000..5f940b22 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimd.cs @@ -0,0 +1,27 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimd : AOpCode, IAOpCodeSimd + { + public int Rd { get; private set; } + public int Rn { get; private set; } + public int Opc { get; private set; } + public int Size { get; protected set; } + + public int SizeF => Size & 1; + + public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rd = (OpCode >> 0) & 0x1f; + Rn = (OpCode >> 5) & 0x1f; + Opc = (OpCode >> 15) & 0x3; + Size = (OpCode >> 22) & 0x3; + + RegisterSize = ((OpCode >> 30) & 1) != 0 + ? ARegisterSize.SIMD128 + : ARegisterSize.SIMD64; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdCvt.cs b/ChocolArm64/Decoder/AOpCodeSimdCvt.cs new file mode 100644 index 00000000..41f4d3b1 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdCvt.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdCvt : AOpCodeSimd + { + public int FBits { get; private set; } + + public AOpCodeSimdCvt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + //TODO: + //Und of Fixed Point variants. + int Scale = (OpCode >> 10) & 0x3f; + int SF = (OpCode >> 31) & 0x1; + + /*if (Type != SF && !(Type == 2 && SF == 1)) + { + Emitter = AInstEmit.Und; + + return; + }*/ + + FBits = 64 - Scale; + + RegisterSize = SF != 0 + ? ARegisterSize.Int64 + : ARegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdFcond.cs b/ChocolArm64/Decoder/AOpCodeSimdFcond.cs new file mode 100644 index 00000000..e38e7424 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdFcond.cs @@ -0,0 +1,17 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdFcond : AOpCodeSimdReg, IAOpCodeCond + { + public int NZCV { get; private set; } + + public ACond Cond { get; private set; } + + public AOpCodeSimdFcond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + NZCV = (OpCode >> 0) & 0xf; + Cond = (ACond)((OpCode >> 12) & 0xf); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdFmov.cs b/ChocolArm64/Decoder/AOpCodeSimdFmov.cs new file mode 100644 index 00000000..3f888959 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdFmov.cs @@ -0,0 +1,33 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdFmov : AOpCode, IAOpCodeSimd + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public AOpCodeSimdFmov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Imm5 = (OpCode >> 5) & 0x1f; + int Type = (OpCode >> 22) & 0x3; + + if (Imm5 != 0b00000 || Type > 1) + { + Emitter = AInstEmit.Und; + + return; + } + + Size = Type; + + long Imm; + + Rd = (OpCode >> 0) & 0x1f; + Imm = (OpCode >> 13) & 0xff; + + this.Imm = ADecoderHelper.DecodeImm8Float(Imm, Type); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdImm.cs b/ChocolArm64/Decoder/AOpCodeSimdImm.cs new file mode 100644 index 00000000..2959aee6 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdImm.cs @@ -0,0 +1,94 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdImm : AOpCode, IAOpCodeSimd + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public AOpCodeSimdImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rd = OpCode & 0x1f; + + int CMode = (OpCode >> 12) & 0xf; + int Op = (OpCode >> 29) & 0x1; + + int ModeLow = CMode & 1; + int ModeHigh = CMode >> 1; + + long Imm; + + Imm = ((uint)OpCode >> 5) & 0x1f; + Imm |= ((uint)OpCode >> 11) & 0xe0; + + if (ModeHigh == 0b111) + { + Size = ModeLow != 0 ? Op : 3; + + switch (Op | (ModeLow << 1)) + { + case 0: + //64-bits Immediate. + //Transform abcd efgh into abcd efgh abcd efgh ... + Imm = (long)((ulong)Imm * 0x0101010101010101); + break; + + case 1: + //64-bits Immediate. + //Transform abcd efgh into aaaa aaaa bbbb bbbb ... + Imm = (Imm & 0xf0) >> 4 | (Imm & 0x0f) << 4; + Imm = (Imm & 0xcc) >> 2 | (Imm & 0x33) << 2; + Imm = (Imm & 0xaa) >> 1 | (Imm & 0x55) << 1; + + Imm = (long)((ulong)Imm * 0x8040201008040201); + Imm = (long)((ulong)Imm & 0x8080808080808080); + + Imm |= Imm >> 4; + Imm |= Imm >> 2; + Imm |= Imm >> 1; + break; + + case 2: + case 3: + //Floating point Immediate. + Imm = ADecoderHelper.DecodeImm8Float(Imm, Size); + break; + } + } + else if ((ModeHigh & 0b110) == 0b100) + { + //16-bits shifted Immediate. + Size = 1; Imm <<= (ModeHigh & 1) << 3; + } + else if ((ModeHigh & 0b100) == 0b000) + { + //32-bits shifted Immediate. + Size = 2; Imm <<= ModeHigh << 3; + } + else if ((ModeHigh & 0b111) == 0b110) + { + //32-bits shifted Immediate (fill with ones). + Size = 2; Imm = ShlOnes(Imm, 8 << ModeLow); + } + else + { + //8 bits without shift. + Size = 0; + } + + this.Imm = Imm; + + RegisterSize = ((OpCode >> 30) & 1) != 0 + ? ARegisterSize.SIMD128 + : ARegisterSize.SIMD64; + } + + private static long ShlOnes(long Value, int Shift) + { + return Value << Shift | (long)(ulong.MaxValue >> (64 - Shift)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdIns.cs b/ChocolArm64/Decoder/AOpCodeSimdIns.cs new file mode 100644 index 00000000..0b60bbe8 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdIns.cs @@ -0,0 +1,36 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdIns : AOpCodeSimd + { + public int SrcIndex { get; private set; } + public int DstIndex { get; private set; } + + public AOpCodeSimdIns(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Imm4 = (OpCode >> 11) & 0xf; + int Imm5 = (OpCode >> 16) & 0x1f; + + if (Imm5 == 0b10000) + { + Emitter = AInstEmit.Und; + + return; + } + + Size = Imm5 & -Imm5; + + switch (Size) + { + case 1: Size = 0; break; + case 2: Size = 1; break; + case 4: Size = 2; break; + case 8: Size = 3; break; + } + + SrcIndex = Imm4 >> Size; + DstIndex = Imm5 >> (Size + 1); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemImm.cs b/ChocolArm64/Decoder/AOpCodeSimdMemImm.cs new file mode 100644 index 00000000..1ef19a5d --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemImm.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemImm : AOpCodeMemImm, IAOpCodeSimd + { + public AOpCodeSimdMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Size |= (OpCode >> 21) & 4; + + if (!WBack && !Unscaled && Size >= 4) + { + Imm <<= 4; + } + + Extend64 = false; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemLit.cs b/ChocolArm64/Decoder/AOpCodeSimdMemLit.cs new file mode 100644 index 00000000..ea6fe00b --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemLit.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemLit : AOpCode, IAOpCodeSimd, IAOpCodeLit + { + public int Rt { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + public bool Signed => false; + public bool Prefetch => false; + + public AOpCodeSimdMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Opc = (OpCode >> 30) & 3; + + if (Opc == 3) + { + Emitter = AInstEmit.Und; + + return; + } + + Rt = OpCode & 0x1f; + + Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); + + Size = Opc + 2; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs b/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs new file mode 100644 index 00000000..9ea979ba --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs @@ -0,0 +1,49 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd + { + public int Reps { get; private set; } + public int SElems { get; private set; } + public int Elems { get; private set; } + public bool WBack { get; private set; } + + public AOpCodeSimdMemMs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + switch ((OpCode >> 12) & 0xf) + { + case 0b0000: Reps = 1; SElems = 4; break; + case 0b0010: Reps = 4; SElems = 1; break; + case 0b0100: Reps = 1; SElems = 3; break; + case 0b0110: Reps = 3; SElems = 1; break; + case 0b0111: Reps = 1; SElems = 1; break; + case 0b1000: Reps = 1; SElems = 2; break; + case 0b1010: Reps = 2; SElems = 1; break; + + default: Inst = AInst.Undefined; return; + } + + Size = (OpCode >> 10) & 0x3; + WBack = ((OpCode >> 23) & 0x1) != 0; + + bool Q = ((OpCode >> 30) & 1) != 0; + + if (!Q && Size == 3 && SElems != 1) + { + Inst = AInst.Undefined; + + return; + } + + Extend64 = false; + + RegisterSize = Q + ? ARegisterSize.SIMD128 + : ARegisterSize.SIMD64; + + Elems = (GetBitsCount() >> 3) >> Size; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs b/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs new file mode 100644 index 00000000..db99e3d4 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemPair : AOpCodeMemPair, IAOpCodeSimd + { + public AOpCodeSimdMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Size = ((OpCode >> 30) & 3) + 2; + + Extend64 = false; + + DecodeImm(OpCode); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemReg.cs b/ChocolArm64/Decoder/AOpCodeSimdMemReg.cs new file mode 100644 index 00000000..aabf4846 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemReg.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemReg : AOpCodeMemReg, IAOpCodeSimd + { + public AOpCodeSimdMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Size |= (OpCode >> 21) & 4; + + Extend64 = false; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemSs.cs b/ChocolArm64/Decoder/AOpCodeSimdMemSs.cs new file mode 100644 index 00000000..be4a8cd9 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdMemSs.cs @@ -0,0 +1,97 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd + { + public int SElems { get; private set; } + public int Index { get; private set; } + public bool Replicate { get; private set; } + public bool WBack { get; private set; } + + public AOpCodeSimdMemSs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + int Size = (OpCode >> 10) & 3; + int S = (OpCode >> 12) & 1; + int SElems = (OpCode >> 12) & 2; + int Scale = (OpCode >> 14) & 3; + int L = (OpCode >> 22) & 1; + int Q = (OpCode >> 30) & 1; + + SElems |= (OpCode >> 21) & 1; + + SElems++; + + int Index = (Q << 3) | (S << 2) | Size; + + switch (Scale) + { + case 1: + { + if ((Size & 1) != 0) + { + Inst = AInst.Undefined; + + return; + } + + Index >>= 1; + + break; + } + + case 2: + { + if ((Size & 2) != 0 || + ((Size & 1) != 0 && S != 0)) + { + Inst = AInst.Undefined; + + return; + } + + if ((Size & 1) != 0) + { + Index >>= 3; + + Scale = 3; + } + else + { + Index >>= 2; + } + + break; + } + + case 3: + { + if (L == 0 || S != 0) + { + Inst = AInst.Undefined; + + return; + } + + Scale = Size; + + Replicate = true; + + break; + } + } + + this.SElems = SElems; + this.Size = Scale; + + Extend64 = false; + + WBack = ((OpCode >> 23) & 0x1) != 0; + + RegisterSize = Q != 0 + ? ARegisterSize.SIMD128 + : ARegisterSize.SIMD64; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdReg.cs b/ChocolArm64/Decoder/AOpCodeSimdReg.cs new file mode 100644 index 00000000..10a4aff8 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdReg.cs @@ -0,0 +1,18 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdReg : AOpCodeSimd + { + public bool Bit3 { get; private set; } + public int Ra { get; private set; } + public int Rm { get; private set; } + + public AOpCodeSimdReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Bit3 = ((OpCode >> 3) & 0x1) != 0; + Ra = (OpCode >> 10) & 0x1f; + Rm = (OpCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdRegElem.cs b/ChocolArm64/Decoder/AOpCodeSimdRegElem.cs new file mode 100644 index 00000000..d878b12e --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdRegElem.cs @@ -0,0 +1,22 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdRegElem : AOpCodeSimdReg + { + public int Index { get; private set; } + + public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + if ((Size & 1) != 0) + { + Index = (OpCode >> 11) & 1; + } + else + { + Index = (OpCode >> 21) & 1 | + (OpCode >> 10) & 2; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdShImm.cs b/ChocolArm64/Decoder/AOpCodeSimdShImm.cs new file mode 100644 index 00000000..6c839881 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdShImm.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdShImm : AOpCodeSimd + { + public int Imm { get; private set; } + + public AOpCodeSimdShImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Imm = (OpCode >> 16) & 0x7f; + + Size = ABitUtils.HighestBitSet32(Imm >> 3); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSimdTbl.cs b/ChocolArm64/Decoder/AOpCodeSimdTbl.cs new file mode 100644 index 00000000..c8ae5bac --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSimdTbl.cs @@ -0,0 +1,12 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSimdTbl : AOpCodeSimdReg + { + public AOpCodeSimdTbl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Size = ((OpCode >> 13) & 3) + 1; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AOpCodeSystem.cs b/ChocolArm64/Decoder/AOpCodeSystem.cs new file mode 100644 index 00000000..3d81a5d4 --- /dev/null +++ b/ChocolArm64/Decoder/AOpCodeSystem.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instruction; + +namespace ChocolArm64.Decoder +{ + class AOpCodeSystem : AOpCode + { + public int Rt { get; private set; } + public int Op2 { get; private set; } + public int CRm { get; private set; } + public int CRn { get; private set; } + public int Op1 { get; private set; } + public int Op0 { get; private set; } + + public AOpCodeSystem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) + { + Rt = (OpCode >> 0) & 0x1f; + Op2 = (OpCode >> 5) & 0x7; + CRm = (OpCode >> 8) & 0xf; + CRn = (OpCode >> 12) & 0xf; + Op1 = (OpCode >> 16) & 0x7; + Op0 = ((OpCode >> 19) & 0x1) | 2; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/AShiftType.cs b/ChocolArm64/Decoder/AShiftType.cs new file mode 100644 index 00000000..34ceea20 --- /dev/null +++ b/ChocolArm64/Decoder/AShiftType.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoder +{ + enum AShiftType + { + Lsl, + Lsr, + Asr, + Ror + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCode.cs b/ChocolArm64/Decoder/IAOpCode.cs new file mode 100644 index 00000000..44bf9cb2 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCode.cs @@ -0,0 +1,13 @@ +using ChocolArm64.Instruction; +using ChocolArm64.State; + +namespace ChocolArm64.Decoder +{ + interface IAOpCode + { + long Position { get; } + + AInstEmitter Emitter { get; } + ARegisterSize RegisterSize { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeAlu.cs b/ChocolArm64/Decoder/IAOpCodeAlu.cs new file mode 100644 index 00000000..22af4c82 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeAlu.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeAlu : IAOpCode + { + int Rd { get; } + int Rn { get; } + + ADataOp DataOp { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeAluImm.cs b/ChocolArm64/Decoder/IAOpCodeAluImm.cs new file mode 100644 index 00000000..04b5c5f7 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeAluImm.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeAluImm : IAOpCodeAlu + { + long Imm { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeAluRs.cs b/ChocolArm64/Decoder/IAOpCodeAluRs.cs new file mode 100644 index 00000000..5ca9de40 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeAluRs.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeAluRs : IAOpCodeAlu + { + int Shift { get; } + int Rm { get; } + + AShiftType ShiftType { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeAluRx.cs b/ChocolArm64/Decoder/IAOpCodeAluRx.cs new file mode 100644 index 00000000..b49d5325 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeAluRx.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeAluRx : IAOpCodeAlu + { + int Shift { get; } + int Rm { get; } + + AIntType IntType { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeCond.cs b/ChocolArm64/Decoder/IAOpCodeCond.cs new file mode 100644 index 00000000..1655abaa --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeCond.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeCond : IAOpCode + { + ACond Cond { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeLit.cs b/ChocolArm64/Decoder/IAOpCodeLit.cs new file mode 100644 index 00000000..0f5092d0 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeLit.cs @@ -0,0 +1,11 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeLit : IAOpCode + { + int Rt { get; } + long Imm { get; } + int Size { get; } + bool Signed { get; } + bool Prefetch { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Decoder/IAOpCodeSimd.cs b/ChocolArm64/Decoder/IAOpCodeSimd.cs new file mode 100644 index 00000000..19032ad9 --- /dev/null +++ b/ChocolArm64/Decoder/IAOpCodeSimd.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoder +{ + interface IAOpCodeSimd : IAOpCode + { + int Size { get; } + } +} \ No newline at end of file diff --git a/ChocolArm64/Exceptions/VmmAccessViolationException.cs b/ChocolArm64/Exceptions/VmmAccessViolationException.cs new file mode 100644 index 00000000..a557502e --- /dev/null +++ b/ChocolArm64/Exceptions/VmmAccessViolationException.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Memory; +using System; + +namespace ChocolArm64.Exceptions +{ + public class VmmAccessViolationException : Exception + { + private const string ExMsg = "Address 0x{0:x16} does not have \"{1}\" permission!"; + + public VmmAccessViolationException() { } + + public VmmAccessViolationException(long Position, AMemoryPerm Perm) : base(string.Format(ExMsg, Position, Perm)) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs b/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs new file mode 100644 index 00000000..c11384da --- /dev/null +++ b/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs @@ -0,0 +1,13 @@ +using System; + +namespace ChocolArm64.Exceptions +{ + public class VmmOutOfMemoryException : Exception + { + private const string ExMsg = "Failed to allocate {0} bytes of memory!"; + + public VmmOutOfMemoryException() { } + + public VmmOutOfMemoryException(long Size) : base(string.Format(ExMsg, Size)) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Exceptions/VmmPageFaultException.cs b/ChocolArm64/Exceptions/VmmPageFaultException.cs new file mode 100644 index 00000000..d55c2c1c --- /dev/null +++ b/ChocolArm64/Exceptions/VmmPageFaultException.cs @@ -0,0 +1,13 @@ +using System; + +namespace ChocolArm64.Exceptions +{ + public class VmmPageFaultException : Exception + { + private const string ExMsg = "Tried to access unmapped address 0x{0:x16}!"; + + public VmmPageFaultException() { } + + public VmmPageFaultException(long Position) : base(string.Format(ExMsg, Position)) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInst.cs b/ChocolArm64/Instruction/AInst.cs new file mode 100644 index 00000000..cab597d6 --- /dev/null +++ b/ChocolArm64/Instruction/AInst.cs @@ -0,0 +1,18 @@ +using System; + +namespace ChocolArm64.Instruction +{ + struct AInst + { + public AInstEmitter Emitter { get; private set; } + public Type Type { get; private set; } + + public static AInst Undefined => new AInst(AInstEmit.Und, null); + + public AInst(AInstEmitter Emitter, Type Type) + { + this.Emitter = Emitter; + this.Type = Type; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitAlu.cs b/ChocolArm64/Instruction/AInstEmitAlu.cs new file mode 100644 index 00000000..72903f5b --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitAlu.cs @@ -0,0 +1,364 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitAluHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Adc(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Add); + + Context.EmitLdflg((int)APState.CBit); + + Type[] MthdTypes = new Type[] { typeof(bool) }; + + MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); + + Context.EmitCall(MthdInfo); + + if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_I8); + } + + Context.Emit(OpCodes.Add); + + EmitDataStore(Context); + } + + public static void Add(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Add); + + public static void Adds(AILEmitterCtx Context) + { + Context.TryOptMarkCondWithoutCmp(); + + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Add); + + Context.EmitZNFlagCheck(); + + EmitAddsCCheck(Context); + EmitAddsVCheck(Context); + EmitDataStoreS(Context); + } + + public static void And(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.And); + + public static void Ands(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.And); + + EmitZeroCVFlags(Context); + + Context.EmitZNFlagCheck(); + + EmitDataStoreS(Context); + } + + public static void Asrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr); + + public static void Bic(AILEmitterCtx Context) => EmitBic(Context, false); + public static void Bics(AILEmitterCtx Context) => EmitBic(Context, true); + + private static void EmitBic(AILEmitterCtx Context, bool SetFlags) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + + if (SetFlags) + { + EmitZeroCVFlags(Context); + + Context.EmitZNFlagCheck(); + } + + EmitDataStore(Context, SetFlags); + } + + public static void Clz(AILEmitterCtx Context) + { + AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Op.RegisterSize == ARegisterSize.Int32) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros32)); + } + else + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros64)); + } + + Context.EmitStintzr(Op.Rd); + } + + public static void Eon(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.Xor); + + EmitDataStore(Context); + } + + public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor); + + public static void Extr(AILEmitterCtx Context) + { + //TODO: Ensure that the Shift is valid for the Is64Bits. + AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp; + + Context.EmitLdintzr(Op.Rm); + + if (Op.Shift > 0) + { + Context.EmitLdc_I4(Op.Shift); + + Context.Emit(OpCodes.Shr_Un); + + Context.EmitLdintzr(Op.Rn); + Context.EmitLdc_I4(Op.GetBitsCount() - Op.Shift); + + Context.Emit(OpCodes.Shl); + Context.Emit(OpCodes.Or); + } + + EmitDataStore(Context); + } + + public static void Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl); + public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un); + + public static void Sbc(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Sub); + + Context.EmitLdflg((int)APState.CBit); + + Type[] MthdTypes = new Type[] { typeof(bool) }; + + MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); + + Context.EmitCall(MthdInfo); + + Context.EmitLdc_I4(1); + + Context.Emit(OpCodes.Xor); + + if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_I8); + } + + Context.Emit(OpCodes.Sub); + + EmitDataStore(Context); + } + + public static void Sub(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Sub); + + public static void Subs(AILEmitterCtx Context) + { + Context.TryOptMarkCondWithoutCmp(); + + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Sub); + + Context.EmitZNFlagCheck(); + + EmitSubsCCheck(Context); + EmitSubsVCheck(Context); + EmitDataStoreS(Context); + } + + public static void Orn(AILEmitterCtx Context) + { + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.Or); + + EmitDataStore(Context); + } + + public static void Orr(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Or); + + public static void Rbit(AILEmitterCtx Context) => EmitFallback32_64(Context, + nameof(ASoftFallback.ReverseBits32), + nameof(ASoftFallback.ReverseBits64)); + + public static void Rev16(AILEmitterCtx Context) => EmitFallback32_64(Context, + nameof(ASoftFallback.ReverseBytes16_32), + nameof(ASoftFallback.ReverseBytes16_64)); + + public static void Rev32(AILEmitterCtx Context) => EmitFallback32_64(Context, + nameof(ASoftFallback.ReverseBytes32_32), + nameof(ASoftFallback.ReverseBytes32_64)); + + public static void EmitFallback32_64(AILEmitterCtx Context, string Name32, string Name64) + { + AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Op.RegisterSize == ARegisterSize.Int32) + { + ASoftFallback.EmitCall(Context, Name32); + } + else + { + ASoftFallback.EmitCall(Context, Name64); + } + + Context.EmitStintzr(Op.Rd); + } + + public static void Rev64(AILEmitterCtx Context) + { + AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBytes64)); + + Context.EmitStintzr(Op.Rd); + } + + public static void Rorv(AILEmitterCtx Context) + { + EmitDataLoadRn(Context); + EmitDataLoadShift(Context); + + Context.Emit(OpCodes.Shr_Un); + + EmitDataLoadRn(Context); + + Context.EmitLdc_I4(Context.CurrOp.GetBitsCount()); + + EmitDataLoadShift(Context); + + Context.Emit(OpCodes.Sub); + Context.Emit(OpCodes.Shl); + Context.Emit(OpCodes.Or); + + EmitDataStore(Context); + } + + public static void Sdiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div); + public static void Udiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div_Un); + + private static void EmitDiv(AILEmitterCtx Context, OpCode ILOp) + { + //If Rm == 0, Rd = 0 (division by zero). + Context.EmitLdc_I(0); + + EmitDataLoadRm(Context); + + Context.EmitLdc_I(0); + + AILLabel BadDiv = new AILLabel(); + + Context.Emit(OpCodes.Beq_S, BadDiv); + Context.Emit(OpCodes.Pop); + + if (ILOp == OpCodes.Div) + { + //If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). + long IntMin = 1L << (Context.CurrOp.GetBitsCount() - 1); + + Context.EmitLdc_I(IntMin); + + EmitDataLoadRn(Context); + + Context.EmitLdc_I(IntMin); + + Context.Emit(OpCodes.Ceq); + + EmitDataLoadRm(Context); + + Context.EmitLdc_I(-1); + + Context.Emit(OpCodes.Ceq); + Context.Emit(OpCodes.And); + Context.Emit(OpCodes.Brtrue_S, BadDiv); + Context.Emit(OpCodes.Pop); + } + + EmitDataLoadRn(Context); + EmitDataLoadRm(Context); + + Context.Emit(ILOp); + + Context.MarkLabel(BadDiv); + + EmitDataStore(Context); + } + + private static void EmitDataOp(AILEmitterCtx Context, OpCode ILOp) + { + EmitDataLoadOpers(Context); + + Context.Emit(ILOp); + + EmitDataStore(Context); + } + + private static void EmitDataOpShift(AILEmitterCtx Context, OpCode ILOp) + { + EmitDataLoadRn(Context); + EmitDataLoadShift(Context); + + Context.Emit(ILOp); + + EmitDataStore(Context); + } + + private static void EmitDataLoadShift(AILEmitterCtx Context) + { + EmitDataLoadRm(Context); + + Context.EmitLdc_I(Context.CurrOp.GetBitsCount() - 1); + + Context.Emit(OpCodes.And); + + //Note: Only 32-bits shift values are valid, so when the value is 64-bits + //we need to cast it to a 32-bits integer. This is fine because we + //AND the value and only keep the lower 5 or 6 bits anyway -- it + //could very well fit on a byte. + if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_I4); + } + } + + private static void EmitZeroCVFlags(AILEmitterCtx Context) + { + Context.EmitLdc_I4(0); + + Context.EmitStflg((int)APState.VBit); + + Context.EmitLdc_I4(0); + + Context.EmitStflg((int)APState.CBit); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitAluHelper.cs b/ChocolArm64/Instruction/AInstEmitAluHelper.cs new file mode 100644 index 00000000..e848742d --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitAluHelper.cs @@ -0,0 +1,168 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static class AInstEmitAluHelper + { + public static void EmitAddsCCheck(AILEmitterCtx Context) + { + //C = Rd < Rn + Context.Emit(OpCodes.Dup); + + EmitDataLoadRn(Context); + + Context.Emit(OpCodes.Clt_Un); + + Context.EmitStflg((int)APState.CBit); + } + + public static void EmitAddsVCheck(AILEmitterCtx Context) + { + //V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 + Context.Emit(OpCodes.Dup); + + EmitDataLoadRn(Context); + + Context.Emit(OpCodes.Xor); + + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Xor); + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + + Context.EmitLdc_I(0); + + Context.Emit(OpCodes.Clt); + + Context.EmitStflg((int)APState.VBit); + } + + public static void EmitSubsCCheck(AILEmitterCtx Context) + { + //C = Rn == Rm || Rn > Rm = !(Rn < Rm) + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Clt_Un); + + Context.EmitLdc_I4(1); + + Context.Emit(OpCodes.Xor); + + Context.EmitStflg((int)APState.CBit); + } + + public static void EmitSubsVCheck(AILEmitterCtx Context) + { + //V = (Rd ^ Rn) & (Rn ^ Rm) < 0 + Context.Emit(OpCodes.Dup); + + EmitDataLoadRn(Context); + + Context.Emit(OpCodes.Xor); + + EmitDataLoadOpers(Context); + + Context.Emit(OpCodes.Xor); + Context.Emit(OpCodes.And); + + Context.EmitLdc_I(0); + + Context.Emit(OpCodes.Clt); + + Context.EmitStflg((int)APState.VBit); + } + + public static void EmitDataLoadRm(AILEmitterCtx Context) + { + Context.EmitLdintzr(((IAOpCodeAluRs)Context.CurrOp).Rm); + } + + public static void EmitDataLoadOpers(AILEmitterCtx Context) + { + EmitDataLoadRn(Context); + EmitDataLoadOper2(Context); + } + + public static void EmitDataLoadRn(AILEmitterCtx Context) + { + IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp; + + if (Op.DataOp == ADataOp.Logical || Op is IAOpCodeAluRs) + { + Context.EmitLdintzr(Op.Rn); + } + else + { + Context.EmitLdint(Op.Rn); + } + } + + public static void EmitDataLoadOper2(AILEmitterCtx Context) + { + switch (Context.CurrOp) + { + case IAOpCodeAluImm Op: + Context.EmitLdc_I(Op.Imm); + break; + + case IAOpCodeAluRs Op: + Context.EmitLdintzr(Op.Rm); + + switch (Op.ShiftType) + { + case AShiftType.Lsl: Context.EmitLsl(Op.Shift); break; + case AShiftType.Lsr: Context.EmitLsr(Op.Shift); break; + case AShiftType.Asr: Context.EmitAsr(Op.Shift); break; + case AShiftType.Ror: Context.EmitRor(Op.Shift); break; + } + break; + + case IAOpCodeAluRx Op: + Context.EmitLdintzr(Op.Rm); + Context.EmitCast(Op.IntType); + Context.EmitLsl(Op.Shift); + break; + } + } + + public static void EmitDataStore(AILEmitterCtx Context) => EmitDataStore(Context, false); + public static void EmitDataStoreS(AILEmitterCtx Context) => EmitDataStore(Context, true); + + public static void EmitDataStore(AILEmitterCtx Context, bool SetFlags) + { + IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp; + + if (SetFlags || Op is IAOpCodeAluRs) + { + Context.EmitStintzr(Op.Rd); + } + else + { + Context.EmitStint(Op.Rd); + } + } + + public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV) + { + Context.EmitLdc_I4((NZCV >> 0) & 1); + + Context.EmitStflg((int)APState.VBit); + + Context.EmitLdc_I4((NZCV >> 1) & 1); + + Context.EmitStflg((int)APState.CBit); + + Context.EmitLdc_I4((NZCV >> 2) & 1); + + Context.EmitStflg((int)APState.ZBit); + + Context.EmitLdc_I4((NZCV >> 3) & 1); + + Context.EmitStflg((int)APState.NBit); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitBfm.cs b/ChocolArm64/Instruction/AInstEmitBfm.cs new file mode 100644 index 00000000..823af738 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitBfm.cs @@ -0,0 +1,217 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Bfm(AILEmitterCtx Context) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + EmitBfmLoadRn(Context); + + Context.EmitLdintzr(Op.Rd); + Context.EmitLdc_I(~Op.WMask & Op.TMask); + + Context.Emit(OpCodes.And); + Context.Emit(OpCodes.Or); + + Context.EmitLdintzr(Op.Rd); + Context.EmitLdc_I(~Op.TMask); + + Context.Emit(OpCodes.And); + Context.Emit(OpCodes.Or); + + Context.EmitStintzr(Op.Rd); + } + + public static void Sbfm(AILEmitterCtx Context) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + int BitsCount = Op.GetBitsCount(); + + if (Op.Pos + 1 == BitsCount) + { + EmitSbfmShift(Context); + } + else if (Op.Pos < Op.Shift) + { + EmitSbfiz(Context); + } + else if (Op.Pos == 7 && Op.Shift == 0) + { + EmitSbfmCast(Context, OpCodes.Conv_I1); + } + else if (Op.Pos == 15 && Op.Shift == 0) + { + EmitSbfmCast(Context, OpCodes.Conv_I2); + } + else if (Op.Pos == 31 && Op.Shift == 0) + { + EmitSbfmCast(Context, OpCodes.Conv_I4); + } + else if (Op.Shift == 0) + { + Context.EmitLdintzr(Op.Rn); + + Context.EmitLsl(BitsCount - 1 - Op.Pos); + Context.EmitAsr(BitsCount - 1); + + Context.EmitStintzr(Op.Rd); + } + else + { + EmitBfmLoadRn(Context); + + Context.EmitLdintzr(Op.Rn); + + Context.EmitLsl(BitsCount - 1 - Op.Pos); + Context.EmitAsr(BitsCount - 1); + + Context.EmitLdc_I(~Op.TMask); + + Context.Emit(OpCodes.And); + Context.Emit(OpCodes.Or); + + Context.EmitStintzr(Op.Rd); + } + } + + public static void Ubfm(AILEmitterCtx Context) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + if (Op.Pos + 1 == Op.GetBitsCount()) + { + EmitUbfmShift(Context); + } + else if (Op.Pos < Op.Shift) + { + EmitUbfiz(Context); + } + else if (Op.Pos + 1 == Op.Shift) + { + EmitBfmLsl(Context); + } + else if (Op.Pos == 7 && Op.Shift == 0) + { + EmitUbfmCast(Context, OpCodes.Conv_U1); + } + else if (Op.Pos == 15 && Op.Shift == 0) + { + EmitUbfmCast(Context, OpCodes.Conv_U2); + } + else + { + EmitBfmLoadRn(Context); + + Context.EmitStintzr(Op.Rd); + } + } + + private static void EmitSbfiz(AILEmitterCtx Context) => EmitBfiz(Context, true); + private static void EmitUbfiz(AILEmitterCtx Context) => EmitBfiz(Context, false); + + private static void EmitBfiz(AILEmitterCtx Context, bool Signed) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + int Width = Op.Pos + 1; + + Context.EmitLdintzr(Op.Rn); + + Context.EmitLsl(Op.GetBitsCount() - Width); + + if (Signed) + { + Context.EmitAsr(Op.Shift - Width); + } + else + { + Context.EmitLsr(Op.Shift - Width); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitSbfmCast(AILEmitterCtx Context, OpCode ILOp) + { + EmitBfmCast(Context, ILOp, true); + } + + private static void EmitUbfmCast(AILEmitterCtx Context, OpCode ILOp) + { + EmitBfmCast(Context, ILOp, false); + } + + private static void EmitBfmCast(AILEmitterCtx Context, OpCode ILOp, bool Signed) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + Context.Emit(ILOp); + + if (Op.RegisterSize != ARegisterSize.Int32) + { + Context.Emit(Signed + ? OpCodes.Conv_I8 + : OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitSbfmShift(AILEmitterCtx Context) + { + EmitBfmShift(Context, true); + } + + private static void EmitUbfmShift(AILEmitterCtx Context) + { + EmitBfmShift(Context, false); + } + + private static void EmitBfmShift(AILEmitterCtx Context, bool Signed) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + Context.EmitLdc_I4(Op.Shift); + + Context.Emit(Signed + ? OpCodes.Shr + : OpCodes.Shr_Un); + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitBfmLsl(AILEmitterCtx Context) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + Context.EmitLsl(Op.GetBitsCount() - Op.Shift); + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitBfmLoadRn(AILEmitterCtx Context) + { + AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + Context.EmitRor(Op.Shift); + + Context.EmitLdc_I(Op.WMask & Op.TMask); + + Context.Emit(OpCodes.And); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitCcmp.cs b/ChocolArm64/Instruction/AInstEmitCcmp.cs new file mode 100644 index 00000000..7153a6a0 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitCcmp.cs @@ -0,0 +1,81 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitAluHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + private enum CcmpOp + { + Cmp, + Cmn + } + + public static void Ccmn(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmn); + public static void Ccmp(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmp); + + private static void EmitCcmp(AILEmitterCtx Context, CcmpOp CmpOp) + { + AOpCodeCcmp Op = (AOpCodeCcmp)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + + Context.EmitLdc_I4((Op.NZCV >> 0) & 1); + + Context.EmitStflg((int)APState.VBit); + + Context.EmitLdc_I4((Op.NZCV >> 1) & 1); + + Context.EmitStflg((int)APState.CBit); + + Context.EmitLdc_I4((Op.NZCV >> 2) & 1); + + Context.EmitStflg((int)APState.ZBit); + + Context.EmitLdc_I4((Op.NZCV >> 3) & 1); + + Context.EmitStflg((int)APState.NBit); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitDataLoadOpers(Context); + + if (CmpOp == CcmpOp.Cmp) + { + Context.Emit(OpCodes.Sub); + + Context.EmitZNFlagCheck(); + + EmitSubsCCheck(Context); + EmitSubsVCheck(Context); + } + else if (CmpOp == CcmpOp.Cmn) + { + Context.Emit(OpCodes.Add); + + Context.EmitZNFlagCheck(); + + EmitAddsCCheck(Context); + EmitAddsVCheck(Context); + } + else + { + throw new ArgumentException(nameof(CmpOp)); + } + + Context.Emit(OpCodes.Pop); + + Context.MarkLabel(LblEnd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitCsel.cs b/ChocolArm64/Instruction/AInstEmitCsel.cs new file mode 100644 index 00000000..33080980 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitCsel.cs @@ -0,0 +1,59 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + private enum CselOperation + { + None, + Increment, + Invert, + Negate + } + + public static void Csel(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.None); + public static void Csinc(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Increment); + public static void Csinv(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Invert); + public static void Csneg(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Negate); + + private static void EmitCsel(AILEmitterCtx Context, CselOperation CselOp) + { + AOpCodeCsel Op = (AOpCodeCsel)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + Context.EmitLdintzr(Op.Rm); + + if (CselOp == CselOperation.Increment) + { + Context.EmitLdc_I(1); + + Context.Emit(OpCodes.Add); + } + else if (CselOp == CselOperation.Invert) + { + Context.Emit(OpCodes.Not); + } + else if (CselOp == CselOperation.Negate) + { + Context.Emit(OpCodes.Neg); + } + + Context.EmitStintzr(Op.Rd); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + Context.EmitLdintzr(Op.Rn); + Context.EmitStintzr(Op.Rd); + + Context.MarkLabel(LblEnd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs new file mode 100644 index 00000000..209ba56f --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitException.cs @@ -0,0 +1,65 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + private const BindingFlags Binding = BindingFlags.NonPublic | BindingFlags.Instance; + + public static void Brk(AILEmitterCtx Context) + { + EmitExceptionCall(Context, nameof(AThreadState.OnBreak)); + } + + public static void Svc(AILEmitterCtx Context) + { + EmitExceptionCall(Context, nameof(AThreadState.OnSvcCall)); + } + + private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName) + { + AOpCodeException Op = (AOpCodeException)Context.CurrOp; + + Context.EmitStoreState(); + + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + Context.EmitLdc_I4(Op.Id); + + MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); + + Context.EmitCall(MthdInfo); + + if (Context.CurrBlock.Next != null) + { + Context.EmitLoadState(Context.CurrBlock.Next); + } + } + + public static void Und(AILEmitterCtx Context) + { + AOpCode Op = Context.CurrOp; + + Context.EmitStoreState(); + + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + Context.EmitLdc_I8(Op.Position); + Context.EmitLdc_I4(Op.RawOpCode); + + string MthdName = nameof(AThreadState.OnUndefined); + + MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); + + Context.EmitCall(MthdInfo); + + if (Context.CurrBlock.Next != null) + { + Context.EmitLoadState(Context.CurrBlock.Next); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitFlow.cs b/ChocolArm64/Instruction/AInstEmitFlow.cs new file mode 100644 index 00000000..be68aa6c --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitFlow.cs @@ -0,0 +1,124 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void B(AILEmitterCtx Context) + { + AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; + + Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm)); + } + + public static void B_Cond(AILEmitterCtx Context) + { + AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp; + + Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond); + } + + public static void Bl(AILEmitterCtx Context) + { + AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; + + Context.EmitLdc_I(Op.Position + 4); + Context.EmitStint(AThreadState.LRIndex); + Context.EmitStoreState(); + + if (Context.TryOptEmitSubroutineCall()) + { + //Note: the return value of the called method will be placed + //at the Stack, the return value is always a Int64 with the + //return address of the function. We check if the address is + //correct, if it isn't we keep returning until we reach the dispatcher. + Context.Emit(OpCodes.Dup); + + Context.EmitLdc_I8(Op.Position + 4); + + AILLabel LblContinue = new AILLabel(); + + Context.Emit(OpCodes.Beq_S, LblContinue); + Context.Emit(OpCodes.Ret); + + Context.MarkLabel(LblContinue); + + Context.Emit(OpCodes.Pop); + + if (Context.CurrBlock.Next != null) + { + Context.EmitLoadState(Context.CurrBlock.Next); + } + } + else + { + Context.EmitLdc_I8(Op.Imm); + + Context.Emit(OpCodes.Ret); + } + } + + public static void Blr(AILEmitterCtx Context) + { + AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp; + + Context.EmitLdc_I(Op.Position + 4); + Context.EmitStint(AThreadState.LRIndex); + Context.EmitStoreState(); + Context.EmitLdintzr(Op.Rn); + + Context.Emit(OpCodes.Ret); + } + + public static void Br(AILEmitterCtx Context) + { + AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp; + + Context.EmitStoreState(); + Context.EmitLdintzr(Op.Rn); + + Context.Emit(OpCodes.Ret); + } + + public static void Cbnz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Bne_Un); + public static void Cbz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Beq); + + private static void EmitCb(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeBImmCmp Op = (AOpCodeBImmCmp)Context.CurrOp; + + Context.EmitLdintzr(Op.Rt); + Context.EmitLdc_I(0); + + Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + } + + public static void Ret(AILEmitterCtx Context) + { + Context.EmitStoreState(); + Context.EmitLdint(AThreadState.LRIndex); + + Context.Emit(OpCodes.Ret); + } + + public static void Tbnz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Bne_Un); + public static void Tbz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Beq); + + private static void EmitTb(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeBImmTest Op = (AOpCodeBImmTest)Context.CurrOp; + + Context.EmitLdintzr(Op.Rt); + Context.EmitLdc_I(1L << Op.Pos); + + Context.Emit(OpCodes.And); + + Context.EmitLdc_I(0); + + Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMemory.cs b/ChocolArm64/Instruction/AInstEmitMemory.cs new file mode 100644 index 00000000..af7de3ba --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMemory.cs @@ -0,0 +1,252 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Adr(AILEmitterCtx Context) + { + AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; + + Context.EmitLdc_I(Op.Position + Op.Imm); + Context.EmitStintzr(Op.Rd); + } + + public static void Adrp(AILEmitterCtx Context) + { + AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; + + Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12)); + Context.EmitStintzr(Op.Rd); + } + + public static void Ldr(AILEmitterCtx Context) => EmitLdr(Context, false); + public static void Ldrs(AILEmitterCtx Context) => EmitLdr(Context, true); + + public static void EmitLdr(AILEmitterCtx Context, bool Signed) + { + AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Signed && Op.Extend64) + { + EmitReadSx64Call(Context, Op.Size); + } + else if (Signed) + { + EmitReadSx32Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Op.Rt); + } + else + { + Context.EmitStintzr(Op.Rt); + } + + EmitWBackIfNeeded(Context); + } + + public static void LdrLit(AILEmitterCtx Context) + { + IAOpCodeLit Op = (IAOpCodeLit)Context.CurrOp; + + if (Op.Prefetch) + { + return; + } + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdc_I8(Op.Imm); + + if (Op.Signed) + { + EmitReadSx64Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Op.Rt); + } + else + { + Context.EmitStint(Op.Rt); + } + } + + public static void Ldp(AILEmitterCtx Context) + { + AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; + + void EmitReadAndStore(int Rt) + { + if (Op.Extend64) + { + EmitReadSx64Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Rt); + } + else + { + Context.EmitStintzr(Rt); + } + } + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + EmitReadAndStore(Op.Rt); + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdtmp(); + Context.EmitLdc_I8(1 << Op.Size); + + Context.Emit(OpCodes.Add); + + EmitReadAndStore(Op.Rt2); + + EmitWBackIfNeeded(Context); + } + + public static void Str(AILEmitterCtx Context) + { + AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt); + } + else + { + Context.EmitLdintzr(Op.Rt); + } + + EmitWriteCall(Context, Op.Size); + + EmitWBackIfNeeded(Context); + } + + public static void Stp(AILEmitterCtx Context) + { + AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt); + } + else + { + Context.EmitLdintzr(Op.Rt); + } + + EmitWriteCall(Context, Op.Size); + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdtmp(); + Context.EmitLdc_I8(1 << Op.Size); + + Context.Emit(OpCodes.Add); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt2); + } + else + { + Context.EmitLdintzr(Op.Rt2); + } + + EmitWriteCall(Context, Op.Size); + + EmitWBackIfNeeded(Context); + } + + private static void EmitLoadAddress(AILEmitterCtx Context) + { + switch (Context.CurrOp) + { + case AOpCodeMemImm Op: + Context.EmitLdint(Op.Rn); + + if (!Op.PostIdx) + { + //Pre-indexing. + Context.EmitLdc_I(Op.Imm); + + Context.Emit(OpCodes.Add); + } + break; + + case AOpCodeMemReg Op: + Context.EmitLdint(Op.Rn); + Context.EmitLdintzr(Op.Rm); + Context.EmitCast(Op.IntType); + + if (Op.Shift) + { + Context.EmitLsl(Op.Size); + } + + Context.Emit(OpCodes.Add); + break; + } + + //Save address to Scratch var since the register value may change. + Context.Emit(OpCodes.Dup); + + Context.EmitSttmp(); + } + + private static void EmitWBackIfNeeded(AILEmitterCtx Context) + { + //Check whenever the current OpCode has post-indexed write back, if so write it. + //Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both. + if (Context.CurrOp is AOpCodeMemImm Op && Op.WBack) + { + Context.EmitLdtmp(); + + if (Op.PostIdx) + { + Context.EmitLdc_I(Op.Imm); + + Context.Emit(OpCodes.Add); + } + + Context.EmitStint(Op.Rn); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMemoryEx.cs b/ChocolArm64/Instruction/AInstEmitMemoryEx.cs new file mode 100644 index 00000000..a339bb69 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMemoryEx.cs @@ -0,0 +1,180 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Memory; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; +using System.Threading; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + [Flags] + private enum AccessType + { + None = 0, + Ordered = 1, + Exclusive = 2, + OrderedEx = Ordered | Exclusive + } + + public static void Clrex(AILEmitterCtx Context) + { + EmitMemoryCall(Context, nameof(AMemory.ClearExclusive)); + } + + public static void Dmb(AILEmitterCtx Context) => EmitBarrier(Context); + public static void Dsb(AILEmitterCtx Context) => EmitBarrier(Context); + + public static void Ldar(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Ordered); + public static void Ldaxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.OrderedEx); + public static void Ldxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Exclusive); + public static void Ldxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.Exclusive); + public static void Ldaxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.OrderedEx); + + private static void EmitLdr(AILEmitterCtx Context, AccessType AccType) + { + EmitLoad(Context, AccType, false); + } + + private static void EmitLdp(AILEmitterCtx Context, AccessType AccType) + { + EmitLoad(Context, AccType, true); + } + + private static void EmitLoad(AILEmitterCtx Context, AccessType AccType, bool Pair) + { + AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + + EmitReadZxCall(Context, Op.Size); + + Context.EmitStintzr(Op.Rt); + + if (Pair) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I(8 << Op.Size); + + Context.Emit(OpCodes.Add); + + EmitReadZxCall(Context, Op.Size); + + Context.EmitStintzr(Op.Rt2); + } + + if (AccType.HasFlag(AccessType.Exclusive)) + { + EmitMemoryCall(Context, nameof(AMemory.SetExclusive), Op.Rn); + } + + if (AccType.HasFlag(AccessType.Ordered)) + { + EmitBarrier(Context); + } + } + + public static void Pfrm(AILEmitterCtx Context) + { + //Memory Prefetch, execute as no-op. + } + + public static void Stlr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Ordered); + public static void Stlxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.OrderedEx); + public static void Stxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Exclusive); + public static void Stxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.Exclusive); + public static void Stlxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.OrderedEx); + + private static void EmitStr(AILEmitterCtx Context, AccessType AccType) + { + EmitStore(Context, AccType, false); + } + + private static void EmitStp(AILEmitterCtx Context, AccessType AccType) + { + EmitStore(Context, AccType, true); + } + + private static void EmitStore(AILEmitterCtx Context, AccessType AccType, bool Pair) + { + AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; + + if (AccType.HasFlag(AccessType.Ordered)) + { + EmitBarrier(Context); + } + + AILLabel LblEx = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + if (AccType.HasFlag(AccessType.Exclusive)) + { + EmitMemoryCall(Context, nameof(AMemory.TestExclusive), Op.Rn); + + Context.Emit(OpCodes.Brtrue_S, LblEx); + + Context.EmitLdc_I8(1); + Context.EmitStintzr(Op.Rs); + + Context.Emit(OpCodes.Br_S, LblEnd); + } + + Context.MarkLabel(LblEx); + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdintzr(Op.Rt); + + EmitWriteCall(Context, Op.Size); + + if (Pair) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I(8 << Op.Size); + + Context.Emit(OpCodes.Add); + + Context.EmitLdintzr(Op.Rt2); + + EmitWriteCall(Context, Op.Size); + } + + if (AccType.HasFlag(AccessType.Exclusive)) + { + Context.EmitLdc_I8(0); + Context.EmitStintzr(Op.Rs); + + Clrex(Context); + } + + Context.MarkLabel(LblEnd); + } + + private static void EmitMemoryCall(AILEmitterCtx Context, string Name, int Rn = -1) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + if (Rn != -1) + { + Context.EmitLdint(Rn); + } + + Context.EmitCall(typeof(AMemory), Name); + } + + private static void EmitBarrier(AILEmitterCtx Context) + { + //Note: This barrier is most likely not necessary, and probably + //doesn't make any difference since we need to do a ton of stuff + //(software MMU emulation) to read or write anything anyway. + Context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs b/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs new file mode 100644 index 00000000..d5a0051b --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMemoryHelper.cs @@ -0,0 +1,138 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Memory; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static class AInstEmitMemoryHelper + { + private enum Extension + { + Zx, + Sx32, + Sx64 + } + + public static void EmitReadZxCall(AILEmitterCtx Context, int Size) + { + EmitReadCall(Context, Extension.Zx, Size); + } + + public static void EmitReadSx32Call(AILEmitterCtx Context, int Size) + { + EmitReadCall(Context, Extension.Sx32, Size); + } + + public static void EmitReadSx64Call(AILEmitterCtx Context, int Size) + { + EmitReadCall(Context, Extension.Sx64, Size); + } + + private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size) + { + bool IsSimd = GetIsSimd(Context); + + string Name = null; + + if (Size < 0 || Size > (IsSimd ? 4 : 3)) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + if (IsSimd) + { + switch (Size) + { + case 0: Name = nameof(AMemory.ReadVector8); break; + case 1: Name = nameof(AMemory.ReadVector16); break; + case 2: Name = nameof(AMemory.ReadVector32); break; + case 3: Name = nameof(AMemory.ReadVector64); break; + case 4: Name = nameof(AMemory.ReadVector128); break; + } + } + else + { + switch (Size) + { + case 0: Name = nameof(AMemory.ReadByte); break; + case 1: Name = nameof(AMemory.ReadUInt16); break; + case 2: Name = nameof(AMemory.ReadUInt32); break; + case 3: Name = nameof(AMemory.ReadUInt64); break; + } + } + + Context.EmitCall(typeof(AMemory), Name); + + if (!IsSimd) + { + if (Ext == Extension.Sx32 || + Ext == Extension.Sx64) + { + switch (Size) + { + case 0: Context.Emit(OpCodes.Conv_I1); break; + case 1: Context.Emit(OpCodes.Conv_I2); break; + case 2: Context.Emit(OpCodes.Conv_I4); break; + } + } + + if (Size < 3) + { + Context.Emit(Ext == Extension.Sx64 + ? OpCodes.Conv_I8 + : OpCodes.Conv_U8); + } + } + } + + public static void EmitWriteCall(AILEmitterCtx Context, int Size) + { + bool IsSimd = GetIsSimd(Context); + + string Name = null; + + if (Size < 0 || Size > (IsSimd ? 4 : 3)) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + if (Size < 3 && !IsSimd) + { + Context.Emit(OpCodes.Conv_I4); + } + + if (IsSimd) + { + switch (Size) + { + case 0: Name = nameof(AMemory.WriteVector8); break; + case 1: Name = nameof(AMemory.WriteVector16); break; + case 2: Name = nameof(AMemory.WriteVector32); break; + case 3: Name = nameof(AMemory.WriteVector64); break; + case 4: Name = nameof(AMemory.WriteVector128); break; + } + } + else + { + switch (Size) + { + case 0: Name = nameof(AMemory.WriteByte); break; + case 1: Name = nameof(AMemory.WriteUInt16); break; + case 2: Name = nameof(AMemory.WriteUInt32); break; + case 3: Name = nameof(AMemory.WriteUInt64); break; + } + } + + Context.EmitCall(typeof(AMemory), Name); + } + + private static bool GetIsSimd(AILEmitterCtx Context) + { + return Context.CurrOp is IAOpCodeSimd && + !(Context.CurrOp is AOpCodeSimdMemMs || + Context.CurrOp is AOpCodeSimdMemSs); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMove.cs b/ChocolArm64/Instruction/AInstEmitMove.cs new file mode 100644 index 00000000..719b53d5 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMove.cs @@ -0,0 +1,41 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Movk(AILEmitterCtx Context) + { + AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; + + Context.EmitLdintzr(Op.Rd); + Context.EmitLdc_I(~(0xffffL << Op.Pos)); + + Context.Emit(OpCodes.And); + + Context.EmitLdc_I(Op.Imm); + + Context.Emit(OpCodes.Or); + + Context.EmitStintzr(Op.Rd); + } + + public static void Movn(AILEmitterCtx Context) + { + AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; + + Context.EmitLdc_I(~Op.Imm); + Context.EmitStintzr(Op.Rd); + } + + public static void Movz(AILEmitterCtx Context) + { + AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; + + Context.EmitLdc_I(Op.Imm); + Context.EmitStintzr(Op.Rd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitMul.cs b/ChocolArm64/Instruction/AInstEmitMul.cs new file mode 100644 index 00000000..3713c81f --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMul.cs @@ -0,0 +1,80 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Madd(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Add); + public static void Msub(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Sub); + + private static void EmitMul(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; + + Context.EmitLdintzr(Op.Ra); + Context.EmitLdintzr(Op.Rn); + Context.EmitLdintzr(Op.Rm); + + Context.Emit(OpCodes.Mul); + Context.Emit(ILOp); + + Context.EmitStintzr(Op.Rd); + } + + public static void Smaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, true); + public static void Smsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, true); + public static void Umaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, false); + public static void Umsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, false); + + private static void EmitMull(AILEmitterCtx Context, OpCode AddSubOp, bool Signed) + { + AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; + + OpCode CastOp = Signed + ? OpCodes.Conv_I8 + : OpCodes.Conv_U8; + + Context.EmitLdintzr(Op.Ra); + Context.EmitLdintzr(Op.Rn); + + Context.Emit(OpCodes.Conv_I4); + Context.Emit(CastOp); + + Context.EmitLdintzr(Op.Rm); + + Context.Emit(OpCodes.Conv_I4); + Context.Emit(CastOp); + Context.Emit(OpCodes.Mul); + + Context.Emit(AddSubOp); + + Context.EmitStintzr(Op.Rd); + } + + public static void Smulh(AILEmitterCtx Context) + { + AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + Context.EmitLdintzr(Op.Rm); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SMulHi128)); + + Context.EmitStintzr(Op.Rd); + } + + public static void Umulh(AILEmitterCtx Context) + { + AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + Context.EmitLdintzr(Op.Rm); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UMulHi128)); + + Context.EmitStintzr(Op.Rd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs new file mode 100644 index 00000000..21ec11a7 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -0,0 +1,367 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Add_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Addp_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size); + + Context.Emit(OpCodes.Add); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Addp_V(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + int Half = Elems >> 1; + + for (int Index = 0; Index < Elems; Index++) + { + int Elem = (Index & (Half - 1)) << 1; + + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size); + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size); + + Context.Emit(OpCodes.Add); + + EmitVectorInsertTmp(Context, Index, Op.Size); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Addv_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + for (int Index = 1; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + + Context.Emit(OpCodes.Add); + } + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Cnt_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, 0); + + Context.Emit(OpCodes.Conv_U1); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8)); + + Context.Emit(OpCodes.Conv_U8); + + EmitVectorInsert(Context, Op.Rd, Index, 0); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Fabs_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Abs)); + }); + } + + public static void Fadd_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Fadd_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Fdiv_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); + } + + public static void Fdiv_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); + } + + public static void Fmadd_S(AILEmitterCtx Context) + { + EmitScalarTernaryRaOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmax_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + EmitBinaryMathCall(Context, nameof(Math.Max)); + }); + } + + public static void Fmin_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + EmitBinaryMathCall(Context, nameof(Math.Min)); + }); + } + + public static void Fmaxnm_S(AILEmitterCtx Context) + { + Fmax_S(Context); + } + + public static void Fminnm_S(AILEmitterCtx Context) + { + Fmin_S(Context); + } + + public static void Fmla_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmla_Ve(AILEmitterCtx Context) + { + EmitVectorTernaryOpByElemF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Fmsub_S(AILEmitterCtx Context) + { + EmitScalarTernaryRaOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Sub); + }); + } + + public static void Fmul_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fmul_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fmul_Ve(AILEmitterCtx Context) + { + EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Fneg_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg)); + } + + public static void Fnmul_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Neg); + }); + } + + public static void Fnmsub_S(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int SizeF = Op.Size & 1; + + EmitVectorExtractF(Context, Op.Rn, 0, SizeF); + EmitVectorExtractF(Context, Op.Rm, 0, SizeF); + + Context.Emit(OpCodes.Mul); + + EmitVectorExtractF(Context, Op.Ra, 0, SizeF); + + Context.Emit(OpCodes.Sub); + + EmitScalarSetF(Context, Op.Rd, SizeF); + } + + public static void Frinta_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Frintm_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Floor)); + }); + } + + public static void Fsqrt_S(AILEmitterCtx Context) + { + EmitScalarUnaryOpF(Context, () => + { + EmitUnaryMathCall(Context, nameof(Math.Sqrt)); + }); + } + + public static void Fsub_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Fsub_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Mla_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpZx(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Add); + }); + } + + public static void Mls_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpZx(Context, () => + { + Context.Emit(OpCodes.Mul); + Context.Emit(OpCodes.Sub); + }); + } + + public static void Mul_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Neg_V(AILEmitterCtx Context) + { + EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); + } + + public static void Saddw_V(AILEmitterCtx Context) + { + EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Smax_V(AILEmitterCtx Context) + { + Type[] Types = new Type[] { typeof(long), typeof(long) }; + + MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types); + + EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); + } + + public static void Smin_V(AILEmitterCtx Context) + { + Type[] Types = new Type[] { typeof(long), typeof(long) }; + + MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); + + EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); + } + + public static void Smull_V(AILEmitterCtx Context) + { + EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul)); + } + + public static void Sub_S(AILEmitterCtx Context) + { + EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Sub_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); + } + + public static void Uaddlv_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + for (int Index = 1; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); + + Context.Emit(OpCodes.Add); + } + + EmitScalarSet(Context, Op.Rd, Op.Size + 1); + } + + public static void Uaddw_V(AILEmitterCtx Context) + { + EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdCmp.cs b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs new file mode 100644 index 00000000..97ccf0ab --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdCmp.cs @@ -0,0 +1,233 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitAluHelper; +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Cmeq_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Beq_S); + } + + public static void Cmge_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bge_S); + } + + public static void Cmgt_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bgt_S); + } + + public static void Cmhi_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bgt_Un_S); + } + + public static void Cmhs_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Bge_Un_S); + } + + public static void Cmle_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Ble_S); + } + + public static void Cmlt_V(AILEmitterCtx Context) + { + EmitVectorCmp(Context, OpCodes.Blt_S); + } + + public static void Fccmp_S(AILEmitterCtx Context) + { + AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + + EmitSetNZCV(Context, Op.NZCV); + + Context.Emit(OpCodes.Br, LblEnd); + + Context.MarkLabel(LblTrue); + + Fcmp_S(Context); + + Context.MarkLabel(LblEnd); + } + + public static void Fccmpe_S(AILEmitterCtx Context) + { + Fccmp_S(Context); + } + + public static void Fcmp_S(AILEmitterCtx Context) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; + + //Handle NaN case. If any number is NaN, then NZCV = 0011. + if (CmpWithZero) + { + EmitNaNCheck(Context, Op.Rn); + } + else + { + EmitNaNCheck(Context, Op.Rn); + EmitNaNCheck(Context, Op.Rm); + + Context.Emit(OpCodes.Or); + } + + AILLabel LblNaN = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(OpCodes.Brtrue_S, LblNaN); + + void EmitLoadOpers() + { + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (CmpWithZero) + { + EmitLdcImmF(Context, 0, Op.Size); + } + else + { + EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); + } + } + + //Z = Rn == Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Ceq); + Context.Emit(OpCodes.Dup); + + Context.EmitStflg((int)APState.ZBit); + + //C = Rn >= Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Cgt); + Context.Emit(OpCodes.Or); + + Context.EmitStflg((int)APState.CBit); + + //N = Rn < Rm + EmitLoadOpers(); + + Context.Emit(OpCodes.Clt); + + Context.EmitStflg((int)APState.NBit); + + //V = 0 + Context.EmitLdc_I4(0); + + Context.EmitStflg((int)APState.VBit); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblNaN); + + EmitSetNZCV(Context, 0b0011); + + Context.MarkLabel(LblEnd); + } + + public static void Fcmpe_S(AILEmitterCtx Context) + { + Fcmp_S(Context); + } + + private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size) + { + if (Size == 0) + { + Context.EmitLdc_R4((float)ImmF); + } + else if (Size == 1) + { + Context.EmitLdc_R8(ImmF); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + private static void EmitNaNCheck(AILEmitterCtx Context, int Reg) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Reg, 0, Op.Size); + + if (Op.Size == 0) + { + Context.EmitCall(typeof(float), nameof(float.IsNaN)); + } + else if (Op.Size == 1) + { + Context.EmitCall(typeof(double), nameof(double.IsNaN)); + } + else + { + throw new InvalidOperationException(); + } + } + + private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); + + if (Op is AOpCodeSimdReg BinOp) + { + EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); + } + else + { + Context.EmitLdc_I8(0); + } + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.Emit(ILOp, LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); + + Context.MarkLabel(LblEnd); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdCvt.cs b/ChocolArm64/Instruction/AInstEmitSimdCvt.cs new file mode 100644 index 00000000..00c2fe9b --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdCvt.cs @@ -0,0 +1,444 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Fcvt_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitFloatCast(Context, Op.Opc); + + EmitScalarSetF(Context, Op.Rd, Op.Opc); + } + + public static void Fcvtas_Gp(AILEmitterCtx Context) + { + Fcvta__Gp(Context, Signed: true); + } + + public static void Fcvtau_Gp(AILEmitterCtx Context) + { + Fcvta__Gp(Context, Signed: false); + } + + public static void Fcvtms_Gp(AILEmitterCtx Context) + { + EmitFcvt_s_Gp(Context, nameof(Math.Floor)); + } + + public static void Fcvtps_Gp(AILEmitterCtx Context) + { + EmitFcvt_s_Gp(Context, nameof(Math.Ceiling)); + } + + public static void Fcvtzs_Gp(AILEmitterCtx Context) + { + EmitFcvtz__Gp(Context, Signed: true); + } + + public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context) + { + EmitFcvtz__Gp_Fix(Context, Signed: true); + } + + public static void Fcvtzs_V(AILEmitterCtx Context) + { + EmitVectorFcvt(Context, Signed: true); + } + + public static void Fcvtzu_Gp(AILEmitterCtx Context) + { + EmitFcvtz__Gp(Context, Signed: false); + } + + public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context) + { + EmitFcvtz__Gp_Fix(Context, Signed: false); + } + + public static void Fcvtzu_V(AILEmitterCtx Context) + { + EmitVectorFcvt(Context, Signed: false); + } + + public static void Scvtf_Gp(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + } + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Scvtf_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Scvtf_V(AILEmitterCtx Context) + { + EmitVectorCvtf(Context, Signed: true); + } + + public static void Ucvtf_Gp(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + } + + Context.Emit(OpCodes.Conv_R_Un); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Ucvtf_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size + 2); + + Context.Emit(OpCodes.Conv_R_Un); + + EmitFloatCast(Context, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Ucvtf_V(AILEmitterCtx Context) + { + EmitVectorCvtf(Context, Signed: false); + } + + private static int GetFBits(AILEmitterCtx Context) + { + if (Context.CurrOp is AOpCodeSimdShImm Op) + { + return GetImmShr(Op); + } + + return 0; + } + + private static void EmitFloatCast(AILEmitterCtx Context, int Size) + { + if (Size == 0) + { + Context.Emit(OpCodes.Conv_R4); + } + else if (Size == 1) + { + Context.Emit(OpCodes.Conv_R8); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + private static void Fcvta__Gp(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, 0); + } + else + { + EmitScalarFcvtu(Context, Op.Size, 0); + } + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitFcvt_s_Gp(AILEmitterCtx Context, string Name) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitUnaryMathCall(Context, Name); + + EmitScalarFcvts(Context, Op.Size, 0); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, 0); + } + else + { + EmitScalarFcvtu(Context, Op.Size, 0); + } + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + if (Signed) + { + EmitScalarFcvts(Context, Op.Size, Op.FBits); + } + else + { + EmitScalarFcvtu(Context, Op.Size, Op.FBits); + } + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rd); + } + + private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + int SizeI = SizeF + 2; + + int FBits = GetFBits(Context); + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeI); Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed); + + if (!Signed) + { + Context.Emit(OpCodes.Conv_R_Un); + } + + Context.Emit(SizeF == 0 + ? OpCodes.Conv_R4 + : OpCodes.Conv_R8); + + EmitI2fFBitsMul(Context, SizeF, FBits); + + EmitVectorInsertF(Context, Op.Rd, Index, SizeF); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + int SizeI = SizeF + 2; + + int FBits = GetFBits(Context); + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeI); Index++) + { + EmitVectorExtractF(Context, Op.Rn, Index, SizeF); + + EmitF2iFBitsMul(Context, SizeF, FBits); + + if (SizeF == 0) + { + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatF32ToS32) + : nameof(ASoftFallback.SatF32ToU32)); + } + else /* if (SizeF == 1) */ + { + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.SatF64ToS64) + : nameof(ASoftFallback.SatF64ToU64)); + } + + if (SizeF == 0) + { + Context.Emit(OpCodes.Conv_U8); + } + + EmitVectorInsert(Context, Op.Rd, Index, SizeI); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitScalarFcvts(AILEmitterCtx Context, int Size, int FBits) + { + if (Size < 0 || Size > 1) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + EmitF2iFBitsMul(Context, Size, FBits); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS32)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS32)); + } + } + else + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS64)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS64)); + } + } + } + + private static void EmitScalarFcvtu(AILEmitterCtx Context, int Size, int FBits) + { + if (Size < 0 || Size > 1) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + EmitF2iFBitsMul(Context, Size, FBits); + + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU32)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU32)); + } + } + else + { + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU64)); + } + else /* if (Size == 1) */ + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU64)); + } + } + } + + private static void EmitF2iFBitsMul(AILEmitterCtx Context, int Size, int FBits) + { + if (FBits != 0) + { + if (Size == 0) + { + Context.EmitLdc_R4(MathF.Pow(2, FBits)); + } + else if (Size == 1) + { + Context.EmitLdc_R8(Math.Pow(2, FBits)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.Emit(OpCodes.Mul); + } + } + + private static void EmitI2fFBitsMul(AILEmitterCtx Context, int Size, int FBits) + { + if (FBits != 0) + { + if (Size == 0) + { + Context.EmitLdc_R4(1f / MathF.Pow(2, FBits)); + } + else if (Size == 1) + { + Context.EmitLdc_R8(1 / Math.Pow(2, FBits)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.Emit(OpCodes.Mul); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs new file mode 100644 index 00000000..20c8be26 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -0,0 +1,616 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; + +namespace ChocolArm64.Instruction +{ + static class AInstEmitSimdHelper + { + [Flags] + public enum OperFlags + { + Rd = 1 << 0, + Rn = 1 << 1, + Rm = 1 << 2, + Ra = 1 << 3, + + RnRm = Rn | Rm, + RdRn = Rd | Rn, + RaRnRm = Ra | Rn | Rm, + RdRnRm = Rd | Rn | Rm + } + + public static int GetImmShl(AOpCodeSimdShImm Op) + { + return Op.Imm - (8 << Op.Size); + } + + public static int GetImmShr(AOpCodeSimdShImm Op) + { + return (8 << (Op.Size + 1)) - Op.Imm; + } + + public static void EmitUnaryMathCall(AILEmitterCtx Context, string Name) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + MethodInfo MthdInfo; + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) }); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) }); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + + public static void EmitBinaryMathCall(AILEmitterCtx Context, string Name) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + MethodInfo MthdInfo; + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + + public static void EmitRoundMathCall(AILEmitterCtx Context, MidpointRounding RoundMode) + { + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + Context.EmitLdc_I4((int)RoundMode); + + MethodInfo MthdInfo; + + Type[] Types = new Type[] { null, typeof(MidpointRounding) }; + + Types[0] = Op.Size == 0 + ? typeof(float) + : typeof(double); + + if (Op.Size == 0) + { + MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); + } + else if (Op.Size == 1) + { + MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); + } + else + { + throw new InvalidOperationException(); + } + + Context.EmitCall(MthdInfo); + } + + public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.Rn, true); + } + + public static void EmitScalarBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RnRm, true); + } + + public static void EmitScalarUnaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.Rn, false); + } + + public static void EmitScalarBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RnRm, false); + } + + public static void EmitScalarTernaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitScalarOp(Context, Emit, OperFlags.RdRnRm, false); + } + + public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed); + } + + Emit(); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void EmitScalarUnaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.Rn); + } + + public static void EmitScalarBinaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.RnRm); + } + + public static void EmitScalarTernaryRaOpF(AILEmitterCtx Context, Action Emit) + { + EmitScalarOpF(Context, Emit, OperFlags.RaRnRm); + } + + public static void EmitScalarOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + + if (Opers.HasFlag(OperFlags.Ra)) + { + EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtractF(Context, Op.Rn, 0, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF); + } + + Emit(); + + EmitScalarSetF(Context, Op.Rd, SizeF); + } + + public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitVectorOpF(Context, Emit, OperFlags.RnRm); + } + + public static void EmitVectorTernaryOpF(AILEmitterCtx Context, Action Emit) + { + EmitVectorOpF(Context, Emit, OperFlags.RdRnRm); + } + + public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false); + } + + public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit) + { + AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; + + EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true); + } + + public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int SizeF = Op.Size & 1; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) + { + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtractF(Context, Op.Rd, Index, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtractF(Context, Op.Rn, Index, SizeF); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtractF(Context, Op.Rm, Index, SizeF); + } + + Emit(); + + EmitVectorInsertF(Context, Op.Rd, Index, SizeF); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int SizeF = Op.Size & 1; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) + { + if (Ternary) + { + EmitVectorExtractF(Context, Op.Rd, Index, SizeF); + } + + EmitVectorExtractF(Context, Op.Rn, Index, SizeF); + EmitVectorExtractF(Context, Op.Rm, Elem, SizeF); + + Emit(); + + EmitVectorInsertTmpF(Context, Index, SizeF); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorUnaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.Rn, true); + } + + public static void EmitVectorBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RnRm, true); + } + + public static void EmitVectorUnaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.Rn, false); + } + + public static void EmitVectorBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RnRm, false); + } + + public static void EmitVectorTernaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false); + } + + public static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + if (Opers.HasFlag(OperFlags.Rd)) + { + EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rn)) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); + } + + if (Opers.HasFlag(OperFlags.Rm)) + { + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); + } + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit) + { + EmitVectorImmOp(Context, Emit, false); + } + + public static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit) + { + EmitVectorImmOp(Context, Emit, true); + } + + public static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary) + { + AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + if (Binary) + { + EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size); + } + + Context.EmitLdc_I8(Op.Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRmBinaryOp(Context, Emit, true); + } + + public static void EmitVectorWidenRmBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRmBinaryOp(Context, Emit, false); + } + + public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); + EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + + public static void EmitVectorWidenRnRmBinaryOpSx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRnRmBinaryOp(Context, Emit, true); + } + + public static void EmitVectorWidenRnRmBinaryOpZx(AILEmitterCtx Context, Action Emit) + { + EmitVectorWidenRnRmBinaryOp(Context, Emit, false); + } + + public static void EmitVectorWidenRnRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); + EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + + public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size) + { + EmitVectorZeroAll(Context, Reg); + EmitVectorInsert(Context, Reg, 0, Size); + } + + public static void EmitScalarSetF(AILEmitterCtx Context, int Reg, int Size) + { + EmitVectorZeroAll(Context, Reg); + EmitVectorInsertF(Context, Reg, 0, Size); + } + + public static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size) + { + EmitVectorExtract(Context, Reg, Index, Size, true); + } + + public static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size) + { + EmitVectorExtract(Context, Reg, Index, Size, false); + } + + public static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; + + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, Signed + ? nameof(ASoftFallback.VectorExtractIntSx) + : nameof(ASoftFallback.VectorExtractIntZx)); + } + + public static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size) + { + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle)); + } + else if (Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } + + public static void EmitVectorZeroAll(AILEmitterCtx Context, int Rd) + { + EmitVectorZeroLower(Context, Rd); + EmitVectorZeroUpper(Context, Rd); + } + + public static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd) + { + EmitVectorInsert(Context, Rd, 0, 3, 0); + } + + public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd) + { + EmitVectorInsert(Context, Rd, 1, 3, 0); + } + + public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvec(Reg); + } + + public static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdvectmp(); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvectmp(); + } + + public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) + { + if (Size < 0 || Size > 3) + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitLdc_I8(Value); + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + Context.EmitLdc_I4(Size); + + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); + + Context.EmitStvec(Reg); + } + + public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size) + { + Context.EmitLdvec(Reg); + Context.EmitLdc_I4(Index); + + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); + } + else if (Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitStvec(Reg); + } + + public static void EmitVectorInsertTmpF(AILEmitterCtx Context, int Index, int Size) + { + Context.EmitLdvectmp(); + Context.EmitLdc_I4(Index); + + if (Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); + } + else if (Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + Context.EmitStvectmp(); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdLogical.cs b/ChocolArm64/Instruction/AInstEmitSimdLogical.cs new file mode 100644 index 00000000..ea4b17b3 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdLogical.cs @@ -0,0 +1,69 @@ +using ChocolArm64.Translation; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void And_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.And)); + } + + public static void Bic_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => + { + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + }); + } + + public static void Bic_Vi(AILEmitterCtx Context) + { + EmitVectorImmBinaryOp(Context, () => + { + Context.Emit(OpCodes.Not); + Context.Emit(OpCodes.And); + }); + } + + public static void Bsl_V(AILEmitterCtx Context) + { + EmitVectorTernaryOpZx(Context, () => + { + Context.EmitSttmp(); + Context.EmitLdtmp(); + + Context.Emit(OpCodes.Xor); + Context.Emit(OpCodes.And); + + Context.EmitLdtmp(); + + Context.Emit(OpCodes.Xor); + }); + } + + public static void Eor_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Xor)); + } + + public static void Not_V(AILEmitterCtx Context) + { + EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not)); + } + + public static void Orr_V(AILEmitterCtx Context) + { + EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Or)); + } + + public static void Orr_Vi(AILEmitterCtx Context) + { + EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdMemory.cs b/ChocolArm64/Instruction/AInstEmitSimdMemory.cs new file mode 100644 index 00000000..d98ec012 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdMemory.cs @@ -0,0 +1,184 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Ld__Vms(AILEmitterCtx Context) + { + EmitSimdMemMs(Context, IsLoad: true); + } + + public static void Ld__Vss(AILEmitterCtx Context) + { + EmitSimdMemSs(Context, IsLoad: true); + } + + public static void St__Vms(AILEmitterCtx Context) + { + EmitSimdMemMs(Context, IsLoad: false); + } + + public static void St__Vss(AILEmitterCtx Context) + { + EmitSimdMemSs(Context, IsLoad: false); + } + + private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) + { + AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp; + + int Offset = 0; + + for (int Rep = 0; Rep < Op.Reps; Rep++) + for (int Elem = 0; Elem < Op.Elems; Elem++) + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rtt = (Op.Rt + Rep + SElem) & 0x1f; + + if (IsLoad) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rtt, Elem, Op.Size); + + if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) + { + EmitVectorZeroUpper(Context, Rtt); + } + } + else + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitVectorExtractZx(Context, Rtt, Elem, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad) + { + AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp; + + int Offset = 0; + + void EmitMemAddress() + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + } + + if (Op.Replicate) + { + //Only loads uses the replicate mode. + if (!IsLoad) + { + throw new InvalidOperationException(); + } + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rt = (Op.Rt + SElem) & 0x1f; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitMemAddress(); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rt, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Rt); + } + + Offset += 1 << Op.Size; + } + } + else + { + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rt = (Op.Rt + SElem) & 0x1f; + + if (IsLoad) + { + EmitMemAddress(); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rt, Op.Index, Op.Size); + } + else + { + EmitMemAddress(); + + EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) + { + AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; + + Context.EmitLdint(Op.Rn); + + if (Op.Rm != AThreadState.ZRIndex) + { + Context.EmitLdint(Op.Rm); + } + else + { + Context.EmitLdc_I8(Offset); + } + + Context.Emit(OpCodes.Add); + + Context.EmitStint(Op.Rn); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdMove.cs b/ChocolArm64/Instruction/AInstEmitSimdMove.cs new file mode 100644 index 00000000..aabb8f34 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdMove.cs @@ -0,0 +1,333 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Dup_Gp(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + Context.EmitLdintzr(Op.Rn); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Dup_S(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Dup_V(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Fcsel_S(AILEmitterCtx Context) + { + AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; + + AILLabel LblTrue = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + Context.EmitCondBranch(LblTrue, Op.Cond); + + EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); + + Context.Emit(OpCodes.Br_S, LblEnd); + + Context.MarkLabel(LblTrue); + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + Context.MarkLabel(LblEnd); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Fmov_Ftoi(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, 3); + + EmitIntZeroHigherIfNeeded(Context); + + Context.EmitStintzr(Op.Rd); + } + + public static void Fmov_Ftoi1(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 1, 3); + + EmitIntZeroHigherIfNeeded(Context); + + Context.EmitStintzr(Op.Rd); + } + + public static void Fmov_Itof(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitIntZeroHigherIfNeeded(Context); + + EmitScalarSet(Context, Op.Rd, 3); + } + + public static void Fmov_Itof1(AILEmitterCtx Context) + { + AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitIntZeroHigherIfNeeded(Context); + + EmitVectorInsert(Context, Op.Rd, 1, 3); + } + + public static void Fmov_S(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); + + EmitScalarSetF(Context, Op.Rd, Op.Size); + } + + public static void Fmov_Si(AILEmitterCtx Context) + { + AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; + + Context.EmitLdc_I8(Op.Imm); + + EmitScalarSet(Context, Op.Rd, Op.Size + 2); + } + + public static void Fmov_V(AILEmitterCtx Context) + { + AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; + + int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 4 : 2; + + for (int Index = 0; Index < (Elems >> Op.Size); Index++) + { + Context.EmitLdc_I8(Op.Imm); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size + 2); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Ins_Gp(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + Context.EmitLdintzr(Op.Rn); + + EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); + } + + public static void Ins_V(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); + } + + public static void Movi_V(AILEmitterCtx Context) + { + EmitVectorImmUnaryOp(Context, () => { }); + } + + public static void Mvni_V(AILEmitterCtx Context) + { + EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not)); + } + + public static void Tbl_V(AILEmitterCtx Context) + { + AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp; + + Context.EmitLdvec(Op.Rm); + + for (int Index = 0; Index < Op.Size; Index++) + { + Context.EmitLdvec((Op.Rn + Index) & 0x1f); + } + + switch (Op.Size) + { + case 1: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl1_V64), + nameof(ASoftFallback.Tbl1_V128)); break; + + case 2: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl2_V64), + nameof(ASoftFallback.Tbl2_V128)); break; + + case 3: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl3_V64), + nameof(ASoftFallback.Tbl3_V128)); break; + + case 4: ASoftFallback.EmitCall(Context, + nameof(ASoftFallback.Tbl4_V64), + nameof(ASoftFallback.Tbl4_V128)); break; + + default: throw new InvalidOperationException(); + } + + Context.EmitStvec(Op.Rd); + } + + public static void Umov_S(AILEmitterCtx Context) + { + AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); + + Context.EmitStintzr(Op.Rd); + } + + public static void Uzp1_V(AILEmitterCtx Context) + { + EmitVectorUnzip(Context, Part: 0); + } + + public static void Uzp2_V(AILEmitterCtx Context) + { + EmitVectorUnzip(Context, Part: 1); + } + + public static void Xtn_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); + + EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); + } + + if (Part == 0) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + public static void Zip1_V(AILEmitterCtx Context) + { + EmitVectorZip(Context, Part: 0); + } + + public static void Zip2_V(AILEmitterCtx Context) + { + EmitVectorZip(Context, Part: 1); + } + + private static void EmitIntZeroHigherIfNeeded(AILEmitterCtx Context) + { + if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) + { + Context.Emit(OpCodes.Conv_U4); + Context.Emit(OpCodes.Conv_U8); + } + } + + private static void EmitVectorUnzip(AILEmitterCtx Context, int Part) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + int Half = Elems >> 1; + + for (int Index = 0; Index < Elems; Index++) + { + int Elem = Part + ((Index & (Half - 1)) << 1); + + EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorZip(AILEmitterCtx Context, int Part) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + int Elems = Bytes >> Op.Size; + int Half = Elems >> 1; + + for (int Index = 0; Index < Elems; Index++) + { + int Elem = Part * Half + (Index >> 1); + + EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSimdShift.cs b/ChocolArm64/Instruction/AInstEmitSimdShift.cs new file mode 100644 index 00000000..8740ba4d --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdShift.cs @@ -0,0 +1,297 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Shl_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdc_I4(GetImmShl(Op)); + + Context.Emit(OpCodes.Shl); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Shl_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Shrn_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = (8 << (Op.Size + 1)) - Op.Imm; + + EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift); + } + + public static void Sshl_V(AILEmitterCtx Context) + { + EmitVectorShl(Context, Signed: true); + } + + public static void Sshll_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Sshr_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size); + + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr); + + EmitScalarSet(Context, Op.Rd, Op.Size); + } + + public static void Sshr_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = (8 << (Op.Size + 1)) - Op.Imm; + + EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); + } + + public static void Ushl_V(AILEmitterCtx Context) + { + EmitVectorShl(Context, Signed: false); + } + + public static void Ushll_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Shift = Op.Imm - (8 << Op.Size); + + EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); + } + + public static void Ushr_S(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitScalarUnaryOpZx(Context, () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + }); + } + + public static void Ushr_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + EmitVectorUnaryOpZx(Context, () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + }); + } + + public static void Usra_V(AILEmitterCtx Context) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + Action Emit = () => + { + Context.EmitLdc_I4(GetImmShr(Op)); + + Context.Emit(OpCodes.Shr_Un); + Context.Emit(OpCodes.Add); + }; + + EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); + } + + private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) + { + //This instruction shifts the value on vector A by the number of bits + //specified on the signed, lower 8 bits of vector B. If the shift value + //is greater or equal to the data size of each lane, then the result is zero. + //Additionally, negative shifts produces right shifts by the negated shift value. + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int MaxShift = 8 << Op.Size; + + Action Emit = () => + { + AILLabel LblShl = new AILLabel(); + AILLabel LblZero = new AILLabel(); + AILLabel LblEnd = new AILLabel(); + + void EmitShift(OpCode ILOp) + { + Context.Emit(OpCodes.Dup); + + Context.EmitLdc_I4(MaxShift); + + Context.Emit(OpCodes.Bge_S, LblZero); + Context.Emit(ILOp); + Context.Emit(OpCodes.Br_S, LblEnd); + } + + Context.Emit(OpCodes.Conv_I1); + Context.Emit(OpCodes.Dup); + + Context.EmitLdc_I4(0); + + Context.Emit(OpCodes.Bge_S, LblShl); + Context.Emit(OpCodes.Neg); + + EmitShift(Signed + ? OpCodes.Shr + : OpCodes.Shr_Un); + + Context.MarkLabel(LblShl); + + EmitShift(OpCodes.Shl); + + Context.MarkLabel(LblZero); + + Context.Emit(OpCodes.Pop); + Context.Emit(OpCodes.Pop); + + Context.EmitLdc_I8(0); + + Context.MarkLabel(LblEnd); + }; + + if (Signed) + { + EmitVectorBinaryOpSx(Context, Emit); + } + else + { + EmitVectorBinaryOpZx(Context, Emit); + } + } + + private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); + } + + if (Part == 0) + { + EmitVectorZeroUpper(Context, Op.Rd); + } + } + + private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true); + } + + private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) + { + EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false); + } + + private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) + { + AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; + + int Elems = 8 >> Op.Size; + + int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; + + for (int Index = 0; Index < Elems; Index++) + { + EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); + + Context.EmitLdc_I4(Imm); + + Emit(); + + EmitVectorInsertTmp(Context, Index, Op.Size + 1); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(Op.Rd); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitSystem.cs b/ChocolArm64/Instruction/AInstEmitSystem.cs new file mode 100644 index 00000000..6754be7a --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSystem.cs @@ -0,0 +1,122 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Mrs(AILEmitterCtx Context) + { + AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + + string PropName; + + switch (GetPackedId(Op)) + { + case 0b11_011_0000_0000_001: PropName = nameof(AThreadState.CtrEl0); break; + case 0b11_011_0000_0000_111: PropName = nameof(AThreadState.DczidEl0); break; + case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr); break; + case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr); break; + case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break; + case 0b11_011_1101_0000_011: PropName = nameof(AThreadState.Tpidr); break; + case 0b11_011_1110_0000_001: PropName = nameof(AThreadState.CntpctEl0); break; + + default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}"); + } + + Context.EmitCallPropGet(typeof(AThreadState), PropName); + + PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName); + + if (PropInfo.PropertyType != typeof(long) && + PropInfo.PropertyType != typeof(ulong)) + { + Context.Emit(OpCodes.Conv_U8); + } + + Context.EmitStintzr(Op.Rt); + } + + public static void Msr(AILEmitterCtx Context) + { + AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.StateArgIdx); + Context.EmitLdintzr(Op.Rt); + + string PropName; + + switch (GetPackedId(Op)) + { + case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr); break; + case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr); break; + case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break; + + default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}"); + } + + PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName); + + if (PropInfo.PropertyType != typeof(long) && + PropInfo.PropertyType != typeof(ulong)) + { + Context.Emit(OpCodes.Conv_U4); + } + + Context.EmitCallPropSet(typeof(AThreadState), PropName); + } + + public static void Nop(AILEmitterCtx Context) + { + //Do nothing. + } + + public static void Sys(AILEmitterCtx Context) + { + //This instruction is used to do some operations on the CPU like cache invalidation, + //address translation and the like. + //We treat it as no-op here since we don't have any cache being emulated anyway. + AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; + + switch (GetPackedId(Op)) + { + case 0b11_011_0111_0100_001: + { + //DC ZVA + for (int Offs = 0; Offs < (4 << AThreadState.DczSizeLog2); Offs += 8) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rt); + Context.EmitLdc_I(Offs); + + Context.Emit(OpCodes.Add); + + Context.EmitLdc_I8(0); + + AInstEmitMemoryHelper.EmitWriteCall(Context, 3); + } + break; + } + } + } + + private static int GetPackedId(AOpCodeSystem Op) + { + int Id; + + Id = Op.Op2 << 0; + Id |= Op.CRm << 3; + Id |= Op.CRn << 7; + Id |= Op.Op1 << 11; + Id |= Op.Op0 << 14; + + return Id; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/AInstEmitter.cs b/ChocolArm64/Instruction/AInstEmitter.cs new file mode 100644 index 00000000..8712a736 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitter.cs @@ -0,0 +1,6 @@ +using ChocolArm64.Translation; + +namespace ChocolArm64.Instruction +{ + delegate void AInstEmitter(AILEmitterCtx Context); +} \ No newline at end of file diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs new file mode 100644 index 00000000..a57966ba --- /dev/null +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -0,0 +1,316 @@ +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace ChocolArm64.Instruction +{ + static class ASoftFallback + { + public static void EmitCall(AILEmitterCtx Context, string Name64, string Name128) + { + bool IsSimd64 = Context.CurrOp.RegisterSize == ARegisterSize.SIMD64; + + Context.EmitCall(typeof(ASoftFallback), IsSimd64 ? Name64 : Name128); + } + + public static void EmitCall(AILEmitterCtx Context, string MthdName) + { + Context.EmitCall(typeof(ASoftFallback), MthdName); + } + + public static uint CountLeadingZeros32(uint Value) => (uint)CountLeadingZeros(Value, 32); + public static ulong CountLeadingZeros64(ulong Value) => (ulong)CountLeadingZeros(Value, 64); + + private static ulong CountLeadingZeros(ulong Value, int Size) + { + int HighBit = Size - 1; + + for (int Bit = HighBit; Bit >= 0; Bit--) + { + if (((Value >> Bit) & 1) != 0) + { + return (ulong)(HighBit - Bit); + } + } + + return (ulong)Size; + } + + public static uint ReverseBits32(uint Value) + { + Value = ((Value & 0xaaaaaaaa) >> 1) | ((Value & 0x55555555) << 1); + Value = ((Value & 0xcccccccc) >> 2) | ((Value & 0x33333333) << 2); + Value = ((Value & 0xf0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f) << 4); + Value = ((Value & 0xff00ff00) >> 8) | ((Value & 0x00ff00ff) << 8); + + return (Value >> 16) | (Value << 16); + } + + public static ulong ReverseBits64(ulong Value) + { + Value = ((Value & 0xaaaaaaaaaaaaaaaa) >> 1) | ((Value & 0x5555555555555555) << 1); + Value = ((Value & 0xcccccccccccccccc) >> 2) | ((Value & 0x3333333333333333) << 2); + Value = ((Value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f0f0f0f0f) << 4); + Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); + Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16); + + return (Value >> 32) | (Value << 32); + } + + public static uint ReverseBytes16_32(uint Value) => (uint)ReverseBytes16_64(Value); + public static uint ReverseBytes32_32(uint Value) => (uint)ReverseBytes32_64(Value); + + public static ulong ReverseBytes16_64(ulong Value) => ReverseBytes(Value, RevSize.Rev16); + public static ulong ReverseBytes32_64(ulong Value) => ReverseBytes(Value, RevSize.Rev32); + public static ulong ReverseBytes64(ulong Value) => ReverseBytes(Value, RevSize.Rev64); + + private enum RevSize + { + Rev16, + Rev32, + Rev64 + } + + private static ulong ReverseBytes(ulong Value, RevSize Size) + { + Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); + + if (Size == RevSize.Rev16) + { + return Value; + } + + Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16); + + if (Size == RevSize.Rev32) + { + return Value; + } + + Value = ((Value & 0xffffffff00000000) >> 32) | ((Value & 0x00000000ffffffff) << 32); + + if (Size == RevSize.Rev64) + { + return Value; + } + + throw new ArgumentException(nameof(Size)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SatF32ToS32(float Value) + { + if (float.IsNaN(Value)) return 0; + + return Value > int.MaxValue ? int.MaxValue : + Value < int.MinValue ? int.MinValue : (int)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SatF32ToS64(float Value) + { + if (float.IsNaN(Value)) return 0; + + return Value > long.MaxValue ? long.MaxValue : + Value < long.MinValue ? long.MinValue : (long)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SatF32ToU32(float Value) + { + if (float.IsNaN(Value)) return 0; + + return Value > uint.MaxValue ? uint.MaxValue : + Value < uint.MinValue ? uint.MinValue : (uint)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SatF32ToU64(float Value) + { + if (float.IsNaN(Value)) return 0; + + return Value > ulong.MaxValue ? ulong.MaxValue : + Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SatF64ToS32(double Value) + { + if (double.IsNaN(Value)) return 0; + + return Value > int.MaxValue ? int.MaxValue : + Value < int.MinValue ? int.MinValue : (int)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long SatF64ToS64(double Value) + { + if (double.IsNaN(Value)) return 0; + + return Value > long.MaxValue ? long.MaxValue : + Value < long.MinValue ? long.MinValue : (long)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SatF64ToU32(double Value) + { + if (double.IsNaN(Value)) return 0; + + return Value > uint.MaxValue ? uint.MaxValue : + Value < uint.MinValue ? uint.MinValue : (uint)Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong SatF64ToU64(double Value) + { + if (double.IsNaN(Value)) return 0; + + return Value > ulong.MaxValue ? ulong.MaxValue : + Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; + } + + public static long SMulHi128(long LHS, long RHS) + { + return (long)(BigInteger.Multiply(LHS, RHS) >> 64); + } + + public static ulong UMulHi128(ulong LHS, ulong RHS) + { + return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64); + } + + public static int CountSetBits8(byte Value) + { + return (Value >> 0) & 1 + (Value >> 1) & 1 + + (Value >> 2) & 1 + (Value >> 3) & 1 + + (Value >> 4) & 1 + (Value >> 5) & 1 + + (Value >> 6) & 1 + (Value >> 7); + } + + public static AVec Tbl1_V64(AVec Vector, AVec Tb0) + { + return Tbl(Vector, 8, Tb0); + } + + public static AVec Tbl1_V128(AVec Vector, AVec Tb0) + { + return Tbl(Vector, 16, Tb0); + } + + public static AVec Tbl2_V64(AVec Vector, AVec Tb0, AVec Tb1) + { + return Tbl(Vector, 8, Tb0, Tb1); + } + + public static AVec Tbl2_V128(AVec Vector, AVec Tb0, AVec Tb1) + { + return Tbl(Vector, 16, Tb0, Tb1); + } + + public static AVec Tbl3_V64(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2) + { + return Tbl(Vector, 8, Tb0, Tb1, Tb2); + } + + public static AVec Tbl3_V128(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2) + { + return Tbl(Vector, 16, Tb0, Tb1, Tb2); + } + + public static AVec Tbl4_V64(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2, AVec Tb3) + { + return Tbl(Vector, 8, Tb0, Tb1, Tb2, Tb3); + } + + public static AVec Tbl4_V128(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2, AVec Tb3) + { + return Tbl(Vector, 16, Tb0, Tb1, Tb2, Tb3); + } + + private static AVec Tbl(AVec Vector, int Bytes, params AVec[] Tb) + { + AVec Res = new AVec(); + + byte[] Table = new byte[Tb.Length * 16]; + + for (int Index = 0; Index < Tb.Length; Index++) + for (int Index2 = 0; Index2 < 16; Index2++) + { + Table[Index * 16 + Index2] = (byte)VectorExtractIntZx(Tb[Index], Index2, 0); + } + + for (int Index = 0; Index < Bytes; Index++) + { + byte TblIdx = (byte)VectorExtractIntZx(Vector, Index, 0); + + if (TblIdx < Table.Length) + { + Res = VectorInsertInt(Table[TblIdx], Res, Index, 0); + } + } + + return Res; + } + + public static ulong VectorExtractIntZx(AVec Vector, int Index, int Size) + { + switch (Size) + { + case 0: return Vector.ExtractByte (Index); + case 1: return Vector.ExtractUInt16(Index); + case 2: return Vector.ExtractUInt32(Index); + case 3: return Vector.ExtractUInt64(Index); + } + + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + public static long VectorExtractIntSx(AVec Vector, int Index, int Size) + { + switch (Size) + { + case 0: return (sbyte)Vector.ExtractByte (Index); + case 1: return (short)Vector.ExtractUInt16(Index); + case 2: return (int)Vector.ExtractUInt32(Index); + case 3: return (long)Vector.ExtractUInt64(Index); + } + + throw new ArgumentOutOfRangeException(nameof(Size)); + } + + public static float VectorExtractSingle(AVec Vector, int Index) + { + return Vector.ExtractSingle(Index); + } + + public static double VectorExtractDouble(AVec Vector, int Index) + { + return Vector.ExtractDouble(Index); + } + + public static AVec VectorInsertSingle(float Value, AVec Vector, int Index) + { + return AVec.InsertSingle(Vector, Index, Value); + } + + public static AVec VectorInsertDouble(double Value, AVec Vector, int Index) + { + return AVec.InsertDouble(Vector, Index, Value); + } + + public static AVec VectorInsertInt(ulong Value, AVec Vector, int Index, int Size) + { + switch (Size) + { + case 0: return AVec.InsertByte (Vector, Index, (byte)Value); + case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value); + case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value); + case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value); + } + + throw new ArgumentOutOfRangeException(nameof(Size)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs new file mode 100644 index 00000000..f2abffbf --- /dev/null +++ b/ChocolArm64/Memory/AMemory.cs @@ -0,0 +1,345 @@ +using ChocolArm64.Exceptions; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ChocolArm64.Memory +{ + public unsafe class AMemory + { + private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; + + public AMemoryMgr Manager { get; private set; } + + private struct ExMonitor + { + public long Position { get; private set; } + + private bool ExState; + + public ExMonitor(long Position, bool ExState) + { + this.Position = Position; + this.ExState = ExState; + } + + public bool HasExclusiveAccess(long Position) + { + return this.Position == Position && ExState; + } + + public void Reset() + { + ExState = false; + } + } + + private Dictionary Monitors; + + private HashSet ExAddrs; + + private byte* RamPtr; + + public AMemory(IntPtr Ram, AMemoryAlloc Allocator) + { + Manager = new AMemoryMgr(Allocator); + + Monitors = new Dictionary(); + + ExAddrs = new HashSet(); + + RamPtr = (byte*)Ram; + } + + public void RemoveMonitor(int ThreadId) + { + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor)) + { + ExAddrs.Remove(Monitor.Position); + } + + Monitors.Remove(ThreadId); + } + } + + public void SetExclusive(AThreadState ThreadState, long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + ExAddrs.Remove(Monitor.Position); + } + + bool ExState = ExAddrs.Add(Position); + + Monitor = new ExMonitor(Position, ExState); + + if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor)) + { + Monitors[ThreadState.ThreadId] = Monitor; + } + } + } + + public bool TestExclusive(AThreadState ThreadState, long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + return false; + } + + return Monitor.HasExclusiveAccess(Position); + } + } + + public void ClearExclusive(AThreadState ThreadState) + { + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + Monitor.Reset(); + ExAddrs.Remove(Monitor.Position); + } + } + } + + public bool AcquireAddress(long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + return ExAddrs.Add(Position); + } + } + + public void ReleaseAddress(long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + ExAddrs.Remove(Position); + } + } + + public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position); + public short ReadInt16(long Position) => (short)ReadUInt16(Position); + public int ReadInt32(long Position) => (int)ReadUInt32(Position); + public long ReadInt64(long Position) => (long)ReadUInt64(Position); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte ReadByte(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((byte*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ushort ReadUInt16(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((ushort*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint ReadUInt32(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((uint*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadUInt64(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((ulong*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector8(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { B0 = ReadByte(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector16(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { H0 = ReadUInt16(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector32(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { W0 = ReadUInt32(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector64(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { X0 = ReadUInt64(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector128(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() + { + X0 = ReadUInt64(Position + 0), + X1 = ReadUInt64(Position + 8) + }; + } + + public void WriteSByte(long Position, sbyte Value) => WriteByte (Position, (byte)Value); + public void WriteInt16(long Position, short Value) => WriteUInt16(Position, (ushort)Value); + public void WriteInt32(long Position, int Value) => WriteUInt32(Position, (uint)Value); + public void WriteInt64(long Position, long Value) => WriteUInt64(Position, (ulong)Value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteByte(long Position, byte Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((byte*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt16(long Position, ushort Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((ushort*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt32(long Position, uint Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((uint*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt64(long Position, ulong Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((ulong*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector8(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteByte(Position, Value.B0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector16(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt16(Position, Value.H0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector32(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt32(Position, Value.W0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector64(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt64(Position, Value.X0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector128(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt64(Position + 0, Value.X0); + WriteUInt64(Position + 8, Value.X1); + } + + private void EnsureAccessIsValid(long Position, AMemoryPerm Perm) + { + if (!Manager.IsMapped(Position)) + { + throw new VmmPageFaultException(Position); + } + + if (!Manager.HasPermission(Position, Perm)) + { + throw new VmmAccessViolationException(Position, Perm); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryAlloc.cs b/ChocolArm64/Memory/AMemoryAlloc.cs new file mode 100644 index 00000000..b11e7793 --- /dev/null +++ b/ChocolArm64/Memory/AMemoryAlloc.cs @@ -0,0 +1,35 @@ +using ChocolArm64.Exceptions; + +namespace ChocolArm64.Memory +{ + public class AMemoryAlloc + { + private long PhysPos; + + public long Alloc(long Size) + { + long Position = PhysPos; + + Size = AMemoryHelper.PageRoundUp(Size); + + PhysPos += Size; + + if (PhysPos > AMemoryMgr.RamSize || PhysPos < 0) + { + throw new VmmOutOfMemoryException(Size); + } + + return Position; + } + + public void Free(long Position) + { + //TODO + } + + public long GetFreeMem() + { + return AMemoryMgr.RamSize - PhysPos; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryHelper.cs b/ChocolArm64/Memory/AMemoryHelper.cs new file mode 100644 index 00000000..219aeebf --- /dev/null +++ b/ChocolArm64/Memory/AMemoryHelper.cs @@ -0,0 +1,73 @@ +using System.IO; +using System.Text; + +namespace ChocolArm64.Memory +{ + public static class AMemoryHelper + { + public static void FillWithZeros(AMemory Memory, long Position, int Size) + { + int Size8 = Size & ~(8 - 1); + + for (int Offs = 0; Offs < Size8; Offs += 8) + { + Memory.WriteInt64(Position + Offs, 0); + } + + for (int Offs = Size8; Offs < (Size - Size8); Offs++) + { + Memory.WriteByte(Position + Offs, 0); + } + } + + public static byte[] ReadBytes(AMemory Memory, long Position, int Size) + { + byte[] Data = new byte[Size]; + + for (int Offs = 0; Offs < Size; Offs++) + { + Data[Offs] = (byte)Memory.ReadByte(Position + Offs); + } + + return Data; + } + + public static void WriteBytes(AMemory Memory, long Position, byte[] Data) + { + for (int Offs = 0; Offs < Data.Length; Offs++) + { + Memory.WriteByte(Position + Offs, Data[Offs]); + } + } + + public static string ReadAsciiString(AMemory Memory, long Position, int MaxSize = -1) + { + using (MemoryStream MS = new MemoryStream()) + { + for (int Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++) + { + byte Value = (byte)Memory.ReadByte(Position + Offs); + + if (Value == 0) + { + break; + } + + MS.WriteByte(Value); + } + + return Encoding.ASCII.GetString(MS.ToArray()); + } + } + + public static long PageRoundUp(long Value) + { + return (Value + AMemoryMgr.PageMask) & ~AMemoryMgr.PageMask; + } + + public static long PageRoundDown(long Value) + { + return Value & ~AMemoryMgr.PageMask; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryMapInfo.cs b/ChocolArm64/Memory/AMemoryMapInfo.cs new file mode 100644 index 00000000..44b2cc07 --- /dev/null +++ b/ChocolArm64/Memory/AMemoryMapInfo.cs @@ -0,0 +1,21 @@ +namespace ChocolArm64.Memory +{ + public struct AMemoryMapInfo + { + public long Position { get; private set; } + public long Size { get; private set; } + public int Type { get; private set; } + public int Attr { get; private set; } + + public AMemoryPerm Perm { get; private set; } + + public AMemoryMapInfo(long Position, long Size, int Type, int Attr, AMemoryPerm Perm) + { + this.Position = Position; + this.Size = Size; + this.Type = Type; + this.Attr = Attr; + this.Perm = Perm; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryMgr.cs b/ChocolArm64/Memory/AMemoryMgr.cs new file mode 100644 index 00000000..05284059 --- /dev/null +++ b/ChocolArm64/Memory/AMemoryMgr.cs @@ -0,0 +1,286 @@ +namespace ChocolArm64.Memory +{ + public class AMemoryMgr + { + public const long AddrSize = RamSize; + public const long RamSize = 4L * 1024 * 1024 * 1024; + + private const int PTLvl0Bits = 11; + private const int PTLvl1Bits = 13; + private const int PTPageBits = 12; + + private const int PTLvl0Size = 1 << PTLvl0Bits; + private const int PTLvl1Size = 1 << PTLvl1Bits; + public const int PageSize = 1 << PTPageBits; + + private const int PTLvl0Mask = PTLvl0Size - 1; + private const int PTLvl1Mask = PTLvl1Size - 1; + public const int PageMask = PageSize - 1; + + private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; + private const int PTLvl1Bit = PTPageBits; + + private AMemoryAlloc Allocator; + + private enum PTMap + { + Unmapped, + Mapped + } + + private struct PTEntry + { + public PTMap Map; + public AMemoryPerm Perm; + + public int Type; + public int Attr; + + public PTEntry(PTMap Map, AMemoryPerm Perm, int Type, int Attr) + { + this.Map = Map; + this.Perm = Perm; + this.Type = Type; + this.Attr = Attr; + } + } + + private PTEntry[][] PageTable; + + private bool IsHeapInitialized; + + public long HeapAddr { get; private set; } + public long HeapSize { get; private set; } + + public AMemoryMgr(AMemoryAlloc Allocator) + { + this.Allocator = Allocator; + + PageTable = new PTEntry[PTLvl0Size][]; + } + + public long GetTotalMemorySize() + { + return Allocator.GetFreeMem() + GetUsedMemorySize(); + } + + public long GetUsedMemorySize() + { + long Size = 0; + + for (int L0 = 0; L0 < PageTable.Length; L0++) + { + if (PageTable[L0] == null) + { + continue; + } + + for (int L1 = 0; L1 < PageTable[L0].Length; L1++) + { + Size += PageTable[L0][L1].Map != PTMap.Unmapped ? PageSize : 0; + } + } + + return Size; + } + + public bool SetHeapAddr(long Position) + { + if (!IsHeapInitialized) + { + HeapAddr = Position; + + IsHeapInitialized = true; + + return true; + } + + return false; + } + + public void SetHeapSize(long Size, int Type) + { + //TODO: Return error when theres no enough space to allocate heap. + Size = AMemoryHelper.PageRoundUp(Size); + + long Position = HeapAddr; + + if ((ulong)Size < (ulong)HeapSize) + { + //Try to free now free area if size is smaller than old size. + Position += Size; + + while ((ulong)Size < (ulong)HeapSize) + { + Allocator.Free(Position); + + Position += PageSize; + } + } + else + { + //Allocate extra needed size. + Position += HeapSize; + Size -= HeapSize; + + MapPhys(Position, Size, Type, AMemoryPerm.RW); + } + + HeapSize = Size; + } + + public void MapPhys(long Position, long Size, int Type, AMemoryPerm Perm) + { + while (Size > 0) + { + if (!IsMapped(Position)) + { + SetPTEntry(Position, new PTEntry(PTMap.Mapped, Perm, Type, 0)); + } + + long CPgSize = PageSize - (Position & PageMask); + + Position += CPgSize; + Size -= CPgSize; + } + } + + public void MapMirror(long Src, long Dst, long Size, int Type) + { + Src = AMemoryHelper.PageRoundDown(Src); + Dst = AMemoryHelper.PageRoundDown(Dst); + + Size = AMemoryHelper.PageRoundUp(Size); + + long PagesCount = Size / PageSize; + + while (PagesCount-- > 0) + { + PTEntry SrcEntry = GetPTEntry(Src); + PTEntry DstEntry = GetPTEntry(Dst); + + DstEntry.Map = PTMap.Mapped; + DstEntry.Type = Type; + DstEntry.Perm = SrcEntry.Perm; + + SrcEntry.Perm = AMemoryPerm.None; + + SrcEntry.Attr |= 1; + + SetPTEntry(Src, SrcEntry); + SetPTEntry(Dst, DstEntry); + + Src += PageSize; + Dst += PageSize; + } + } + + public void Reprotect(long Position, long Size, AMemoryPerm Perm) + { + Position = AMemoryHelper.PageRoundDown(Position); + + Size = AMemoryHelper.PageRoundUp(Size); + + long PagesCount = Size / PageSize; + + while (PagesCount-- > 0) + { + PTEntry Entry = GetPTEntry(Position); + + Entry.Perm = Perm; + + SetPTEntry(Position, Entry); + + Position += PageSize; + } + } + + public AMemoryMapInfo GetMapInfo(long Position) + { + Position = AMemoryHelper.PageRoundDown(Position); + + PTEntry BaseEntry = GetPTEntry(Position); + + bool IsSameSegment(long Pos) + { + PTEntry Entry = GetPTEntry(Pos); + + return Entry.Map == BaseEntry.Map && + Entry.Perm == BaseEntry.Perm && + Entry.Type == BaseEntry.Type && + Entry.Attr == BaseEntry.Attr; + } + + long Start = Position; + long End = Position + PageSize; + + while (Start > 0 && IsSameSegment(Start - PageSize)) + { + Start -= PageSize; + } + + while (End < AddrSize && IsSameSegment(End)) + { + End += PageSize; + } + + long Size = End - Start; + + return new AMemoryMapInfo( + Start, + Size, + BaseEntry.Type, + BaseEntry.Attr, + BaseEntry.Perm); + } + + public bool HasPermission(long Position, AMemoryPerm Perm) + { + return GetPTEntry(Position).Perm.HasFlag(Perm); + } + + public bool IsMapped(long Position) + { + if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) + { + return false; + } + + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return false; + } + + return PageTable[L0][L1].Map != PTMap.Unmapped; + } + + private PTEntry GetPTEntry(long Position) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return default(PTEntry); + } + + return PageTable[L0][L1]; + } + + private void SetPTEntry(long Position, PTEntry Entry) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + PageTable[L0] = new PTEntry[PTLvl1Size]; + } + + PageTable[L0][L1] = Entry; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryPerm.cs b/ChocolArm64/Memory/AMemoryPerm.cs new file mode 100644 index 00000000..b425eb94 --- /dev/null +++ b/ChocolArm64/Memory/AMemoryPerm.cs @@ -0,0 +1,15 @@ +using System; + +namespace ChocolArm64.Memory +{ + [Flags] + public enum AMemoryPerm + { + None = 0, + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + RW = Read | Write, + RX = Read | Execute + } +} \ No newline at end of file diff --git a/ChocolArm64/State/AInstExceptEventArgs.cs b/ChocolArm64/State/AInstExceptEventArgs.cs new file mode 100644 index 00000000..f2ee039b --- /dev/null +++ b/ChocolArm64/State/AInstExceptEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace ChocolArm64.State +{ + public class AInstExceptEventArgs : EventArgs + { + public int Id { get; private set; } + + public AInstExceptEventArgs(int Id) + { + this.Id = Id; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/AInstUndEventArgs.cs b/ChocolArm64/State/AInstUndEventArgs.cs new file mode 100644 index 00000000..53de65a3 --- /dev/null +++ b/ChocolArm64/State/AInstUndEventArgs.cs @@ -0,0 +1,16 @@ +using System; + +namespace ChocolArm64.State +{ + public class AInstUndEventArgs : EventArgs + { + public long Position { get; private set; } + public int RawOpCode { get; private set; } + + public AInstUndEventArgs(long Position, int RawOpCode) + { + this.Position = Position; + this.RawOpCode = RawOpCode; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/APState.cs b/ChocolArm64/State/APState.cs new file mode 100644 index 00000000..f55431a6 --- /dev/null +++ b/ChocolArm64/State/APState.cs @@ -0,0 +1,23 @@ +using System; + +namespace ChocolArm64.State +{ + [Flags] + public enum APState + { + VBit = 28, + CBit = 29, + ZBit = 30, + NBit = 31, + + V = 1 << VBit, + C = 1 << CBit, + Z = 1 << ZBit, + N = 1 << NBit, + + NZ = N | Z, + CV = C | V, + + NZCV = NZ | CV + } +} \ No newline at end of file diff --git a/ChocolArm64/State/ARegister.cs b/ChocolArm64/State/ARegister.cs new file mode 100644 index 00000000..5861db8c --- /dev/null +++ b/ChocolArm64/State/ARegister.cs @@ -0,0 +1,142 @@ +using System; +using System.Reflection; + +namespace ChocolArm64.State +{ + struct ARegister + { + public int Index; + + public ARegisterType Type; + + public ARegister(int Index, ARegisterType Type) + { + this.Index = Index; + this.Type = Type; + } + + public override int GetHashCode() + { + return (ushort)Index | ((ushort)Type << 16); + } + + public override bool Equals(object Obj) + { + return Obj is ARegister Reg && + Reg.Index == Index && + Reg.Type == Type; + } + + public FieldInfo GetField() + { + switch (Type) + { + case ARegisterType.Flag: return GetFieldFlag(); + case ARegisterType.Int: return GetFieldInt(); + case ARegisterType.Vector: return GetFieldVector(); + } + + throw new InvalidOperationException(); + } + + private FieldInfo GetFieldFlag() + { + switch ((APState)Index) + { + case APState.VBit: return GetField(nameof(AThreadState.Overflow)); + case APState.CBit: return GetField(nameof(AThreadState.Carry)); + case APState.ZBit: return GetField(nameof(AThreadState.Zero)); + case APState.NBit: return GetField(nameof(AThreadState.Negative)); + } + + throw new InvalidOperationException(); + } + + private FieldInfo GetFieldInt() + { + switch (Index) + { + case 0: return GetField(nameof(AThreadState.X0)); + case 1: return GetField(nameof(AThreadState.X1)); + case 2: return GetField(nameof(AThreadState.X2)); + case 3: return GetField(nameof(AThreadState.X3)); + case 4: return GetField(nameof(AThreadState.X4)); + case 5: return GetField(nameof(AThreadState.X5)); + case 6: return GetField(nameof(AThreadState.X6)); + case 7: return GetField(nameof(AThreadState.X7)); + case 8: return GetField(nameof(AThreadState.X8)); + case 9: return GetField(nameof(AThreadState.X9)); + case 10: return GetField(nameof(AThreadState.X10)); + case 11: return GetField(nameof(AThreadState.X11)); + case 12: return GetField(nameof(AThreadState.X12)); + case 13: return GetField(nameof(AThreadState.X13)); + case 14: return GetField(nameof(AThreadState.X14)); + case 15: return GetField(nameof(AThreadState.X15)); + case 16: return GetField(nameof(AThreadState.X16)); + case 17: return GetField(nameof(AThreadState.X17)); + case 18: return GetField(nameof(AThreadState.X18)); + case 19: return GetField(nameof(AThreadState.X19)); + case 20: return GetField(nameof(AThreadState.X20)); + case 21: return GetField(nameof(AThreadState.X21)); + case 22: return GetField(nameof(AThreadState.X22)); + case 23: return GetField(nameof(AThreadState.X23)); + case 24: return GetField(nameof(AThreadState.X24)); + case 25: return GetField(nameof(AThreadState.X25)); + case 26: return GetField(nameof(AThreadState.X26)); + case 27: return GetField(nameof(AThreadState.X27)); + case 28: return GetField(nameof(AThreadState.X28)); + case 29: return GetField(nameof(AThreadState.X29)); + case 30: return GetField(nameof(AThreadState.X30)); + case 31: return GetField(nameof(AThreadState.X31)); + } + + throw new InvalidOperationException(); + } + + private FieldInfo GetFieldVector() + { + switch (Index) + { + case 0: return GetField(nameof(AThreadState.V0)); + case 1: return GetField(nameof(AThreadState.V1)); + case 2: return GetField(nameof(AThreadState.V2)); + case 3: return GetField(nameof(AThreadState.V3)); + case 4: return GetField(nameof(AThreadState.V4)); + case 5: return GetField(nameof(AThreadState.V5)); + case 6: return GetField(nameof(AThreadState.V6)); + case 7: return GetField(nameof(AThreadState.V7)); + case 8: return GetField(nameof(AThreadState.V8)); + case 9: return GetField(nameof(AThreadState.V9)); + case 10: return GetField(nameof(AThreadState.V10)); + case 11: return GetField(nameof(AThreadState.V11)); + case 12: return GetField(nameof(AThreadState.V12)); + case 13: return GetField(nameof(AThreadState.V13)); + case 14: return GetField(nameof(AThreadState.V14)); + case 15: return GetField(nameof(AThreadState.V15)); + case 16: return GetField(nameof(AThreadState.V16)); + case 17: return GetField(nameof(AThreadState.V17)); + case 18: return GetField(nameof(AThreadState.V18)); + case 19: return GetField(nameof(AThreadState.V19)); + case 20: return GetField(nameof(AThreadState.V20)); + case 21: return GetField(nameof(AThreadState.V21)); + case 22: return GetField(nameof(AThreadState.V22)); + case 23: return GetField(nameof(AThreadState.V23)); + case 24: return GetField(nameof(AThreadState.V24)); + case 25: return GetField(nameof(AThreadState.V25)); + case 26: return GetField(nameof(AThreadState.V26)); + case 27: return GetField(nameof(AThreadState.V27)); + case 28: return GetField(nameof(AThreadState.V28)); + case 29: return GetField(nameof(AThreadState.V29)); + case 30: return GetField(nameof(AThreadState.V30)); + case 31: return GetField(nameof(AThreadState.V31)); + } + + throw new InvalidOperationException(); + } + + private FieldInfo GetField(string Name) + { + return typeof(AThreadState).GetField(Name); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/ARegisterSize.cs b/ChocolArm64/State/ARegisterSize.cs new file mode 100644 index 00000000..144f36b9 --- /dev/null +++ b/ChocolArm64/State/ARegisterSize.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.State +{ + enum ARegisterSize + { + Int32, + Int64, + SIMD64, + SIMD128 + } +} \ No newline at end of file diff --git a/ChocolArm64/State/ARegisterType.cs b/ChocolArm64/State/ARegisterType.cs new file mode 100644 index 00000000..f9776bb7 --- /dev/null +++ b/ChocolArm64/State/ARegisterType.cs @@ -0,0 +1,9 @@ +namespace ChocolArm64.State +{ + enum ARegisterType + { + Flag, + Int, + Vector + } +} \ No newline at end of file diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs new file mode 100644 index 00000000..cdab4034 --- /dev/null +++ b/ChocolArm64/State/AThreadState.cs @@ -0,0 +1,64 @@ +using System; + +namespace ChocolArm64.State +{ + public class AThreadState + { + internal const int LRIndex = 30; + internal const int ZRIndex = 31; + + internal const int ErgSizeLog2 = 4; + internal const int DczSizeLog2 = 4; + + public ulong X0, X1, X2, X3, X4, X5, X6, X7, + X8, X9, X10, X11, X12, X13, X14, X15, + X16, X17, X18, X19, X20, X21, X22, X23, + X24, X25, X26, X27, X28, X29, X30, X31; + + public AVec V0, V1, V2, V3, V4, V5, V6, V7, + V8, V9, V10, V11, V12, V13, V14, V15, + V16, V17, V18, V19, V20, V21, V22, V23, + V24, V25, V26, V27, V28, V29, V30, V31; + + public bool Overflow; + public bool Carry; + public bool Zero; + public bool Negative; + + public int ProcessId; + public int ThreadId; + + public long TpidrEl0 { get; set; } + public long Tpidr { get; set; } + + public int Fpcr { get; set; } + public int Fpsr { get; set; } + + public uint CtrEl0 => 0x8444c004; + public uint DczidEl0 => 0x00000004; + + private const long TicksPerS = 19_200_000; + private const long TicksPerMS = TicksPerS / 1_000; + + public long CntpctEl0 => Environment.TickCount * TicksPerMS; + + public event EventHandler Break; + public event EventHandler SvcCall; + public event EventHandler Undefined; + + internal void OnBreak(int Imm) + { + Break?.Invoke(this, new AInstExceptEventArgs(Imm)); + } + + internal void OnSvcCall(int Imm) + { + SvcCall?.Invoke(this, new AInstExceptEventArgs(Imm)); + } + + internal void OnUndefined(long Position, int RawOpCode) + { + Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/AVec.cs b/ChocolArm64/State/AVec.cs new file mode 100644 index 00000000..f7eb2e22 --- /dev/null +++ b/ChocolArm64/State/AVec.cs @@ -0,0 +1,243 @@ +using System; +using System.Runtime.InteropServices; + +namespace ChocolArm64.State +{ + [StructLayout(LayoutKind.Explicit, Size = 16)] + public struct AVec + { + [FieldOffset(0x0)] public byte B0; + [FieldOffset(0x1)] public byte B1; + [FieldOffset(0x2)] public byte B2; + [FieldOffset(0x3)] public byte B3; + [FieldOffset(0x4)] public byte B4; + [FieldOffset(0x5)] public byte B5; + [FieldOffset(0x6)] public byte B6; + [FieldOffset(0x7)] public byte B7; + [FieldOffset(0x8)] public byte B8; + [FieldOffset(0x9)] public byte B9; + [FieldOffset(0xa)] public byte B10; + [FieldOffset(0xb)] public byte B11; + [FieldOffset(0xc)] public byte B12; + [FieldOffset(0xd)] public byte B13; + [FieldOffset(0xe)] public byte B14; + [FieldOffset(0xf)] public byte B15; + + [FieldOffset(0x0)] public ushort H0; + [FieldOffset(0x2)] public ushort H1; + [FieldOffset(0x4)] public ushort H2; + [FieldOffset(0x6)] public ushort H3; + [FieldOffset(0x8)] public ushort H4; + [FieldOffset(0xa)] public ushort H5; + [FieldOffset(0xc)] public ushort H6; + [FieldOffset(0xe)] public ushort H7; + + [FieldOffset(0x0)] public uint W0; + [FieldOffset(0x4)] public uint W1; + [FieldOffset(0x8)] public uint W2; + [FieldOffset(0xc)] public uint W3; + + [FieldOffset(0x0)] public float S0; + [FieldOffset(0x4)] public float S1; + [FieldOffset(0x8)] public float S2; + [FieldOffset(0xc)] public float S3; + + [FieldOffset(0x0)] public ulong X0; + [FieldOffset(0x8)] public ulong X1; + + [FieldOffset(0x0)] public double D0; + [FieldOffset(0x8)] public double D1; + + public byte ExtractByte(int Index) + { + switch (Index) + { + case 0: return B0; + case 1: return B1; + case 2: return B2; + case 3: return B3; + case 4: return B4; + case 5: return B5; + case 6: return B6; + case 7: return B7; + case 8: return B8; + case 9: return B9; + case 10: return B10; + case 11: return B11; + case 12: return B12; + case 13: return B13; + case 14: return B14; + case 15: return B15; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public ushort ExtractUInt16(int Index) + { + switch (Index) + { + case 0: return H0; + case 1: return H1; + case 2: return H2; + case 3: return H3; + case 4: return H4; + case 5: return H5; + case 6: return H6; + case 7: return H7; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public uint ExtractUInt32(int Index) + { + switch (Index) + { + case 0: return W0; + case 1: return W1; + case 2: return W2; + case 3: return W3; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public float ExtractSingle(int Index) + { + switch (Index) + { + case 0: return S0; + case 1: return S1; + case 2: return S2; + case 3: return S3; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public ulong ExtractUInt64(int Index) + { + switch (Index) + { + case 0: return X0; + case 1: return X1; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public double ExtractDouble(int Index) + { + switch (Index) + { + case 0: return D0; + case 1: return D1; + } + + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + public static AVec InsertByte(AVec Vec, int Index, byte Value) + { + switch (Index) + { + case 0: Vec.B0 = Value; break; + case 1: Vec.B1 = Value; break; + case 2: Vec.B2 = Value; break; + case 3: Vec.B3 = Value; break; + case 4: Vec.B4 = Value; break; + case 5: Vec.B5 = Value; break; + case 6: Vec.B6 = Value; break; + case 7: Vec.B7 = Value; break; + case 8: Vec.B8 = Value; break; + case 9: Vec.B9 = Value; break; + case 10: Vec.B10 = Value; break; + case 11: Vec.B11 = Value; break; + case 12: Vec.B12 = Value; break; + case 13: Vec.B13 = Value; break; + case 14: Vec.B14 = Value; break; + case 15: Vec.B15 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + + public static AVec InsertUInt16(AVec Vec, int Index, ushort Value) + { + switch (Index) + { + case 0: Vec.H0 = Value; break; + case 1: Vec.H1 = Value; break; + case 2: Vec.H2 = Value; break; + case 3: Vec.H3 = Value; break; + case 4: Vec.H4 = Value; break; + case 5: Vec.H5 = Value; break; + case 6: Vec.H6 = Value; break; + case 7: Vec.H7 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + + public static AVec InsertUInt32(AVec Vec, int Index, uint Value) + { + switch (Index) + { + case 0: Vec.W0 = Value; break; + case 1: Vec.W1 = Value; break; + case 2: Vec.W2 = Value; break; + case 3: Vec.W3 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + + public static AVec InsertSingle(AVec Vec, int Index, float Value) + { + switch (Index) + { + case 0: Vec.S0 = Value; break; + case 1: Vec.S1 = Value; break; + case 2: Vec.S2 = Value; break; + case 3: Vec.S3 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + + public static AVec InsertUInt64(AVec Vec, int Index, ulong Value) + { + switch (Index) + { + case 0: Vec.X0 = Value; break; + case 1: Vec.X1 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + + public static AVec InsertDouble(AVec Vec, int Index, double Value) + { + switch (Index) + { + case 0: Vec.D0 = Value; break; + case 1: Vec.D1 = Value; break; + + default: throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Vec; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILBlock.cs b/ChocolArm64/Translation/AILBlock.cs new file mode 100644 index 00000000..bed195aa --- /dev/null +++ b/ChocolArm64/Translation/AILBlock.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; + +namespace ChocolArm64.Translation +{ + class AILBlock : IAILEmit + { + public long IntInputs { get; private set; } + public long IntOutputs { get; private set; } + + public long VecInputs { get; private set; } + public long VecOutputs { get; private set; } + + public bool HasStateStore { get; private set; } + + public List ILEmitters { get; private set; } + + public AILBlock Next { get; set; } + public AILBlock Branch { get; set; } + + public AILBlock() + { + ILEmitters = new List(); + } + + public void Add(IAILEmit ILEmitter) + { + if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index)) + { + switch (Ld.IoType) + { + case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntOutputs; break; + case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntOutputs; break; + case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecOutputs; break; + } + } + else if (ILEmitter is AILOpCodeStore St) + { + if (AILEmitter.IsRegIndex(St.Index)) + { + switch (St.IoType) + { + case AIoType.Flag: IntOutputs |= (1L << St.Index) << 32; break; + case AIoType.Int: IntOutputs |= 1L << St.Index; break; + case AIoType.Vector: VecOutputs |= 1L << St.Index; break; + } + } + + if (St.IoType == AIoType.Fields) + { + HasStateStore = true; + } + } + + ILEmitters.Add(ILEmitter); + } + + public void Emit(AILEmitter Context) + { + foreach (IAILEmit ILEmitter in ILEmitters) + { + ILEmitter.Emit(Context); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILEmitter.cs b/ChocolArm64/Translation/AILEmitter.cs new file mode 100644 index 00000000..8f6e1210 --- /dev/null +++ b/ChocolArm64/Translation/AILEmitter.cs @@ -0,0 +1,187 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + class AILEmitter + { + public ALocalAlloc LocalAlloc { get; private set; } + + public ILGenerator Generator { get; private set; } + + private Dictionary Locals; + + private AILBlock[] ILBlocks; + + private AILBlock Root; + + private ATranslatedSub Subroutine; + + private string SubName; + + private int LocalsCount; + + public AILEmitter(ABlock[] Graph, ABlock Root, string SubName) + { + this.SubName = SubName; + + Locals = new Dictionary(); + + ILBlocks = new AILBlock[Graph.Length]; + + AILBlock GetBlock(int Index) + { + if (Index < 0 || Index >= ILBlocks.Length) + { + return null; + } + + if (ILBlocks[Index] == null) + { + ILBlocks[Index] = new AILBlock(); + } + + return ILBlocks[Index]; + } + + for (int Index = 0; Index < ILBlocks.Length; Index++) + { + AILBlock Block = GetBlock(Index); + + Block.Next = GetBlock(Array.IndexOf(Graph, Graph[Index].Next)); + Block.Branch = GetBlock(Array.IndexOf(Graph, Graph[Index].Branch)); + } + + this.Root = ILBlocks[Array.IndexOf(Graph, Root)]; + } + + public ATranslatedSub GetSubroutine() + { + LocalAlloc = new ALocalAlloc(ILBlocks, Root); + + InitSubroutine(); + InitLocals(); + + foreach (AILBlock ILBlock in ILBlocks) + { + ILBlock.Emit(this); + } + + return Subroutine; + } + + public AILBlock GetILBlock(int Index) => ILBlocks[Index]; + + private void InitLocals() + { + int ParamsStart = ATranslatedSub.FixedArgTypes.Length; + + Locals = new Dictionary(); + + for (int Index = 0; Index < Subroutine.Params.Count; Index++) + { + ARegister Reg = Subroutine.Params[Index]; + + Generator.EmitLdarg(Index + ParamsStart); + Generator.EmitStloc(GetLocalIndex(Reg)); + } + } + + private void InitSubroutine() + { + List Params = new List(); + + void SetParams(long Inputs, ARegisterType BaseType) + { + for (int Bit = 0; Bit < 64; Bit++) + { + long Mask = 1L << Bit; + + if ((Inputs & Mask) != 0) + { + Params.Add(GetRegFromBit(Bit, BaseType)); + } + } + } + + SetParams(LocalAlloc.GetIntInputs(Root), ARegisterType.Int); + SetParams(LocalAlloc.GetVecInputs(Root), ARegisterType.Vector); + + DynamicMethod Mthd = new DynamicMethod(SubName, typeof(long), GetParamTypes(Params)); + + Generator = Mthd.GetILGenerator(); + + Subroutine = new ATranslatedSub(Mthd, Params); + } + + private Type[] GetParamTypes(IList Params) + { + Type[] FixedArgs = ATranslatedSub.FixedArgTypes; + + Type[] Output = new Type[Params.Count + FixedArgs.Length]; + + FixedArgs.CopyTo(Output, 0); + + int TypeIdx = FixedArgs.Length; + + for (int Index = 0; Index < Params.Count; Index++) + { + Output[TypeIdx++] = GetFieldType(Params[Index].Type); + } + + return Output; + } + + public int GetLocalIndex(ARegister Reg) + { + if (!Locals.TryGetValue(Reg, out int Index)) + { + Generator.DeclareLocal(GetLocalType(Reg)); + + Index = LocalsCount++; + + Locals.Add(Reg, Index); + } + + return Index; + } + + public Type GetLocalType(ARegister Reg) => GetFieldType(Reg.Type); + + public Type GetFieldType(ARegisterType RegType) + { + switch (RegType) + { + case ARegisterType.Flag: return typeof(bool); + case ARegisterType.Int: return typeof(ulong); + case ARegisterType.Vector: return typeof(AVec); + } + + throw new ArgumentException(nameof(RegType)); + } + + public static ARegister GetRegFromBit(int Bit, ARegisterType BaseType) + { + if (Bit < 32) + { + return new ARegister(Bit, BaseType); + } + else if (BaseType == ARegisterType.Int) + { + return new ARegister(Bit & 0x1f, ARegisterType.Flag); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Bit)); + } + } + + public static bool IsRegIndex(int Index) + { + return Index >= 0 && Index < 32; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs new file mode 100644 index 00000000..cf644540 --- /dev/null +++ b/ChocolArm64/Translation/AILEmitterCtx.cs @@ -0,0 +1,487 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Instruction; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + class AILEmitterCtx + { + private ATranslator Translator; + + private Dictionary Labels; + + private AILEmitter Emitter; + + private AILBlock ILBlock; + + private AOpCode LastCmpOp; + private AOpCode LastFlagOp; + + private int BlkIndex; + private int OpcIndex; + + private ABlock[] Graph; + private ABlock Root; + public ABlock CurrBlock => Graph[BlkIndex]; + public AOpCode CurrOp => Graph[BlkIndex].OpCodes[OpcIndex]; + + //This is the index of the temporary register, used to store temporary + //values needed by some functions, since IL doesn't have a swap instruction. + //You can use any value here as long it doesn't conflict with the indices + //for the other registers. Any value >= 64 or < 0 will do. + private const int Tmp1Index = -1; + private const int Tmp2Index = -2; + private const int Tmp3Index = -3; + private const int Tmp4Index = -4; + private const int Tmp5Index = -5; + + public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root) + { + this.Translator = Translator; + this.Graph = Graph; + this.Root = Root; + + string SubName = $"Sub{Root.Position:X16}"; + + Labels = new Dictionary(); + + Emitter = new AILEmitter(Graph, Root, SubName); + + ILBlock = Emitter.GetILBlock(0); + + OpcIndex = -1; + + if (!AdvanceOpCode()) + { + throw new ArgumentException(nameof(Graph)); + } + } + + public ATranslatedSub GetSubroutine() => Emitter.GetSubroutine(); + + public bool AdvanceOpCode() + { + while (++OpcIndex >= (CurrBlock?.OpCodes.Count ?? 0)) + { + if (BlkIndex + 1 >= Graph.Length) + { + return false; + } + + BlkIndex++; + OpcIndex = -1; + + ILBlock = Emitter.GetILBlock(BlkIndex); + } + + return true; + } + + public void EmitOpCode() + { + if (OpcIndex == 0) + { + MarkLabel(GetLabel(CurrBlock.Position)); + } + + CurrOp.Emitter(this); + } + + public bool TryOptEmitSubroutineCall() + { + if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub)) + { + return false; + } + + for (int Index = 0; Index < ATranslatedSub.FixedArgTypes.Length; Index++) + { + EmitLdarg(Index); + } + + foreach (ARegister Reg in Sub.Params) + { + switch (Reg.Type) + { + case ARegisterType.Flag: Ldloc(Reg.Index, AIoType.Flag); break; + case ARegisterType.Int: Ldloc(Reg.Index, AIoType.Int); break; + case ARegisterType.Vector: Ldloc(Reg.Index, AIoType.Vector); break; + } + } + + EmitCall(Sub.Method); + + return true; + } + + public void TryOptMarkCondWithoutCmp() + { + LastCmpOp = CurrOp; + + AInstEmitAluHelper.EmitDataLoadOpers(this); + + Stloc(Tmp4Index, AIoType.Int); + Stloc(Tmp3Index, AIoType.Int); + } + + private Dictionary BranchOps = new Dictionary() + { + { ACond.Eq, OpCodes.Beq }, + { ACond.Ne, OpCodes.Bne_Un }, + { ACond.Ge_Un, OpCodes.Bge_Un }, + { ACond.Lt_Un, OpCodes.Blt_Un }, + { ACond.Gt_Un, OpCodes.Bgt_Un }, + { ACond.Le_Un, OpCodes.Ble_Un }, + { ACond.Ge, OpCodes.Bge }, + { ACond.Lt, OpCodes.Blt }, + { ACond.Gt, OpCodes.Bgt }, + { ACond.Le, OpCodes.Ble } + }; + + public void EmitCondBranch(AILLabel Target, ACond Cond) + { + OpCode ILOp; + + int IntCond = (int)Cond; + + if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) + { + Ldloc(Tmp3Index, AIoType.Int, LastCmpOp.RegisterSize); + Ldloc(Tmp4Index, AIoType.Int, LastCmpOp.RegisterSize); + + if (LastCmpOp.Emitter == AInstEmit.Adds) + { + Emit(OpCodes.Neg); + } + + ILOp = BranchOps[Cond]; + } + else if (IntCond < 14) + { + int CondTrue = IntCond >> 1; + + switch (CondTrue) + { + case 0: EmitLdflg((int)APState.ZBit); break; + case 1: EmitLdflg((int)APState.CBit); break; + case 2: EmitLdflg((int)APState.NBit); break; + case 3: EmitLdflg((int)APState.VBit); break; + + case 4: + EmitLdflg((int)APState.CBit); + EmitLdflg((int)APState.ZBit); + + Emit(OpCodes.Not); + Emit(OpCodes.And); + break; + + case 5: + case 6: + EmitLdflg((int)APState.NBit); + EmitLdflg((int)APState.VBit); + + Emit(OpCodes.Ceq); + + if (CondTrue == 6) + { + EmitLdflg((int)APState.ZBit); + + Emit(OpCodes.Not); + Emit(OpCodes.And); + } + break; + } + + ILOp = (IntCond & 1) != 0 + ? OpCodes.Brfalse + : OpCodes.Brtrue; + } + else + { + ILOp = OpCodes.Br; + } + + Emit(ILOp, Target); + } + + public void EmitCast(AIntType IntType) + { + switch (IntType) + { + case AIntType.UInt8: Emit(OpCodes.Conv_U1); break; + case AIntType.UInt16: Emit(OpCodes.Conv_U2); break; + case AIntType.UInt32: Emit(OpCodes.Conv_U4); break; + case AIntType.UInt64: Emit(OpCodes.Conv_U8); break; + case AIntType.Int8: Emit(OpCodes.Conv_I1); break; + case AIntType.Int16: Emit(OpCodes.Conv_I2); break; + case AIntType.Int32: Emit(OpCodes.Conv_I4); break; + case AIntType.Int64: Emit(OpCodes.Conv_I8); break; + } + + if (IntType == AIntType.UInt64 || + IntType == AIntType.Int64) + { + return; + } + + if (CurrOp.RegisterSize != ARegisterSize.Int32) + { + Emit(IntType >= AIntType.Int8 + ? OpCodes.Conv_I8 + : OpCodes.Conv_U8); + } + } + + public void EmitLsl(int Amount) => EmitILShift(Amount, OpCodes.Shl); + public void EmitLsr(int Amount) => EmitILShift(Amount, OpCodes.Shr_Un); + public void EmitAsr(int Amount) => EmitILShift(Amount, OpCodes.Shr); + + private void EmitILShift(int Amount, OpCode ILOp) + { + if (Amount > 0) + { + EmitLdc_I4(Amount); + + Emit(ILOp); + } + } + + public void EmitRor(int Amount) + { + if (Amount > 0) + { + Stloc(Tmp2Index, AIoType.Int); + Ldloc(Tmp2Index, AIoType.Int); + + EmitLdc_I4(Amount); + + Emit(OpCodes.Shr_Un); + + Ldloc(Tmp2Index, AIoType.Int); + + EmitLdc_I4(CurrOp.GetBitsCount() - Amount); + + Emit(OpCodes.Shl); + Emit(OpCodes.Or); + } + } + + public AILLabel GetLabel(long Position) + { + if (!Labels.TryGetValue(Position, out AILLabel Output)) + { + Output = new AILLabel(); + + Labels.Add(Position, Output); + } + + return Output; + } + + public void MarkLabel(AILLabel Label) + { + ILBlock.Add(Label); + } + + public void Emit(OpCode ILOp) + { + ILBlock.Add(new AILOpCode(ILOp)); + } + + public void Emit(OpCode ILOp, AILLabel Label) + { + ILBlock.Add(new AILOpCodeBranch(ILOp, Label)); + } + + public void Emit(string Text) + { + ILBlock.Add(new AILOpCodeLog(Text)); + } + + public void EmitLdarg(int Index) + { + ILBlock.Add(new AILOpCodeLoad(Index, AIoType.Arg)); + } + + public void EmitLdintzr(int Index) + { + if (Index != AThreadState.ZRIndex) + { + EmitLdint(Index); + } + else + { + EmitLdc_I(0); + } + } + + public void EmitStintzr(int Index) + { + if (Index != AThreadState.ZRIndex) + { + EmitStint(Index); + } + else + { + Emit(OpCodes.Pop); + } + } + + public void EmitLoadState(ABlock RetBlk) + { + ILBlock.Add(new AILOpCodeLoad(Array.IndexOf(Graph, RetBlk), AIoType.Fields)); + } + + public void EmitStoreState() + { + ILBlock.Add(new AILOpCodeStore(Array.IndexOf(Graph, CurrBlock), AIoType.Fields)); + } + + public void EmitLdtmp() => EmitLdint(Tmp1Index); + public void EmitSttmp() => EmitStint(Tmp1Index); + + public void EmitLdvectmp() => EmitLdvec(Tmp5Index); + public void EmitStvectmp() => EmitStvec(Tmp5Index); + + public void EmitLdint(int Index) => Ldloc(Index, AIoType.Int); + public void EmitStint(int Index) => Stloc(Index, AIoType.Int); + + public void EmitLdvec(int Index) => Ldloc(Index, AIoType.Vector); + public void EmitStvec(int Index) => Stloc(Index, AIoType.Vector); + + public void EmitLdflg(int Index) => Ldloc(Index, AIoType.Flag); + public void EmitStflg(int Index) + { + LastFlagOp = CurrOp; + + Stloc(Index, AIoType.Flag); + } + + private void Ldloc(int Index, AIoType IoType) + { + ILBlock.Add(new AILOpCodeLoad(Index, IoType, CurrOp.RegisterSize)); + } + + private void Ldloc(int Index, AIoType IoType, ARegisterSize RegisterSize) + { + ILBlock.Add(new AILOpCodeLoad(Index, IoType, RegisterSize)); + } + + private void Stloc(int Index, AIoType IoType) + { + ILBlock.Add(new AILOpCodeStore(Index, IoType, CurrOp.RegisterSize)); + } + + public void EmitCallPropGet(Type ObjType, string PropName) + { + if (ObjType == null) + { + throw new ArgumentNullException(nameof(ObjType)); + } + + if (PropName == null) + { + throw new ArgumentNullException(nameof(PropName)); + } + + EmitCall(ObjType.GetMethod($"get_{PropName}")); + } + + public void EmitCallPropSet(Type ObjType, string PropName) + { + if (ObjType == null) + { + throw new ArgumentNullException(nameof(ObjType)); + } + + if (PropName == null) + { + throw new ArgumentNullException(nameof(PropName)); + } + + EmitCall(ObjType.GetMethod($"set_{PropName}")); + } + + public void EmitCall(Type ObjType, string MthdName) + { + if (ObjType == null) + { + throw new ArgumentNullException(nameof(ObjType)); + } + + if (MthdName == null) + { + throw new ArgumentNullException(nameof(MthdName)); + } + + EmitCall(ObjType.GetMethod(MthdName)); + } + + public void EmitCall(MethodInfo MthdInfo) + { + if (MthdInfo == null) + { + throw new ArgumentNullException(nameof(MthdInfo)); + } + + ILBlock.Add(new AILOpCodeCall(MthdInfo)); + } + + public void EmitLdc_I(long Value) + { + if (CurrOp.RegisterSize == ARegisterSize.Int32) + { + EmitLdc_I4((int)Value); + } + else + { + EmitLdc_I8(Value); + } + } + + public void EmitLdc_I4(int Value) + { + ILBlock.Add(new AILOpCodeConst(Value)); + } + + public void EmitLdc_I8(long Value) + { + ILBlock.Add(new AILOpCodeConst(Value)); + } + + public void EmitLdc_R4(float Value) + { + ILBlock.Add(new AILOpCodeConst(Value)); + } + + public void EmitLdc_R8(double Value) + { + ILBlock.Add(new AILOpCodeConst(Value)); + } + + public void EmitZNFlagCheck() + { + EmitZNCheck(OpCodes.Ceq, (int)APState.ZBit); + EmitZNCheck(OpCodes.Clt, (int)APState.NBit); + } + + private void EmitZNCheck(OpCode ILCmpOp, int Flag) + { + Emit(OpCodes.Dup); + Emit(OpCodes.Ldc_I4_0); + + if (CurrOp.RegisterSize != ARegisterSize.Int32) + { + Emit(OpCodes.Conv_I8); + } + + Emit(ILCmpOp); + + EmitStflg(Flag); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILLabel.cs b/ChocolArm64/Translation/AILLabel.cs new file mode 100644 index 00000000..0ee39ad7 --- /dev/null +++ b/ChocolArm64/Translation/AILLabel.cs @@ -0,0 +1,28 @@ +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + class AILLabel : IAILEmit + { + private bool HasLabel; + + private Label Lbl; + + public void Emit(AILEmitter Context) + { + Context.Generator.MarkLabel(GetLabel(Context)); + } + + public Label GetLabel(AILEmitter Context) + { + if (!HasLabel) + { + Lbl = Context.Generator.DefineLabel(); + + HasLabel = true; + } + + return Lbl; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCode.cs b/ChocolArm64/Translation/AILOpCode.cs new file mode 100644 index 00000000..a4bc93a0 --- /dev/null +++ b/ChocolArm64/Translation/AILOpCode.cs @@ -0,0 +1,19 @@ +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + struct AILOpCode : IAILEmit + { + private OpCode ILOp; + + public AILOpCode(OpCode ILOp) + { + this.ILOp = ILOp; + } + + public void Emit(AILEmitter Context) + { + Context.Generator.Emit(ILOp); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeBranch.cs b/ChocolArm64/Translation/AILOpCodeBranch.cs new file mode 100644 index 00000000..e4caad1f --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeBranch.cs @@ -0,0 +1,21 @@ +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + struct AILOpCodeBranch : IAILEmit + { + private OpCode ILOp; + private AILLabel Label; + + public AILOpCodeBranch(OpCode ILOp, AILLabel Label) + { + this.ILOp = ILOp; + this.Label = Label; + } + + public void Emit(AILEmitter Context) + { + Context.Generator.Emit(ILOp, Label.GetLabel(Context)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeCall.cs b/ChocolArm64/Translation/AILOpCodeCall.cs new file mode 100644 index 00000000..8cd944eb --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeCall.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + struct AILOpCodeCall : IAILEmit + { + private MethodInfo MthdInfo; + + public AILOpCodeCall(MethodInfo MthdInfo) + { + this.MthdInfo = MthdInfo; + } + + public void Emit(AILEmitter Context) + { + Context.Generator.Emit(OpCodes.Call, MthdInfo); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeConst.cs b/ChocolArm64/Translation/AILOpCodeConst.cs new file mode 100644 index 00000000..80150ec5 --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeConst.cs @@ -0,0 +1,81 @@ +using System.Reflection.Emit; +using System.Runtime.InteropServices; + +namespace ChocolArm64.Translation +{ + class AILOpCodeConst : IAILEmit + { + [StructLayout(LayoutKind.Explicit, Size = 8)] + private struct ImmVal + { + [FieldOffset(0)] public int I4; + [FieldOffset(0)] public long I8; + [FieldOffset(0)] public float R4; + [FieldOffset(0)] public double R8; + } + + private ImmVal Value; + + private enum ConstType + { + Int32, + Int64, + Single, + Double + } + + private ConstType Type; + + private AILOpCodeConst(ConstType Type) + { + this.Type = Type; + } + + public AILOpCodeConst(int Value) : this(ConstType.Int32) + { + this.Value = new ImmVal { I4 = Value }; + } + + public AILOpCodeConst(long Value) : this(ConstType.Int64) + { + this.Value = new ImmVal { I8 = Value }; + } + + public AILOpCodeConst(float Value) : this(ConstType.Single) + { + this.Value = new ImmVal { R4 = Value }; + } + + public AILOpCodeConst(double Value) : this(ConstType.Double) + { + this.Value = new ImmVal { R8 = Value }; + } + + public void Emit(AILEmitter Context) + { + switch (Type) + { + case ConstType.Int32: Context.Generator.EmitLdc_I4(Value.I4); break; + + case ConstType.Int64: + { + if (Value.I8 >= int.MinValue && + Value.I8 <= int.MaxValue) + { + Context.Generator.EmitLdc_I4(Value.I4); + + Context.Generator.Emit(OpCodes.Conv_I8); + } + else + { + Context.Generator.Emit(OpCodes.Ldc_I8, Value.I8); + } + break; + } + + case ConstType.Single: Context.Generator.Emit(OpCodes.Ldc_R4, Value.R4); break; + case ConstType.Double: Context.Generator.Emit(OpCodes.Ldc_R8, Value.R8); break; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeLoad.cs b/ChocolArm64/Translation/AILOpCodeLoad.cs new file mode 100644 index 00000000..7cb431e2 --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeLoad.cs @@ -0,0 +1,77 @@ +using ChocolArm64.State; +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + struct AILOpCodeLoad : IAILEmit + { + public int Index { get; private set; } + + public AIoType IoType { get; private set; } + + public ARegisterSize RegisterSize { get; private set; } + + public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { } + + public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize) + { + this.IoType = IoType; + this.Index = Index; + this.RegisterSize = RegisterSize; + } + + public void Emit(AILEmitter Context) + { + switch (IoType) + { + case AIoType.Arg: Context.Generator.EmitLdarg(Index); break; + + case AIoType.Fields: + { + long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index)); + long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index)); + + LoadLocals(Context, IntInputs, ARegisterType.Int); + LoadLocals(Context, VecInputs, ARegisterType.Vector); + + break; + } + + case AIoType.Flag: EmitLdloc(Context, Index, ARegisterType.Flag); break; + case AIoType.Int: EmitLdloc(Context, Index, ARegisterType.Int); break; + case AIoType.Vector: EmitLdloc(Context, Index, ARegisterType.Vector); break; + } + } + + private void LoadLocals(AILEmitter Context, long Inputs, ARegisterType BaseType) + { + for (int Bit = 0; Bit < 64; Bit++) + { + long Mask = 1L << Bit; + + if ((Inputs & Mask) != 0) + { + ARegister Reg = AILEmitter.GetRegFromBit(Bit, BaseType); + + Context.Generator.EmitLdarg(ATranslatedSub.StateArgIdx); + Context.Generator.Emit(OpCodes.Ldfld, Reg.GetField()); + + Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); + } + } + } + + private void EmitLdloc(AILEmitter Context, int Index, ARegisterType RegisterType) + { + ARegister Reg = new ARegister(Index, RegisterType); + + Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); + + if (RegisterType == ARegisterType.Int && + RegisterSize == ARegisterSize.Int32) + { + Context.Generator.Emit(OpCodes.Conv_U4); + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeLog.cs b/ChocolArm64/Translation/AILOpCodeLog.cs new file mode 100644 index 00000000..1338ca1f --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeLog.cs @@ -0,0 +1,17 @@ +namespace ChocolArm64.Translation +{ + struct AILOpCodeLog : IAILEmit + { + private string Text; + + public AILOpCodeLog(string Text) + { + this.Text = Text; + } + + public void Emit(AILEmitter Context) + { + Context.Generator.EmitWriteLine(Text); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILOpCodeStore.cs b/ChocolArm64/Translation/AILOpCodeStore.cs new file mode 100644 index 00000000..c4ea53ab --- /dev/null +++ b/ChocolArm64/Translation/AILOpCodeStore.cs @@ -0,0 +1,75 @@ +using ChocolArm64.State; +using System.Reflection.Emit; + +namespace ChocolArm64.Translation +{ + struct AILOpCodeStore : IAILEmit + { + public int Index { get; private set; } + + public AIoType IoType { get; private set; } + + public ARegisterSize RegisterSize { get; private set; } + + public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = ARegisterSize.Int64) + { + this.IoType = IoType; + this.Index = Index; + this.RegisterSize = RegisterSize; + } + + public void Emit(AILEmitter Context) + { + switch (IoType) + { + case AIoType.Arg: Context.Generator.EmitStarg(Index); break; + + case AIoType.Fields: + { + long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index)); + long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index)); + + StoreLocals(Context, IntOutputs, ARegisterType.Int); + StoreLocals(Context, VecOutputs, ARegisterType.Vector); + + break; + } + + case AIoType.Flag: EmitStloc(Context, Index, ARegisterType.Flag); break; + case AIoType.Int: EmitStloc(Context, Index, ARegisterType.Int); break; + case AIoType.Vector: EmitStloc(Context, Index, ARegisterType.Vector); break; + } + } + + private void StoreLocals(AILEmitter Context, long Outputs, ARegisterType BaseType) + { + for (int Bit = 0; Bit < 64; Bit++) + { + long Mask = 1L << Bit; + + if ((Outputs & Mask) != 0) + { + ARegister Reg = AILEmitter.GetRegFromBit(Bit, BaseType); + + Context.Generator.EmitLdarg(ATranslatedSub.StateArgIdx); + Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); + + Context.Generator.Emit(OpCodes.Stfld, Reg.GetField()); + } + } + } + + private void EmitStloc(AILEmitter Context, int Index, ARegisterType RegisterType) + { + ARegister Reg = new ARegister(Index, RegisterType); + + if (RegisterType == ARegisterType.Int && + RegisterSize == ARegisterSize.Int32) + { + Context.Generator.Emit(OpCodes.Conv_U8); + } + + Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AIoType.cs b/ChocolArm64/Translation/AIoType.cs new file mode 100644 index 00000000..94f89081 --- /dev/null +++ b/ChocolArm64/Translation/AIoType.cs @@ -0,0 +1,15 @@ +using System; + +namespace ChocolArm64.Translation +{ + [Flags] + enum AIoType + { + Arg, + Fields, + Flag, + Int, + Float, + Vector + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/ALocalAlloc.cs b/ChocolArm64/Translation/ALocalAlloc.cs new file mode 100644 index 00000000..0661ddc8 --- /dev/null +++ b/ChocolArm64/Translation/ALocalAlloc.cs @@ -0,0 +1,231 @@ +using System.Collections.Generic; + +namespace ChocolArm64.Translation +{ + class ALocalAlloc + { + private class PathIo + { + private Dictionary AllInputs; + private Dictionary CmnOutputs; + + private long AllOutputs; + + public PathIo() + { + AllInputs = new Dictionary(); + CmnOutputs = new Dictionary(); + } + + public PathIo(AILBlock Root, long Inputs, long Outputs) : this() + { + Set(Root, Inputs, Outputs); + } + + public void Set(AILBlock Root, long Inputs, long Outputs) + { + if (!AllInputs.TryAdd(Root, Inputs)) + { + AllInputs[Root] |= Inputs; + } + + if (!CmnOutputs.TryAdd(Root, Outputs)) + { + CmnOutputs[Root] &= Outputs; + } + + AllOutputs |= Outputs; + } + + public long GetInputs(AILBlock Root) + { + if (AllInputs.TryGetValue(Root, out long Inputs)) + { + return Inputs | (AllOutputs & ~CmnOutputs[Root]); + } + + return 0; + } + + public long GetOutputs() + { + return AllOutputs; + } + } + + private Dictionary IntPaths; + private Dictionary VecPaths; + + private struct BlockIo + { + public AILBlock Block; + public AILBlock Entry; + + public long IntInputs; + public long VecInputs; + public long IntOutputs; + public long VecOutputs; + } + + private const int MaxOptGraphLength = 120; + + public ALocalAlloc(AILBlock[] Graph, AILBlock Root) + { + IntPaths = new Dictionary(); + VecPaths = new Dictionary(); + + if (Graph.Length < MaxOptGraphLength) + { + InitializeOptimal(Graph, Root); + } + else + { + InitializeFast(Graph); + } + } + + private void InitializeOptimal(AILBlock[] Graph, AILBlock Root) + { + //This will go through all possible paths on the graph, + //and store all inputs/outputs for each block. A register + //that was previously written to already is not considered an input. + //When a block can be reached by more than one path, then the + //output from all paths needs to be set for this block, and + //only outputs present in all of the parent blocks can be considered + //when doing input elimination. Each block chain have a root, that's where + //the code starts executing. They are present on the subroutine start point, + //and on call return points too (address written to X30 by BL). + HashSet Visited = new HashSet(); + + Queue Unvisited = new Queue(); + + void Enqueue(BlockIo Block) + { + if (!Visited.Contains(Block)) + { + Unvisited.Enqueue(Block); + + Visited.Add(Block); + } + } + + Enqueue(new BlockIo() + { + Block = Root, + Entry = Root + }); + + while (Unvisited.Count > 0) + { + BlockIo Current = Unvisited.Dequeue(); + + Current.IntInputs |= Current.Block.IntInputs & ~Current.IntOutputs; + Current.VecInputs |= Current.Block.VecInputs & ~Current.VecOutputs; + Current.IntOutputs |= Current.Block.IntOutputs; + Current.VecOutputs |= Current.Block.VecOutputs; + + //Check if this is a exit block + //(a block that returns or calls another sub). + if ((Current.Block.Next == null && + Current.Block.Branch == null) || Current.Block.HasStateStore) + { + if (!IntPaths.TryGetValue(Current.Block, out PathIo IntPath)) + { + IntPaths.Add(Current.Block, IntPath = new PathIo()); + } + + if (!VecPaths.TryGetValue(Current.Block, out PathIo VecPath)) + { + VecPaths.Add(Current.Block, VecPath = new PathIo()); + } + + IntPath.Set(Current.Entry, Current.IntInputs, Current.IntOutputs); + VecPath.Set(Current.Entry, Current.VecInputs, Current.VecOutputs); + } + + void EnqueueFromCurrent(AILBlock Block, bool RetTarget) + { + BlockIo BlkIO = new BlockIo() { Block = Block }; + + if (RetTarget) + { + BlkIO.Entry = Block; + BlkIO.IntInputs = 0; + BlkIO.VecInputs = 0; + BlkIO.IntOutputs = 0; + BlkIO.VecOutputs = 0; + } + else + { + BlkIO.Entry = Current.Entry; + BlkIO.IntInputs = Current.IntInputs; + BlkIO.VecInputs = Current.VecInputs; + BlkIO.IntOutputs = Current.IntOutputs; + BlkIO.VecOutputs = Current.VecOutputs; + } + + Enqueue(BlkIO); + } + + if (Current.Block.Next != null) + { + EnqueueFromCurrent(Current.Block.Next, Current.Block.HasStateStore); + } + + if (Current.Block.Branch != null) + { + EnqueueFromCurrent(Current.Block.Branch, false); + } + } + } + + private void InitializeFast(AILBlock[] Graph) + { + //This is WAY faster than InitializeOptimal, but results in + //uneeded loads and stores, so the resulting code will be slower. + long IntInputs = 0; + long IntOutputs = 0; + long VecInputs = 0; + long VecOutputs = 0; + + foreach (AILBlock Block in Graph) + { + IntInputs |= Block.IntInputs; + IntOutputs |= Block.IntOutputs; + VecInputs |= Block.VecInputs; + VecOutputs |= Block.VecOutputs; + } + + //It's possible that not all code paths writes to those output registers, + //in those cases if we attempt to write an output registers that was + //not written, we will be just writing zero and messing up the old register value. + //So we just need to ensure that all outputs are loaded. + IntInputs |= IntOutputs; + VecInputs |= VecOutputs; + + foreach (AILBlock Block in Graph) + { + IntPaths.Add(Block, new PathIo(Block, IntInputs, IntOutputs)); + VecPaths.Add(Block, new PathIo(Block, VecInputs, VecOutputs)); + } + } + + public long GetIntInputs(AILBlock Root) => GetInputsImpl(Root, IntPaths.Values); + public long GetVecInputs(AILBlock Root) => GetInputsImpl(Root, VecPaths.Values); + + private long GetInputsImpl(AILBlock Root, IEnumerable Values) + { + long Inputs = 0; + + foreach (PathIo Path in Values) + { + Inputs |= Path.GetInputs(Root); + } + + return Inputs; + } + + public long GetIntOutputs(AILBlock Block) => IntPaths[Block].GetOutputs(); + public long GetVecOutputs(AILBlock Block) => VecPaths[Block].GetOutputs(); + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/IAILEmit.cs b/ChocolArm64/Translation/IAILEmit.cs new file mode 100644 index 00000000..6e4e9a78 --- /dev/null +++ b/ChocolArm64/Translation/IAILEmit.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Translation +{ + interface IAILEmit + { + void Emit(AILEmitter Context); + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/ILGeneratorEx.cs b/ChocolArm64/Translation/ILGeneratorEx.cs new file mode 100644 index 00000000..abb35ec3 --- /dev/null +++ b/ChocolArm64/Translation/ILGeneratorEx.cs @@ -0,0 +1,129 @@ +using System; + +namespace ChocolArm64 +{ + using System.Reflection.Emit; + + static class ILGeneratorEx + { + public static void EmitLdc_I4(this ILGenerator Generator,int Value) + { + switch (Value) + { + case 0: Generator.Emit(OpCodes.Ldc_I4_0); break; + case 1: Generator.Emit(OpCodes.Ldc_I4_1); break; + case 2: Generator.Emit(OpCodes.Ldc_I4_2); break; + case 3: Generator.Emit(OpCodes.Ldc_I4_3); break; + case 4: Generator.Emit(OpCodes.Ldc_I4_4); break; + case 5: Generator.Emit(OpCodes.Ldc_I4_5); break; + case 6: Generator.Emit(OpCodes.Ldc_I4_6); break; + case 7: Generator.Emit(OpCodes.Ldc_I4_7); break; + case 8: Generator.Emit(OpCodes.Ldc_I4_8); break; + case -1: Generator.Emit(OpCodes.Ldc_I4_M1); break; + default: Generator.Emit(OpCodes.Ldc_I4, Value); break; + } + } + + public static void EmitLdarg(this ILGenerator Generator, int Index) + { + switch (Index) + { + case 0: Generator.Emit(OpCodes.Ldarg_0); break; + case 1: Generator.Emit(OpCodes.Ldarg_1); break; + case 2: Generator.Emit(OpCodes.Ldarg_2); break; + case 3: Generator.Emit(OpCodes.Ldarg_3); break; + + default: + if ((uint)Index <= byte.MaxValue) + { + Generator.Emit(OpCodes.Ldarg_S, (byte)Index); + } + else if ((uint)Index < ushort.MaxValue) + { + Generator.Emit(OpCodes.Ldarg, (short)Index); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + break; + } + } + + public static void EmitStarg(this ILGenerator Generator, int Index) + { + if ((uint)Index <= byte.MaxValue) + { + Generator.Emit(OpCodes.Starg_S, (byte)Index); + } + else if ((uint)Index < ushort.MaxValue) + { + Generator.Emit(OpCodes.Starg, (short)Index); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + } + + public static void EmitLdloc(this ILGenerator Generator, int Index) + { + switch (Index) + { + case 0: Generator.Emit(OpCodes.Ldloc_0); break; + case 1: Generator.Emit(OpCodes.Ldloc_1); break; + case 2: Generator.Emit(OpCodes.Ldloc_2); break; + case 3: Generator.Emit(OpCodes.Ldloc_3); break; + + default: + if ((uint)Index <= byte.MaxValue) + { + Generator.Emit(OpCodes.Ldloc_S, (byte)Index); + } + else if ((uint)Index < ushort.MaxValue) + { + Generator.Emit(OpCodes.Ldloc, (short)Index); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + break; + } + } + + public static void EmitStloc(this ILGenerator Generator, int Index) + { + switch (Index) + { + case 0: Generator.Emit(OpCodes.Stloc_0); break; + case 1: Generator.Emit(OpCodes.Stloc_1); break; + case 2: Generator.Emit(OpCodes.Stloc_2); break; + case 3: Generator.Emit(OpCodes.Stloc_3); break; + + default: + if ((uint)Index <= byte.MaxValue) + { + Generator.Emit(OpCodes.Stloc_S, (byte)Index); + } + else if ((uint)Index < ushort.MaxValue) + { + Generator.Emit(OpCodes.Stloc, (short)Index); + } + else + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + break; + } + } + + public static void EmitLdargSeq(this ILGenerator Generator, int Count) + { + for (int Index = 0; Index < Count; Index++) + { + Generator.EmitLdarg(Index); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Config.cs b/Ryujinx.Core/Config.cs new file mode 100644 index 00000000..b97e80b8 --- /dev/null +++ b/Ryujinx.Core/Config.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Ryujinx.Core +{ + public static class Config + { + public static bool LoggingEnableInfo { get; private set; } + public static bool LoggingEnableTrace { get; private set; } + public static bool LoggingEnableDebug { get; private set; } + public static bool LoggingEnableWarn { get; private set; } + public static bool LoggingEnableError { get; private set; } + public static bool LoggingEnableFatal { get; private set; } + public static bool LoggingEnableLogFile { get; private set; } + + public static JoyCon FakeJoyCon { get; private set; } + + public static void Read() + { + var iniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + var iniPath = Path.Combine(iniFolder, "Ryujinx.conf"); + IniParser Parser = new IniParser(iniPath); + + LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info")); + LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace")); + LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug")); + LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn")); + LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error")); + LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal")); + LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile")); + + FakeJoyCon = new JoyCon + { + Left = new JoyConLeft + { + StickUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Up")), + StickDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Down")), + StickLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Left")), + StickRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Right")), + StickButton = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Button")), + DPadUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Up")), + DPadDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Down")), + DPadLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Left")), + DPadRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Right")), + ButtonMinus = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_Minus")), + ButtonL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_L")), + ButtonZL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_ZL")) + }, + + Right = new JoyConRight + { + StickUp = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Up")), + StickDown = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Down")), + StickLeft = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Left")), + StickRight = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Right")), + StickButton = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Button")), + ButtonA = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_A")), + ButtonB = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_B")), + ButtonX = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_X")), + ButtonY = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Y")), + ButtonPlus = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Plus")), + ButtonR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_R")), + ButtonZR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_ZR")) + } + }; + } + } + + // https://stackoverflow.com/a/37772571 + public class IniParser + { + private readonly Dictionary Values; + + public IniParser(string Path) + { + Values = File.ReadLines(Path) + .Where(Line => !string.IsNullOrWhiteSpace(Line) && !Line.StartsWith('#')) + .Select(Line => Line.Split('=', 2)) + .ToDictionary(Parts => Parts[0].Trim(), Parts => Parts.Length > 1 ? Parts[1].Trim() : null); + } + + /// + /// Gets the setting value for the requested setting . + /// + /// Setting Name + /// Default value of the setting + public string Value(string Name, string defaultValue = null) + { + return Values.TryGetValue(Name, out var value) ? value : defaultValue; + } + } +} diff --git a/Ryujinx.Core/Hid.cs b/Ryujinx.Core/Hid.cs new file mode 100644 index 00000000..44d3e0fb --- /dev/null +++ b/Ryujinx.Core/Hid.cs @@ -0,0 +1,185 @@ +using Ryujinx.Core.OsHle; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + public class Hid + { + /* + Thanks to: + https://github.com/reswitched/libtransistor/blob/development/lib/hid.c + https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h + https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c + https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h + + struct HidSharedMemory + { + header[0x400]; + touchscreen[0x3000]; + mouse[0x400]; + keyboard[0x400]; + unkSection1[0x400]; + unkSection2[0x400]; + unkSection3[0x400]; + unkSection4[0x400]; + unkSection5[0x200]; + unkSection6[0x200]; + unkSection7[0x200]; + unkSection8[0x800]; + controllerSerials[0x4000]; + controllers[0x5000 * 10]; + unkSection9[0x4600]; + } + */ + + private const int Hid_Num_Entries = 16; + private Switch Ns; + private long SharedMemOffset; + + public Hid(Switch Ns) + { + this.Ns = Ns; + } + + public void Init(long HidOffset) + { + unsafe + { + if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue) + { + return; + } + + SharedMemOffset = HidOffset; + + uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)); + + IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); + + HidTouchScreen TouchScreen = new HidTouchScreen(); + TouchScreen.Header.TimestampTicks = (ulong)Environment.TickCount; + TouchScreen.Header.NumEntries = (ulong)Hid_Num_Entries; + TouchScreen.Header.LatestEntry = 0; + TouchScreen.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; + TouchScreen.Header.Timestamp = (ulong)Environment.TickCount; + + //TODO: Write this structure when the input is implemented + //Marshal.StructureToPtr(TouchScreen, HidPtr, false); + + InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreen)); + HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); + + HidMouse Mouse = new HidMouse(); + Mouse.Header.TimestampTicks = (ulong)Environment.TickCount; + Mouse.Header.NumEntries = (ulong)Hid_Num_Entries; + Mouse.Header.LatestEntry = 0; + Mouse.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; + + //TODO: Write this structure when the input is implemented + //Marshal.StructureToPtr(Mouse, HidPtr, false); + + InnerOffset += (uint)Marshal.SizeOf(typeof(HidMouse)); + HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); + + HidKeyboard Keyboard = new HidKeyboard(); + Keyboard.Header.TimestampTicks = (ulong)Environment.TickCount; + Keyboard.Header.NumEntries = (ulong)Hid_Num_Entries; + Keyboard.Header.LatestEntry = 0; + Keyboard.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; + + //TODO: Write this structure when the input is implemented + //Marshal.StructureToPtr(Keyboard, HidPtr, false); + + InnerOffset += (uint)Marshal.SizeOf(typeof(HidKeyboard)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + + (uint)Marshal.SizeOf(typeof(HidControllerSerials)); + + //Increase the loop to initialize more controller. + for (int i = 8; i < Enum.GetNames(typeof(HidControllerID)).Length - 1; i++) + { + HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset + (uint)(Marshal.SizeOf(typeof(HidController)) * i)); + + HidController Controller = new HidController(); + Controller.Header.Type = (uint)(HidControllerType.ControllerType_Handheld | HidControllerType.ControllerType_JoyconPair); + Controller.Header.IsHalf = 0; + Controller.Header.SingleColorsDescriptor = (uint)(HidControllerColorDescription.ColorDesc_ColorsNonexistent); + Controller.Header.SingleColorBody = 0; + Controller.Header.SingleColorButtons = 0; + Controller.Header.SplitColorsDescriptor = 0; + Controller.Header.LeftColorBody = (uint)JoyConColor.Body_Neon_Red; + Controller.Header.LeftColorButtons = (uint)JoyConColor.Buttons_Neon_Red; + Controller.Header.RightColorBody = (uint)JoyConColor.Body_Neon_Blue; + Controller.Header.RightColorButtons = (uint)JoyConColor.Buttons_Neon_Blue; + + Controller.Layouts = new HidControllerLayout[Enum.GetNames(typeof(HidControllerLayouts)).Length]; + Controller.Layouts[(int)HidControllerLayouts.Main] = new HidControllerLayout(); + Controller.Layouts[(int)HidControllerLayouts.Main].Header.LatestEntry = (ulong)Hid_Num_Entries; + + Marshal.StructureToPtr(Controller, HidPtr, false); + } + + Logging.Info("HID Initialized!"); + } + } + + public void SendControllerButtons(HidControllerID ControllerId, + HidControllerLayouts Layout, + HidControllerKeys Buttons, + JoystickPosition LeftJoystick, + JoystickPosition RightJoystick) + { + uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)) + + (uint)Marshal.SizeOf(typeof(HidTouchScreen)) + + (uint)Marshal.SizeOf(typeof(HidMouse)) + + (uint)Marshal.SizeOf(typeof(HidKeyboard)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + + (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + + (uint)Marshal.SizeOf(typeof(HidControllerSerials)) + + ((uint)(Marshal.SizeOf(typeof(HidController)) * (int)ControllerId)) + + (uint)Marshal.SizeOf(typeof(HidControllerHeader)) + + (uint)Layout * (uint)Marshal.SizeOf(typeof(HidControllerLayout)); + + IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); + + HidControllerLayoutHeader OldControllerHeaderLayout = (HidControllerLayoutHeader)Marshal.PtrToStructure(HidPtr, typeof(HidControllerLayoutHeader)); + + HidControllerLayoutHeader ControllerLayoutHeader = new HidControllerLayoutHeader + { + TimestampTicks = (ulong)Environment.TickCount, + NumEntries = (ulong)Hid_Num_Entries, + MaxEntryIndex = (ulong)Hid_Num_Entries - 1, + LatestEntry = (OldControllerHeaderLayout.LatestEntry < (ulong)Hid_Num_Entries ? OldControllerHeaderLayout.LatestEntry + 1 : 0) + }; + + Marshal.StructureToPtr(ControllerLayoutHeader, HidPtr, false); + + InnerOffset += (uint)Marshal.SizeOf(typeof(HidControllerLayoutHeader)) + (uint)((uint)(ControllerLayoutHeader.LatestEntry) * Marshal.SizeOf(typeof(HidControllerInputEntry))); + HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); + + HidControllerInputEntry ControllerInputEntry = new HidControllerInputEntry(); + ControllerInputEntry.Timestamp = (ulong)Environment.TickCount; + ControllerInputEntry.Timestamp_2 = (ulong)Environment.TickCount; + ControllerInputEntry.Buttons = (ulong)Buttons; + ControllerInputEntry.Joysticks = new JoystickPosition[(int)HidControllerJoystick.Joystick_Num_Sticks]; + ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Left] = LeftJoystick; + ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Right] = RightJoystick; + ControllerInputEntry.ConnectionState = (ulong)(HidControllerConnectionState.Controller_State_Connected | HidControllerConnectionState.Controller_State_Wired); + + Marshal.StructureToPtr(ControllerInputEntry, HidPtr, false); + } + } +} diff --git a/Ryujinx.Core/Hid/HidController.cs b/Ryujinx.Core/Hid/HidController.cs new file mode 100644 index 00000000..641bc556 --- /dev/null +++ b/Ryujinx.Core/Hid/HidController.cs @@ -0,0 +1,188 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + [Flags] + public enum HidControllerKeys + { + KEY_A = (1 << 0), + KEY_B = (1 << 1), + KEY_X = (1 << 2), + KEY_Y = (1 << 3), + KEY_LSTICK = (1 << 4), + KEY_RSTICK = (1 << 5), + KEY_L = (1 << 6), + KEY_R = (1 << 7), + KEY_ZL = (1 << 8), + KEY_ZR = (1 << 9), + KEY_PLUS = (1 << 10), + KEY_MINUS = (1 << 11), + KEY_DLEFT = (1 << 12), + KEY_DUP = (1 << 13), + KEY_DRIGHT = (1 << 14), + KEY_DDOWN = (1 << 15), + KEY_LSTICK_LEFT = (1 << 16), + KEY_LSTICK_UP = (1 << 17), + KEY_LSTICK_RIGHT = (1 << 18), + KEY_LSTICK_DOWN = (1 << 19), + KEY_RSTICK_LEFT = (1 << 20), + KEY_RSTICK_UP = (1 << 21), + KEY_RSTICK_RIGHT = (1 << 22), + KEY_RSTICK_DOWN = (1 << 23), + KEY_SL = (1 << 24), + KEY_SR = (1 << 25), + + // Pseudo-key for at least one finger on the touch screen + KEY_TOUCH = (1 << 26), + + // Buttons by orientation (for single Joy-Con), also works with Joy-Con pairs, Pro Controller + KEY_JOYCON_RIGHT = (1 << 0), + KEY_JOYCON_DOWN = (1 << 1), + KEY_JOYCON_UP = (1 << 2), + KEY_JOYCON_LEFT = (1 << 3), + + // Generic catch-all directions, also works for single Joy-Con + KEY_UP = KEY_DUP | KEY_LSTICK_UP | KEY_RSTICK_UP, + KEY_DOWN = KEY_DDOWN | KEY_LSTICK_DOWN | KEY_RSTICK_DOWN, + KEY_LEFT = KEY_DLEFT | KEY_LSTICK_LEFT | KEY_RSTICK_LEFT, + KEY_RIGHT = KEY_DRIGHT | KEY_LSTICK_RIGHT | KEY_RSTICK_RIGHT, + } + + public enum HidControllerID + { + CONTROLLER_PLAYER_1 = 0, + CONTROLLER_PLAYER_2 = 1, + CONTROLLER_PLAYER_3 = 2, + CONTROLLER_PLAYER_4 = 3, + CONTROLLER_PLAYER_5 = 4, + CONTROLLER_PLAYER_6 = 5, + CONTROLLER_PLAYER_7 = 6, + CONTROLLER_PLAYER_8 = 7, + CONTROLLER_HANDHELD = 8, + CONTROLLER_UNKNOWN = 9 + } + + public enum HidControllerJoystick + { + Joystick_Left = 0, + Joystick_Right = 1, + Joystick_Num_Sticks = 2 + } + + public enum HidControllerLayouts + { + Pro_Controller, + Handheld_Joined, + Joined, + Left, + Right, + Main_No_Analog, + Main + } + + [Flags] + public enum HidControllerConnectionState + { + Controller_State_Connected = (1 << 0), + Controller_State_Wired = (1 << 1) + } + + [Flags] + public enum HidControllerType + { + ControllerType_ProController = (1 << 0), + ControllerType_Handheld = (1 << 1), + ControllerType_JoyconPair = (1 << 2), + ControllerType_JoyconLeft = (1 << 3), + ControllerType_JoyconRight = (1 << 4) + } + + public enum HidControllerColorDescription + { + ColorDesc_ColorsNonexistent = (1 << 1), + } + + [StructLayout(LayoutKind.Sequential, Size = 0x8)] + public struct JoystickPosition + { + public int DX; + public int DY; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x20)] + public struct HidControllerMAC + { + public ulong Timestamp; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] MAC; + public ulong Unknown; + public ulong Timestamp_2; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x28)] + public struct HidControllerHeader + { + public uint Type; + public uint IsHalf; + public uint SingleColorsDescriptor; + public uint SingleColorBody; + public uint SingleColorButtons; + public uint SplitColorsDescriptor; + public uint LeftColorBody; + public uint LeftColorButtons; + public uint RightColorBody; + public uint RightColorButtons; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x20)] + public struct HidControllerLayoutHeader + { + public ulong TimestampTicks; + public ulong NumEntries; + public ulong LatestEntry; + public ulong MaxEntryIndex; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x30)] + public struct HidControllerInputEntry + { + public ulong Timestamp; + public ulong Timestamp_2; + public ulong Buttons; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)HidControllerJoystick.Joystick_Num_Sticks)] + public JoystickPosition[] Joysticks; + public ulong ConnectionState; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x350)] + public struct HidControllerLayout + { + public HidControllerLayoutHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public HidControllerInputEntry[] Entries; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x5000)] + public struct HidController + { + public HidControllerHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public HidControllerLayout[] Layouts; + /* + pro_controller + handheld_joined + joined + left + right + main_no_analog + main + */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2A70)] + public byte[] Unknown_1; + public HidControllerMAC MacLeft; + public HidControllerMAC MacRight; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xDF8)] + public byte[] Unknown_2; + } +} diff --git a/Ryujinx.Core/Hid/HidKeyboard.cs b/Ryujinx.Core/Hid/HidKeyboard.cs new file mode 100644 index 00000000..f9987f68 --- /dev/null +++ b/Ryujinx.Core/Hid/HidKeyboard.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20)] + public struct HidKeyboardHeader + { + public ulong TimestampTicks; + public ulong NumEntries; + public ulong LatestEntry; + public ulong MaxEntryIndex; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x38)] + public struct HidKeyboardEntry + { + public ulong Timestamp; + public ulong Timestamp_2; + public ulong Modifier; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public uint[] Keys; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidKeyboard + { + public HidKeyboardHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public HidKeyboardEntry[] Entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)] + public byte[] Padding; + } +} diff --git a/Ryujinx.Core/Hid/HidMouse.cs b/Ryujinx.Core/Hid/HidMouse.cs new file mode 100644 index 00000000..9a019dd5 --- /dev/null +++ b/Ryujinx.Core/Hid/HidMouse.cs @@ -0,0 +1,37 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20)] + public struct HidMouseHeader + { + public ulong TimestampTicks; + public ulong NumEntries; + public ulong LatestEntry; + public ulong MaxEntryIndex; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x30)] + public struct HidMouseEntry + { + public ulong Timestamp; + public ulong Timestamp_2; + public uint X; + public uint Y; + public uint VelocityX; + public uint VelocityY; + public uint ScrollVelocityX; + public uint ScrollVelocityY; + public ulong Buttons; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidMouse + { + public HidMouseHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public HidMouseEntry[] Entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xB0)] + public byte[] Padding; + } +} diff --git a/Ryujinx.Core/Hid/HidTouchScreen.cs b/Ryujinx.Core/Hid/HidTouchScreen.cs new file mode 100644 index 00000000..b755cb95 --- /dev/null +++ b/Ryujinx.Core/Hid/HidTouchScreen.cs @@ -0,0 +1,54 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + [StructLayout(LayoutKind.Sequential, Size = 0x28)] + public struct HidTouchScreenHeader + { + public ulong TimestampTicks; + public ulong NumEntries; + public ulong LatestEntry; + public ulong MaxEntryIndex; + public ulong Timestamp; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x10)] + public struct HidTouchScreenEntryHeader + { + public ulong Timestamp; + public ulong NumTouches; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x28)] + public struct HidTouchScreenEntryTouch + { + public ulong Timestamp; + public uint Padding; + public uint TouchIndex; + public uint X; + public uint Y; + public uint DiameterX; + public uint DiameterY; + public uint Angle; + public uint Padding_2; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x298)] + public struct HidTouchScreenEntry + { + public HidTouchScreenEntryHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public HidTouchScreenEntryTouch[] Touches; + public ulong Unknown; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x3000)] + public struct HidTouchScreen + { + public HidTouchScreenHeader Header; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] + public HidTouchScreenEntry[] Entries; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3C0)] + public byte[] Padding; + } +} diff --git a/Ryujinx.Core/Hid/HidUnknown.cs b/Ryujinx.Core/Hid/HidUnknown.cs new file mode 100644 index 00000000..c3fe68a8 --- /dev/null +++ b/Ryujinx.Core/Hid/HidUnknown.cs @@ -0,0 +1,81 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidSharedMemHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidUnknownSection1 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidUnknownSection2 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidUnknownSection3 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + public struct HidUnknownSection4 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x200)] + public struct HidUnknownSection5 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x200)] + public struct HidUnknownSection6 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x200)] + public struct HidUnknownSection7 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x800)] + public struct HidUnknownSection8 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x4000)] + public struct HidControllerSerials + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)] + public byte[] Padding; + } + + [StructLayout(LayoutKind.Sequential, Size = 0x4600)] + public struct HidUnknownSection9 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4600)] + public byte[] Padding; + } +} diff --git a/Ryujinx.Core/Hid/JoyCon.cs b/Ryujinx.Core/Hid/JoyCon.cs new file mode 100644 index 00000000..8c9518e5 --- /dev/null +++ b/Ryujinx.Core/Hid/JoyCon.cs @@ -0,0 +1,66 @@ +namespace Ryujinx +{ + /// + /// Common RGB color hex codes for JoyCon coloring. + /// + public enum JoyConColor //Thanks to CTCaer + { + Body_Grey = 0x828282, + Body_Neon_Blue = 0x0AB9E6, + Body_Neon_Red = 0xFF3C28, + Body_Neon_Yellow = 0xE6FF00, + Body_Neon_Pink = 0xFF3278, + Body_Neon_Green = 0x1EDC00, + Body_Red = 0xE10F00, + + Buttons_Grey = 0x0F0F0F, + Buttons_Neon_Blue = 0x001E1E, + Buttons_Neon_Red = 0x1E0A0A, + Buttons_Neon_Yellow = 0x142800, + Buttons_Neon_Pink = 0x28001E, + Buttons_Neon_Green = 0x002800, + Buttons_Red = 0x280A0A + } + + public struct JoyConLeft + { + public int StickUp; + public int StickDown; + public int StickLeft; + public int StickRight; + public int StickButton; + public int DPadUp; + public int DPadDown; + public int DPadLeft; + public int DPadRight; + public int ButtonMinus; + public int ButtonL; + public int ButtonZL; + public int ButtonSL; + public int ButtonSR; + } + + public struct JoyConRight + { + public int StickUp; + public int StickDown; + public int StickLeft; + public int StickRight; + public int StickButton; + public int ButtonA; + public int ButtonB; + public int ButtonX; + public int ButtonY; + public int ButtonPlus; + public int ButtonR; + public int ButtonZR; + public int ButtonSL; + public int ButtonSR; + } + + public struct JoyCon + { + public JoyConLeft Left; + public JoyConRight Right; + } +} diff --git a/Ryujinx.Core/Loaders/Compression/Lz4.cs b/Ryujinx.Core/Loaders/Compression/Lz4.cs new file mode 100644 index 00000000..eb1602a0 --- /dev/null +++ b/Ryujinx.Core/Loaders/Compression/Lz4.cs @@ -0,0 +1,78 @@ +using System; + +namespace Ryujinx.Core.Loaders.Compression +{ + static class Lz4 + { + public static byte[] Decompress(byte[] Cmp, int DecLength) + { + byte[] Dec = new byte[DecLength]; + + int CmpPos = 0; + int DecPos = 0; + + int GetLength(int Length) + { + byte Sum; + + if (Length == 0xf) + { + do + { + Length += (Sum = Cmp[CmpPos++]); + } + while (Sum == 0xff); + } + + return Length; + } + + do + { + byte Token = Cmp[CmpPos++]; + + int EncCount = (Token >> 0) & 0xf; + int LitCount = (Token >> 4) & 0xf; + + //Copy literal chunck + LitCount = GetLength(LitCount); + + Buffer.BlockCopy(Cmp, CmpPos, Dec, DecPos, LitCount); + + CmpPos += LitCount; + DecPos += LitCount; + + if (CmpPos >= Cmp.Length) + { + break; + } + + //Copy compressed chunck + int Back = Cmp[CmpPos++] << 0 | + Cmp[CmpPos++] << 8; + + EncCount = GetLength(EncCount) + 4; + + int EncPos = DecPos - Back; + + if (EncCount <= Back) + { + Buffer.BlockCopy(Dec, EncPos, Dec, DecPos, EncCount); + + DecPos += EncCount; + } + else + { + while (EncCount-- > 0) + { + Dec[DecPos++] = Dec[EncPos++]; + } + } + } + while (CmpPos < Cmp.Length && + DecPos < Dec.Length); + + return Dec; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfDyn.cs b/Ryujinx.Core/Loaders/ElfDyn.cs new file mode 100644 index 00000000..2ed50b3e --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfDyn.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Core.Loaders +{ + struct ElfDyn + { + public ElfDynTag Tag { get; private set; } + + public long Value { get; private set; } + + public ElfDyn(ElfDynTag Tag, long Value) + { + this.Tag = Tag; + this.Value = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfDynTag.cs b/Ryujinx.Core/Loaders/ElfDynTag.cs new file mode 100644 index 00000000..1616c223 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfDynTag.cs @@ -0,0 +1,72 @@ +namespace Ryujinx.Core.Loaders +{ + enum ElfDynTag + { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_TEXTREL = 22, + DT_JMPREL = 23, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_FLAGS = 30, + DT_ENCODING = 32, + DT_PREINIT_ARRAY = 32, + DT_PREINIT_ARRAYSZ = 33, + DT_GNU_PRELINKED = 0x6ffffdf5, + DT_GNU_CONFLICTSZ = 0x6ffffdf6, + DT_GNU_LIBLISTSZ = 0x6ffffdf7, + DT_CHECKSUM = 0x6ffffdf8, + DT_PLTPADSZ = 0x6ffffdf9, + DT_MOVEENT = 0x6ffffdfa, + DT_MOVESZ = 0x6ffffdfb, + DT_FEATURE_1 = 0x6ffffdfc, + DT_POSFLAG_1 = 0x6ffffdfd, + DT_SYMINSZ = 0x6ffffdfe, + DT_SYMINENT = 0x6ffffdff, + DT_GNU_HASH = 0x6ffffef5, + DT_TLSDESC_PLT = 0x6ffffef6, + DT_TLSDESC_GOT = 0x6ffffef7, + DT_GNU_CONFLICT = 0x6ffffef8, + DT_GNU_LIBLIST = 0x6ffffef9, + DT_CONFIG = 0x6ffffefa, + DT_DEPAUDIT = 0x6ffffefb, + DT_AUDIT = 0x6ffffefc, + DT_PLTPAD = 0x6ffffefd, + DT_MOVETAB = 0x6ffffefe, + DT_SYMINFO = 0x6ffffeff, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + DT_AUXILIARY = 0x7ffffffd, + DT_FILTER = 0x7fffffff + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfRel.cs b/Ryujinx.Core/Loaders/ElfRel.cs new file mode 100644 index 00000000..8db27452 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfRel.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.Core.Loaders +{ + struct ElfRel + { + public long Offset { get; private set; } + public long Addend { get; private set; } + + public ElfSym Symbol { get; private set; } + public ElfRelType Type { get; private set; } + + public ElfRel(long Offset, long Addend, ElfSym Symbol, ElfRelType Type) + { + this.Offset = Offset; + this.Addend = Addend; + this.Symbol = Symbol; + this.Type = Type; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfRelType.cs b/Ryujinx.Core/Loaders/ElfRelType.cs new file mode 100644 index 00000000..a0533138 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfRelType.cs @@ -0,0 +1,128 @@ +namespace Ryujinx.Core.Loaders +{ + enum ElfRelType + { + R_AARCH64_NONE = 0, + R_AARCH64_ABS64 = 257, + R_AARCH64_ABS32 = 258, + R_AARCH64_ABS16 = 259, + R_AARCH64_PREL64 = 260, + R_AARCH64_PREL32 = 261, + R_AARCH64_PREL16 = 262, + R_AARCH64_MOVW_UABS_G0 = 263, + R_AARCH64_MOVW_UABS_G0_NC = 264, + R_AARCH64_MOVW_UABS_G1 = 265, + R_AARCH64_MOVW_UABS_G1_NC = 266, + R_AARCH64_MOVW_UABS_G2 = 267, + R_AARCH64_MOVW_UABS_G2_NC = 268, + R_AARCH64_MOVW_UABS_G3 = 269, + R_AARCH64_MOVW_SABS_G0 = 270, + R_AARCH64_MOVW_SABS_G1 = 271, + R_AARCH64_MOVW_SABS_G2 = 272, + R_AARCH64_LD_PREL_LO19 = 273, + R_AARCH64_ADR_PREL_LO21 = 274, + R_AARCH64_ADR_PREL_PG_HI21 = 275, + R_AARCH64_ADR_PREL_PG_HI21_NC = 276, + R_AARCH64_ADD_ABS_LO12_NC = 277, + R_AARCH64_LDST8_ABS_LO12_NC = 278, + R_AARCH64_TSTBR14 = 279, + R_AARCH64_CONDBR19 = 280, + R_AARCH64_JUMP26 = 282, + R_AARCH64_CALL26 = 283, + R_AARCH64_LDST16_ABS_LO12_NC = 284, + R_AARCH64_LDST32_ABS_LO12_NC = 285, + R_AARCH64_LDST64_ABS_LO12_NC = 286, + R_AARCH64_MOVW_PREL_G0 = 287, + R_AARCH64_MOVW_PREL_G0_NC = 288, + R_AARCH64_MOVW_PREL_G1 = 289, + R_AARCH64_MOVW_PREL_G1_NC = 290, + R_AARCH64_MOVW_PREL_G2 = 291, + R_AARCH64_MOVW_PREL_G2_NC = 292, + R_AARCH64_MOVW_PREL_G3 = 293, + R_AARCH64_LDST128_ABS_LO12_NC = 299, + R_AARCH64_MOVW_GOTOFF_G0 = 300, + R_AARCH64_MOVW_GOTOFF_G0_NC = 301, + R_AARCH64_MOVW_GOTOFF_G1 = 302, + R_AARCH64_MOVW_GOTOFF_G1_NC = 303, + R_AARCH64_MOVW_GOTOFF_G2 = 304, + R_AARCH64_MOVW_GOTOFF_G2_NC = 305, + R_AARCH64_MOVW_GOTOFF_G3 = 306, + R_AARCH64_GOTREL64 = 307, + R_AARCH64_GOTREL32 = 308, + R_AARCH64_GOT_LD_PREL19 = 309, + R_AARCH64_LD64_GOTOFF_LO15 = 310, + R_AARCH64_ADR_GOT_PAGE = 311, + R_AARCH64_LD64_GOT_LO12_NC = 312, + R_AARCH64_LD64_GOTPAGE_LO15 = 313, + R_AARCH64_TLSGD_ADR_PREL21 = 512, + R_AARCH64_TLSGD_ADR_PAGE21 = 513, + R_AARCH64_TLSGD_ADD_LO12_NC = 514, + R_AARCH64_TLSGD_MOVW_G1 = 515, + R_AARCH64_TLSGD_MOVW_G0_NC = 516, + R_AARCH64_TLSLD_ADR_PREL21 = 517, + R_AARCH64_TLSLD_ADR_PAGE21 = 518, + R_AARCH64_TLSLD_ADD_LO12_NC = 519, + R_AARCH64_TLSLD_MOVW_G1 = 520, + R_AARCH64_TLSLD_MOVW_G0_NC = 521, + R_AARCH64_TLSLD_LD_PREL19 = 522, + R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523, + R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524, + R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525, + R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526, + R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527, + R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528, + R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529, + R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531, + R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533, + R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535, + R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537, + R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538, + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539, + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540, + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541, + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542, + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543, + R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544, + R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545, + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546, + R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547, + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548, + R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549, + R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550, + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551, + R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552, + R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553, + R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554, + R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555, + R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556, + R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557, + R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558, + R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559, + R_AARCH64_TLSDESC_LD_PREL19 = 560, + R_AARCH64_TLSDESC_ADR_PREL21 = 561, + R_AARCH64_TLSDESC_ADR_PAGE21 = 562, + R_AARCH64_TLSDESC_LD64_LO12 = 563, + R_AARCH64_TLSDESC_ADD_LO12 = 564, + R_AARCH64_TLSDESC_OFF_G1 = 565, + R_AARCH64_TLSDESC_OFF_G0_NC = 566, + R_AARCH64_TLSDESC_LDR = 567, + R_AARCH64_TLSDESC_ADD = 568, + R_AARCH64_TLSDESC_CALL = 569, + R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570, + R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571, + R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572, + R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573, + R_AARCH64_COPY = 1024, + R_AARCH64_GLOB_DAT = 1025, + R_AARCH64_JUMP_SLOT = 1026, + R_AARCH64_RELATIVE = 1027, + R_AARCH64_TLS_DTPMOD64 = 1028, + R_AARCH64_TLS_DTPREL64 = 1029, + R_AARCH64_TLS_TPREL64 = 1030, + R_AARCH64_TLSDESC = 1031 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfSym.cs b/Ryujinx.Core/Loaders/ElfSym.cs new file mode 100644 index 00000000..35a45500 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfSym.cs @@ -0,0 +1,43 @@ +namespace Ryujinx.Core.Loaders +{ + struct ElfSym + { + public string Name { get; private set; } + + public ElfSymType Type { get; private set; } + public ElfSymBinding Binding { get; private set; } + public ElfSymVisibility Visibility { get; private set; } + + public bool IsFuncOrObject => + Type == ElfSymType.STT_FUNC || + Type == ElfSymType.STT_OBJECT; + + public bool IsGlobalOrWeak => + Binding == ElfSymBinding.STB_GLOBAL || + Binding == ElfSymBinding.STB_WEAK; + + public int SHIdx { get; private set; } + public long ValueAbs { get; private set; } + public long Value { get; private set; } + public long Size { get; private set; } + + public ElfSym( + string Name, + int Info, + int Other, + int SHIdx, + long ImageBase, + long Value, + long Size) + { + this.Name = Name; + this.Type = (ElfSymType)(Info & 0xf); + this.Binding = (ElfSymBinding)(Info >> 4); + this.Visibility = (ElfSymVisibility)Other; + this.SHIdx = SHIdx; + this.ValueAbs = Value + ImageBase; + this.Value = Value; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfSymBinding.cs b/Ryujinx.Core/Loaders/ElfSymBinding.cs new file mode 100644 index 00000000..c8789496 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfSymBinding.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.Loaders +{ + enum ElfSymBinding + { + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfSymType.cs b/Ryujinx.Core/Loaders/ElfSymType.cs new file mode 100644 index 00000000..786395e6 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfSymType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Core.Loaders +{ + enum ElfSymType + { + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4, + STT_COMMON = 5, + STT_TLS = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/ElfSymVisibility.cs b/Ryujinx.Core/Loaders/ElfSymVisibility.cs new file mode 100644 index 00000000..e72eb5b8 --- /dev/null +++ b/Ryujinx.Core/Loaders/ElfSymVisibility.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Core.Loaders +{ + enum ElfSymVisibility + { + STV_DEFAULT = 0, + STV_INTERNAL = 1, + STV_HIDDEN = 2, + STV_PROTECTED = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs new file mode 100644 index 00000000..6a6073ef --- /dev/null +++ b/Ryujinx.Core/Loaders/Executable.cs @@ -0,0 +1,149 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Loaders.Executables; +using Ryujinx.Core.OsHle; +using System.Collections.Generic; + +namespace Ryujinx.Core.Loaders +{ + class Executable + { + private AMemory Memory; + + private ElfDyn[] Dynamic; + + public long ImageBase { get; private set; } + public long ImageEnd { get; private set; } + + public Executable(IExecutable Exe, AMemory Memory, long ImageBase) + { + this.Memory = Memory; + this.ImageBase = ImageBase; + this.ImageEnd = ImageBase; + + WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX); + WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.Normal, AMemoryPerm.Read); + WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.Normal, AMemoryPerm.RW); + + if (Exe.Mod0Offset == 0) + { + MapBss(ImageBase + Exe.DataOffset + Exe.Data.Count, Exe.BssSize); + + return; + } + + long Mod0Offset = ImageBase + Exe.Mod0Offset; + + int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0); + long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset; + long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset; + long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset; + long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset; + long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset; + long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset; + + MapBss(BssStartOffset, BssEndOffset - BssStartOffset); + + ImageEnd = BssEndOffset; + + List Dynamic = new List(); + + while (true) + { + long TagVal = Memory.ReadInt64(DynamicOffset + 0); + long Value = Memory.ReadInt64(DynamicOffset + 8); + + DynamicOffset += 0x10; + + ElfDynTag Tag = (ElfDynTag)TagVal; + + if (Tag == ElfDynTag.DT_NULL) + { + break; + } + + Dynamic.Add(new ElfDyn(Tag, Value)); + } + + this.Dynamic = Dynamic.ToArray(); + } + + private void WriteData( + long Position, + IList Data, + MemoryType Type, + AMemoryPerm Perm) + { + Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write); + + for (int Index = 0; Index < Data.Count; Index++) + { + Memory.WriteByte(Position + Index, Data[Index]); + } + + Memory.Manager.Reprotect(Position, Data.Count, Perm); + } + + private void MapBss(long Position, long Size) + { + Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); + } + + private ElfRel GetRelocation(long Position) + { + long Offset = Memory.ReadInt64(Position + 0); + long Info = Memory.ReadInt64(Position + 8); + long Addend = Memory.ReadInt64(Position + 16); + + int RelType = (int)(Info >> 0); + int SymIdx = (int)(Info >> 32); + + ElfSym Symbol = GetSymbol(SymIdx); + + return new ElfRel(Offset, Addend, Symbol, (ElfRelType)RelType); + } + + private ElfSym GetSymbol(int Index) + { + long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB); + long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB); + + long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT); + + long Position = SymTblAddr + Index * SymEntSize; + + return GetSymbol(Position, StrTblAddr); + } + + private ElfSym GetSymbol(long Position, long StrTblAddr) + { + int NameIndex = Memory.ReadInt32(Position + 0); + int Info = Memory.ReadByte(Position + 4); + int Other = Memory.ReadByte(Position + 5); + int SHIdx = Memory.ReadInt16(Position + 6); + long Value = Memory.ReadInt64(Position + 8); + long Size = Memory.ReadInt64(Position + 16); + + string Name = string.Empty; + + for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;) + { + Name += (char)Chr; + } + + return new ElfSym(Name, Info, Other, SHIdx, ImageBase, Value, Size); + } + + private long GetFirstValue(ElfDynTag Tag) + { + foreach (ElfDyn Entry in Dynamic) + { + if (Entry.Tag == Tag) + { + return Entry.Value; + } + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/Executables/IExecutable.cs b/Ryujinx.Core/Loaders/Executables/IExecutable.cs new file mode 100644 index 00000000..73787b1d --- /dev/null +++ b/Ryujinx.Core/Loaders/Executables/IExecutable.cs @@ -0,0 +1,17 @@ +using System.Collections.ObjectModel; + +namespace Ryujinx.Core.Loaders.Executables +{ + public interface IExecutable + { + ReadOnlyCollection Text { get; } + ReadOnlyCollection RO { get; } + ReadOnlyCollection Data { get; } + + int Mod0Offset { get; } + int TextOffset { get; } + int ROOffset { get; } + int DataOffset { get; } + int BssSize { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/Executables/Nro.cs b/Ryujinx.Core/Loaders/Executables/Nro.cs new file mode 100644 index 00000000..3cbc4c5d --- /dev/null +++ b/Ryujinx.Core/Loaders/Executables/Nro.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.ObjectModel; +using System.IO; + +namespace Ryujinx.Core.Loaders.Executables +{ + class Nro : IExecutable + { + private byte[] m_Text; + private byte[] m_RO; + private byte[] m_Data; + + public ReadOnlyCollection Text => Array.AsReadOnly(m_Text); + public ReadOnlyCollection RO => Array.AsReadOnly(m_RO); + public ReadOnlyCollection Data => Array.AsReadOnly(m_Data); + + public int Mod0Offset { get; private set; } + public int TextOffset { get; private set; } + public int ROOffset { get; private set; } + public int DataOffset { get; private set; } + public int BssSize { get; private set; } + + public Nro(Stream Input) + { + BinaryReader Reader = new BinaryReader(Input); + + Input.Seek(4, SeekOrigin.Begin); + + int Mod0Offset = Reader.ReadInt32(); + int Padding8 = Reader.ReadInt32(); + int Paddingc = Reader.ReadInt32(); + int NroMagic = Reader.ReadInt32(); + int Unknown14 = Reader.ReadInt32(); + int FileSize = Reader.ReadInt32(); + int Unknown1c = Reader.ReadInt32(); + int TextOffset = Reader.ReadInt32(); + int TextSize = Reader.ReadInt32(); + int ROOffset = Reader.ReadInt32(); + int ROSize = Reader.ReadInt32(); + int DataOffset = Reader.ReadInt32(); + int DataSize = Reader.ReadInt32(); + int BssSize = Reader.ReadInt32(); + + this.Mod0Offset = Mod0Offset; + this.TextOffset = TextOffset; + this.ROOffset = ROOffset; + this.DataOffset = DataOffset; + this.BssSize = BssSize; + + byte[] Read(long Position, int Size) + { + Input.Seek(Position, SeekOrigin.Begin); + + return Reader.ReadBytes(Size); + } + + m_Text = Read(TextOffset, TextSize); + m_RO = Read(ROOffset, ROSize); + m_Data = Read(DataOffset, DataSize); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Loaders/Executables/Nso.cs b/Ryujinx.Core/Loaders/Executables/Nso.cs new file mode 100644 index 00000000..7b8bf253 --- /dev/null +++ b/Ryujinx.Core/Loaders/Executables/Nso.cs @@ -0,0 +1,122 @@ +using Ryujinx.Core.Loaders.Compression; +using System; +using System.Collections.ObjectModel; +using System.IO; + +namespace Ryujinx.Core.Loaders.Executables +{ + class Nso : IExecutable + { + private byte[] m_Text; + private byte[] m_RO; + private byte[] m_Data; + + public ReadOnlyCollection Text => Array.AsReadOnly(m_Text); + public ReadOnlyCollection RO => Array.AsReadOnly(m_RO); + public ReadOnlyCollection Data => Array.AsReadOnly(m_Data); + + public int Mod0Offset { get; private set; } + public int TextOffset { get; private set; } + public int ROOffset { get; private set; } + public int DataOffset { get; private set; } + public int BssSize { get; private set; } + + [Flags] + private enum NsoFlags + { + IsTextCompressed = 1 << 0, + IsROCompressed = 1 << 1, + IsDataCompressed = 1 << 2, + HasTextHash = 1 << 3, + HasROHash = 1 << 4, + HasDataHash = 1 << 5 + } + + public Nso(Stream Input) + { + BinaryReader Reader = new BinaryReader(Input); + + Input.Seek(0, SeekOrigin.Begin); + + int NsoMagic = Reader.ReadInt32(); + int Version = Reader.ReadInt32(); + int Reserved = Reader.ReadInt32(); + int FlagsMsk = Reader.ReadInt32(); + int TextOffset = Reader.ReadInt32(); + int TextMemOffset = Reader.ReadInt32(); + int TextDecSize = Reader.ReadInt32(); + int ModNameOffset = Reader.ReadInt32(); + int ROOffset = Reader.ReadInt32(); + int ROMemOffset = Reader.ReadInt32(); + int RODecSize = Reader.ReadInt32(); + int ModNameSize = Reader.ReadInt32(); + int DataOffset = Reader.ReadInt32(); + int DataMemOffset = Reader.ReadInt32(); + int DataDecSize = Reader.ReadInt32(); + int BssSize = Reader.ReadInt32(); + + byte[] BuildId = Reader.ReadBytes(0x20); + + int TextSize = Reader.ReadInt32(); + int ROSize = Reader.ReadInt32(); + int DataSize = Reader.ReadInt32(); + + Input.Seek(0x24, SeekOrigin.Current); + + int DynStrOffset = Reader.ReadInt32(); + int DynStrSize = Reader.ReadInt32(); + int DynSymOffset = Reader.ReadInt32(); + int DynSymSize = Reader.ReadInt32(); + + byte[] TextHash = Reader.ReadBytes(0x20); + byte[] ROHash = Reader.ReadBytes(0x20); + byte[] DataHash = Reader.ReadBytes(0x20); + + NsoFlags Flags = (NsoFlags)FlagsMsk; + + this.TextOffset = TextMemOffset; + this.ROOffset = ROMemOffset; + this.DataOffset = DataMemOffset; + this.BssSize = BssSize; + + //Text segment + Input.Seek(TextOffset, SeekOrigin.Begin); + + m_Text = Reader.ReadBytes(TextSize); + + if (Flags.HasFlag(NsoFlags.IsTextCompressed) || true) + { + m_Text = Lz4.Decompress(m_Text, TextDecSize); + } + + //Read-only data segment + Input.Seek(ROOffset, SeekOrigin.Begin); + + m_RO = Reader.ReadBytes(ROSize); + + if (Flags.HasFlag(NsoFlags.IsROCompressed) || true) + { + m_RO = Lz4.Decompress(m_RO, RODecSize); + } + + //Data segment + Input.Seek(DataOffset, SeekOrigin.Begin); + + m_Data = Reader.ReadBytes(DataSize); + + if (Flags.HasFlag(NsoFlags.IsDataCompressed) || true) + { + m_Data = Lz4.Decompress(m_Data, DataDecSize); + } + + using (MemoryStream Text = new MemoryStream(m_Text)) + { + BinaryReader TextReader = new BinaryReader(Text); + + Text.Seek(4, SeekOrigin.Begin); + + Mod0Offset = TextReader.ReadInt32(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs new file mode 100644 index 00000000..e14e5587 --- /dev/null +++ b/Ryujinx.Core/Logging.cs @@ -0,0 +1,132 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace Ryujinx.Core +{ + public static class Logging + { + private static Stopwatch ExecutionTime = new Stopwatch(); + private const string LogFileName = "Ryujinx.log"; + + public static bool EnableInfo = Config.LoggingEnableInfo; + public static bool EnableTrace = Config.LoggingEnableTrace; + public static bool EnableDebug = Config.LoggingEnableDebug; + public static bool EnableWarn = Config.LoggingEnableWarn; + public static bool EnableError = Config.LoggingEnableError; + public static bool EnableFatal = Config.LoggingEnableFatal; + public static bool EnableLogFile = Config.LoggingEnableLogFile; + + static Logging() + { + ExecutionTime.Start(); + + if (File.Exists(LogFileName)) File.Delete(LogFileName); + } + + public static string GetExecutionTime() + { + return ExecutionTime.ElapsedMilliseconds.ToString().PadLeft(8, '0') + "ms"; + } + + private static string WhoCalledMe() + { + return new StackTrace().GetFrame(2).GetMethod().Name; + } + + private static void LogFile(string Message) + { + if (EnableLogFile) + { + using (StreamWriter Writer = File.AppendText(LogFileName)) + { + Writer.WriteLine(Message); + } + } + } + + public static void Info(string Message) + { + if (EnableInfo) + { + string Text = $"{GetExecutionTime()} | INFO > {Message}"; + + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + + public static void Trace(string Message) + { + if (EnableTrace) + { + string Text = $"{GetExecutionTime()} | TRACE > {WhoCalledMe()} - {Message}"; + + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + + public static void Debug(string Message) + { + if (EnableDebug) + { + string Text = $"{GetExecutionTime()} | DEBUG > {WhoCalledMe()} - {Message}"; + + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + + public static void Warn(string Message) + { + if (EnableWarn) + { + string Text = $"{GetExecutionTime()} | WARN > {WhoCalledMe()} - {Message}"; + + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + + public static void Error(string Message) + { + if (EnableError) + { + string Text = $"{GetExecutionTime()} | ERROR > {WhoCalledMe()} - {Message}"; + + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + + public static void Fatal(string Message) + { + if (EnableFatal) + { + string Text = $"{GetExecutionTime()} | FATAL > {WhoCalledMe()} - {Message}"; + + Console.ForegroundColor = ConsoleColor.Magenta; + Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); + Console.ResetColor(); + + LogFile(Text); + } + } + } +} diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs new file mode 100644 index 00000000..7b3e1852 --- /dev/null +++ b/Ryujinx.Core/OsHle/CondVar.cs @@ -0,0 +1,138 @@ +using Ryujinx.Core.OsHle.Handles; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.Core.OsHle +{ + public class CondVar + { + private Process Process; + + private long CondVarAddress; + private long Timeout; + + private bool OwnsCondVarValue; + + private List WaitingThreads; + + public CondVar(Process Process, long CondVarAddress, long Timeout) + { + this.Process = Process; + this.CondVarAddress = CondVarAddress; + this.Timeout = Timeout; + + WaitingThreads = new List(); + } + + public void WaitForSignal(HThread Thread) + { + int Count = Process.Memory.ReadInt32(CondVarAddress); + + if (Count <= 0) + { + lock (WaitingThreads) + { + WaitingThreads.Add(Thread); + } + + if (Timeout == -1) + { + Process.Scheduler.WaitForSignal(Thread); + } + else + { + Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000)); + + lock (WaitingThreads) + { + WaitingThreads.Remove(Thread); + } + } + } + + AcquireCondVarValue(); + + Count = Process.Memory.ReadInt32(CondVarAddress); + + if (Count > 0) + { + Process.Memory.WriteInt32(CondVarAddress, Count - 1); + } + + ReleaseCondVarValue(); + } + + public void SetSignal(HThread Thread, int Count) + { + lock (WaitingThreads) + { + if (Count == -1) + { + Process.Scheduler.Signal(WaitingThreads.ToArray()); + + AcquireCondVarValue(); + + Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count); + + ReleaseCondVarValue(); + + WaitingThreads.Clear(); + } + else + { + if (WaitingThreads.Count > 0) + { + int HighestPriority = WaitingThreads[0].Priority; + int HighestPrioIndex = 0; + + for (int Index = 1; Index < WaitingThreads.Count; Index++) + { + if (HighestPriority > WaitingThreads[Index].Priority) + { + HighestPriority = WaitingThreads[Index].Priority; + + HighestPrioIndex = Index; + } + } + + Process.Scheduler.Signal(WaitingThreads[HighestPrioIndex]); + + WaitingThreads.RemoveAt(HighestPrioIndex); + } + + AcquireCondVarValue(); + + Process.Memory.WriteInt32(CondVarAddress, Count); + + ReleaseCondVarValue(); + } + } + + Process.Scheduler.Suspend(Thread.ProcessorId); + Process.Scheduler.Resume(Thread); + } + + private void AcquireCondVarValue() + { + if (!OwnsCondVarValue) + { + while (!Process.Memory.AcquireAddress(CondVarAddress)) + { + Thread.Yield(); + } + + OwnsCondVarValue = true; + } + } + + private void ReleaseCondVarValue() + { + if (OwnsCondVarValue) + { + OwnsCondVarValue = false; + + Process.Memory.ReleaseAddress(CondVarAddress); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Display.cs b/Ryujinx.Core/OsHle/Display.cs new file mode 100644 index 00000000..590841fc --- /dev/null +++ b/Ryujinx.Core/OsHle/Display.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle +{ + class Display + { + public string Name { get; private set; } + + public Display(string Name) + { + this.Name = Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Exceptions/GuestBrokeExecutionException.cs b/Ryujinx.Core/OsHle/Exceptions/GuestBrokeExecutionException.cs new file mode 100644 index 00000000..db4929c5 --- /dev/null +++ b/Ryujinx.Core/OsHle/Exceptions/GuestBrokeExecutionException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.Core.OsHle.Exceptions +{ + public class GuestBrokeExecutionException : Exception + { + private const string ExMsg = "The guest program broke execution!"; + + public GuestBrokeExecutionException() : base(ExMsg) { } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Exceptions/UndefinedInstructionException.cs b/Ryujinx.Core/OsHle/Exceptions/UndefinedInstructionException.cs new file mode 100644 index 00000000..20cf8386 --- /dev/null +++ b/Ryujinx.Core/OsHle/Exceptions/UndefinedInstructionException.cs @@ -0,0 +1,13 @@ +using System; + +namespace Ryujinx.Core.OsHle.Exceptions +{ + public class UndefinedInstructionException : Exception + { + private const string ExMsg = "The instruction at 0x{0:x16} (opcode 0x{1:x8}) is undefined!"; + + public UndefinedInstructionException() : base() { } + + public UndefinedInstructionException(long Position, int OpCode) : base(string.Format(ExMsg, Position, OpCode)) { } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/FileDesc.cs b/Ryujinx.Core/OsHle/FileDesc.cs new file mode 100644 index 00000000..4be83bb0 --- /dev/null +++ b/Ryujinx.Core/OsHle/FileDesc.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle +{ + class FileDesc + { + public string Name { get; private set; } + + public FileDesc(string Name) + { + this.Name = Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs new file mode 100644 index 00000000..ca287a5f --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HDomain.cs @@ -0,0 +1,58 @@ +using Ryujinx.Core.OsHle.Utilities; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Handles +{ + class HDomain : HSession + { + private Dictionary Objects; + + private IdPool ObjIds; + + public HDomain(HSession Session) : base(Session) + { + Objects = new Dictionary(); + + ObjIds = new IdPool(); + } + + public int GenerateObjectId(object Obj) + { + int Id = ObjIds.GenerateId(); + + if (Id == -1) + { + throw new InvalidOperationException(); + } + + Objects.Add(Id, Obj); + + return Id; + } + + public void DeleteObject(int Id) + { + if (Objects.TryGetValue(Id, out object Obj)) + { + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + + ObjIds.DeleteId(Id); + Objects.Remove(Id); + } + } + + public object GetObject(int Id) + { + if (Objects.TryGetValue(Id, out object Obj)) + { + return Obj; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HEvent.cs b/Ryujinx.Core/OsHle/Handles/HEvent.cs new file mode 100644 index 00000000..4e881ca2 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HEvent.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Core.OsHle.Handles +{ + class HEvent + { + + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HNvMap.cs b/Ryujinx.Core/OsHle/Handles/HNvMap.cs new file mode 100644 index 00000000..09173730 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HNvMap.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.Core.OsHle.Handles +{ + class HNvMap + { + public int Id { get; private set; } + public int Size { get; private set; } + + public int Align { get; set; } + public int Kind { get; set; } + public long Address { get; set; } + + public HNvMap(int Id, int Size) + { + this.Id = Id; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSession.cs b/Ryujinx.Core/OsHle/Handles/HSession.cs new file mode 100644 index 00000000..8aa1c06b --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HSession.cs @@ -0,0 +1,27 @@ +namespace Ryujinx.Core.OsHle.Handles +{ + class HSession + { + public string ServiceName { get; private set; } + + public bool IsInitialized { get; private set; } + + public int State { get; set; } + + public HSession(string ServiceName) + { + this.ServiceName = ServiceName; + } + + public HSession(HSession Session) + { + ServiceName = Session.ServiceName; + IsInitialized = Session.IsInitialized; + } + + public void Initialize() + { + IsInitialized = true; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSessionObj.cs b/Ryujinx.Core/OsHle/Handles/HSessionObj.cs new file mode 100644 index 00000000..ed0530f7 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HSessionObj.cs @@ -0,0 +1,30 @@ +using System; + +namespace Ryujinx.Core.OsHle.Handles +{ + class HSessionObj : HSession, IDisposable + { + public object Obj { get; private set; } + + public HSessionObj(HSession Session, object Obj) : base(Session) + { + this.Obj = Obj; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing && Obj != null) + { + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs new file mode 100644 index 00000000..3d56ff92 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Handles +{ + class HSharedMem + { + private List Positions; + + public int PositionsCount => Positions.Count; + + public EventHandler MemoryMapped; + public EventHandler MemoryUnmapped; + + public HSharedMem(long PhysPos) + { + Positions = new List(); + } + + public void AddVirtualPosition(long Position) + { + lock (Positions) + { + Positions.Add(Position); + + MemoryMapped?.Invoke(this, EventArgs.Empty); + } + } + + public void RemoveVirtualPosition(long Position) + { + lock (Positions) + { + Positions.Remove(Position); + + MemoryUnmapped?.Invoke(this, EventArgs.Empty); + } + } + + public long GetVirtualPosition(int Index) + { + lock (Positions) + { + if (Index < 0 || Index >= Positions.Count) + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + return Positions[Index]; + } + } + + public bool TryGetLastVirtualPosition(out long Position) + { + lock (Positions) + { + if (Positions.Count > 0) + { + Position = Positions[Positions.Count - 1]; + + return true; + } + + Position = 0; + + return false; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HThread.cs b/Ryujinx.Core/OsHle/Handles/HThread.cs new file mode 100644 index 00000000..8bb276fa --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HThread.cs @@ -0,0 +1,21 @@ +using ChocolArm64; + +namespace Ryujinx.Core.OsHle.Handles +{ + public class HThread + { + public AThread Thread { get; private set; } + + public int ProcessorId { get; private set; } + public int Priority { get; private set; } + + public int ThreadId => Thread.ThreadId; + + public HThread(AThread Thread, int ProcessorId, int Priority) + { + this.Thread = Thread; + this.ProcessorId = ProcessorId; + this.Priority = Priority; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/HTransferMem.cs b/Ryujinx.Core/OsHle/Handles/HTransferMem.cs new file mode 100644 index 00000000..701fc451 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/HTransferMem.cs @@ -0,0 +1,21 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.OsHle.Handles +{ + class HTransferMem + { + public AMemory Memory { get; private set; } + public AMemoryPerm Perm { get; private set; } + + public long Position { get; private set; } + public long Size { get; private set; } + + public HTransferMem(AMemory Memory, AMemoryPerm Perm, long Position, long Size) + { + this.Memory = Memory; + this.Perm = Perm; + this.Position = Position; + this.Size = Size; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs new file mode 100644 index 00000000..2045f8a1 --- /dev/null +++ b/Ryujinx.Core/OsHle/Handles/KProcessScheduler.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.Core.OsHle.Handles +{ + public class KProcessScheduler : IDisposable + { + private class SchedulerThread : IDisposable + { + public HThread Thread { get; private set; } + + public AutoResetEvent WaitEvent { get; private set; } + + public SchedulerThread(HThread Thread) + { + this.Thread = Thread; + + WaitEvent = new AutoResetEvent(false); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + WaitEvent.Dispose(); + } + } + } + + private class ThreadQueue + { + private List Threads; + + public ThreadQueue() + { + Threads = new List(); + } + + public void Push(SchedulerThread Thread) + { + lock (Threads) + { + Threads.Add(Thread); + } + } + + public SchedulerThread Pop(int MinPriority = 0x40) + { + lock (Threads) + { + SchedulerThread SchedThread; + + int HighestPriority = MinPriority; + + int HighestPrioIndex = -1; + + for (int Index = 0; Index < Threads.Count; Index++) + { + SchedThread = Threads[Index]; + + if (HighestPriority > SchedThread.Thread.Priority) + { + HighestPriority = SchedThread.Thread.Priority; + + HighestPrioIndex = Index; + } + } + + if (HighestPrioIndex == -1) + { + return null; + } + + SchedThread = Threads[HighestPrioIndex]; + + Threads.RemoveAt(HighestPrioIndex); + + return SchedThread; + } + } + + public bool HasThread(SchedulerThread SchedThread) + { + lock (Threads) + { + return Threads.Contains(SchedThread); + } + } + } + + private ConcurrentDictionary AllThreads; + + private ThreadQueue[] WaitingToRun; + + private HashSet ActiveProcessors; + + private object SchedLock; + + public KProcessScheduler() + { + AllThreads = new ConcurrentDictionary(); + + WaitingToRun = new ThreadQueue[4]; + + for (int Index = 0; Index < 4; Index++) + { + WaitingToRun[Index] = new ThreadQueue(); + } + + ActiveProcessors = new HashSet(); + + SchedLock = new object(); + } + + public void StartThread(HThread Thread) + { + lock (SchedLock) + { + SchedulerThread SchedThread = new SchedulerThread(Thread); + + if (!AllThreads.TryAdd(Thread, SchedThread)) + { + return; + } + + if (!ActiveProcessors.Contains(Thread.ProcessorId)) + { + ActiveProcessors.Add(Thread.ProcessorId); + + Thread.Thread.Execute(); + + Logging.Debug($"{GetDbgThreadInfo(Thread)} running."); + } + else + { + WaitingToRun[Thread.ProcessorId].Push(SchedThread); + + Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run."); + } + } + } + + public void Suspend(int ProcessorId) + { + lock (SchedLock) + { + SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop(); + + if (SchedThread != null) + { + RunThread(SchedThread); + } + else + { + ActiveProcessors.Remove(ProcessorId); + } + } + } + + public void Resume(HThread CurrThread) + { + SchedulerThread SchedThread; + + Logging.Debug($"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state."); + + lock (SchedLock) + { + if (!AllThreads.TryGetValue(CurrThread, out SchedThread)) + { + Logging.Error($"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!"); + + return; + } + } + + TryResumingExecution(SchedThread); + } + + public void WaitForSignal(HThread Thread, int Timeout = -1) + { + SchedulerThread SchedThread; + + Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state."); + + lock (SchedLock) + { + SchedThread = WaitingToRun[Thread.ProcessorId].Pop(); + + if (SchedThread != null) + { + RunThread(SchedThread); + } + else + { + ActiveProcessors.Remove(Thread.ProcessorId); + } + + if (!AllThreads.TryGetValue(Thread, out SchedThread)) + { + Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); + + return; + } + } + + if (Timeout >= 0) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms."); + + SchedThread.WaitEvent.WaitOne(Timeout); + } + else + { + SchedThread.WaitEvent.WaitOne(); + } + + TryResumingExecution(SchedThread); + } + + private void TryResumingExecution(SchedulerThread SchedThread) + { + HThread Thread = SchedThread.Thread; + + lock (SchedLock) + { + if (ActiveProcessors.Add(Thread.ProcessorId)) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); + + return; + } + + WaitingToRun[Thread.ProcessorId].Push(SchedThread); + } + + SchedThread.WaitEvent.WaitOne(); + + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); + } + + public void Yield(HThread Thread) + { + SchedulerThread SchedThread; + + Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution."); + + lock (SchedLock) + { + SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority); + + if (SchedThread == null) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run."); + + return; + } + + RunThread(SchedThread); + + if (!AllThreads.TryGetValue(Thread, out SchedThread)) + { + Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); + + return; + } + + WaitingToRun[Thread.ProcessorId].Push(SchedThread); + } + + SchedThread.WaitEvent.WaitOne(); + + Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); + } + + private void RunThread(SchedulerThread SchedThread) + { + if (!SchedThread.Thread.Thread.Execute()) + { + SchedThread.WaitEvent.Set(); + } + else + { + Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running."); + } + } + + public void Signal(params HThread[] Threads) + { + lock (SchedLock) + { + foreach (HThread Thread in Threads) + { + if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) + { + if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread)) + { + Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled."); + + SchedThread.WaitEvent.Set(); + } + } + } + } + } + + private string GetDbgThreadInfo(HThread Thread) + { + return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}"; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + foreach (SchedulerThread SchedThread in AllThreads.Values) + { + SchedThread.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs new file mode 100644 index 00000000..e2d38d52 --- /dev/null +++ b/Ryujinx.Core/OsHle/Horizon.cs @@ -0,0 +1,197 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.Loaders.Executables; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Utilities; +using System; +using System.Collections.Concurrent; +using System.IO; + +namespace Ryujinx.Core.OsHle +{ + public class Horizon + { + internal const int HidSize = 0x40000; + internal const int FontSize = 0x50; + + internal int HidHandle { get; private set; } + internal int FontHandle { get; private set; } + + public long HidOffset { get; private set; } + public long FontOffset { get; private set; } + + internal IdPool IdGen { get; private set; } + internal IdPool NvMapIds { get; private set; } + + internal IdPoolWithObj Handles { get; private set; } + internal IdPoolWithObj Fds { get; private set; } + internal IdPoolWithObj Displays { get; private set; } + + public ConcurrentDictionary Mutexes { get; private set; } + public ConcurrentDictionary CondVars { get; private set; } + + private ConcurrentDictionary Processes; + + private HSharedMem HidSharedMem; + + private AMemoryAlloc Allocator; + + private Switch Ns; + + public Horizon(Switch Ns) + { + this.Ns = Ns; + + IdGen = new IdPool(); + NvMapIds = new IdPool(); + + Handles = new IdPoolWithObj(); + Fds = new IdPoolWithObj(); + Displays = new IdPoolWithObj(); + + Mutexes = new ConcurrentDictionary(); + CondVars = new ConcurrentDictionary(); + + Processes = new ConcurrentDictionary(); + + Allocator = new AMemoryAlloc(); + + HidOffset = Allocator.Alloc(HidSize); + FontOffset = Allocator.Alloc(FontSize); + + HidSharedMem = new HSharedMem(HidOffset); + + HidSharedMem.MemoryMapped += HidInit; + + HidHandle = Handles.GenerateId(HidSharedMem); + + FontHandle = Handles.GenerateId(new HSharedMem(FontOffset)); + } + + public void LoadCart(string ExeFsDir, string RomFsFile = null) + { + if (RomFsFile != null) + { + Ns.VFs.LoadRomFs(RomFsFile); + } + + int ProcessId = IdGen.GenerateId(); + + Process MainProcess = new Process(Ns, Allocator, ProcessId); + + void LoadNso(string FileName) + { + foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) + { + if (Path.GetExtension(File) != string.Empty) + { + continue; + } + + Logging.Info($"Loading {Path.GetFileNameWithoutExtension(File)}..."); + + using (FileStream Input = new FileStream(File, FileMode.Open)) + { + Nso Program = new Nso(Input); + + MainProcess.LoadProgram(Program); + } + } + } + + LoadNso("rtld"); + + MainProcess.SetEmptyArgs(); + + LoadNso("main"); + LoadNso("subsdk*"); + LoadNso("sdk"); + + MainProcess.InitializeHeap(); + MainProcess.Run(); + + Processes.TryAdd(ProcessId, MainProcess); + } + + public void LoadProgram(string FileName) + { + int ProcessId = IdGen.GenerateId(); + + Process MainProcess = new Process(Ns, Allocator, ProcessId); + + using (FileStream Input = new FileStream(FileName, FileMode.Open)) + { + if (Path.GetExtension(FileName).ToLower() == ".nro") + { + MainProcess.LoadProgram(new Nro(Input)); + } + else + { + MainProcess.LoadProgram(new Nso(Input)); + } + } + + MainProcess.SetEmptyArgs(); + MainProcess.InitializeHeap(); + MainProcess.Run(); + + Processes.TryAdd(ProcessId, MainProcess); + } + + public void FinalizeAllProcesses() + { + foreach (Process Process in Processes.Values) + { + Process.StopAllThreads(); + Process.Dispose(); + } + } + + internal bool ExitProcess(int ProcessId) + { + bool Success = Processes.TryRemove(ProcessId, out Process Process); + + if (Success) + { + Process.StopAllThreads(); + } + + if (Processes.Count == 0) + { + Ns.OnFinish(EventArgs.Empty); + } + + return Success; + } + + internal bool TryGetProcess(int ProcessId, out Process Process) + { + return Processes.TryGetValue(ProcessId, out Process); + } + + internal void CloseHandle(int Handle) + { + object HndData = Handles.GetData(Handle); + + if (HndData is HTransferMem TransferMem) + { + TransferMem.Memory.Manager.Reprotect( + TransferMem.Position, + TransferMem.Size, + TransferMem.Perm); + } + + Handles.Delete(Handle); + } + + private void HidInit(object sender, EventArgs e) + { + HSharedMem SharedMem = (HSharedMem)sender; + + if (SharedMem.TryGetLastVirtualPosition(out long Position)) + { + Logging.Info($"HID shared memory successfully mapped to {Position:x16}!"); + Ns.Hid.Init(Position); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs new file mode 100644 index 00000000..01bb1539 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcBuffDesc.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + struct IpcBuffDesc + { + public long Position { get; private set; } + public long Size { get; private set; } + public int Flags { get; private set; } + + public IpcBuffDesc(BinaryReader Reader) + { + long Word0 = Reader.ReadUInt32(); + long Word1 = Reader.ReadUInt32(); + long Word2 = Reader.ReadUInt32(); + + Position = Word1; + Position |= (Word2 << 4) & 0x0f00000000; + Position |= (Word2 << 34) & 0x7000000000; + + Size = Word0; + Size |= (Word2 << 8) & 0xf00000000; + + Flags = (int)Word2 & 3; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs b/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs new file mode 100644 index 00000000..1ef0c408 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcDomCmd.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Core.OsHle.Ipc +{ + enum IpcDomCmd + { + SendMsg = 1, + DeleteObj = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs new file mode 100644 index 00000000..572c0e64 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcHandleDesc.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + class IpcHandleDesc + { + public bool HasPId { get; private set; } + + public long PId { get; private set; } + + public int[] ToCopy { get; private set; } + public int[] ToMove { get; private set; } + + public IpcHandleDesc(BinaryReader Reader) + { + int Word = Reader.ReadInt32(); + + HasPId = (Word & 1) != 0; + + ToCopy = new int[(Word >> 1) & 0xf]; + ToMove = new int[(Word >> 5) & 0xf]; + + PId = HasPId ? Reader.ReadInt64() : 0; + + for (int Index = 0; Index < ToCopy.Length; Index++) + { + ToCopy[Index] = Reader.ReadInt32(); + } + + for (int Index = 0; Index < ToMove.Length; Index++) + { + ToMove[Index] = Reader.ReadInt32(); + } + } + + public IpcHandleDesc(int[] Copy, int[] Move) + { + ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy)); + ToMove = Move ?? throw new ArgumentNullException(nameof(Move)); + } + + public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move) + { + this.PId = PId; + + HasPId = true; + } + + public static IpcHandleDesc MakeCopy(int Handle) => new IpcHandleDesc( + new int[] { Handle }, + new int[0]); + + public static IpcHandleDesc MakeMove(int Handle) => new IpcHandleDesc( + new int[0], + new int[] { Handle }); + + public byte[] GetBytes() + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + int Word = HasPId ? 1 : 0; + + Word |= (ToCopy.Length & 0xf) << 1; + Word |= (ToMove.Length & 0xf) << 5; + + Writer.Write(Word); + + if (HasPId) + { + Writer.Write((long)PId); + } + + foreach (int Handle in ToCopy) + { + Writer.Write(Handle); + } + + foreach (int Handle in ToMove) + { + Writer.Write(Handle); + } + + return MS.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs new file mode 100644 index 00000000..deab8896 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs @@ -0,0 +1,277 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Objects; +using Ryujinx.Core.OsHle.Services; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + static class IpcHandler + { + private static Dictionary<(string, int), ServiceProcessRequest> ServiceCmds = + new Dictionary<(string, int), ServiceProcessRequest>() + { + { ( "acc:u0", 3), Service.AccU0ListOpenUsers }, + { ( "acc:u0", 5), Service.AccU0GetProfile }, + { ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo }, + { ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication }, + { ( "apm", 0), Service.ApmOpenSession }, + { ( "apm:p", 0), Service.ApmOpenSession }, + { ( "appletOE", 0), Service.AppletOpenApplicationProxy }, + { ( "audout:u", 0), Service.AudOutListAudioOuts }, + { ( "audout:u", 1), Service.AudOutOpenAudioOut }, + { ( "audren:u", 0), Service.AudRenOpenAudioRenderer }, + { ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize }, + { ( "friend:a", 0), Service.FriendCreateFriendService }, + { ( "fsp-srv", 1), Service.FspSrvInitialize }, + { ( "fsp-srv", 18), Service.FspSrvMountSdCard }, + { ( "fsp-srv", 51), Service.FspSrvMountSaveData }, + { ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess }, + { ( "fsp-srv", 203), Service.FspSrvOpenRomStorage }, + { ( "fsp-srv", 1005), Service.FspSrvGetGlobalAccessLogMode }, + { ( "hid", 0), Service.HidCreateAppletResource }, + { ( "hid", 11), Service.HidActivateTouchScreen }, + { ( "hid", 100), Service.HidSetSupportedNpadStyleSet }, + { ( "hid", 102), Service.HidSetSupportedNpadIdType }, + { ( "hid", 103), Service.HidActivateNpad }, + { ( "hid", 120), Service.HidSetNpadJoyHoldType }, + { ( "lm", 0), Service.LmInitialize }, + { ( "nvdrv", 0), Service.NvDrvOpen }, + { ( "nvdrv", 1), Service.NvDrvIoctl }, + { ( "nvdrv", 2), Service.NvDrvClose }, + { ( "nvdrv", 3), Service.NvDrvInitialize }, + { ( "nvdrv", 4), Service.NvDrvQueryEvent }, + { ( "nvdrv", 8), Service.NvDrvSetClientPid }, + { ( "nvdrv:a", 0), Service.NvDrvOpen }, + { ( "nvdrv:a", 1), Service.NvDrvIoctl }, + { ( "nvdrv:a", 2), Service.NvDrvClose }, + { ( "nvdrv:a", 3), Service.NvDrvInitialize }, + { ( "nvdrv:a", 4), Service.NvDrvQueryEvent }, + { ( "nvdrv:a", 8), Service.NvDrvSetClientPid }, + { ( "pctl:a", 0), Service.PctlCreateService }, + { ( "pl:u", 1), Service.PlGetLoadState }, + { ( "pl:u", 2), Service.PlGetFontSize }, + { ( "pl:u", 3), Service.PlGetSharedMemoryAddressOffset }, + { ( "pl:u", 4), Service.PlGetSharedMemoryNativeHandle }, + { ( "set", 1), Service.SetGetAvailableLanguageCodes }, + { ( "sm:", 0), Service.SmInitialize }, + { ( "sm:", 1), Service.SmGetService }, + { ( "time:u", 0), Service.TimeGetStandardUserSystemClock }, + { ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock }, + { ( "time:u", 2), Service.TimeGetStandardSteadyClock }, + { ( "time:u", 3), Service.TimeGetTimeZoneService }, + { ( "time:u", 4), Service.TimeGetStandardLocalSystemClock }, + { ( "time:s", 0), Service.TimeGetStandardUserSystemClock }, + { ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock }, + { ( "time:s", 2), Service.TimeGetStandardSteadyClock }, + { ( "time:s", 3), Service.TimeGetTimeZoneService }, + { ( "time:s", 4), Service.TimeGetStandardLocalSystemClock }, + { ( "vi:m", 2), Service.ViGetDisplayService }, + }; + + private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; + private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; + + public static void IpcCall( + Switch Ns, + AMemory Memory, + HSession Session, + IpcMessage Request, + long CmdPtr, + int HndId) + { + IpcMessage Response = new IpcMessage(Request.IsDomain); + + using (MemoryStream Raw = new MemoryStream(Request.RawData)) + { + BinaryReader ReqReader = new BinaryReader(Raw); + + if (Request.Type == IpcMessageType.Request) + { + string ServiceName = Session.ServiceName; + + ServiceProcessRequest ProcReq = null; + + bool IgnoreNullPR = false; + + string DbgServiceName = string.Empty; + + if (Session is HDomain Dom) + { + if (Request.DomCmd == IpcDomCmd.SendMsg) + { + long Magic = ReqReader.ReadInt64(); + int CmdId = (int)ReqReader.ReadInt64(); + + object Obj = Dom.GetObject(Request.DomObjId); + + if (Obj is HDomain) + { + ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); + + DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}"; + } + else if (Obj != null) + { + ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq); + + DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; + } + } + else if (Request.DomCmd == IpcDomCmd.DeleteObj) + { + Dom.DeleteObject(Request.DomObjId); + + Response = FillResponse(Response, 0); + + IgnoreNullPR = true; + } + } + else + { + long Magic = ReqReader.ReadInt64(); + int CmdId = (int)ReqReader.ReadInt64(); + + if (Session is HSessionObj) + { + object Obj = ((HSessionObj)Session).Obj; + + ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq); + + DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; + } + else + { + ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); + + DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}"; + } + } + + Logging.Debug($"IpcMessage: {DbgServiceName}"); + + if (ProcReq != null) + { + using (MemoryStream ResMS = new MemoryStream()) + { + BinaryWriter ResWriter = new BinaryWriter(ResMS); + + ServiceCtx Context = new ServiceCtx( + Ns, + Memory, + Session, + Request, + Response, + ReqReader, + ResWriter); + + long Result = ProcReq(Context); + + Response = FillResponse(Response, Result, ResMS.ToArray()); + } + } + else if (!IgnoreNullPR) + { + throw new NotImplementedException(DbgServiceName); + } + } + else if (Request.Type == IpcMessageType.Control) + { + long Magic = ReqReader.ReadInt64(); + long CmdId = ReqReader.ReadInt64(); + + switch (CmdId) + { + case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break; + case 3: Request = IpcQueryBufferPointerSize(Response); break; + case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break; + + default: throw new NotImplementedException(CmdId.ToString()); + } + } + else if (Request.Type == IpcMessageType.Unknown2) + { + //TODO + } + else + { + throw new NotImplementedException(Request.Type.ToString()); + } + + AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr)); + } + } + + private static IpcMessage IpcConvertSessionToDomain( + Switch Ns, + HSession Session, + IpcMessage Response, + int HndId) + { + HDomain Dom = new HDomain(Session); + + Ns.Os.Handles.ReplaceData(HndId, Dom); + + return FillResponse(Response, 0, Dom.GenerateObjectId(Dom)); + } + + private static IpcMessage IpcDuplicateSessionEx( + Switch Ns, + HSession Session, + IpcMessage Response, + BinaryReader ReqReader) + { + int Unknown = ReqReader.ReadInt32(); + + int Handle = Ns.Os.Handles.GenerateId(Session); + + Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + return FillResponse(Response, 0); + } + + private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response) + { + return FillResponse(Response, 0, 0x500); + } + + private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values) + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + foreach (int Value in Values) + { + Writer.Write(Value); + } + + return FillResponse(Response, Result, MS.ToArray()); + } + } + + private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null) + { + Response.Type = IpcMessageType.Response; + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write(SfcoMagic); + Writer.Write(Result); + + if (Data != null) + { + Writer.Write(Data); + } + + Response.RawData = MS.ToArray(); + } + + return Response; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs new file mode 100644 index 00000000..3b38c451 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessage.cs @@ -0,0 +1,231 @@ +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + class IpcMessage + { + public IpcMessageType Type { get; set; } + + public IpcHandleDesc HandleDesc { get; set; } + + public List PtrBuff { get; private set; } + public List SendBuff { get; private set; } + public List ReceiveBuff { get; private set; } + public List ExchangeBuff { get; private set; } + public List RecvListBuff { get; private set; } + + public List ResponseObjIds { get; private set; } + + public bool IsDomain { get; private set; } + public IpcDomCmd DomCmd { get; private set; } + public int DomObjId { get; private set; } + + public byte[] RawData { get; set; } + + public IpcMessage() + { + PtrBuff = new List(); + SendBuff = new List(); + ReceiveBuff = new List(); + ExchangeBuff = new List(); + RecvListBuff = new List(); + + ResponseObjIds = new List(); + } + + public IpcMessage(bool Domain) : this() + { + IsDomain = Domain; + } + + public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this() + { + using (MemoryStream MS = new MemoryStream(Data)) + { + BinaryReader Reader = new BinaryReader(MS); + + Initialize(Reader, CmdPtr, Domain); + } + } + + private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain) + { + IsDomain = Domain; + + int Word0 = Reader.ReadInt32(); + int Word1 = Reader.ReadInt32(); + + Type = (IpcMessageType)(Word0 & 0xffff); + + int PtrBuffCount = (Word0 >> 16) & 0xf; + int SendBuffCount = (Word0 >> 20) & 0xf; + int RecvBuffCount = (Word0 >> 24) & 0xf; + int XchgBuffCount = (Word0 >> 28) & 0xf; + + int RawDataSize = (Word1 >> 0) & 0x3ff; + int RecvListFlags = (Word1 >> 10) & 0xf; + bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0; + + if (HndDescEnable) + { + HandleDesc = new IpcHandleDesc(Reader); + } + + for (int Index = 0; Index < PtrBuffCount; Index++) + { + PtrBuff.Add(new IpcPtrBuffDesc(Reader)); + } + + void ReadBuff(List Buff, int Count) + { + for (int Index = 0; Index < Count; Index++) + { + Buff.Add(new IpcBuffDesc(Reader)); + } + } + + ReadBuff(SendBuff, SendBuffCount); + ReadBuff(ReceiveBuff, RecvBuffCount); + ReadBuff(ExchangeBuff, XchgBuffCount); + + RawDataSize *= 4; + + long RecvListPos = Reader.BaseStream.Position + RawDataSize; + + long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr); + + Reader.BaseStream.Seek(Pad0, SeekOrigin.Current); + + int RecvListCount = RecvListFlags - 2; + + if (RecvListCount == 0) + { + RecvListCount = 1; + } + else if (RecvListCount < 0) + { + RecvListCount = 0; + } + + if (Domain) + { + int DomWord0 = Reader.ReadInt32(); + + DomCmd = (IpcDomCmd)(DomWord0 & 0xff); + + RawDataSize = (DomWord0 >> 16) & 0xffff; + + DomObjId = Reader.ReadInt32(); + + Reader.ReadInt64(); //Padding + } + + RawData = Reader.ReadBytes(RawDataSize); + + Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); + + for (int Index = 0; Index < RecvListCount; Index++) + { + RecvListBuff.Add(new IpcRecvListBuffDesc(Reader)); + } + } + + public byte[] GetBytes(long CmdPtr) + { + //todo + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + int Word0; + int Word1; + + Word0 = (int)Type; + Word0 |= (PtrBuff.Count & 0xf) << 16; + Word0 |= (SendBuff.Count & 0xf) << 20; + Word0 |= (ReceiveBuff.Count & 0xf) << 24; + Word0 |= (ExchangeBuff.Count & 0xf) << 28; + + byte[] HandleData = new byte[0]; + + if (HandleDesc != null) + { + HandleData = HandleDesc.GetBytes(); + } + + int DataLength = RawData?.Length ?? 0; + + int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length); + + //Apparently, padding after Raw Data is 16 bytes, however when there is + //padding before Raw Data too, we need to subtract the size of this padding. + //This is the weirdest padding I've seen so far... + int Pad1 = 0x10 - Pad0; + + DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4; + + DataLength += ResponseObjIds.Count; + + Word1 = DataLength & 0x3ff; + + if (HandleDesc != null) + { + Word1 |= 1 << 31; + } + + Writer.Write(Word0); + Writer.Write(Word1); + Writer.Write(HandleData); + + MS.Seek(Pad0, SeekOrigin.Current); + + if (IsDomain) + { + Writer.Write(ResponseObjIds.Count); + Writer.Write(0); + Writer.Write(0L); + } + + if (RawData != null) + { + Writer.Write(RawData); + } + + foreach (int Id in ResponseObjIds) + { + Writer.Write(Id); + } + + Writer.Write(new byte[Pad1]); + + return MS.ToArray(); + } + } + + private long GetPadSize16(long Position) + { + if ((Position & 0xf) != 0) + { + return 0x10 - (Position & 0xf); + } + + return 0; + } + + public long GetSendBuffPtr() + { + if (SendBuff.Count > 0 && SendBuff[0].Position != 0) + { + return SendBuff[0].Position; + } + + if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0) + { + return PtrBuff[0].Position; + } + + return -1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs new file mode 100644 index 00000000..8027508d --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Core.OsHle.Ipc +{ + enum IpcMessageType + { + Response = 0, + Unknown2 = 2, + Request = 4, + Control = 5 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs new file mode 100644 index 00000000..d39f78db --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcPtrBuffDesc.cs @@ -0,0 +1,26 @@ +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + struct IpcPtrBuffDesc + { + public long Position { get; private set; } + public int Index { get; private set; } + public short Size { get; private set; } + + public IpcPtrBuffDesc(BinaryReader Reader) + { + long Word0 = Reader.ReadUInt32(); + long Word1 = Reader.ReadUInt32(); + + Position = Word1; + Position |= (Word0 << 20) & 0x0f00000000; + Position |= (Word0 << 30) & 0x7000000000; + + Index = ((int)Word0 >> 0) & 0x03f; + Index |= ((int)Word0 >> 3) & 0x1c0; + + Size = (short)(Word0 >> 16); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs new file mode 100644 index 00000000..c647208f --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/IpcRecvListBuffDesc.cs @@ -0,0 +1,19 @@ +using System.IO; + +namespace Ryujinx.Core.OsHle.Ipc +{ + struct IpcRecvListBuffDesc + { + public long Position { get; private set; } + public short Size { get; private set; } + + public IpcRecvListBuffDesc(BinaryReader Reader) + { + long Value = Reader.ReadInt64(); + + Position = Value & 0xffffffffffff; + + Size = (short)(Value >> 48); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs b/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs new file mode 100644 index 00000000..ea758074 --- /dev/null +++ b/Ryujinx.Core/OsHle/Ipc/ServiceProcessRequest.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Core.OsHle.Ipc +{ + delegate long ServiceProcessRequest(ServiceCtx Context); +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/MemoryInfo.cs b/Ryujinx.Core/OsHle/MemoryInfo.cs new file mode 100644 index 00000000..76a4bef3 --- /dev/null +++ b/Ryujinx.Core/OsHle/MemoryInfo.cs @@ -0,0 +1,28 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.OsHle +{ + struct MemoryInfo + { + public long BaseAddress; + public long Size; + public int MemType; + public int MemAttr; + public int MemPerm; + public int IpcRefCount; + public int DeviceRefCount; + public int Padding; //SBZ + + public MemoryInfo(AMemoryMapInfo MapInfo) + { + BaseAddress = MapInfo.Position; + Size = MapInfo.Size; + MemType = MapInfo.Type; + MemAttr = MapInfo.Attr; + MemPerm = (int)MapInfo.Perm; + IpcRefCount = 0; + DeviceRefCount = 0; + Padding = 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/MemoryType.cs b/Ryujinx.Core/OsHle/MemoryType.cs new file mode 100644 index 00000000..d3b43dd5 --- /dev/null +++ b/Ryujinx.Core/OsHle/MemoryType.cs @@ -0,0 +1,25 @@ +namespace Ryujinx.Core.OsHle +{ + enum MemoryType + { + Unmapped = 0, + Io = 1, + Normal = 2, + CodeStatic = 3, + CodeMutable = 4, + Heap = 5, + SharedMemory = 6, + ModCodeStatic = 8, + ModCodeMutable = 9, + IpcBuffer0 = 10, + MappedMemory = 11, + ThreadLocal = 12, + TransferMemoryIsolated = 13, + TransferMemory = 14, + ProcessMemory = 15, + Reserved = 16, + IpcBuffer1 = 17, + IpcBuffer3 = 18, + KernelStack = 19 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs new file mode 100644 index 00000000..c95ed771 --- /dev/null +++ b/Ryujinx.Core/OsHle/Mutex.cs @@ -0,0 +1,122 @@ +using Ryujinx.Core.OsHle.Handles; +using System.Collections.Concurrent; +using System.Threading; + +namespace Ryujinx.Core.OsHle +{ + public class Mutex + { + private const int MutexHasListenersMask = 0x40000000; + + private Process Process; + + private long MutexAddress; + + private bool OwnsMutexValue; + + private object EnterWaitLock; + + private ConcurrentQueue WaitingThreads; + + public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle) + { + this.Process = Process; + this.MutexAddress = MutexAddress; + + //Process.Memory.WriteInt32(MutexAddress, OwnerThreadHandle); + + EnterWaitLock = new object(); + + WaitingThreads = new ConcurrentQueue(); + } + + public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle) + { + AcquireMutexValue(); + + lock (EnterWaitLock) + { + int CurrentThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; + + if (CurrentThreadHandle == RequestingThreadHandle || + CurrentThreadHandle == 0) + { + return; + } + + Process.Memory.WriteInt32(MutexAddress, CurrentThreadHandle | MutexHasListenersMask); + + ReleaseMutexValue(); + + WaitingThreads.Enqueue(RequestingThread); + } + + Process.Scheduler.WaitForSignal(RequestingThread); + } + + public void GiveUpLock(int ThreadHandle) + { + AcquireMutexValue(); + + lock (EnterWaitLock) + { + int CurrentThread = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; + + if (CurrentThread == ThreadHandle) + { + Unlock(); + } + } + + ReleaseMutexValue(); + } + + public void Unlock() + { + AcquireMutexValue(); + + lock (EnterWaitLock) + { + int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0; + + Process.Memory.WriteInt32(MutexAddress, HasListeners); + + ReleaseMutexValue(); + + HThread[] UnlockedThreads = new HThread[WaitingThreads.Count]; + + int Index = 0; + + while (WaitingThreads.TryDequeue(out HThread Thread)) + { + UnlockedThreads[Index++] = Thread; + } + + Process.Scheduler.Signal(UnlockedThreads); + } + } + + private void AcquireMutexValue() + { + if (!OwnsMutexValue) + { + while (!Process.Memory.AcquireAddress(MutexAddress)) + { + Thread.Yield(); + } + + OwnsMutexValue = true; + } + } + + private void ReleaseMutexValue() + { + if (OwnsMutexValue) + { + OwnsMutexValue = false; + + Process.Memory.ReleaseAddress(MutexAddress); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Acc/IManagerForApplication.cs b/Ryujinx.Core/OsHle/Objects/Acc/IManagerForApplication.cs new file mode 100644 index 00000000..afbfab24 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Acc/IManagerForApplication.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Acc +{ + class IManagerForApplication : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IManagerForApplication() + { + m_Commands = new Dictionary() + { + { 0, CheckAvailability }, + { 1, GetAccountId } + }; + } + + public long CheckAvailability(ServiceCtx Context) + { + return 0; + } + + public long GetAccountId(ServiceCtx Context) + { + Context.ResponseData.Write(0xcafeL); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Acc/IProfile.cs b/Ryujinx.Core/OsHle/Objects/Acc/IProfile.cs new file mode 100644 index 00000000..94d17183 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Acc/IProfile.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Acc +{ + class IProfile : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IProfile() + { + m_Commands = new Dictionary() + { + { 1, GetBase } + }; + } + + public long GetBase(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + Context.ResponseData.Write(0L); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IApplicationFunctions.cs b/Ryujinx.Core/OsHle/Objects/Am/IApplicationFunctions.cs new file mode 100644 index 00000000..939ad248 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IApplicationFunctions.cs @@ -0,0 +1,80 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IApplicationFunctions : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IApplicationFunctions() + { + m_Commands = new Dictionary() + { + { 1, PopLaunchParameter }, + { 20, EnsureSaveData }, + { 21, GetDesiredLanguage }, + { 40, NotifyRunning } + }; + } + + private const uint LaunchParamsMagic = 0xc79497ca; + + public long PopLaunchParameter(ServiceCtx Context) + { + //Only the first 0x18 bytes of the Data seems to be actually used. + MakeObject(Context, new IStorage(MakeLaunchParams())); + + return 0; + } + + public long EnsureSaveData(ServiceCtx Context) + { + long UIdLow = Context.RequestData.ReadInt64(); + long UIdHigh = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0L); + + return 0; + } + + public long GetDesiredLanguage(ServiceCtx Context) + { + //This is an enumerator where each number is a differnet language. + //0 is Japanese and 1 is English, need to figure out the other codes. + Context.ResponseData.Write(1L); + + return 0; + } + + public long NotifyRunning(ServiceCtx Context) + { + Context.ResponseData.Write(1); + + return 0; + } + + private byte[] MakeLaunchParams() + { + //Size needs to be at least 0x88 bytes otherwise application errors. + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + MS.SetLength(0x88); + + Writer.Write(LaunchParamsMagic); + Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used. + Writer.Write(1L); //User Id Low (note: User Id needs to be != 0) + Writer.Write(0L); //User Id High + + return MS.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IApplicationProxy.cs b/Ryujinx.Core/OsHle/Objects/Am/IApplicationProxy.cs new file mode 100644 index 00000000..4a164daf --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IApplicationProxy.cs @@ -0,0 +1,85 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IApplicationProxy : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IApplicationProxy() + { + m_Commands = new Dictionary() + { + { 0, GetCommonStateGetter }, + { 1, GetSelfController }, + { 2, GetWindowController }, + { 3, GetAudioController }, + { 4, GetDisplayController }, + { 11, GetLibraryAppletCreator }, + { 20, GetApplicationFunctions }, + { 1000, GetDebugFunctions } + }; + } + + public long GetCommonStateGetter(ServiceCtx Context) + { + MakeObject(Context, new ICommonStateGetter()); + + return 0; + } + + public long GetSelfController(ServiceCtx Context) + { + MakeObject(Context, new ISelfController()); + + return 0; + } + + public long GetWindowController(ServiceCtx Context) + { + MakeObject(Context, new IWindowController()); + + return 0; + } + + public long GetAudioController(ServiceCtx Context) + { + MakeObject(Context, new IAudioController()); + + return 0; + } + + public long GetDisplayController(ServiceCtx Context) + { + MakeObject(Context, new IDisplayController()); + + return 0; + } + + public long GetLibraryAppletCreator(ServiceCtx Context) + { + MakeObject(Context, new ILibraryAppletCreator()); + + return 0; + } + + public long GetApplicationFunctions(ServiceCtx Context) + { + MakeObject(Context, new IApplicationFunctions()); + + return 0; + } + + public long GetDebugFunctions(ServiceCtx Context) + { + MakeObject(Context, new IDebugFunctions()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IAudioController.cs b/Ryujinx.Core/OsHle/Objects/Am/IAudioController.cs new file mode 100644 index 00000000..c37042fd --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IAudioController.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IAudioController : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/ICommonStateGetter.cs b/Ryujinx.Core/OsHle/Objects/Am/ICommonStateGetter.cs new file mode 100644 index 00000000..83d61fa6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/ICommonStateGetter.cs @@ -0,0 +1,74 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class ICommonStateGetter : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ICommonStateGetter() + { + m_Commands = new Dictionary() + { + { 0, GetEventHandle }, + { 1, ReceiveMessage }, + { 5, GetOperationMode }, + { 6, GetPerformanceMode }, + { 9, GetCurrentFocusState }, + }; + } + + private enum FocusState + { + InFocus = 1, + OutOfFocus = 2 + } + + private enum OperationMode + { + Handheld = 0, + Docked = 1 + } + + public long GetEventHandle(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + return 0; + } + + public long ReceiveMessage(ServiceCtx Context) + { + //Program expects 0xF at 0x17ae70 on puyo sdk, + //otherwise runs on a infinite loop until it reads said value. + //What it means is still unknown. + Context.ResponseData.Write(0xfL); + + return 0; //0x680; + } + + public long GetOperationMode(ServiceCtx Context) + { + Context.ResponseData.Write((byte)OperationMode.Handheld); + + return 0; + } + + public long GetPerformanceMode(ServiceCtx Context) + { + Context.ResponseData.Write((byte)0); + + return 0; + } + + public long GetCurrentFocusState(ServiceCtx Context) + { + Context.ResponseData.Write((byte)FocusState.InFocus); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IDebugFunctions.cs b/Ryujinx.Core/OsHle/Objects/Am/IDebugFunctions.cs new file mode 100644 index 00000000..d04d8363 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IDebugFunctions.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IDebugFunctions : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IDebugFunctions() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IDisplayController.cs b/Ryujinx.Core/OsHle/Objects/Am/IDisplayController.cs new file mode 100644 index 00000000..9eafa70d --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IDisplayController.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IDisplayController : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IDisplayController() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/ILibraryAppletCreator.cs b/Ryujinx.Core/OsHle/Objects/Am/ILibraryAppletCreator.cs new file mode 100644 index 00000000..10e0f4f4 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/ILibraryAppletCreator.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class ILibraryAppletCreator : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ILibraryAppletCreator() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IParentalControlService.cs b/Ryujinx.Core/OsHle/Objects/Am/IParentalControlService.cs new file mode 100644 index 00000000..1feacfa6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IParentalControlService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IParentalControlService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IParentalControlService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/ISelfController.cs b/Ryujinx.Core/OsHle/Objects/Am/ISelfController.cs new file mode 100644 index 00000000..691bb202 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/ISelfController.cs @@ -0,0 +1,53 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class ISelfController : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISelfController() + { + m_Commands = new Dictionary() + { + { 11, SetOperationModeChangedNotification }, + { 12, SetPerformanceModeChangedNotification }, + { 13, SetFocusHandlingMode }, + { 16, SetOutOfFocusSuspendingEnabled } + }; + } + + public long SetOperationModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetPerformanceModeChangedNotification(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetFocusHandlingMode(ServiceCtx Context) + { + bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false; + bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false; + bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + + public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) + { + bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IStorage.cs b/Ryujinx.Core/OsHle/Objects/Am/IStorage.cs new file mode 100644 index 00000000..b30059ba --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IStorage.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IStorage : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public byte[] Data { get; private set; } + + public IStorage(byte[] Data) + { + m_Commands = new Dictionary() + { + { 0, Open } + }; + + this.Data = Data; + } + + public long Open(ServiceCtx Context) + { + MakeObject(Context, new IStorageAccessor(this)); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IStorageAccessor.cs b/Ryujinx.Core/OsHle/Objects/Am/IStorageAccessor.cs new file mode 100644 index 00000000..df260cc3 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IStorageAccessor.cs @@ -0,0 +1,62 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IStorageAccessor : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private IStorage Storage; + + public IStorageAccessor(IStorage Storage) + { + m_Commands = new Dictionary() + { + { 0, GetSize }, + { 11, Read } + }; + + this.Storage = Storage; + } + + public long GetSize(ServiceCtx Context) + { + Context.ResponseData.Write((long)Storage.Data.Length); + + return 0; + } + + public long Read(ServiceCtx Context) + { + long ReadPosition = Context.RequestData.ReadInt64(); + + if (Context.Request.RecvListBuff.Count > 0) + { + long Position = Context.Request.RecvListBuff[0].Position; + short Size = Context.Request.RecvListBuff[0].Size; + + byte[] Data; + + if (Storage.Data.Length > Size) + { + Data = new byte[Size]; + + Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size); + } + else + { + Data = Storage.Data; + } + + AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Am/IWindowController.cs b/Ryujinx.Core/OsHle/Objects/Am/IWindowController.cs new file mode 100644 index 00000000..aa6e961e --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Am/IWindowController.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Am +{ + class IWindowController : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IWindowController() + { + m_Commands = new Dictionary() + { + { 1, GetAppletResourceUserId }, + { 10, AcquireForegroundRights } + }; + } + + public long GetAppletResourceUserId(ServiceCtx Context) + { + Context.ResponseData.Write(0L); + + return 0; + } + + public long AcquireForegroundRights(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Apm/ISession.cs b/Ryujinx.Core/OsHle/Objects/Apm/ISession.cs new file mode 100644 index 00000000..3ab33005 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Apm/ISession.cs @@ -0,0 +1,28 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Apm +{ + class ISession : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISession() + { + m_Commands = new Dictionary() + { + { 0, SetPerformanceConfiguration } + }; + } + + public long SetPerformanceConfiguration(ServiceCtx Context) + { + int PerfMode = Context.RequestData.ReadInt32(); + int PerfConfig = Context.RequestData.ReadInt32(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Objects/Aud/IAudioOut.cs new file mode 100644 index 00000000..061c6376 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Aud/IAudioOut.cs @@ -0,0 +1,180 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using OpenTK.Audio; +using OpenTK.Audio.OpenAL; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.Objects.Aud +{ + class IAudioOut : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioOut() + { + m_Commands = new Dictionary() + { + { 0, GetAudioOutState }, + { 1, StartAudioOut }, + { 2, StopAudioOut }, + { 3, AppendAudioOutBuffer }, + { 4, RegisterBufferEvent }, + { 5, GetReleasedAudioOutBuffer }, + { 6, ContainsAudioOutBuffer }, + { 7, AppendAudioOutBuffer_ex }, + { 8, GetReleasedAudioOutBuffer_ex } + }; + } + + enum AudioOutState + { + Started, + Stopped + }; + + //IAudioOut + private AudioOutState State = AudioOutState.Stopped; + private Queue KeysQueue = new Queue(); + + //OpenAL + private bool OpenALInstalled = true; + private AudioContext AudioCtx; + private int Source; + private int Buffer; + + //Return State of IAudioOut + public long GetAudioOutState(ServiceCtx Context) + { + Context.ResponseData.Write((int)State); + + return 0; + } + + public long StartAudioOut(ServiceCtx Context) + { + if (State == AudioOutState.Stopped) + { + State = AudioOutState.Started; + + try + { + AudioCtx = new AudioContext(); //Create the audio context + } + catch (Exception) + { + Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!"); + OpenALInstalled = false; + } + + if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it + } + + return 0; + } + + public long StopAudioOut(ServiceCtx Context) + { + if (State == AudioOutState.Started) + { + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + AL.SourceStop(Source); + AL.DeleteSource(Source); + } + State = AudioOutState.Stopped; + } + + return 0; + } + + public long AppendAudioOutBuffer(ServiceCtx Context) + { + long BufferId = Context.RequestData.ReadInt64(); + + KeysQueue.Enqueue(BufferId); + + byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5); + using (MemoryStream MS = new MemoryStream(AudioOutBuffer)) + { + BinaryReader Reader = new BinaryReader(MS); + long PointerNextBuffer = Reader.ReadInt64(); + long PointerSampleBuffer = Reader.ReadInt64(); + long CapacitySampleBuffer = Reader.ReadInt64(); + long SizeDataInSampleBuffer = Reader.ReadInt64(); + long OffsetDataInSampleBuffer = Reader.ReadInt64(); + + byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); + + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + Buffer = AL.GenBuffer(); + AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); + + Source = AL.GenSource(); + AL.SourceQueueBuffer(Source, Buffer); + } + } + + return 0; + } + + public long RegisterBufferEvent(ServiceCtx Context) + { + int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + public long GetReleasedAudioOutBuffer(ServiceCtx Context) + { + long TempKey = 0; + + if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue(); + + AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey)); + + int ReleasedBuffersCount = 1; + Context.ResponseData.Write(ReleasedBuffersCount); + + if (OpenALInstalled) + { + if (AudioCtx == null) //Needed to call the instance of AudioContext() + return 0; + + AL.SourcePlay(Source); + int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1); + AL.DeleteBuffers(FreeBuffers); + } + + return 0; + } + + public long ContainsAudioOutBuffer(ServiceCtx Context) + { + return 0; + } + + public long AppendAudioOutBuffer_ex(ServiceCtx Context) + { + return 0; + } + + public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context) + { + return 0; + } + } +} diff --git a/Ryujinx.Core/OsHle/Objects/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Objects/Aud/IAudioRenderer.cs new file mode 100644 index 00000000..05356477 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Aud/IAudioRenderer.cs @@ -0,0 +1,66 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Aud +{ + class IAudioRenderer : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IAudioRenderer() + { + m_Commands = new Dictionary() + { + { 4, RequestUpdateAudioRenderer }, + { 5, StartAudioRenderer }, + { 6, StopAudioRenderer }, + { 7, QuerySystemEvent } + }; + } + + public long RequestUpdateAudioRenderer(ServiceCtx Context) + { + //(buffer) -> (buffer, buffer) + + long Position = Context.Request.ReceiveBuff[0].Position; + + //0x40 bytes header + Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section) + Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size? + Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size? + Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size? + Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size? + Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size? + Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header) + + for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10) + { + Context.Memory.WriteInt32(Position + Offset, 5); + } + + return 0; + } + + public long StartAudioRenderer(ServiceCtx Context) + { + return 0; + } + + public long StopAudioRenderer(ServiceCtx Context) + { + return 0; + } + + public long QuerySystemEvent(ServiceCtx Context) + { + int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Friend/IFriendService.cs b/Ryujinx.Core/OsHle/Objects/Friend/IFriendService.cs new file mode 100644 index 00000000..e98e27ca --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Friend/IFriendService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Friend +{ + class IFriendService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IFriendService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/FspSrv/IDirectory.cs b/Ryujinx.Core/OsHle/Objects/FspSrv/IDirectory.cs new file mode 100644 index 00000000..88fce28e --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/FspSrv/IDirectory.cs @@ -0,0 +1,133 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Core.OsHle.Objects.FspSrv +{ + [StructLayout(LayoutKind.Sequential, Size = 0x310)] + struct DirectoryEntry + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x300)] + public byte[] Name; + public int Unknown; + public byte Type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] + public byte[] Padding; + public long Size; + } + + enum DirectoryEntryType + { + Directory, + File + } + + class IDirectory : IIpcInterface + { + private List DirectoryEntries = new List(); + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private string HostPath; + + public IDirectory(string HostPath, int flags) + { + m_Commands = new Dictionary() + { + { 0, Read }, + { 1, GetEntryCount } + }; + + this.HostPath = HostPath; + + if ((flags & 1) == 1) + { + string[] Directories = Directory.GetDirectories(HostPath, "*", SearchOption.TopDirectoryOnly). + Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray(); + + foreach (string Directory in Directories) + { + DirectoryEntry Info = new DirectoryEntry + { + Name = Encoding.UTF8.GetBytes(Directory), + Type = (byte)DirectoryEntryType.Directory, + Size = 0 + }; + + Array.Resize(ref Info.Name, 0x300); + DirectoryEntries.Add(Info); + } + } + + if ((flags & 2) == 2) + { + string[] Files = Directory.GetFiles(HostPath, "*", SearchOption.TopDirectoryOnly). + Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray(); + + foreach (string FileName in Files) + { + DirectoryEntry Info = new DirectoryEntry + { + Name = Encoding.UTF8.GetBytes(Path.GetFileName(FileName)), + Type = (byte)DirectoryEntryType.File, + Size = new FileInfo(Path.Combine(HostPath, FileName)).Length + }; + + Array.Resize(ref Info.Name, 0x300); + DirectoryEntries.Add(Info); + } + } + } + + private int LastItem = 0; + public long Read(ServiceCtx Context) + { + long BufferPosition = Context.Request.ReceiveBuff[0].Position; + long BufferLen = Context.Request.ReceiveBuff[0].Size; + long MaxDirectories = BufferLen / Marshal.SizeOf(typeof(DirectoryEntry)); + + if (MaxDirectories > DirectoryEntries.Count - LastItem) + { + MaxDirectories = DirectoryEntries.Count - LastItem; + } + + int CurrentIndex; + for (CurrentIndex = 0; CurrentIndex < MaxDirectories; CurrentIndex++) + { + int CurrentItem = LastItem + CurrentIndex; + + byte[] DirectoryEntry = new byte[Marshal.SizeOf(typeof(DirectoryEntry))]; + IntPtr Ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DirectoryEntry))); + Marshal.StructureToPtr(DirectoryEntries[CurrentItem], Ptr, true); + Marshal.Copy(Ptr, DirectoryEntry, 0, Marshal.SizeOf(typeof(DirectoryEntry))); + Marshal.FreeHGlobal(Ptr); + + AMemoryHelper.WriteBytes(Context.Memory, BufferPosition + Marshal.SizeOf(typeof(DirectoryEntry)) * CurrentIndex, DirectoryEntry); + } + + if (LastItem < DirectoryEntries.Count) + { + LastItem += CurrentIndex; + Context.ResponseData.Write((long)CurrentIndex); // index = number of entries written this call. + } + else + { + Context.ResponseData.Write((long)0); + } + + return 0; + } + + public long GetEntryCount(ServiceCtx Context) + { + Context.ResponseData.Write((long)DirectoryEntries.Count); + return 0; + } + } +} diff --git a/Ryujinx.Core/OsHle/Objects/FspSrv/IFile.cs b/Ryujinx.Core/OsHle/Objects/FspSrv/IFile.cs new file mode 100644 index 00000000..95fbc650 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/FspSrv/IFile.cs @@ -0,0 +1,93 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.Objects.FspSrv +{ + class IFile : IIpcInterface, IDisposable + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private Stream BaseStream; + + public IFile(Stream BaseStream) + { + m_Commands = new Dictionary() + { + { 0, Read }, + { 1, Write }, + // { 2, Flush }, + { 3, SetSize }, + { 4, GetSize } + }; + + this.BaseStream = BaseStream; + } + + public long Read(ServiceCtx Context) + { + long Position = Context.Request.ReceiveBuff[0].Position; + + long Zero = Context.RequestData.ReadInt64(); + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + byte[] Data = new byte[Size]; + + BaseStream.Seek(Offset, SeekOrigin.Begin); + int ReadSize = BaseStream.Read(Data, 0, (int)Size); + + AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + + Context.ResponseData.Write((long)ReadSize); + + return 0; + } + + public long Write(ServiceCtx Context) + { + long Position = Context.Request.SendBuff[0].Position; + + long Zero = Context.RequestData.ReadInt64(); + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size); + + BaseStream.Seek(Offset, SeekOrigin.Begin); + BaseStream.Write(Data, 0, (int)Size); + + return 0; + } + + public long GetSize(ServiceCtx Context) + { + Context.ResponseData.Write(BaseStream.Length); + return 0; + } + + public long SetSize(ServiceCtx Context) + { + long Size = Context.RequestData.ReadInt64(); + BaseStream.SetLength(Size); + return 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && BaseStream != null) + { + BaseStream.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/FspSrv/IFileSystem.cs b/Ryujinx.Core/OsHle/Objects/FspSrv/IFileSystem.cs new file mode 100644 index 00000000..68b15845 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/FspSrv/IFileSystem.cs @@ -0,0 +1,247 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Objects.FspSrv +{ + class IFileSystem : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private string Path; + + public IFileSystem(string Path) + { + //TODO: implement. + m_Commands = new Dictionary() + { + { 0, CreateFile }, + { 1, DeleteFile }, + { 2, CreateDirectory }, + { 3, DeleteDirectory }, + { 4, DeleteDirectoryRecursively }, + { 5, RenameFile }, + { 6, RenameDirectory }, + { 7, GetEntryType }, + { 8, OpenFile }, + { 9, OpenDirectory }, + { 10, Commit }, + //{ 11, GetFreeSpaceSize }, + //{ 12, GetTotalSpaceSize }, + //{ 13, CleanDirectoryRecursively }, + //{ 14, GetFileTimeStampRaw } + }; + + this.Path = Path; + } + + public long CreateFile(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + ulong Mode = Context.RequestData.ReadUInt64(); + uint Size = Context.RequestData.ReadUInt32(); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + FileStream NewFile = File.Create(FileName); + NewFile.SetLength(Size); + NewFile.Close(); + return 0; + } + + //TODO: Correct error code. + return -1; + } + + public long DeleteFile(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + File.Delete(FileName); + return 0; + } + + //TODO: Correct error code. + return -1; + } + + public long CreateDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.CreateDirectory(FileName); + return 0; + } + + //TODO: Correct error code. + return -1; + } + + public long DeleteDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.Delete(FileName); + return 0; + } + + // TODO: Correct error code. + return -1; + } + + public long DeleteDirectoryRecursively(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.Delete(FileName, true); // recursive = true + return 0; + } + + // TODO: Correct error code. + return -1; + } + + public long RenameFile(ServiceCtx Context) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); + string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); + + if (OldFileName != null && NewFileName != null) + { + File.Move(OldFileName, NewFileName); + return 0; + } + + // TODO: Correct error code. + return -1; + } + + public long RenameDirectory(ServiceCtx Context) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); + string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); + + if (OldDirName != null && NewDirName != null) + { + Directory.Move(OldDirName, NewDirName); + return 0; + } + + // TODO: Correct error code. + return -1; + } + + public long GetEntryType(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName == null) + { + //TODO: Correct error code. + return -1; + } + + bool IsFile = File.Exists(FileName); + + Context.ResponseData.Write(IsFile ? 1 : 0); + + return 0; + } + + public long OpenFile(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName == null) + { + //TODO: Correct error code. + return -1; + } + + if (File.Exists(FileName)) + { + FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate); + MakeObject(Context, new IFile(Stream)); + + return 0; + } + + //TODO: Correct error code. + return -1; + } + + public long OpenDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + string DirName = Context.Ns.VFs.GetFullPath(Path, Name); + + if(DirName != null) + { + if (Directory.Exists(DirName)) + { + MakeObject(Context, new IDirectory(DirName, FilterFlags)); + return 0; + } + else + { + // TODO: correct error code. + return -1; + } + } + + // TODO: Correct error code. + return -1; + } + + public long Commit(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/FspSrv/IStorage.cs b/Ryujinx.Core/OsHle/Objects/FspSrv/IStorage.cs new file mode 100644 index 00000000..4eca37e8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/FspSrv/IStorage.cs @@ -0,0 +1,52 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.Core.OsHle.Objects.FspSrv +{ + class IStorage : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private Stream BaseStream; + + public IStorage(Stream BaseStream) + { + m_Commands = new Dictionary() + { + { 0, Read } + }; + + this.BaseStream = BaseStream; + } + + public long Read(ServiceCtx Context) + { + long Offset = Context.RequestData.ReadInt64(); + long Size = Context.RequestData.ReadInt64(); + + if (Context.Request.ReceiveBuff.Count > 0) + { + IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0]; + + //Use smaller length to avoid overflows. + if (Size > BuffDesc.Size) + { + Size = BuffDesc.Size; + } + + byte[] Data = new byte[Size]; + + BaseStream.Seek(Offset, SeekOrigin.Begin); + BaseStream.Read(Data, 0, Data.Length); + + AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data); + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Objects/Hid/IAppletResource.cs new file mode 100644 index 00000000..d6e8947b --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Hid/IAppletResource.cs @@ -0,0 +1,32 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Hid +{ + class IAppletResource : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public HSharedMem Handle; + + public IAppletResource(HSharedMem Handle) + { + m_Commands = new Dictionary() + { + { 0, GetSharedMemoryHandle } + }; + + this.Handle = Handle; + } + + public static long GetSharedMemoryHandle(ServiceCtx Context) + { + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/IIpcInterface.cs b/Ryujinx.Core/OsHle/Objects/IIpcInterface.cs new file mode 100644 index 00000000..c57a0974 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/IIpcInterface.cs @@ -0,0 +1,10 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects +{ + interface IIpcInterface + { + IReadOnlyDictionary Commands { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/ObjHelper.cs b/Ryujinx.Core/OsHle/Objects/ObjHelper.cs new file mode 100644 index 00000000..a151a287 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/ObjHelper.cs @@ -0,0 +1,24 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; + +namespace Ryujinx.Core.OsHle.Objects +{ + static class ObjHelper + { + public static void MakeObject(ServiceCtx Context, object Obj) + { + if (Context.Session is HDomain Dom) + { + Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj)); + } + else + { + HSessionObj HndData = new HSessionObj(Context.Session, Obj); + + int VHandle = Context.Ns.Os.Handles.GenerateId(HndData); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Parcel.cs b/Ryujinx.Core/OsHle/Objects/Parcel.cs new file mode 100644 index 00000000..cd7179e1 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Parcel.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; + +namespace Ryujinx.Core.OsHle.Objects.Android +{ + static class Parcel + { + public static byte[] GetParcelData(byte[] Parcel) + { + if (Parcel == null) + { + throw new ArgumentNullException(nameof(Parcel)); + } + + using (MemoryStream MS = new MemoryStream(Parcel)) + { + BinaryReader Reader = new BinaryReader(MS); + + int DataSize = Reader.ReadInt32(); + int DataOffset = Reader.ReadInt32(); + int ObjsSize = Reader.ReadInt32(); + int ObjsOffset = Reader.ReadInt32(); + + MS.Seek(DataOffset - 0x10, SeekOrigin.Current); + + return Reader.ReadBytes(DataSize); + } + } + + public static byte[] MakeParcel(byte[] Data, byte[] Objs) + { + if (Data == null) + { + throw new ArgumentNullException(nameof(Data)); + } + + if (Objs == null) + { + throw new ArgumentNullException(nameof(Objs)); + } + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + Writer.Write(Data.Length); + Writer.Write(0x10); + Writer.Write(Objs.Length); + Writer.Write(Data.Length + 0x10); + + Writer.Write(Data); + Writer.Write(Objs); + + return MS.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Time/ISteadyClock.cs b/Ryujinx.Core/OsHle/Objects/Time/ISteadyClock.cs new file mode 100644 index 00000000..1116b849 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Time/ISteadyClock.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Time +{ + class ISteadyClock : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISteadyClock() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Time/ISystemClock.cs b/Ryujinx.Core/OsHle/Objects/Time/ISystemClock.cs new file mode 100644 index 00000000..3aa70691 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Time/ISystemClock.cs @@ -0,0 +1,42 @@ +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Time +{ + class ISystemClock : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private SystemClockType ClockType; + + public ISystemClock(SystemClockType ClockType) + { + m_Commands = new Dictionary() + { + { 0, GetCurrentTime } + }; + + this.ClockType = ClockType; + } + + public long GetCurrentTime(ServiceCtx Context) + { + DateTime CurrentTime = DateTime.Now; + + if (ClockType == SystemClockType.User || + ClockType == SystemClockType.Network) + { + CurrentTime = CurrentTime.ToUniversalTime(); + } + + Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Time/ITimeZoneService.cs b/Ryujinx.Core/OsHle/Objects/Time/ITimeZoneService.cs new file mode 100644 index 00000000..c083628b --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Time/ITimeZoneService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Time +{ + class ITimeZoneService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ITimeZoneService() + { + m_Commands = new Dictionary() + { + //... + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Time/SystemClockType.cs b/Ryujinx.Core/OsHle/Objects/Time/SystemClockType.cs new file mode 100644 index 00000000..f447ca1c --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Time/SystemClockType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Core.OsHle.Objects.Time +{ + enum SystemClockType + { + User, + Network, + Local + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Objects/Vi/IApplicationDisplayService.cs new file mode 100644 index 00000000..b3ec0e90 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Vi/IApplicationDisplayService.cs @@ -0,0 +1,176 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; + +using static Ryujinx.Core.OsHle.Objects.Android.Parcel; +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Objects.Vi +{ + class IApplicationDisplayService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IApplicationDisplayService() + { + m_Commands = new Dictionary() + { + { 100, GetRelayService }, + { 101, GetSystemDisplayService }, + { 102, GetManagerDisplayService }, + { 103, GetIndirectDisplayTransactionService }, + { 1010, OpenDisplay }, + { 2020, OpenLayer }, + { 2030, CreateStrayLayer }, + { 2101, SetLayerScalingMode }, + { 5202, GetDisplayVSyncEvent } + }; + } + + public long GetRelayService(ServiceCtx Context) + { + MakeObject(Context, new IHOSBinderDriver()); + + return 0; + } + + public long GetSystemDisplayService(ServiceCtx Context) + { + MakeObject(Context, new ISystemDisplayService()); + + return 0; + } + + public long GetManagerDisplayService(ServiceCtx Context) + { + MakeObject(Context, new IManagerDisplayService()); + + return 0; + } + + public long GetIndirectDisplayTransactionService(ServiceCtx Context) + { + MakeObject(Context, new IHOSBinderDriver()); + + return 0; + } + + public long OpenDisplay(ServiceCtx Context) + { + string Name = GetDisplayName(Context); + + long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name)); + + Context.ResponseData.Write(DisplayId); + + return 0; + } + + public long OpenLayer(ServiceCtx Context) + { + long LayerId = Context.RequestData.ReadInt64(); + long UserId = Context.RequestData.ReadInt64(); + + long ParcelPtr = Context.Request.ReceiveBuff[0].Position; + + byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); + + AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); + + Context.ResponseData.Write((long)Parcel.Length); + + return 0; + } + + public long CreateStrayLayer(ServiceCtx Context) + { + long LayerFlags = Context.RequestData.ReadInt64(); + long DisplayId = Context.RequestData.ReadInt64(); + + long ParcelPtr = Context.Request.ReceiveBuff[0].Position; + + Display Disp = Context.Ns.Os.Displays.GetData((int)DisplayId); + + byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); + + AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); + + Context.ResponseData.Write(0L); + Context.ResponseData.Write((long)Parcel.Length); + + return 0; + } + + public long SetLayerScalingMode(ServiceCtx Context) + { + int ScalingMode = Context.RequestData.ReadInt32(); + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public long GetDisplayVSyncEvent(ServiceCtx Context) + { + string Name = GetDisplayName(Context); + + int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); + + return 0; + } + + private byte[] MakeIGraphicsBufferProducer(long BasePtr) + { + long Id = 0x20; + long CookiePtr = 0L; + + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + //flat_binder_object (size is 0x28) + Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) + Writer.Write(0); //Flags + Writer.Write((int)(Id >> 0)); + Writer.Write((int)(Id >> 32)); + Writer.Write((int)(CookiePtr >> 0)); + Writer.Write((int)(CookiePtr >> 32)); + Writer.Write((byte)'d'); + Writer.Write((byte)'i'); + Writer.Write((byte)'s'); + Writer.Write((byte)'p'); + Writer.Write((byte)'d'); + Writer.Write((byte)'r'); + Writer.Write((byte)'v'); + Writer.Write((byte)'\0'); + Writer.Write(0L); //Pad + + return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 }); + } + } + + private string GetDisplayName(ServiceCtx Context) + { + string Name = string.Empty; + + for (int Index = 0; Index < 8 && + Context.RequestData.BaseStream.Position < + Context.RequestData.BaseStream.Length; Index++) + { + byte Chr = Context.RequestData.ReadByte(); + + if (Chr >= 0x20 && Chr < 0x7f) + { + Name += (char)Chr; + } + } + + return Name; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs new file mode 100644 index 00000000..cfd271e8 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Vi/IHOSBinderDriver.cs @@ -0,0 +1,214 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using static Ryujinx.Core.OsHle.Objects.Android.Parcel; + +namespace Ryujinx.Core.OsHle.Objects.Vi +{ + class IHOSBinderDriver : IIpcInterface + { + private delegate long ServiceProcessParcel(ServiceCtx Context, byte[] ParcelData); + + private Dictionary m_Commands; + + private Dictionary<(string, int), ServiceProcessParcel> m_Methods; + + public IReadOnlyDictionary Commands => m_Commands; + + private class BufferObj + { + + } + + private IdPoolWithObj BufferSlots; + + private byte[] Gbfr; + + public IHOSBinderDriver() + { + m_Commands = new Dictionary() + { + { 0, TransactParcel }, + { 1, AdjustRefcount }, + { 2, GetNativeHandle } + }; + + m_Methods = new Dictionary<(string, int), ServiceProcessParcel>() + { + { ("android.gui.IGraphicBufferProducer", 0x1), GraphicBufferProducerRequestBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x3), GraphicBufferProducerDequeueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x7), GraphicBufferProducerQueueBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x8), GraphicBufferProducerCancelBuffer }, + { ("android.gui.IGraphicBufferProducer", 0x9), GraphicBufferProducerQuery }, + { ("android.gui.IGraphicBufferProducer", 0xa), GraphicBufferProducerConnect }, + { ("android.gui.IGraphicBufferProducer", 0xe), GraphicBufferPreallocateBuffer } + }; + + BufferSlots = new IdPoolWithObj(); + } + + public long TransactParcel(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + int Code = Context.RequestData.ReadInt32(); + + long DataPos = Context.Request.SendBuff[0].Position; + long DataSize = Context.Request.SendBuff[0].Size; + + byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)DataSize); + + Data = GetParcelData(Data); + + using (MemoryStream MS = new MemoryStream(Data)) + { + BinaryReader Reader = new BinaryReader(MS); + + MS.Seek(4, SeekOrigin.Current); + + int StrSize = Reader.ReadInt32(); + + string InterfaceName = Encoding.Unicode.GetString(Data, 8, StrSize * 2); + + if (m_Methods.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq)) + { + return ProcReq(Context, Data); + } + else + { + throw new NotImplementedException($"{InterfaceName} {Code}"); + } + } + } + + private long GraphicBufferProducerRequestBuffer(ServiceCtx Context, byte[] ParcelData) + { + int GbfrSize = Gbfr?.Length ?? 0; + + byte[] Data = new byte[GbfrSize + 4]; + + if (Gbfr != null) + { + Buffer.BlockCopy(Gbfr, 0, Data, 0, GbfrSize); + } + + return MakeReplyParcel(Context, Data); + } + + private long GraphicBufferProducerDequeueBuffer(ServiceCtx Context, byte[] ParcelData) + { + //Note: It seems that the maximum number of slots is 64, because if we return + //a Slot number > 63, it seems to cause a buffer overrun and it reads garbage. + //Note 2: The size of each object associated with the slot is 0x30. + int Slot = BufferSlots.GenerateId(new BufferObj()); + + return MakeReplyParcel(Context, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } + + private long GraphicBufferProducerQueueBuffer(ServiceCtx Context, byte[] ParcelData) + { + return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); + } + + private long GraphicBufferProducerCancelBuffer(ServiceCtx Context, byte[] ParcelData) + { + using (MemoryStream MS = new MemoryStream(ParcelData)) + { + BinaryReader Reader = new BinaryReader(MS); + + MS.Seek(0x50, SeekOrigin.Begin); + + int Slot = Reader.ReadInt32(); + + BufferSlots.Delete(Slot); + + return MakeReplyParcel(Context, 0); + } + } + + private long GraphicBufferProducerQuery(ServiceCtx Context, byte[] ParcelData) + { + return MakeReplyParcel(Context, 0, 0); + } + + private long GraphicBufferProducerConnect(ServiceCtx Context, byte[] ParcelData) + { + return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); + } + + private long GraphicBufferPreallocateBuffer(ServiceCtx Context, byte[] ParcelData) + { + int GbfrSize = ParcelData.Length - 0x54; + + Gbfr = new byte[GbfrSize]; + + Buffer.BlockCopy(ParcelData, 0x54, Gbfr, 0, GbfrSize); + + using (MemoryStream MS = new MemoryStream(ParcelData)) + { + BinaryReader Reader = new BinaryReader(MS); + + MS.Seek(0xd4, SeekOrigin.Begin); + + int Handle = Reader.ReadInt32(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + Context.Ns.Gpu.Renderer.FrameBufferPtr = NvMap.Address; + } + + return MakeReplyParcel(Context, 0); + } + + private long MakeReplyParcel(ServiceCtx Context, params int[] Ints) + { + using (MemoryStream MS = new MemoryStream()) + { + BinaryWriter Writer = new BinaryWriter(MS); + + foreach (int Int in Ints) + { + Writer.Write(Int); + } + + return MakeReplyParcel(Context, MS.ToArray()); + } + } + + private long MakeReplyParcel(ServiceCtx Context, byte[] Data) + { + long ReplyPos = Context.Request.ReceiveBuff[0].Position; + long ReplySize = Context.Request.ReceiveBuff[0].Position; + + byte[] Reply = MakeParcel(Data, new byte[0]); + + AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply); + + return 0; + } + + public long AdjustRefcount(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + int AddVal = Context.RequestData.ReadInt32(); + int Type = Context.RequestData.ReadInt32(); + + return 0; + } + + public long GetNativeHandle(ServiceCtx Context) + { + int Id = Context.RequestData.ReadInt32(); + uint Unk = Context.RequestData.ReadUInt32(); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Vi/IManagerDisplayService.cs b/Ryujinx.Core/OsHle/Objects/Vi/IManagerDisplayService.cs new file mode 100644 index 00000000..f1b3cdd0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Vi/IManagerDisplayService.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Vi +{ + class IManagerDisplayService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public IManagerDisplayService() + { + m_Commands = new Dictionary() + { + { 2010, CreateManagedLayer }, + { 6000, AddToLayerStack } + }; + } + + public static long CreateManagedLayer(ServiceCtx Context) + { + Context.ResponseData.Write(0L); //LayerId + + return 0; + } + + public static long AddToLayerStack(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Objects/Vi/ISystemDisplayService.cs b/Ryujinx.Core/OsHle/Objects/Vi/ISystemDisplayService.cs new file mode 100644 index 00000000..4c83c25f --- /dev/null +++ b/Ryujinx.Core/OsHle/Objects/Vi/ISystemDisplayService.cs @@ -0,0 +1,25 @@ +using Ryujinx.Core.OsHle.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Objects.Vi +{ + class ISystemDisplayService : IIpcInterface + { + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + public ISystemDisplayService() + { + m_Commands = new Dictionary() + { + { 2205, SetLayerZ } + }; + } + + public static long SetLayerZ(ServiceCtx Context) + { + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs new file mode 100644 index 00000000..84267885 --- /dev/null +++ b/Ryujinx.Core/OsHle/Process.cs @@ -0,0 +1,257 @@ +using ChocolArm64; +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.Core.Loaders; +using Ryujinx.Core.Loaders.Executables; +using Ryujinx.Core.OsHle.Exceptions; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Svc; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.Core.OsHle +{ + public class Process : IDisposable + { + private const int MaxStackSize = 8 * 1024 * 1024; + + private const int TlsSize = 0x200; + private const int TotalTlsSlots = 32; + private const int TlsTotalSize = TotalTlsSlots * TlsSize; + private const long TlsPageAddr = (AMemoryMgr.AddrSize - TlsTotalSize) & ~AMemoryMgr.PageMask; + + private Switch Ns; + + public int ProcessId { get; private set; } + + public AMemory Memory { get; private set; } + + public KProcessScheduler Scheduler { get; private set; } + + private SvcHandler SvcHandler; + + private ConcurrentDictionary TlsSlots; + + private ConcurrentDictionary ThreadsByTpidr; + + private List Executables; + + private HThread MainThread; + + private long ImageBase; + + public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId) + { + this.Ns = Ns; + this.ProcessId = ProcessId; + + Memory = new AMemory(Ns.Ram, Allocator); + + Scheduler = new KProcessScheduler(); + + SvcHandler = new SvcHandler(Ns, this); + + TlsSlots = new ConcurrentDictionary(); + + ThreadsByTpidr = new ConcurrentDictionary(); + + Executables = new List(); + + ImageBase = 0x8000000; + + Memory.Manager.MapPhys( + TlsPageAddr, + TlsTotalSize, + (int)MemoryType.ThreadLocal, + AMemoryPerm.RW); + } + + public void LoadProgram(IExecutable Program) + { + Logging.Info($"Image base at 0x{ImageBase:x16}."); + + Executable Executable = new Executable(Program, Memory, ImageBase); + + Executables.Add(Executable); + + ImageBase = AMemoryHelper.PageRoundUp(Executable.ImageEnd); + } + + public void SetEmptyArgs() + { + ImageBase += AMemoryMgr.PageSize; + } + + public void InitializeHeap() + { + Memory.Manager.SetHeapAddr((ImageBase + 0x3fffffff) & ~0x3fffffff); + } + + public bool Run() + { + if (Executables.Count == 0) + { + return false; + } + + long StackBot = TlsPageAddr - MaxStackSize; + + Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW); + + int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 0, 0); + + if (Handle == -1) + { + return false; + } + + MainThread = Ns.Os.Handles.GetData(Handle); + + Scheduler.StartThread(MainThread); + + return true; + } + + public void StopAllThreads() + { + if (MainThread != null) + { + while (MainThread.Thread.IsAlive) + { + MainThread.Thread.StopExecution(); + } + } + + foreach (AThread Thread in TlsSlots.Values) + { + while (Thread.IsAlive) + { + Thread.StopExecution(); + } + } + } + + public int MakeThread( + long EntryPoint, + long StackTop, + long ArgsPtr, + int Priority, + int ProcessorId) + { + ThreadPriority ThreadPrio; + + if (Priority < 12) + { + ThreadPrio = ThreadPriority.Highest; + } + else if (Priority < 24) + { + ThreadPrio = ThreadPriority.AboveNormal; + } + else if (Priority < 36) + { + ThreadPrio = ThreadPriority.Normal; + } + else if (Priority < 48) + { + ThreadPrio = ThreadPriority.BelowNormal; + } + else + { + ThreadPrio = ThreadPriority.Lowest; + } + + AThread Thread = new AThread(Memory, ThreadPrio, EntryPoint); + + HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority); + + int Handle = Ns.Os.Handles.GenerateId(ThreadHnd); + + int TlsSlot = GetFreeTlsSlot(Thread); + + if (TlsSlot == -1 || Handle == -1) + { + return -1; + } + + Thread.ThreadState.Break += BreakHandler; + Thread.ThreadState.SvcCall += SvcHandler.SvcCall; + Thread.ThreadState.Undefined += UndefinedHandler; + Thread.ThreadState.ProcessId = ProcessId; + Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId(); + Thread.ThreadState.Tpidr = TlsPageAddr + TlsSlot * TlsSize; + Thread.ThreadState.X0 = (ulong)ArgsPtr; + Thread.ThreadState.X1 = (ulong)Handle; + Thread.ThreadState.X31 = (ulong)StackTop; + + Thread.WorkFinished += ThreadFinished; + + ThreadsByTpidr.TryAdd(Thread.ThreadState.Tpidr, ThreadHnd); + + return Handle; + } + + private void BreakHandler(object sender, AInstExceptEventArgs e) + { + throw new GuestBrokeExecutionException(); + } + + private void UndefinedHandler(object sender, AInstUndEventArgs e) + { + throw new UndefinedInstructionException(e.Position, e.RawOpCode); + } + + private int GetFreeTlsSlot(AThread Thread) + { + for (int Index = 1; Index < TotalTlsSlots; Index++) + { + if (TlsSlots.TryAdd(Index, Thread)) + { + return Index; + } + } + + return -1; + } + + private void ThreadFinished(object sender, EventArgs e) + { + if (sender is AThread Thread) + { + TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _); + + Ns.Os.IdGen.DeleteId(Thread.ThreadId); + } + } + + private int GetTlsSlot(long Position) + { + return (int)((Position - TlsPageAddr) / TlsSize); + } + + public HThread GetThread(long Tpidr) + { + if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread)) + { + Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!"); + } + + return Thread; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + Scheduler.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/ServiceCtx.cs b/Ryujinx.Core/OsHle/ServiceCtx.cs new file mode 100644 index 00000000..31ecce3d --- /dev/null +++ b/Ryujinx.Core/OsHle/ServiceCtx.cs @@ -0,0 +1,36 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System.IO; + +namespace Ryujinx.Core.OsHle +{ + class ServiceCtx + { + public Switch Ns { get; private set; } + public AMemory Memory { get; private set; } + public HSession Session { get; private set; } + public IpcMessage Request { get; private set; } + public IpcMessage Response { get; private set; } + public BinaryReader RequestData { get; private set; } + public BinaryWriter ResponseData { get; private set; } + + public ServiceCtx( + Switch Ns, + AMemory Memory, + HSession Session, + IpcMessage Request, + IpcMessage Response, + BinaryReader RequestData, + BinaryWriter ResponseData) + { + this.Ns = Ns; + this.Memory = Memory; + this.Session = Session; + this.Request = Request; + this.Response = Response; + this.RequestData = RequestData; + this.ResponseData = ResponseData; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceAcc.cs b/Ryujinx.Core/OsHle/Services/ServiceAcc.cs new file mode 100644 index 00000000..f25113e5 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceAcc.cs @@ -0,0 +1,33 @@ +using Ryujinx.Core.OsHle.Objects.Acc; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long AccU0ListOpenUsers(ServiceCtx Context) + { + return 0; + } + + public static long AccU0GetProfile(ServiceCtx Context) + { + MakeObject(Context, new IProfile()); + + return 0; + } + + public static long AccU0InitializeApplicationInfo(ServiceCtx Context) + { + return 0; + } + + public static long AccU0GetBaasAccountManagerForApplication(ServiceCtx Context) + { + MakeObject(Context, new IManagerForApplication()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceApm.cs b/Ryujinx.Core/OsHle/Services/ServiceApm.cs new file mode 100644 index 00000000..e1bc0d34 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceApm.cs @@ -0,0 +1,16 @@ +using Ryujinx.Core.OsHle.Objects.Apm; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long ApmOpenSession(ServiceCtx Context) + { + MakeObject(Context, new ISession()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceAppletOE.cs b/Ryujinx.Core/OsHle/Services/ServiceAppletOE.cs new file mode 100644 index 00000000..bbb2484b --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceAppletOE.cs @@ -0,0 +1,16 @@ +using Ryujinx.Core.OsHle.Objects.Am; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long AppletOpenApplicationProxy(ServiceCtx Context) + { + MakeObject(Context, new IApplicationProxy()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceAud.cs b/Ryujinx.Core/OsHle/Services/ServiceAud.cs new file mode 100644 index 00000000..a8ba7dc0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceAud.cs @@ -0,0 +1,71 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Objects.Aud; +using System.Text; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long AudOutListAudioOuts(ServiceCtx Context) + { + long Position = Context.Request.ReceiveBuff[0].Position; + + AMemoryHelper.WriteBytes(Context.Memory, Position, Encoding.ASCII.GetBytes("iface")); + + Context.ResponseData.Write(1); + + return 0; + } + + public static long AudOutOpenAudioOut(ServiceCtx Context) + { + MakeObject(Context, new IAudioOut()); + + Context.ResponseData.Write(48000); //Sample Rate + Context.ResponseData.Write(2); //Channel Count + Context.ResponseData.Write(2); //PCM Format + /* + 0 - Invalid + 1 - INT8 + 2 - INT16 + 3 - INT24 + 4 - INT32 + 5 - PCM Float + 6 - ADPCM + */ + Context.ResponseData.Write(0); //Unknown + + return 0; + } + + public static long AudRenOpenAudioRenderer(ServiceCtx Context) + { + MakeObject(Context, new IAudioRenderer()); + + return 0; + } + + public static long AudRenGetAudioRendererWorkBufferSize(ServiceCtx Context) + { + int SampleRate = Context.RequestData.ReadInt32(); + int Unknown4 = Context.RequestData.ReadInt32(); + int Unknown8 = Context.RequestData.ReadInt32(); + int UnknownC = Context.RequestData.ReadInt32(); + int Unknown10 = Context.RequestData.ReadInt32(); + int Unknown14 = Context.RequestData.ReadInt32(); + int Unknown18 = Context.RequestData.ReadInt32(); + int Unknown1c = Context.RequestData.ReadInt32(); + int Unknown20 = Context.RequestData.ReadInt32(); + int Unknown24 = Context.RequestData.ReadInt32(); + int Unknown28 = Context.RequestData.ReadInt32(); + int Unknown2c = Context.RequestData.ReadInt32(); + int Rev1Magic = Context.RequestData.ReadInt32(); + + Context.ResponseData.Write(0x400L); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceFriend.cs b/Ryujinx.Core/OsHle/Services/ServiceFriend.cs new file mode 100644 index 00000000..d1229bd4 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceFriend.cs @@ -0,0 +1,16 @@ +using Ryujinx.Core.OsHle.Objects.Friend; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long FriendCreateFriendService(ServiceCtx Context) + { + MakeObject(Context, new IFriendService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceFspSrv.cs b/Ryujinx.Core/OsHle/Services/ServiceFspSrv.cs new file mode 100644 index 00000000..3fe41cf0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceFspSrv.cs @@ -0,0 +1,49 @@ +using Ryujinx.Core.OsHle.Objects.FspSrv; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long FspSrvInitialize(ServiceCtx Context) + { + return 0; + } + + public static long FspSrvMountSdCard(ServiceCtx Context) + { + MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath())); + + return 0; + } + + public static long FspSrvMountSaveData(ServiceCtx Context) + { + MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetGameSavesPath())); + + return 0; + } + + public static long FspSrvOpenDataStorageByCurrentProcess(ServiceCtx Context) + { + MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); + + return 0; + } + + public static long FspSrvOpenRomStorage(ServiceCtx Context) + { + MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); + + return 0; + } + + public static long FspSrvGetGlobalAccessLogMode(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/ServiceHid.cs new file mode 100644 index 00000000..4b2e82ff --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceHid.cs @@ -0,0 +1,56 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Objects.Hid; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long HidCreateAppletResource(ServiceCtx Context) + { + HSharedMem HidHndData = Context.Ns.Os.Handles.GetData(Context.Ns.Os.HidHandle); + + MakeObject(Context, new IAppletResource(HidHndData)); + + return 0; + } + + public static long HidActivateTouchScreen(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public static long HidSetSupportedNpadStyleSet(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + return 0; + } + + public static long HidSetSupportedNpadIdType(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public static long HidActivateNpad(ServiceCtx Context) + { + long Unknown = Context.RequestData.ReadInt64(); + + return 0; + } + + public static long HidSetNpadJoyHoldType(ServiceCtx Context) + { + long Unknown0 = Context.RequestData.ReadInt64(); + long Unknown8 = Context.RequestData.ReadInt64(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceLm.cs b/Ryujinx.Core/OsHle/Services/ServiceLm.cs new file mode 100644 index 00000000..1fdde552 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceLm.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long LmInitialize(ServiceCtx Context) + { + Context.Session.Initialize(); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/ServiceNvDrv.cs new file mode 100644 index 00000000..6c5fdaed --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceNvDrv.cs @@ -0,0 +1,610 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using Ryujinx.Core.OsHle.Utilities; +using Ryujinx.Graphics.Gpu; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + private delegate long ServiceProcessRequest(ServiceCtx Context); + + private static Dictionary<(string, int), ServiceProcessRequest> IoctlCmds = + new Dictionary<(string, int), ServiceProcessRequest>() + { + { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, + { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, + { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, + { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, + { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, + { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, + { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, + { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, + { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, + { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, + { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, + { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, + { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, + { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, + { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, + { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, + { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, + { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, + { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, + { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, + { ("/dev/nvmap", 0x0101), NvMapIocCreate }, + { ("/dev/nvmap", 0x0103), NvMapIocFromId }, + { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, + { ("/dev/nvmap", 0x0109), NvMapIocParam }, + { ("/dev/nvmap", 0x010e), NvMapIocGetId }, + }; + + public static long NvDrvOpen(ServiceCtx Context) + { + long NamePtr = Context.Request.SendBuff[0].Position; + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); + + int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name)); + + Context.ResponseData.Write(Fd); + Context.ResponseData.Write(0); + + return 0; + } + + public static long NvDrvIoctl(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int Cmd = Context.RequestData.ReadInt32() & 0xffff; + + FileDesc FdData = Context.Ns.Os.Fds.GetData(Fd); + + long Position = Context.Request.PtrBuff[0].Position; + + Context.ResponseData.Write(0); + + if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessRequest ProcReq)) + { + return ProcReq(Context); + } + else + { + throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); + } + } + + public static long NvDrvClose(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + + Context.Ns.Os.Fds.Delete(Fd); + + Context.ResponseData.Write(0); + + return 0; + } + + public static long NvDrvInitialize(ServiceCtx Context) + { + long TransferMemSize = Context.RequestData.ReadInt64(); + int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; + + Context.ResponseData.Write(0); + + return 0; + } + + public static long NvDrvQueryEvent(ServiceCtx Context) + { + int Fd = Context.RequestData.ReadInt32(); + int EventId = Context.RequestData.ReadInt32(); + + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); + + Context.ResponseData.Write(0); + + return 0; + } + + public static long NvDrvSetClientPid(ServiceCtx Context) + { + long Pid = Context.RequestData.ReadInt64(); + + Context.ResponseData.Write(0); + + return 0; + } + + private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Fd = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Pages = Reader.ReadInt32(); + int PageSize = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + long Align = Reader.ReadInt64(); + + if ((Flags & 1) != 0) + { + Align = Context.Ns.Gpu.ReserveMemory(Align, (long)Pages * PageSize, 1); + } + else + { + Align = Context.Ns.Gpu.ReserveMemory((long)Pages * PageSize, Align); + } + + Context.Memory.WriteInt64(Position + 0x10, Align); + + return 0; + } + + private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Flags = Reader.ReadInt32(); + int Kind = Reader.ReadInt32(); + int Handle = Reader.ReadInt32(); + int PageSize = Reader.ReadInt32(); + long BuffAddr = Reader.ReadInt64(); + long MapSize = Reader.ReadInt64(); + long Offset = Reader.ReadInt64(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + if (NvMap != null) + { + if ((Flags & 1) != 0) + { + Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size); + } + else + { + Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size); + } + } + + Context.Memory.WriteInt64(Position + 0x20, Offset); + + return 0; + } + + private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position); + + long Unused = Reader.ReadInt64(); + int BuffSize = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + BuffSize = 0x30; + + Writer.WriteInt64(Unused); + Writer.WriteInt32(BuffSize); + Writer.WriteInt32(Padding); + + Writer.WriteInt64(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt64(0); + + Writer.WriteInt64(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt64(0); + + return 0; + } + + private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int BigPageSize = Reader.ReadInt32(); + int AsFd = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Reserved = Reader.ReadInt32(); + long Unknown10 = Reader.ReadInt64(); + long Unknown18 = Reader.ReadInt64(); + long Unknown20 = Reader.ReadInt64(); + + return 0; + } + + private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82); + + for (int Index = 0; Index < 0x101; Index++) + { + Writer.WriteByte(0); + } + + return 0; + } + + private static long NvHostIoctlCtrlEventWait(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int SyncPtId = Reader.ReadInt32(); + int Threshold = Reader.ReadInt32(); + int Timeout = Reader.ReadInt32(); + int Value = Reader.ReadInt32(); + + Context.Memory.WriteInt32(Position + 0xc, 0xcafe); + + return 0; + } + + private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + Context.Memory.WriteInt32(Position, 1); + + return 0; + } + + private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemWriter Writer = new MemWriter(Context.Memory, Position); + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position); + + //Note: We should just ignore the BuffAddr, because official code + //does __memcpy_device from Position + 0x10 to BuffAddr. + long BuffSize = Reader.ReadInt64(); + long BuffAddr = Reader.ReadInt64(); + + BuffSize = 0xa0; + + Writer.WriteInt64(BuffSize); + Writer.WriteInt64(BuffAddr); + Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200 + Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B + Writer.WriteInt32(0xa1); + Writer.WriteInt32(1); + Writer.WriteInt64(0x40000); + Writer.WriteInt64(0); + Writer.WriteInt32(2); + Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI + Writer.WriteInt32(0x20000); + Writer.WriteInt32(0x20000); + Writer.WriteInt32(0x1b); + Writer.WriteInt32(0x30000); + Writer.WriteInt32(1); + Writer.WriteInt32(0x503); + Writer.WriteInt32(0x503); + Writer.WriteInt32(0x80); + Writer.WriteInt32(0x28); + Writer.WriteInt32(0); + Writer.WriteInt64(0x55); + Writer.WriteInt32(0x902d); //FERMI_TWOD_A + Writer.WriteInt32(0xb197); //MAXWELL_B + Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B + Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A + Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B + Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A + Writer.WriteInt32(1); + Writer.WriteInt32(0); + Writer.WriteInt32(2); + Writer.WriteInt32(1); + Writer.WriteInt32(0); + Writer.WriteInt32(1); + Writer.WriteInt32(0x21d70); + Writer.WriteInt32(0); + Writer.WriteByte((byte)'g'); + Writer.WriteByte((byte)'m'); + Writer.WriteByte((byte)'2'); + Writer.WriteByte((byte)'0'); + Writer.WriteByte((byte)'b'); + Writer.WriteByte((byte)'\0'); + Writer.WriteByte((byte)'\0'); + Writer.WriteByte((byte)'\0'); + Writer.WriteInt64(0); + + return 0; + } + + private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + int MaskBuffSize = Reader.ReadInt32(); + int Reserved = Reader.ReadInt32(); + long MaskBuffAddr = Reader.ReadInt64(); + long Unknown = Reader.ReadInt64(); + + return 0; + } + + private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + Context.Memory.WriteInt32(Position + 0, 7); + Context.Memory.WriteInt32(Position + 4, 1); + + return 0; + } + + private static long NvMapIoctlChannelSetUserData(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + return 0; + } + + private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Fd = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10); + + long GpFifo = Reader.ReadInt64(); + int Count = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int FenceId = Reader.ReadInt32(); + int FenceVal = Reader.ReadInt32(); + + for (int Index = 0; Index < Count; Index++) + { + long GpFifoHdr = Reader.ReadInt64(); + + long GpuAddr = GpFifoHdr & 0xffffffffff; + + int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc; + + long CpuAddr = Context.Ns.Gpu.GetCpuAddr(GpuAddr); + + if (CpuAddr != -1) + { + byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size); + + NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data); + + Context.Ns.Gpu.ProcessPushBuffer(PushBuffer, Context.Memory); + } + } + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int ClassNum = Context.Memory.ReadInt32(Position + 0); + int Flags = Context.Memory.ReadInt32(Position + 4); + + Context.Memory.WriteInt32(Position + 8, 0); + + return 0; + } + + private static long NvMapIoctlChannelZcullBind(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + long GpuVa = Reader.ReadInt64(); + int Mode = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + return 0; + } + + private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + + long Offset = Reader.ReadInt64(); + long Size = Reader.ReadInt64(); + int Mem = Reader.ReadInt32(); + int Padding = Reader.ReadInt32(); + + return 0; + } + + private static long NvMapIoctlChannelSetPriority(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int Priority = Context.Memory.ReadInt32(Position); + + return 0; + } + + private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + MemReader Reader = new MemReader(Context.Memory, Position); + MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc); + + int Count = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Unknown8 = Reader.ReadInt32(); + long Fence = Reader.ReadInt64(); + int Unknown14 = Reader.ReadInt32(); + int Unknown18 = Reader.ReadInt32(); + + Writer.WriteInt32(0); + Writer.WriteInt32(0); + + return 0; + } + + private static long NvMapIocCreate(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Size = Context.Memory.ReadInt32(Position); + + int Id = Context.Ns.Os.NvMapIds.GenerateId(); + + int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size)); + + Context.Memory.WriteInt32(Position + 4, Handle); + + return 0; + } + + private static long NvMapIocFromId(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Id = Context.Memory.ReadInt32(Position); + + int Handle = -1; + + foreach (KeyValuePair KV in Context.Ns.Os.Handles) + { + if (KV.Value is HNvMap NvMap && NvMap.Id == Id) + { + Handle = KV.Key; + + break; + } + } + + Context.Memory.WriteInt32(Position + 4, Handle); + + return 0; + } + + private static long NvMapIocAlloc(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Handle = Reader.ReadInt32(); + int HeapMask = Reader.ReadInt32(); + int Flags = Reader.ReadInt32(); + int Align = Reader.ReadInt32(); + byte Kind = (byte)Reader.ReadInt64(); + long Addr = Reader.ReadInt64(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + if (NvMap != null) + { + NvMap.Address = Addr; + NvMap.Align = Align; + NvMap.Kind = Kind; + } + + Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}"); + + return 0; + } + + private static long NvMapIocParam(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + MemReader Reader = new MemReader(Context.Memory, Position); + + int Handle = Reader.ReadInt32(); + int Param = Reader.ReadInt32(); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + int Response = 0; + + switch (Param) + { + case 1: Response = NvMap.Size; break; + case 2: Response = NvMap.Align; break; + case 4: Response = 0x40000000; break; + case 5: Response = NvMap.Kind; break; + } + + Context.Memory.WriteInt32(Position + 8, Response); + + return 0; + } + + private static long NvMapIocGetId(ServiceCtx Context) + { + long Position = Context.Request.GetSendBuffPtr(); + + int Handle = Context.Memory.ReadInt32(Position + 4); + + HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); + + Context.Memory.WriteInt32(Position, NvMap.Id); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServicePctl.cs b/Ryujinx.Core/OsHle/Services/ServicePctl.cs new file mode 100644 index 00000000..9c4406bb --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServicePctl.cs @@ -0,0 +1,16 @@ +using Ryujinx.Core.OsHle.Objects.Am; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long PctlCreateService(ServiceCtx Context) + { + MakeObject(Context, new IParentalControlService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServicePl.cs b/Ryujinx.Core/OsHle/Services/ServicePl.cs new file mode 100644 index 00000000..21e6741c --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServicePl.cs @@ -0,0 +1,35 @@ +using Ryujinx.Core.OsHle.Ipc; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long PlGetLoadState(ServiceCtx Context) + { + Context.ResponseData.Write(1); //Loaded + + return 0; + } + + public static long PlGetFontSize(ServiceCtx Context) + { + Context.ResponseData.Write(Horizon.FontSize); + + return 0; + } + + public static long PlGetSharedMemoryAddressOffset(ServiceCtx Context) + { + Context.ResponseData.Write(0); + + return 0; + } + + public static long PlGetSharedMemoryNativeHandle(ServiceCtx Context) + { + Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceSet.cs b/Ryujinx.Core/OsHle/Services/ServiceSet.cs new file mode 100644 index 00000000..83ea5b2c --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceSet.cs @@ -0,0 +1,32 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + private const int LangCodesCount = 13; + + public static long SetGetAvailableLanguageCodes(ServiceCtx Context) + { + int PtrBuffSize = Context.RequestData.ReadInt32(); + + if (Context.Request.RecvListBuff.Count > 0) + { + long Position = Context.Request.RecvListBuff[0].Position; + short Size = Context.Request.RecvListBuff[0].Size; + + //This should return an array of ints with values matching the LanguageCode enum. + byte[] Data = new byte[Size]; + + Data[0] = 0; + Data[1] = 1; + + AMemoryHelper.WriteBytes(Context.Memory, Position, Data); + } + + Context.ResponseData.Write(LangCodesCount); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/ServiceSm.cs new file mode 100644 index 00000000..58abed24 --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceSm.cs @@ -0,0 +1,48 @@ +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + private const int SmNotInitialized = 0x415; + + public static long SmInitialize(ServiceCtx Context) + { + Context.Session.Initialize(); + + return 0; + } + + public static long SmGetService(ServiceCtx Context) + { + //Only for kernel version > 3.0.0. + if (!Context.Session.IsInitialized) + { + //return SmNotInitialized; + } + + string Name = string.Empty; + + for (int Index = 0; Index < 8 && + Context.RequestData.BaseStream.Position < + Context.RequestData.BaseStream.Length; Index++) + { + byte Chr = Context.RequestData.ReadByte(); + + if (Chr >= 0x20 && Chr < 0x7f) + { + Name += (char)Chr; + } + } + + HSession Session = new HSession(Name); + + int Handle = Context.Ns.Os.Handles.GenerateId(Session); + + Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceTime.cs b/Ryujinx.Core/OsHle/Services/ServiceTime.cs new file mode 100644 index 00000000..a5fddcba --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceTime.cs @@ -0,0 +1,45 @@ +using Ryujinx.Core.OsHle.Objects.Time; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long TimeGetStandardUserSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.User)); + + return 0; + } + + public static long TimeGetStandardNetworkSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.Network)); + + return 0; + } + + public static long TimeGetStandardSteadyClock(ServiceCtx Context) + { + MakeObject(Context, new ISteadyClock()); + + return 0; + } + + public static long TimeGetTimeZoneService(ServiceCtx Context) + { + MakeObject(Context, new ITimeZoneService()); + + return 0; + } + + public static long TimeGetStandardLocalSystemClock(ServiceCtx Context) + { + MakeObject(Context, new ISystemClock(SystemClockType.Local)); + + return 0; + } + + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Services/ServiceVi.cs b/Ryujinx.Core/OsHle/Services/ServiceVi.cs new file mode 100644 index 00000000..75cdc31b --- /dev/null +++ b/Ryujinx.Core/OsHle/Services/ServiceVi.cs @@ -0,0 +1,18 @@ +using Ryujinx.Core.OsHle.Objects.Vi; + +using static Ryujinx.Core.OsHle.Objects.ObjHelper; + +namespace Ryujinx.Core.OsHle.Services +{ + static partial class Service + { + public static long ViGetDisplayService(ServiceCtx Context) + { + int Unknown = Context.RequestData.ReadInt32(); + + MakeObject(Context, new IApplicationDisplayService()); + + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs new file mode 100644 index 00000000..60af1e11 --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs @@ -0,0 +1,80 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Svc +{ + partial class SvcHandler + { + private delegate void SvcFunc(AThreadState ThreadState); + + private Dictionary SvcFuncs; + + private Switch Ns; + private Process Process; + private AMemory Memory; + + private static Random Rng; + + public SvcHandler(Switch Ns, Process Process) + { + SvcFuncs = new Dictionary() + { + { 0x01, SvcSetHeapSize }, + { 0x03, SvcSetMemoryAttribute }, + { 0x04, SvcMapMemory }, + { 0x06, SvcQueryMemory }, + { 0x07, SvcExitProcess }, + { 0x08, SvcCreateThread }, + { 0x09, SvcStartThread }, + { 0x0b, SvcSleepThread }, + { 0x0c, SvcGetThreadPriority }, + { 0x13, SvcMapSharedMemory }, + { 0x14, SvcUnmapSharedMemory }, + { 0x15, SvcCreateTransferMemory }, + { 0x16, SvcCloseHandle }, + { 0x17, SvcResetSignal }, + { 0x18, SvcWaitSynchronization }, + { 0x1a, SvcArbitrateLock }, + { 0x1b, SvcArbitrateUnlock }, + { 0x1c, SvcWaitProcessWideKeyAtomic }, + { 0x1d, SvcSignalProcessWideKey }, + { 0x1e, SvcGetSystemTick }, + { 0x1f, SvcConnectToNamedPort }, + { 0x21, SvcSendSyncRequest }, + { 0x22, SvcSendSyncRequestWithUserBuffer }, + { 0x26, SvcBreak }, + { 0x27, SvcOutputDebugString }, + { 0x29, SvcGetInfo } + }; + + this.Ns = Ns; + this.Process = Process; + this.Memory = Process.Memory; + } + + static SvcHandler() + { + Rng = new Random(); + } + + public void SvcCall(object sender, AInstExceptEventArgs e) + { + AThreadState ThreadState = (AThreadState)sender; + + if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func)) + { + Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} called."); + + Func(ThreadState); + + Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} ended."); + } + else + { + throw new NotImplementedException(e.Id.ToString("x4")); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs new file mode 100644 index 00000000..7528f4e0 --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs @@ -0,0 +1,121 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.Core.OsHle.Handles; + +namespace Ryujinx.Core.OsHle.Svc +{ + partial class SvcHandler + { + private void SvcSetHeapSize(AThreadState ThreadState) + { + uint Size = (uint)ThreadState.X1; + + Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap); + + ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X1 = (ulong)Memory.Manager.HeapAddr; + } + + private void SvcSetMemoryAttribute(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + int State0 = (int)ThreadState.X2; + int State1 = (int)ThreadState.X3; + + //TODO + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcMapMemory(AThreadState ThreadState) + { + long Dst = (long)ThreadState.X0; + long Src = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcQueryMemory(AThreadState ThreadState) + { + long InfoPtr = (long)ThreadState.X0; + long Position = (long)ThreadState.X2; + + AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); + + MemoryInfo Info = new MemoryInfo(MapInfo); + + Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress); + Memory.WriteInt64(InfoPtr + 0x08, Info.Size); + Memory.WriteInt32(InfoPtr + 0x10, Info.MemType); + Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr); + Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm); + Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount); + Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount); + Memory.WriteInt32(InfoPtr + 0x24, Info.Padding); + + //TODO: X1. + + ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X1 = 0; + } + + private void SvcMapSharedMemory(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + long Src = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + int Perm = (int)ThreadState.X3; + + HSharedMem SharedMem = Ns.Os.Handles.GetData(Handle); + + if (SharedMem != null) + { + SharedMem.AddVirtualPosition(Src); + + Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); + + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } + + private void SvcUnmapSharedMemory(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + + HSharedMem HndData = Ns.Os.Handles.GetData(Handle); + + if (HndData != null) + { + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } + + private void SvcCreateTransferMemory(AThreadState ThreadState) + { + long Position = (long)ThreadState.X1; + long Size = (long)ThreadState.X2; + int Perm = (int)ThreadState.X3; + + AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); + + Memory.Manager.Reprotect(Position, Size, (AMemoryPerm)Perm); + + HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Position, Size); + + int Handle = Ns.Os.Handles.GenerateId(HndData); + + ThreadState.X1 = (ulong)Handle; + ThreadState.X0 = (int)SvcResult.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcResult.cs b/Ryujinx.Core/OsHle/Svc/SvcResult.cs new file mode 100644 index 00000000..a5be9a94 --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcResult.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Core.OsHle.Svc +{ + enum SvcResult + { + Success = 0, + ErrBadHandle = 0xe401, + ErrTimeout = 0xea01, + ErrBadInfo = 0xf001, + ErrBadIpcReq = 0xf601 + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs new file mode 100644 index 00000000..7f593c8f --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs @@ -0,0 +1,227 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using Ryujinx.Core.OsHle.Exceptions; +using Ryujinx.Core.OsHle.Handles; +using Ryujinx.Core.OsHle.Ipc; +using System; +using System.Threading; + +namespace Ryujinx.Core.OsHle.Svc +{ + partial class SvcHandler + { + private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId); + + private void SvcCloseHandle(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + Ns.Os.CloseHandle(Handle); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcResetSignal(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + //TODO: Implement events. + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcWaitSynchronization(AThreadState ThreadState) + { + long HandlesPtr = (long)ThreadState.X0; + int HandlesCount = (int)ThreadState.X2; + long Timeout = (long)ThreadState.X3; + + //TODO: Implement events. + + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + Process.Scheduler.Suspend(CurrThread.ProcessorId); + Process.Scheduler.Resume(CurrThread); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcGetSystemTick(AThreadState ThreadState) + { + ThreadState.X0 = (ulong)ThreadState.CntpctEl0; + } + + private void SvcConnectToNamedPort(AThreadState ThreadState) + { + long StackPtr = (long)ThreadState.X0; + long NamePtr = (long)ThreadState.X1; + + string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8); + + //TODO: Validate that app has perms to access the service, and that the service + //actually exists, return error codes otherwise. + + HSession Session = new HSession(Name); + + ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session); + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcSendSyncRequest(AThreadState ThreadState) + { + SendSyncRequest(ThreadState, false); + } + + private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) + { + SendSyncRequest(ThreadState, true); + } + + private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer) + { + long CmdPtr = ThreadState.Tpidr; + long Size = 0x100; + int Handle = 0; + + if (UserBuffer) + { + CmdPtr = (long)ThreadState.X0; + Size = (long)ThreadState.X1; + Handle = (int)ThreadState.X2; + } + else + { + Handle = (int)ThreadState.X0; + } + + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + Process.Scheduler.Suspend(CurrThread.ProcessorId); + + byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); + + HSession Session = Ns.Os.Handles.GetData(Handle); + + IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain); + + if (Session != null) + { + IpcHandler.IpcCall(Ns, Memory, Session, Cmd, CmdPtr, Handle); + + byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); + + ThreadState.X0 = (int)SvcResult.Success; + } + else + { + ThreadState.X0 = (int)SvcResult.ErrBadIpcReq; + } + + Thread.Yield(); + + Process.Scheduler.Resume(CurrThread); + } + + private void SvcBreak(AThreadState ThreadState) + { + long Reason = (long)ThreadState.X0; + long Unknown = (long)ThreadState.X1; + long Info = (long)ThreadState.X2; + + throw new GuestBrokeExecutionException(); + } + + private void SvcOutputDebugString(AThreadState ThreadState) + { + long Position = (long)ThreadState.X0; + long Size = (long)ThreadState.X1; + + string Str = AMemoryHelper.ReadAsciiString(Memory, Position, (int)Size); + + Logging.Info($"SvcOutputDebugString: {Str}"); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcGetInfo(AThreadState ThreadState) + { + long StackPtr = (long)ThreadState.X0; + int InfoType = (int)ThreadState.X1; + long Handle = (long)ThreadState.X2; + int InfoId = (int)ThreadState.X3; + + //Fail for info not available on older Kernel versions. + if (InfoType == 18 || + InfoType == 19) + { + ThreadState.X0 = (int)SvcResult.ErrBadInfo; + + return; + } + + switch (InfoType) + { + case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break; + case 3: ThreadState.X1 = GetMapRegionSize(); break; + case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break; + case 5: ThreadState.X1 = GetHeapRegionSize(); break; + case 6: ThreadState.X1 = GetTotalMem(); break; + case 7: ThreadState.X1 = GetUsedMem(); break; + case 11: ThreadState.X1 = GetRnd64(); break; + case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break; + case 13: ThreadState.X1 = GetAddrSpaceSize(); break; + case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break; + case 15: ThreadState.X1 = GetMapRegionSize(); break; + + default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); + } + + ThreadState.X0 = (int)SvcResult.Success; + } + + private ulong GetTotalMem() + { + return (ulong)Memory.Manager.GetTotalMemorySize(); + } + + private ulong GetUsedMem() + { + return (ulong)Memory.Manager.GetUsedMemorySize(); + } + + private ulong GetRnd64() + { + return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); + } + + private ulong GetAddrSpaceBaseAddr() + { + return 0x08000000; + } + + private ulong GetAddrSpaceSize() + { + return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr(); + } + + private ulong GetMapRegionBaseAddr() + { + return 0x80000000; + } + + private ulong GetMapRegionSize() + { + return 0x40000000; + } + + private ulong GetHeapRegionBaseAddr() + { + return GetMapRegionBaseAddr() + GetMapRegionSize(); + } + + private ulong GetHeapRegionSize() + { + return 0x40000000; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs new file mode 100644 index 00000000..a635edb1 --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs @@ -0,0 +1,85 @@ +using ChocolArm64.State; +using Ryujinx.Core.OsHle.Handles; + +namespace Ryujinx.Core.OsHle.Svc +{ + partial class SvcHandler + { + private void SvcCreateThread(AThreadState ThreadState) + { + long EntryPoint = (long)ThreadState.X1; + long ArgsPtr = (long)ThreadState.X2; + long StackTop = (long)ThreadState.X3; + int Priority = (int)ThreadState.X4; + int ProcessorId = (int)ThreadState.X5; + + if (Ns.Os.TryGetProcess(ThreadState.ProcessId, out Process Process)) + { + if (ProcessorId == -2) + { + //TODO: Get this value from the NPDM file. + ProcessorId = 0; + } + + int Handle = Process.MakeThread( + EntryPoint, + StackTop, + ArgsPtr, + Priority, + ProcessorId); + + ThreadState.X0 = (int)SvcResult.Success; + ThreadState.X1 = (ulong)Handle; + } + + //TODO: Error codes. + } + + private void SvcStartThread(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X0; + + HThread Thread = Ns.Os.Handles.GetData(Handle); + + if (Thread != null) + { + Process.Scheduler.StartThread(Thread); + + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } + + private void SvcSleepThread(AThreadState ThreadState) + { + ulong NanoSecs = ThreadState.X0; + + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + if (NanoSecs == 0) + { + Process.Scheduler.Yield(CurrThread); + } + else + { + Process.Scheduler.WaitForSignal(CurrThread, (int)(NanoSecs / 1000000)); + } + } + + private void SvcGetThreadPriority(AThreadState ThreadState) + { + int Handle = (int)ThreadState.X1; + + HThread Thread = Ns.Os.Handles.GetData(Handle); + + if (Thread != null) + { + ThreadState.X1 = (ulong)Thread.Priority; + ThreadState.X0 = (int)SvcResult.Success; + } + + //TODO: Error codes. + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs new file mode 100644 index 00000000..dec13f75 --- /dev/null +++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs @@ -0,0 +1,78 @@ +using ChocolArm64.State; +using Ryujinx.Core.OsHle.Handles; + +namespace Ryujinx.Core.OsHle.Svc +{ + partial class SvcHandler + { + private void SvcArbitrateLock(AThreadState ThreadState) + { + int OwnerThreadHandle = (int)ThreadState.X0; + long MutexAddress = (long)ThreadState.X1; + int RequestingThreadHandle = (int)ThreadState.X2; + + HThread RequestingThread = Ns.Os.Handles.GetData(RequestingThreadHandle); + + Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle); + + M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); + + M.WaitForLock(RequestingThread, RequestingThreadHandle); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcArbitrateUnlock(AThreadState ThreadState) + { + long MutexAddress = (long)ThreadState.X0; + + if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M)) + { + M.Unlock(); + } + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) + { + long MutexAddress = (long)ThreadState.X0; + long CondVarAddress = (long)ThreadState.X1; + int ThreadHandle = (int)ThreadState.X2; + long Timeout = (long)ThreadState.X3; + + HThread Thread = Ns.Os.Handles.GetData(ThreadHandle); + + Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); + + M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); + + M.GiveUpLock(ThreadHandle); + + CondVar Cv = new CondVar(Process, CondVarAddress, Timeout); + + Cv = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Cv); + + Cv.WaitForSignal(Thread); + + M.WaitForLock(Thread, ThreadHandle); + + ThreadState.X0 = (int)SvcResult.Success; + } + + private void SvcSignalProcessWideKey(AThreadState ThreadState) + { + long CondVarAddress = (long)ThreadState.X0; + int Count = (int)ThreadState.X1; + + HThread CurrThread = Process.GetThread(ThreadState.Tpidr); + + if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv)) + { + Cv.SetSignal(CurrThread, Count); + } + + ThreadState.X0 = (int)SvcResult.Success; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Utilities/IdPool.cs b/Ryujinx.Core/OsHle/Utilities/IdPool.cs new file mode 100644 index 00000000..a7e181fa --- /dev/null +++ b/Ryujinx.Core/OsHle/Utilities/IdPool.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Utilities +{ + class IdPool + { + private HashSet Ids; + + private int CurrId; + private int MinId; + private int MaxId; + + public IdPool(int Min, int Max) + { + Ids = new HashSet(); + + CurrId = Min; + MinId = Min; + MaxId = Max; + } + + public IdPool() : this(1, int.MaxValue) { } + + public int GenerateId() + { + lock (Ids) + { + for (int Cnt = MinId; Cnt < MaxId; Cnt++) + { + if (Ids.Add(CurrId)) + { + return CurrId; + } + + if (CurrId++ == MaxId) + { + CurrId = MinId; + } + } + + return -1; + } + } + + public bool DeleteId(int Id) + { + lock (Ids) + { + return Ids.Remove(Id); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs b/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs new file mode 100644 index 00000000..f0a339df --- /dev/null +++ b/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Ryujinx.Core.OsHle.Utilities +{ + class IdPoolWithObj : IEnumerable> + { + private IdPool Ids; + + private ConcurrentDictionary Objs; + + public IdPoolWithObj() + { + Ids = new IdPool(); + + Objs = new ConcurrentDictionary(); + } + + public int GenerateId(object Data) + { + int Id = Ids.GenerateId(); + + if (Id == -1 || !Objs.TryAdd(Id, Data)) + { + throw new InvalidOperationException(); + } + + return Id; + } + + public bool ReplaceData(int Id, object Data) + { + if (Objs.ContainsKey(Id)) + { + Objs[Id] = Data; + + return true; + } + + return false; + } + + public T GetData(int Id) + { + if (Objs.TryGetValue(Id, out object Data) && Data is T) + { + return (T)Data; + } + + return default(T); + } + + public void Delete(int Id) + { + if (Objs.TryRemove(Id, out object Obj)) + { + if (Obj is IDisposable DisposableObj) + { + DisposableObj.Dispose(); + } + + Ids.DeleteId(Id); + } + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return Objs.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return Objs.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Utilities/MemReader.cs b/Ryujinx.Core/OsHle/Utilities/MemReader.cs new file mode 100644 index 00000000..fe92f68f --- /dev/null +++ b/Ryujinx.Core/OsHle/Utilities/MemReader.cs @@ -0,0 +1,44 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.OsHle.Utilities +{ + class MemReader + { + private AMemory Memory; + + public long Position { get; private set; } + + public MemReader(AMemory Memory, long Position) + { + this.Memory = Memory; + this.Position = Position; + } + + public byte ReadByte() + { + byte Value = Memory.ReadByte(Position); + + Position++; + + return Value; + } + + public int ReadInt32() + { + int Value = Memory.ReadInt32(Position); + + Position += 4; + + return Value; + } + + public long ReadInt64() + { + long Value = Memory.ReadInt64(Position); + + Position += 8; + + return Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Utilities/MemWriter.cs b/Ryujinx.Core/OsHle/Utilities/MemWriter.cs new file mode 100644 index 00000000..21b6a3b6 --- /dev/null +++ b/Ryujinx.Core/OsHle/Utilities/MemWriter.cs @@ -0,0 +1,38 @@ +using ChocolArm64.Memory; + +namespace Ryujinx.Core.OsHle.Utilities +{ + class MemWriter + { + private AMemory Memory; + + public long Position { get; private set; } + + public MemWriter(AMemory Memory, long Position) + { + this.Memory = Memory; + this.Position = Position; + } + + public void WriteByte(byte Value) + { + Memory.WriteByte(Position, Value); + + Position++; + } + + public void WriteInt32(int Value) + { + Memory.WriteInt32(Position, Value); + + Position += 4; + } + + public void WriteInt64(long Value) + { + Memory.WriteInt64(Position, Value); + + Position += 8; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/Ryujinx.Core.csproj b/Ryujinx.Core/Ryujinx.Core.csproj new file mode 100644 index 00000000..7d5ad718 --- /dev/null +++ b/Ryujinx.Core/Ryujinx.Core.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + + + true + + + + true + + + + + + + + diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs new file mode 100644 index 00000000..2b6a9045 --- /dev/null +++ b/Ryujinx.Core/Switch.cs @@ -0,0 +1,75 @@ +using ChocolArm64.Memory; +using Ryujinx.Core.OsHle; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Gpu; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Core +{ + public class Switch : IDisposable + { + public IntPtr Ram {get; private set; } + + internal NsGpu Gpu { get; private set; } + internal Horizon Os { get; private set; } + internal VirtualFs VFs { get; private set; } + internal Hid Hid { get; private set; } + + public event EventHandler Finish; + + public Switch(IGalRenderer Renderer) + { + Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); + + Gpu = new NsGpu(Renderer); + Os = new Horizon(this); + VFs = new VirtualFs(); + Hid = new Hid(this); + } + + public void FinalizeAllProcesses() + { + Os.FinalizeAllProcesses(); + } + + public void LoadCart(string ExeFsDir, string RomFsFile = null) + { + Os.LoadCart(ExeFsDir, RomFsFile); + } + + public void LoadProgram(string FileName) + { + Os.LoadProgram(FileName); + } + + public void SendControllerButtons(HidControllerID ControllerId, + HidControllerLayouts Layout, + HidControllerKeys Buttons, + JoystickPosition LeftJoystick, + JoystickPosition RightJoystick) + { + Hid.SendControllerButtons(ControllerId, Layout, Buttons, LeftJoystick, RightJoystick); + } + + internal virtual void OnFinish(EventArgs e) + { + Finish?.Invoke(this, e); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + VFs.Dispose(); + } + + Marshal.FreeHGlobal(Ram); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Core/VirtualFs.cs b/Ryujinx.Core/VirtualFs.cs new file mode 100644 index 00000000..23c7285c --- /dev/null +++ b/Ryujinx.Core/VirtualFs.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; + +namespace Ryujinx.Core +{ + class VirtualFs : IDisposable + { + private const string BasePath = "Fs"; + private const string SavesPath = "Saves"; + private const string SdCardPath = "SdCard"; + + public Stream RomFs { get; private set; } + + public void LoadRomFs(string FileName) + { + RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read); + } + + public string GetFullPath(string BasePath, string FileName) + { + if (FileName.StartsWith('/')) + { + FileName = FileName.Substring(1); + } + + string FullPath = Path.GetFullPath(Path.Combine(BasePath, FileName)); + + if (!FullPath.StartsWith(GetBasePath())) + { + return null; + } + + return FullPath; + } + + public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath); + + public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath); + + private static string MakeDirAndGetFullPath(string Dir) + { + string FullPath = Path.Combine(GetBasePath(), Dir); + + if (!Directory.Exists(FullPath)) + { + Directory.CreateDirectory(FullPath); + } + + return FullPath; + } + + public static string GetBasePath() + { + return Path.Combine(Directory.GetCurrentDirectory(), BasePath); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + RomFs?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalPrimitiveType.cs b/Ryujinx.Graphics/Gal/GalPrimitiveType.cs new file mode 100644 index 00000000..ce084149 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalPrimitiveType.cs @@ -0,0 +1,21 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalPrimitiveType + { + Points = 0x0, + Lines = 0x1, + LineLoop = 0x2, + LineStrip = 0x3, + Triangles = 0x4, + TriangleStrip = 0x5, + TriangleFan = 0x6, + Quads = 0x7, + QuadStrip = 0x8, + Polygon = 0x9, + LinesAdjacency = 0xa, + LineStripAdjacency = 0xb, + TrianglesAdjacency = 0xc, + TriangleStripAdjacency = 0xd, + Patches = 0xe + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalVertexAttrib.cs b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs new file mode 100644 index 00000000..dc38c593 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.Graphics.Gal +{ + public struct GalVertexAttrib + { + public int Index { get; private set; } + public int Buffer { get; private set; } + public bool IsConst { get; private set; } + public int Offset { get; private set; } + + public GalVertexAttribSize Size { get; private set; } + public GalVertexAttribType Type { get; private set; } + + public bool IsBgra { get; private set; } + + public GalVertexAttrib( + int Index, + int Buffer, + bool IsConst, + int Offset, + GalVertexAttribSize Size, + GalVertexAttribType Type, + bool IsBgra) + { + this.Index = Index; + this.Buffer = Buffer; + this.IsConst = IsConst; + this.Offset = Offset; + this.Size = Size; + this.Type = Type; + this.IsBgra = IsBgra; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalVertexAttribSize.cs b/Ryujinx.Graphics/Gal/GalVertexAttribSize.cs new file mode 100644 index 00000000..d3ce60ac --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalVertexAttribSize.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalVertexAttribSize + { + _32_32_32_32 = 0x1, + _32_32_32 = 0x2, + _16_16_16_16 = 0x3, + _32_32 = 0x4, + _16_16_16 = 0x5, + _8_8_8_8 = 0xa, + _16_16 = 0xf, + _32 = 0x12, + _8_8_8 = 0x13, + _8_8 = 0x18, + _16 = 0x1b, + _8 = 0x1d, + _10_10_10_2 = 0x30, + _11_11_10 = 0x31 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalVertexAttribType.cs b/Ryujinx.Graphics/Gal/GalVertexAttribType.cs new file mode 100644 index 00000000..358836fd --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalVertexAttribType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalVertexAttribType + { + Snorm = 1, + Unorm = 2, + Sint = 3, + Uint = 4, + Uscaled = 5, + Sscaled = 6, + Float = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs new file mode 100644 index 00000000..1870aca5 --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -0,0 +1,17 @@ +using System; + +namespace Ryujinx.Graphics.Gal +{ + public interface IGalRenderer + { + long FrameBufferPtr { get; set; } + + void QueueAction(Action ActionMthd); + void RunActions(); + + void Render(); + void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs); + void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height); + void BindTexture(int Index); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs new file mode 100644 index 00000000..7429569b --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -0,0 +1,282 @@ +using OpenTK.Graphics.OpenGL; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + public class OpenGLRenderer : IGalRenderer + { + private struct VertexBuffer + { + public int VaoHandle; + public int VboHandle; + + public int PrimCount; + } + + private struct Texture + { + public int Handle; + } + + private List VertexBuffers; + + private Texture[] Textures; + + private Queue ActionsQueue; + + public long FrameBufferPtr { get; set; } + + public OpenGLRenderer() + { + VertexBuffers = new List(); + + Textures = new Texture[8]; + + ActionsQueue = new Queue(); + } + + public void QueueAction(Action ActionMthd) + { + ActionsQueue.Enqueue(ActionMthd); + } + + public void RunActions() + { + while (ActionsQueue.Count > 0) + { + ActionsQueue.Dequeue()(); + } + } + + public void Render() + { + for (int Index = 0; Index < VertexBuffers.Count; Index++) + { + VertexBuffer Vb = VertexBuffers[Index]; + + if (Vb.VaoHandle != 0 && + Vb.PrimCount != 0) + { + GL.BindVertexArray(Vb.VaoHandle); + GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount); + } + } + + } + + public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs) + { + if (Index < 0) + { + throw new ArgumentOutOfRangeException(nameof(Index)); + } + + if (Buffer.Length == 0 || Stride == 0) + { + return; + } + + EnsureVbInitialized(Index); + + VertexBuffer Vb = VertexBuffers[Index]; + + Vb.PrimCount = Buffer.Length / Stride; + + VertexBuffers[Index] = Vb; + + IntPtr Length = new IntPtr(Buffer.Length); + + GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); + GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); + GL.BindBuffer(BufferTarget.ArrayBuffer, 0); + + GL.BindVertexArray(Vb.VaoHandle); + + for (int Attr = 0; Attr < 16; Attr++) + { + GL.DisableVertexAttribArray(Attr); + } + + foreach (GalVertexAttrib Attrib in Attribs) + { + if (Attrib.Index >= 3) break; + + GL.EnableVertexAttribArray(Attrib.Index); + + GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); + + int Size = 0; + + switch (Attrib.Size) + { + case GalVertexAttribSize._8: + case GalVertexAttribSize._16: + case GalVertexAttribSize._32: + Size = 1; + break; + case GalVertexAttribSize._8_8: + case GalVertexAttribSize._16_16: + case GalVertexAttribSize._32_32: + Size = 2; + break; + case GalVertexAttribSize._8_8_8: + case GalVertexAttribSize._11_11_10: + case GalVertexAttribSize._16_16_16: + case GalVertexAttribSize._32_32_32: + Size = 3; + break; + case GalVertexAttribSize._8_8_8_8: + case GalVertexAttribSize._10_10_10_2: + case GalVertexAttribSize._16_16_16_16: + case GalVertexAttribSize._32_32_32_32: + Size = 4; + break; + } + + bool Signed = + Attrib.Type == GalVertexAttribType.Snorm || + Attrib.Type == GalVertexAttribType.Sint || + Attrib.Type == GalVertexAttribType.Sscaled; + + bool Normalize = + Attrib.Type == GalVertexAttribType.Snorm || + Attrib.Type == GalVertexAttribType.Unorm; + + VertexAttribPointerType Type = 0; + + switch (Attrib.Type) + { + case GalVertexAttribType.Snorm: + case GalVertexAttribType.Unorm: + case GalVertexAttribType.Sint: + case GalVertexAttribType.Uint: + case GalVertexAttribType.Uscaled: + case GalVertexAttribType.Sscaled: + { + switch (Attrib.Size) + { + case GalVertexAttribSize._8: + case GalVertexAttribSize._8_8: + case GalVertexAttribSize._8_8_8: + case GalVertexAttribSize._8_8_8_8: + { + Type = Signed + ? VertexAttribPointerType.Byte + : VertexAttribPointerType.UnsignedByte; + + break; + } + + case GalVertexAttribSize._16: + case GalVertexAttribSize._16_16: + case GalVertexAttribSize._16_16_16: + case GalVertexAttribSize._16_16_16_16: + { + Type = Signed + ? VertexAttribPointerType.Short + : VertexAttribPointerType.UnsignedShort; + + break; + } + + case GalVertexAttribSize._10_10_10_2: + case GalVertexAttribSize._11_11_10: + case GalVertexAttribSize._32: + case GalVertexAttribSize._32_32: + case GalVertexAttribSize._32_32_32: + case GalVertexAttribSize._32_32_32_32: + { + Type = Signed + ? VertexAttribPointerType.Int + : VertexAttribPointerType.UnsignedInt; + + break; + } + } + + break; + } + + case GalVertexAttribType.Float: + { + Type = VertexAttribPointerType.Float; + + break; + } + } + + GL.VertexAttribPointer( + Attrib.Index, + Size, + Type, + Normalize, + Stride, + Attrib.Offset); + } + + GL.BindVertexArray(0); + } + + public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height) + { + EnsureTexInitialized(Index); + + GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); + GL.TexImage2D(TextureTarget.Texture2D, + 0, + PixelInternalFormat.Rgba, + Width, + Height, + 0, + PixelFormat.Rgba, + PixelType.UnsignedByte, + Buffer); + } + + public void BindTexture(int Index) + { + GL.ActiveTexture(TextureUnit.Texture0 + Index); + + GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); + } + + private void EnsureVbInitialized(int VbIndex) + { + while (VbIndex >= VertexBuffers.Count) + { + VertexBuffers.Add(new VertexBuffer()); + } + + VertexBuffer Vb = VertexBuffers[VbIndex]; + + if (Vb.VaoHandle == 0) + { + Vb.VaoHandle = GL.GenVertexArray(); + } + + if (Vb.VboHandle == 0) + { + Vb.VboHandle = GL.GenBuffer(); + } + + VertexBuffers[VbIndex] = Vb; + } + + private void EnsureTexInitialized(int TexIndex) + { + Texture Tex = Textures[TexIndex]; + + if (Tex.Handle == 0) + { + Tex.Handle = GL.GenTexture(); + } + + Textures[TexIndex] = Tex; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/BCn.cs b/Ryujinx.Graphics/Gpu/BCn.cs new file mode 100644 index 00000000..b1caf467 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/BCn.cs @@ -0,0 +1,468 @@ +using System; +using System.Drawing; + +namespace Ryujinx.Graphics.Gpu +{ + static class BCn + { + public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset) + { + int W = (Tex.Width + 3) / 4; + int H = (Tex.Height + 3) / 4; + + byte[] Output = new byte[W * H * 64]; + + SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8); + + for (int Y = 0; Y < H; Y++) + { + for (int X = 0; X < W; X++) + { + int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8; + + byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true); + + int TOffset = 0; + + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + Output[OOffset + 0] = Tile[TOffset + 0]; + Output[OOffset + 1] = Tile[TOffset + 1]; + Output[OOffset + 2] = Tile[TOffset + 2]; + Output[OOffset + 3] = Tile[TOffset + 3]; + + TOffset += 4; + } + } + } + } + + return Output; + } + + public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset) + { + int W = (Tex.Width + 3) / 4; + int H = (Tex.Height + 3) / 4; + + byte[] Output = new byte[W * H * 64]; + + SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); + + for (int Y = 0; Y < H; Y++) + { + for (int X = 0; X < W; X++) + { + int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; + + byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); + + int AlphaLow = Get32(Tex.Data, IOffs + 0); + int AlphaHigh = Get32(Tex.Data, IOffs + 4); + + ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; + + int TOffset = 0; + + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + ulong Alpha = (AlphaCh >> (TY * 16 + TX * 4)) & 0xf; + + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + Output[OOffset + 0] = Tile[TOffset + 0]; + Output[OOffset + 1] = Tile[TOffset + 1]; + Output[OOffset + 2] = Tile[TOffset + 2]; + Output[OOffset + 3] = (byte)(Alpha | (Alpha << 4)); + + TOffset += 4; + } + } + } + } + + return Output; + } + + public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset) + { + int W = (Tex.Width + 3) / 4; + int H = (Tex.Height + 3) / 4; + + byte[] Output = new byte[W * H * 64]; + + SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); + + for (int Y = 0; Y < H; Y++) + { + for (int X = 0; X < W; X++) + { + int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; + + byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); + + byte[] Alpha = new byte[8]; + + Alpha[0] = Tex.Data[IOffs + 0]; + Alpha[1] = Tex.Data[IOffs + 1]; + + CalculateBC3Alpha(Alpha); + + int AlphaLow = Get32(Tex.Data, IOffs + 2); + int AlphaHigh = Get16(Tex.Data, IOffs + 6); + + ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; + + int TOffset = 0; + + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + byte AlphaPx = Alpha[(AlphaCh >> (TY * 12 + TX * 3)) & 7]; + + Output[OOffset + 0] = Tile[TOffset + 0]; + Output[OOffset + 1] = Tile[TOffset + 1]; + Output[OOffset + 2] = Tile[TOffset + 2]; + Output[OOffset + 3] = AlphaPx; + + TOffset += 4; + } + } + } + } + + return Output; + } + + public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset) + { + int W = (Tex.Width + 3) / 4; + int H = (Tex.Height + 3) / 4; + + byte[] Output = new byte[W * H * 64]; + + SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8); + + for (int Y = 0; Y < H; Y++) + { + for (int X = 0; X < W; X++) + { + int IOffs = Swizzle.GetSwizzledAddress64(X, Y) * 8; + + byte[] Red = new byte[8]; + + Red[0] = Tex.Data[IOffs + 0]; + Red[1] = Tex.Data[IOffs + 1]; + + CalculateBC3Alpha(Red); + + int RedLow = Get32(Tex.Data, IOffs + 2); + int RedHigh = Get16(Tex.Data, IOffs + 6); + + ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; + + int TOffset = 0; + + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + byte RedPx = Red[(RedCh >> (TY * 12 + TX * 3)) & 7]; + + Output[OOffset + 0] = RedPx; + Output[OOffset + 1] = RedPx; + Output[OOffset + 2] = RedPx; + Output[OOffset + 3] = 0xff; + + TOffset += 4; + } + } + } + } + + return Output; + } + + public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm) + { + int W = (Tex.Width + 3) / 4; + int H = (Tex.Height + 3) / 4; + + byte[] Output = new byte[W * H * 64]; + + SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); + + for (int Y = 0; Y < H; Y++) + { + for (int X = 0; X < W; X++) + { + int IOffs = Swizzle.GetSwizzledAddress128(X, Y) * 16; + + byte[] Red = new byte[8]; + byte[] Green = new byte[8]; + + Red[0] = Tex.Data[IOffs + 0]; + Red[1] = Tex.Data[IOffs + 1]; + + Green[0] = Tex.Data[IOffs + 8]; + Green[1] = Tex.Data[IOffs + 9]; + + if (SNorm) + { + CalculateBC3AlphaS(Red); + CalculateBC3AlphaS(Green); + } + else + { + CalculateBC3Alpha(Red); + CalculateBC3Alpha(Green); + } + + int RedLow = Get32(Tex.Data, IOffs + 2); + int RedHigh = Get16(Tex.Data, IOffs + 6); + + int GreenLow = Get32(Tex.Data, IOffs + 10); + int GreenHigh = Get16(Tex.Data, IOffs + 14); + + ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; + ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32; + + int TOffset = 0; + + if (SNorm) + { + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int Shift = TY * 12 + TX * 3; + + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + byte RedPx = Red [(RedCh >> Shift) & 7]; + byte GreenPx = Green[(GreenCh >> Shift) & 7]; + + RedPx += 0x80; + GreenPx += 0x80; + + float NX = (RedPx / 255f) * 2 - 1; + float NY = (GreenPx / 255f) * 2 - 1; + + float NZ = (float)Math.Sqrt(1 - (NX * NX + NY * NY)); + + Output[OOffset + 0] = Clamp((NZ + 1) * 0.5f); + Output[OOffset + 1] = Clamp((NY + 1) * 0.5f); + Output[OOffset + 2] = Clamp((NX + 1) * 0.5f); + Output[OOffset + 3] = 0xff; + + TOffset += 4; + } + } + } + else + { + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int Shift = TY * 12 + TX * 3; + + int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; + + byte RedPx = Red [(RedCh >> Shift) & 7]; + byte GreenPx = Green[(GreenCh >> Shift) & 7]; + + Output[OOffset + 0] = RedPx; + Output[OOffset + 1] = RedPx; + Output[OOffset + 2] = RedPx; + Output[OOffset + 3] = GreenPx; + + TOffset += 4; + } + } + } + } + } + + return Output; + } + + private static byte Clamp(float Value) + { + if (Value > 1) + { + return 0xff; + } + else if (Value < 0) + { + return 0; + } + else + { + return (byte)(Value * 0xff); + } + } + + private static void CalculateBC3Alpha(byte[] Alpha) + { + for (int i = 2; i < 8; i++) + { + if (Alpha[0] > Alpha[1]) + { + Alpha[i] = (byte)(((8 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7); + } + else if (i < 6) + { + Alpha[i] = (byte)(((6 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7); + } + else if (i == 6) + { + Alpha[i] = 0; + } + else /* i == 7 */ + { + Alpha[i] = 0xff; + } + } + } + + private static void CalculateBC3AlphaS(byte[] Alpha) + { + for (int i = 2; i < 8; i++) + { + if ((sbyte)Alpha[0] > (sbyte)Alpha[1]) + { + Alpha[i] = (byte)(((8 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7); + } + else if (i < 6) + { + Alpha[i] = (byte)(((6 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7); + } + else if (i == 6) + { + Alpha[i] = 0x80; + } + else /* i == 7 */ + { + Alpha[i] = 0x7f; + } + } + } + + private static byte[] BCnDecodeTile( + byte[] Input, + int Offset, + bool IsBC1) + { + Color[] CLUT = new Color[4]; + + int c0 = Get16(Input, Offset + 0); + int c1 = Get16(Input, Offset + 2); + + CLUT[0] = DecodeRGB565(c0); + CLUT[1] = DecodeRGB565(c1); + CLUT[2] = CalculateCLUT2(CLUT[0], CLUT[1], c0, c1, IsBC1); + CLUT[3] = CalculateCLUT3(CLUT[0], CLUT[1], c0, c1, IsBC1); + + int Indices = Get32(Input, Offset + 4); + + int IdxShift = 0; + + byte[] Output = new byte[4 * 4 * 4]; + + int OOffset = 0; + + for (int TY = 0; TY < 4; TY++) + { + for (int TX = 0; TX < 4; TX++) + { + int Idx = (Indices >> IdxShift) & 3; + + IdxShift += 2; + + Color Pixel = CLUT[Idx]; + + Output[OOffset + 0] = Pixel.R; + Output[OOffset + 1] = Pixel.G; + Output[OOffset + 2] = Pixel.B; + Output[OOffset + 3] = Pixel.A; + + OOffset += 4; + } + } + + return Output; + } + + private static Color CalculateCLUT2(Color C0, Color C1, int c0, int c1, bool IsBC1) + { + if (c0 > c1 || !IsBC1) + { + return Color.FromArgb( + (2 * C0.R + C1.R) / 3, + (2 * C0.G + C1.G) / 3, + (2 * C0.B + C1.B) / 3); + } + else + { + return Color.FromArgb( + (C0.R + C1.R) / 2, + (C0.G + C1.G) / 2, + (C0.B + C1.B) / 2); + } + } + + private static Color CalculateCLUT3(Color C0, Color C1, int c0, int c1, bool IsBC1) + { + if (c0 > c1 || !IsBC1) + { + return + Color.FromArgb( + (2 * C1.R + C0.R) / 3, + (2 * C1.G + C0.G) / 3, + (2 * C1.B + C0.B) / 3); + } + + return Color.Transparent; + } + + private static Color DecodeRGB565(int Value) + { + int B = ((Value >> 0) & 0x1f) << 3; + int G = ((Value >> 5) & 0x3f) << 2; + int R = ((Value >> 11) & 0x1f) << 3; + + return Color.FromArgb( + R | (R >> 5), + G | (G >> 6), + B | (B >> 5)); + } + + private static int Get16(byte[] Data, int Address) + { + return + Data[Address + 0] << 0 | + Data[Address + 1] << 8; + } + + private static int Get32(byte[] Data, int Address) + { + return + Data[Address + 0] << 0 | + Data[Address + 1] << 8 | + Data[Address + 2] << 16 | + Data[Address + 3] << 24; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpu.cs b/Ryujinx.Graphics/Gpu/NsGpu.cs new file mode 100644 index 00000000..133d0af2 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpu.cs @@ -0,0 +1,53 @@ +using ChocolArm64.Memory; +using Ryujinx.Graphics.Gal; + +namespace Ryujinx.Graphics.Gpu +{ + public class NsGpu + { + public IGalRenderer Renderer { get; private set; } + + internal NsGpuMemoryMgr MemoryMgr { get; private set; } + + internal NsGpuPGraph PGraph { get; private set; } + + public NsGpu(IGalRenderer Renderer) + { + this.Renderer = Renderer; + + MemoryMgr = new NsGpuMemoryMgr(); + + PGraph = new NsGpuPGraph(this); + } + + public long GetCpuAddr(long Position) + { + return MemoryMgr.GetCpuAddr(Position); + } + + public long MapMemory(long CpuAddr, long Size) + { + return MemoryMgr.Map(CpuAddr, Size); + } + + public long MapMemory(long CpuAddr, long GpuAddr, long Size) + { + return MemoryMgr.Map(CpuAddr, GpuAddr, Size); + } + + public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory) + { + PGraph.ProcessPushBuffer(PushBuffer, Memory); + } + + public long ReserveMemory(long Size, long Align) + { + return MemoryMgr.Reserve(Size, Align); + } + + public long ReserveMemory(long GpuAddr, long Size, long Align) + { + return MemoryMgr.Reserve(GpuAddr, Size, Align); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuEngine.cs b/Ryujinx.Graphics/Gpu/NsGpuEngine.cs new file mode 100644 index 00000000..118e2b72 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuEngine.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gpu +{ + enum NsGpuEngine + { + None = 0, + _2d = 0x902d, + _3d = 0xb197, + Compute = 0xb1c0, + Kepler = 0xa140, + Dma = 0xb0b5, + GpFifo = 0xb06f + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs new file mode 100644 index 00000000..54fabc67 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs @@ -0,0 +1,204 @@ +namespace Ryujinx.Graphics.Gpu +{ + class NsGpuMemoryMgr + { + private const long AddrSize = 1L << 40; + + private const int PTLvl0Bits = 14; + private const int PTLvl1Bits = 14; + private const int PTPageBits = 12; + + private const int PTLvl0Size = 1 << PTLvl0Bits; + private const int PTLvl1Size = 1 << PTLvl1Bits; + private const int PageSize = 1 << PTPageBits; + + private const int PTLvl0Mask = PTLvl0Size - 1; + private const int PTLvl1Mask = PTLvl1Size - 1; + private const int PageMask = PageSize - 1; + + private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; + private const int PTLvl1Bit = PTPageBits; + + private const long PteUnmapped = -1; + private const long PteReserved = -2; + + private long[][] PageTable; + + public NsGpuMemoryMgr() + { + PageTable = new long[PTLvl0Size][]; + } + + public long Map(long CpuAddr, long GpuAddr, long Size) + { + CpuAddr &= ~PageMask; + GpuAddr &= ~PageMask; + + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + if (GetPTAddr(GpuAddr + Offset) != PteReserved) + { + return Map(CpuAddr, Size); + } + } + + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPTAddr(GpuAddr + Offset, CpuAddr + Offset); + } + + return GpuAddr; + } + + public long Map(long CpuAddr, long Size) + { + CpuAddr &= ~PageMask; + + long Position = GetFreePosition(Size); + + if (Position != -1) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPTAddr(Position + Offset, CpuAddr + Offset); + } + } + + return Position; + } + + public long Reserve(long GpuAddr, long Size, long Align) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + if (HasPTAddr(GpuAddr + Offset)) + { + return Reserve(Size, Align); + } + } + + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPTAddr(GpuAddr + Offset, PteReserved); + } + + return GpuAddr; + } + + public long Reserve(long Size, long Align) + { + long Position = GetFreePosition(Size, Align); + + if (Position != -1) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPTAddr(Position + Offset, PteReserved); + } + } + + return Position; + } + + private long GetFreePosition(long Size, long Align = 1) + { + long Position = 0; + long FreeSize = 0; + + if (Align < 1) + { + Align = 1; + } + + Align = (Align + PageMask) & ~PageMask; + + while (Position + FreeSize < AddrSize) + { + if (!HasPTAddr(Position + FreeSize)) + { + FreeSize += PageSize; + + if (FreeSize >= Size) + { + return Position; + } + } + else + { + Position += FreeSize + PageSize; + FreeSize = 0; + + long Remainder = Position % Align; + + if (Remainder != 0) + { + Position = (Position - Remainder) + Align; + } + } + } + + return -1; + } + + public long GetCpuAddr(long Position) + { + long BasePos = GetPTAddr(Position); + + if (BasePos < 0) + { + return -1; + } + + return BasePos + (Position & PageMask); + } + + private bool HasPTAddr(long Position) + { + if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) + { + return false; + } + + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return false; + } + + return PageTable[L0][L1] != PteUnmapped; + } + + private long GetPTAddr(long Position) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + return -1; + } + + return PageTable[L0][L1]; + } + + private void SetPTAddr(long Position, long TgtAddr) + { + long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; + long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + + if (PageTable[L0] == null) + { + PageTable[L0] = new long[PTLvl1Size]; + + for (int Index = 0; Index < PTLvl1Size; Index++) + { + PageTable[L0][Index] = PteUnmapped; + } + } + + PageTable[L0][L1] = TgtAddr; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs b/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs new file mode 100644 index 00000000..8063651a --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuPBEntry.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; + +namespace Ryujinx.Graphics.Gpu +{ + public struct NsGpuPBEntry + { + public NsGpuRegister Register { get; private set; } + + public int SubChannel { get; private set; } + + private int[] m_Arguments; + + public ReadOnlyCollection Arguments => Array.AsReadOnly(m_Arguments); + + public NsGpuPBEntry(NsGpuRegister Register, int SubChannel, params int[] Arguments) + { + this.Register = Register; + this.SubChannel = SubChannel; + this.m_Arguments = Arguments; + } + + public static NsGpuPBEntry[] DecodePushBuffer(byte[] Data) + { + using (MemoryStream MS = new MemoryStream(Data)) + { + BinaryReader Reader = new BinaryReader(MS); + + List GpFifos = new List(); + + bool CanRead() => MS.Position + 4 <= MS.Length; + + while (CanRead()) + { + int Packed = Reader.ReadInt32(); + + int Reg = (Packed << 2) & 0x7ffc; + int SubC = (Packed >> 13) & 7; + int Args = (Packed >> 16) & 0x1fff; + int Mode = (Packed >> 29) & 7; + + if (Mode == 4) + { + //Inline Mode. + GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Args)); + } + else + { + //Word mode. + if (Mode == 1) + { + //Sequential Mode. + for (int Index = 0; Index < Args && CanRead(); Index++, Reg += 4) + { + GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Reader.ReadInt32())); + } + } + else + { + //Non-Sequential Mode. + int[] Arguments = new int[Args]; + + for (int Index = 0; Index < Args && CanRead(); Index++) + { + Arguments[Index] = Reader.ReadInt32(); + } + + GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Arguments)); + } + } + } + + return GpFifos.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs new file mode 100644 index 00000000..eb893f74 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuPGraph.cs @@ -0,0 +1,276 @@ +using ChocolArm64.Memory; +using Ryujinx.Graphics.Gal; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gpu +{ + class NsGpuPGraph + { + private NsGpu Gpu; + + private int[] Registers; + + public NsGpuEngine[] SubChannels; + + private Dictionary CurrentVertexBuffers; + + public NsGpuPGraph(NsGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0x1000]; + + SubChannels = new NsGpuEngine[8]; + + CurrentVertexBuffers = new Dictionary(); + } + + public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory) + { + bool HasQuery = false; + + foreach (NsGpuPBEntry Entry in PushBuffer) + { + if (Entry.Arguments.Count == 1) + { + SetRegister(Entry.Register, Entry.Arguments[0]); + } + + switch (Entry.Register) + { + case NsGpuRegister.BindChannel: + if (Entry.Arguments.Count > 0) + { + SubChannels[Entry.SubChannel] = (NsGpuEngine)Entry.Arguments[0]; + } + break; + + case NsGpuRegister._3dVertexArray0Fetch: + SendVertexBuffers(Memory); + break; + + case NsGpuRegister._3dCbData0: + if (GetRegister(NsGpuRegister._3dCbPos) == 0x20) + { + SendTexture(Memory); + } + break; + + case NsGpuRegister._3dQueryAddressHigh: + case NsGpuRegister._3dQueryAddressLow: + case NsGpuRegister._3dQuerySequence: + case NsGpuRegister._3dQueryGet: + HasQuery = true; + break; + } + } + + if (HasQuery) + { + long Position = + (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 | + (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; + + int Seq = GetRegister(NsGpuRegister._3dQuerySequence); + int Get = GetRegister(NsGpuRegister._3dQueryGet); + + int Mode = Get & 3; + + if (Mode == 0) + { + //Write + Position = Gpu.MemoryMgr.GetCpuAddr(Position); + + if (Position != -1) + { + Gpu.Renderer.QueueAction(delegate() + { + Memory.WriteInt32(Position, Seq); + }); + } + } + } + } + + private void SendVertexBuffers(AMemory Memory) + { + long Position = + (long)GetRegister(NsGpuRegister._3dVertexArray0StartHigh) << 32 | + (long)GetRegister(NsGpuRegister._3dVertexArray0StartLow) << 0; + + long Limit = + (long)GetRegister(NsGpuRegister._3dVertexArray0LimitHigh) << 32 | + (long)GetRegister(NsGpuRegister._3dVertexArray0LimitLow) << 0; + + int VbIndex = CurrentVertexBuffers.Count; + + if (!CurrentVertexBuffers.TryAdd(Position, VbIndex)) + { + VbIndex = CurrentVertexBuffers[Position]; + } + + if (Limit != 0) + { + long Size = (Limit - Position) + 1; + + Position = Gpu.MemoryMgr.GetCpuAddr(Position); + + if (Position != -1) + { + byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, (int)Size); + + int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; + + List Attribs = new List(); + + for (int Attr = 0; Attr < 16; Attr++) + { + int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4); + + GalVertexAttrib Attrib = new GalVertexAttrib(Attr, + (Packed >> 0) & 0x1f, + ((Packed >> 6) & 0x1) != 0, + (Packed >> 7) & 0x3fff, + (GalVertexAttribSize)((Packed >> 21) & 0x3f), + (GalVertexAttribType)((Packed >> 27) & 0x7), + ((Packed >> 31) & 0x1) != 0); + + if (Attrib.Offset < Stride) + { + Attribs.Add(Attrib); + } + } + + Gpu.Renderer.QueueAction(delegate() + { + Gpu.Renderer.SendVertexBuffer(VbIndex, Buffer, Stride, Attribs.ToArray()); + }); + } + } + } + + private void SendTexture(AMemory Memory) + { + long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 | + (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0; + + int CbData = GetRegister(NsGpuRegister._3dCbData0); + + int TicIndex = (CbData >> 0) & 0xfffff; + int TscIndex = (CbData >> 20) & 0xfff; //I guess? + + TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20); + + if (TicPos != -1) + { + int Word0 = Memory.ReadInt32(TicPos + 0x0); + int Word1 = Memory.ReadInt32(TicPos + 0x4); + int Word2 = Memory.ReadInt32(TicPos + 0x8); + int Word3 = Memory.ReadInt32(TicPos + 0xc); + int Word4 = Memory.ReadInt32(TicPos + 0x10); + int Word5 = Memory.ReadInt32(TicPos + 0x14); + int Word6 = Memory.ReadInt32(TicPos + 0x18); + int Word7 = Memory.ReadInt32(TicPos + 0x1c); + + long TexAddress = Word1; + + TexAddress |= (long)(Word2 & 0xff) << 32; + + TexAddress = Gpu.MemoryMgr.GetCpuAddr(TexAddress); + + if (TexAddress != -1) + { + NsGpuTextureFormat Format = (NsGpuTextureFormat)(Word0 & 0x7f); + + int Width = (Word4 & 0xffff) + 1; + int Height = (Word5 & 0xffff) + 1; + + byte[] Buffer = GetDecodedTexture(Memory, Format, TexAddress, Width, Height); + + if (Buffer != null) + { + Gpu.Renderer.QueueAction(delegate() + { + Gpu.Renderer.SendR8G8B8A8Texture(0, Buffer, Width, Height); + }); + } + } + } + } + + private static byte[] GetDecodedTexture( + AMemory Memory, + NsGpuTextureFormat Format, + long Position, + int Width, + int Height) + { + byte[] Data = null; + + switch (Format) + { + case NsGpuTextureFormat.BC1: + { + int Size = (Width * Height) >> 1; + + Data = AMemoryHelper.ReadBytes(Memory, Position, Size); + + Data = BCn.DecodeBC1(new NsGpuTexture() + { + Width = Width, + Height = Height, + Data = Data + }, 0); + + break; + } + + case NsGpuTextureFormat.BC2: + { + int Size = Width * Height; + + Data = AMemoryHelper.ReadBytes(Memory, Position, Size); + + Data = BCn.DecodeBC2(new NsGpuTexture() + { + Width = Width, + Height = Height, + Data = Data + }, 0); + + break; + } + + case NsGpuTextureFormat.BC3: + { + int Size = Width * Height; + + Data = AMemoryHelper.ReadBytes(Memory, Position, Size); + + Data = BCn.DecodeBC3(new NsGpuTexture() + { + Width = Width, + Height = Height, + Data = Data + }, 0); + + break; + } + + //default: throw new NotImplementedException(Format.ToString()); + } + + return Data; + } + + public int GetRegister(NsGpuRegister Register) + { + return Registers[((int)Register >> 2) & 0xfff]; + } + + public void SetRegister(NsGpuRegister Register, int Value) + { + Registers[((int)Register >> 2) & 0xfff] = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuRegister.cs b/Ryujinx.Graphics/Gpu/NsGpuRegister.cs new file mode 100644 index 00000000..319e2c01 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuRegister.cs @@ -0,0 +1,93 @@ +namespace Ryujinx.Graphics.Gpu +{ + public enum NsGpuRegister + { + BindChannel = 0, + + _2dClipEnable = 0x0290, + _2dOperation = 0x02ac, + + _3dGlobalBase = 0x02c8, + _3dRt0AddressHigh = 0x0800, + _3dRt0AddressLow = 0x0804, + _3dRt0Horiz = 0x0808, + _3dRt0Vert = 0x080c, + _3dRt0Format = 0x0810, + _3dRt0BlockDimensions = 0x0814, + _3dRt0ArrayMode = 0x0818, + _3dRt0LayerStride = 0x081c, + _3dRt0BaseLayer = 0x0820, + _3dViewportScaleX = 0x0a00, + _3dViewportScaleY = 0x0a04, + _3dViewportScaleZ = 0x0a08, + _3dViewportTranslateX = 0x0a0c, + _3dViewportTranslateY = 0x0a10, + _3dViewportTranslateZ = 0x0a14, + _3dViewportHoriz = 0x0c00, + _3dViewportVert = 0x0c04, + _3dDepthRangeNear = 0x0c08, + _3dDepthRangeFar = 0x0c0c, + _3dClearColorR = 0x0d80, + _3dClearColorG = 0x0d84, + _3dClearColorB = 0x0d88, + _3dClearColorA = 0x0d8c, + _3dScreenScissorHoriz = 0x0ff4, + _3dScreenScissorVert = 0x0ff8, + _3dVertexAttrib0Format = 0x1160, + _3dVertexAttrib1Format = 0x1164, + _3dVertexAttrib2Format = 0x1168, + _3dVertexAttrib3Format = 0x116c, + _3dVertexAttrib4Format = 0x1170, + _3dVertexAttrib5Format = 0x1174, + _3dVertexAttrib6Format = 0x1178, + _3dVertexAttrib7Format = 0x117c, + _3dVertexAttrib8Format = 0x1180, + _3dVertexAttrib9Format = 0x1184, + _3dVertexAttrib10Format = 0x1188, + _3dVertexAttrib11Format = 0x118c, + _3dVertexAttrib12Format = 0x1190, + _3dVertexAttrib13Format = 0x1194, + _3dVertexAttrib14Format = 0x1198, + _3dVertexAttrib15Format = 0x119c, + _3dScreenYControl = 0x13ac, + _3dTscAddressHigh = 0x155c, + _3dTscAddressLow = 0x1560, + _3dTscLimit = 0x1564, + _3dTicAddressHigh = 0x1574, + _3dTicAddressLow = 0x1578, + _3dTicLimit = 0x157c, + _3dMultiSampleMode = 0x15d0, + _3dVertexEndGl = 0x1614, + _3dVertexBeginGl = 0x1618, + _3dQueryAddressHigh = 0x1b00, + _3dQueryAddressLow = 0x1b04, + _3dQuerySequence = 0x1b08, + _3dQueryGet = 0x1b0c, + _3dVertexArray0Fetch = 0x1c00, + _3dVertexArray0StartHigh = 0x1c04, + _3dVertexArray0StartLow = 0x1c08, + _3dVertexArray1Fetch = 0x1c10, //todo: the rest + _3dVertexArray0LimitHigh = 0x1f00, + _3dVertexArray0LimitLow = 0x1f04, + _3dCbSize = 0x2380, + _3dCbAddressHigh = 0x2384, + _3dCbAddressLow = 0x2388, + _3dCbPos = 0x238c, + _3dCbData0 = 0x2390, + _3dCbData1 = 0x2394, + _3dCbData2 = 0x2398, + _3dCbData3 = 0x239c, + _3dCbData4 = 0x23a0, + _3dCbData5 = 0x23a4, + _3dCbData6 = 0x23a8, + _3dCbData7 = 0x23ac, + _3dCbData8 = 0x23b0, + _3dCbData9 = 0x23b4, + _3dCbData10 = 0x23b8, + _3dCbData11 = 0x23bc, + _3dCbData12 = 0x23c0, + _3dCbData13 = 0x23c4, + _3dCbData14 = 0x23c8, + _3dCbData15 = 0x23cc, + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuTexture.cs b/Ryujinx.Graphics/Gpu/NsGpuTexture.cs new file mode 100644 index 00000000..aac42200 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuTexture.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Gpu +{ + struct NsGpuTexture + { + public int Width; + public int Height; + + public byte[] Data; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs b/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs new file mode 100644 index 00000000..2993840b --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NsGpuTextureFormat.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Gpu +{ + enum NsGpuTextureFormat + { + BC1 = 0x24, + BC2 = 0x25, + BC3 = 0x26 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/SwizzleAddr.cs b/Ryujinx.Graphics/Gpu/SwizzleAddr.cs new file mode 100644 index 00000000..08e61eb5 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/SwizzleAddr.cs @@ -0,0 +1,144 @@ +using System; + +namespace Ryujinx.Graphics.Gpu +{ + class SwizzleAddr + { + private int Width; + + private int XB; + private int YB; + + public SwizzleAddr(int Width, int Height, int Pad) + { + int W = Pow2RoundUp(Width); + int H = Pow2RoundUp(Height); + + XB = CountZeros(W); + YB = CountZeros(H); + + int HH = H >> 1; + + if (!IsPow2(Height) && Height <= HH + HH / 3 && YB > 3) + { + YB--; + } + + this.Width = RoundSize(Width, Pad); + } + + private static int Pow2RoundUp(int Value) + { + Value--; + + Value |= (Value >> 1); + Value |= (Value >> 2); + Value |= (Value >> 4); + Value |= (Value >> 8); + Value |= (Value >> 16); + + return ++Value; + } + + private static bool IsPow2(int Value) + { + return Value != 0 && (Value & (Value - 1)) == 0; + } + + private static int CountZeros(int Value) + { + int Count = 0; + + for (int i = 0; i < 32; i++) + { + if ((Value & (1 << i)) != 0) + { + break; + } + + Count++; + } + + return Count; + } + + private static int RoundSize(int Size, int Pad) + { + int Mask = Pad - 1; + + if ((Size & Mask) != 0) + { + Size &= ~Mask; + Size += Pad; + } + + return Size; + } + + public int GetSwizzledAddress8(int X, int Y) + { + return GetSwizzledAddress(X, Y, 4); + } + + public int GetSwizzledAddress16(int X, int Y) + { + return GetSwizzledAddress(X, Y, 3); + } + + public int GetSwizzledAddress32(int X, int Y) + { + return GetSwizzledAddress(X, Y, 2); + } + + public int GetSwizzledAddress64(int X, int Y) + { + return GetSwizzledAddress(X, Y, 1); + } + + public int GetSwizzledAddress128(int X, int Y) + { + return GetSwizzledAddress(X, Y, 0); + } + + private int GetSwizzledAddress(int X, int Y, int XBase) + { + /* + * Examples of patterns: + * x x y x y y x y 0 0 0 0 64 x 64 dxt5 + * x x x x x y y y y x y y x y 0 0 0 0 512 x 512 dxt5 + * y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5 + * y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1 + * y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888 + * + * Read from right to left, LSB first. + */ + int XCnt = XBase; + int YCnt = 1; + int XUsed = 0; + int YUsed = 0; + int Address = 0; + + while (XUsed < XBase + 2 && XUsed + XCnt < XB) + { + int XMask = (1 << XCnt) - 1; + int YMask = (1 << YCnt) - 1; + + Address |= (X & XMask) << XUsed + YUsed; + Address |= (Y & YMask) << XUsed + YUsed + XCnt; + + X >>= XCnt; + Y >>= YCnt; + + XUsed += XCnt; + YUsed += YCnt; + + XCnt = Math.Min(XB - XUsed, 1); + YCnt = Math.Min(YB - YUsed, YCnt << 1); + } + + Address |= (X + Y * (Width >> XUsed)) << (XUsed + YUsed); + + return Address; + } + } +} diff --git a/Ryujinx.Graphics/Ryujinx.Graphics.csproj b/Ryujinx.Graphics/Ryujinx.Graphics.csproj new file mode 100644 index 00000000..657beb82 --- /dev/null +++ b/Ryujinx.Graphics/Ryujinx.Graphics.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.0 + + + + + + + + + + + diff --git a/Ryujinx.sln b/Ryujinx.sln index 77753988..34a5f488 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -1,11 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.8 +VisualStudioVersion = 15.0.27130.2027 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx", "Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Tests", "Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Core", "Ryujinx.Core\Ryujinx.Core.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChocolArm64", "ChocolArm64\ChocolArm64.csproj", "{2345A1A7-8DEF-419B-9AFB-4DFD41D20D05}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics", "Ryujinx.Graphics\Ryujinx.Graphics.csproj", "{EAAE36AF-7781-4578-A7E0-F0EFD2025569}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +27,18 @@ Global {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU + {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU + {2345A1A7-8DEF-419B-9AFB-4DFD41D20D05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2345A1A7-8DEF-419B-9AFB-4DFD41D20D05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2345A1A7-8DEF-419B-9AFB-4DFD41D20D05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2345A1A7-8DEF-419B-9AFB-4DFD41D20D05}.Release|Any CPU.Build.0 = Release|Any CPU + {EAAE36AF-7781-4578-A7E0-F0EFD2025569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAAE36AF-7781-4578-A7E0-F0EFD2025569}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAAE36AF-7781-4578-A7E0-F0EFD2025569}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAAE36AF-7781-4578-A7E0-F0EFD2025569}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs deleted file mode 100644 index b5361421..00000000 --- a/Ryujinx/Config.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace Ryujinx -{ - public static class Config - { - public static bool LoggingEnableInfo { get; private set; } - public static bool LoggingEnableTrace { get; private set; } - public static bool LoggingEnableDebug { get; private set; } - public static bool LoggingEnableWarn { get; private set; } - public static bool LoggingEnableError { get; private set; } - public static bool LoggingEnableFatal { get; private set; } - public static bool LoggingEnableLogFile { get; private set; } - - public static JoyCon FakeJoyCon { get; private set; } - - public static void Read() - { - var iniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - var iniPath = Path.Combine(iniFolder, "Ryujinx.conf"); - IniParser Parser = new IniParser(iniPath); - - LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info")); - LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace")); - LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug")); - LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn")); - LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error")); - LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal")); - LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile")); - - FakeJoyCon = new JoyCon - { - Left = new JoyConLeft - { - StickUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Up")), - StickDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Down")), - StickLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Left")), - StickRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Right")), - StickButton = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Button")), - DPadUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Up")), - DPadDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Down")), - DPadLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Left")), - DPadRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Right")), - ButtonMinus = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_Minus")), - ButtonL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_L")), - ButtonZL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_ZL")) - }, - - Right = new JoyConRight - { - StickUp = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Up")), - StickDown = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Down")), - StickLeft = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Left")), - StickRight = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Right")), - StickButton = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Button")), - ButtonA = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_A")), - ButtonB = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_B")), - ButtonX = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_X")), - ButtonY = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Y")), - ButtonPlus = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Plus")), - ButtonR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_R")), - ButtonZR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_ZR")) - } - }; - } - } - - // https://stackoverflow.com/a/37772571 - public class IniParser - { - private readonly Dictionary Values; - - public IniParser(string Path) - { - Values = File.ReadLines(Path) - .Where(Line => !string.IsNullOrWhiteSpace(Line) && !Line.StartsWith('#')) - .Select(Line => Line.Split('=', 2)) - .ToDictionary(Parts => Parts[0].Trim(), Parts => Parts.Length > 1 ? Parts[1].Trim() : null); - } - - /// - /// Gets the setting value for the requested setting . - /// - /// Setting Name - /// Default value of the setting - public string Value(string Name, string defaultValue = null) - { - return Values.TryGetValue(Name, out var value) ? value : defaultValue; - } - } -} diff --git a/Ryujinx/Cpu/ABitUtils.cs b/Ryujinx/Cpu/ABitUtils.cs deleted file mode 100644 index 357dd45d..00000000 --- a/Ryujinx/Cpu/ABitUtils.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace ChocolArm64 -{ - static class ABitUtils - { - public static int CountBitsSet(long Value) - { - int Count = 0; - - for (int Bit = 0; Bit < 64; Bit++) - { - Count += (int)(Value >> Bit) & 1; - } - - return Count; - } - - public static int HighestBitSet32(int Value) - { - for (int Bit = 31; Bit >= 0; Bit--) - { - if (((Value >> Bit) & 1) != 0) - { - return Bit; - } - } - - return -1; - } - - public static long Replicate(long Bits, int Size) - { - long Output = 0; - - for (int Bit = 0; Bit < 64; Bit += Size) - { - Output |= Bits << Bit; - } - - return Output; - } - - public static long FillWithOnes(int Bits) - { - return Bits == 64 ? -1L : (1L << Bits) - 1; - } - - public static long RotateRight(long Bits, int Shift, int Size) - { - return (Bits >> Shift) | (Bits << (Size - Shift)); - } - - public static bool IsPow2(int Value) - { - return Value != 0 && (Value & (Value - 1)) == 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs deleted file mode 100644 index ff2796b8..00000000 --- a/Ryujinx/Cpu/AOpCodeTable.cs +++ /dev/null @@ -1,408 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Instruction; -using System; - -namespace ChocolArm64 -{ - static class AOpCodeTable - { - static AOpCodeTable() - { - #region "OpCode Table" - //Integer - Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs)); - Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm)); - Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs)); - Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx)); - Set("x01100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluImm)); - Set("x0101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRs)); - Set("x0101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adds, typeof(AOpCodeAluRx)); - Set("0xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adr, typeof(AOpCodeAdr)); - Set("1xx10000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Adrp, typeof(AOpCodeAdr)); - Set("x00100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.And, typeof(AOpCodeAluImm)); - Set("x0001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.And, typeof(AOpCodeAluRs)); - Set("x11100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ands, typeof(AOpCodeAluImm)); - Set("x1101010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ands, typeof(AOpCodeAluRs)); - Set("x0011010110xxxxx001010xxxxxxxxxx", AInstEmit.Asrv, typeof(AOpCodeAluRs)); - Set("000101xxxxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.B, typeof(AOpCodeBImmAl)); - Set("01010100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.B_Cond, typeof(AOpCodeBImmCond)); - Set("x01100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bfm, typeof(AOpCodeBfm)); - Set("x0001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bic, typeof(AOpCodeAluRs)); - Set("x1101010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bics, typeof(AOpCodeAluRs)); - Set("100101xxxxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Bl, typeof(AOpCodeBImmAl)); - Set("11010110001xxxxx000000xxxxxxxxxx", AInstEmit.Blr, typeof(AOpCodeBReg)); - Set("11010110000xxxxx000000xxxxxxxxxx", AInstEmit.Br, typeof(AOpCodeBReg)); - Set("11010100001xxxxxxxxxxxxxxxx00000", AInstEmit.Brk, typeof(AOpCodeException)); - Set("x0110101xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Cbnz, typeof(AOpCodeBImmCmp)); - Set("x0110100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Cbz, typeof(AOpCodeBImmCmp)); - Set("x0111010010xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ccmn, typeof(AOpCodeCcmpImm)); - Set("x0111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmn, typeof(AOpCodeCcmpReg)); - Set("x1111010010xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpImm)); - Set("x1111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpReg)); - Set("11010101000000110011xxxx01011111", AInstEmit.Clrex, typeof(AOpCodeSystem)); - Set("x101101011000000000100xxxxxxxxxx", AInstEmit.Clz, typeof(AOpCodeAlu)); - Set("x0011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csel, typeof(AOpCodeCsel)); - Set("x0011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csinc, typeof(AOpCodeCsel)); - Set("x1011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csinv, typeof(AOpCodeCsel)); - Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel)); - Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem)); - Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem)); - Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs)); - Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm)); - Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs)); - Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs)); - Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx)); - Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx)); - Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx)); - Set("<<10100xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp, typeof(AOpCodeMemPair)); - Set("xx111000010xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm)); - Set("xx11100101xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm)); - Set("xx111000011xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemReg)); - Set("xx011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeMemLit)); - Set("0x1110001x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); - Set("0x1110011xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); - Set("10111000100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); - Set("1011100110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm)); - Set("0x1110001x1xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemReg)); - Set("10111000101xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemReg)); - Set("xx001000010xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Ldxr, typeof(AOpCodeMemEx)); - Set("1x001000011xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Ldxp, typeof(AOpCodeMemEx)); - Set("x0011010110xxxxx001000xxxxxxxxxx", AInstEmit.Lslv, typeof(AOpCodeAluRs)); - Set("x0011010110xxxxx001001xxxxxxxxxx", AInstEmit.Lsrv, typeof(AOpCodeAluRs)); - Set("x0011011000xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Madd, typeof(AOpCodeMul)); - Set("x11100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movk, typeof(AOpCodeMov)); - Set("x00100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movn, typeof(AOpCodeMov)); - Set("x10100101xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Movz, typeof(AOpCodeMov)); - Set("110101010011xxxxxxxxxxxxxxxxxxxx", AInstEmit.Mrs, typeof(AOpCodeSystem)); - Set("110101010001xxxxxxxxxxxxxxxxxxxx", AInstEmit.Msr, typeof(AOpCodeSystem)); - Set("x0011011000xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Msub, typeof(AOpCodeMul)); - Set("11010101000000110010000000011111", AInstEmit.Nop, typeof(AOpCodeSystem)); - Set("x0101010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orn, typeof(AOpCodeAluRs)); - Set("x01100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluImm)); - Set("x0101010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluRs)); - Set("1111100110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemImm)); - Set("11011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemLit)); - Set("x101101011000000000000xxxxxxxxxx", AInstEmit.Rbit, typeof(AOpCodeAlu)); - Set("11010110010xxxxx000000xxxxxxxxxx", AInstEmit.Ret, typeof(AOpCodeBReg)); - Set("x101101011000000000001xxxxxxxxxx", AInstEmit.Rev16, typeof(AOpCodeAlu)); - Set("x101101011000000000010xxxxxxxxxx", AInstEmit.Rev32, typeof(AOpCodeAlu)); - Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu)); - Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs)); - Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs)); - Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm)); - Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs)); - Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul)); - Set("10011011001xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Smsubl, typeof(AOpCodeMul)); - Set("10011011010xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smulh, typeof(AOpCodeMul)); - Set("xx001000100xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlr, typeof(AOpCodeMemEx)); - Set("1x001000001xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlxp, typeof(AOpCodeMemEx)); - Set("xx001000000xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Stlxr, typeof(AOpCodeMemEx)); - Set("x010100xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeMemPair)); - Set("xx111000000xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemImm)); - Set("xx11100100xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemImm)); - Set("xx111000001xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeMemReg)); - Set("1x001000001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxp, typeof(AOpCodeMemEx)); - Set("xx001000000xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Stxr, typeof(AOpCodeMemEx)); - Set("x10100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluImm)); - Set("x1001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRs)); - Set("x1001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sub, typeof(AOpCodeAluRx)); - Set("x11100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluImm)); - Set("x1101011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRs)); - Set("x1101011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Subs, typeof(AOpCodeAluRx)); - Set("11010100000xxxxxxxxxxxxxxxx00001", AInstEmit.Svc, typeof(AOpCodeException)); - Set("1101010100001xxxxxxxxxxxxxxxxxxx", AInstEmit.Sys, typeof(AOpCodeSystem)); - Set("x0110111xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Tbnz, typeof(AOpCodeBImmTest)); - Set("x0110110xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Tbz, typeof(AOpCodeBImmTest)); - Set("x10100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ubfm, typeof(AOpCodeBfm)); - Set("x0011010110xxxxx000010xxxxxxxxxx", AInstEmit.Udiv, typeof(AOpCodeAluRs)); - Set("10011011101xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Umaddl, typeof(AOpCodeMul)); - Set("10011011101xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Umsubl, typeof(AOpCodeMul)); - Set("10011011110xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Umulh, typeof(AOpCodeMul)); - - //Vector - Set("0>001110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Add_V, typeof(AOpCodeSimdReg)); - Set("01011110xx110001101110xxxxxxxxxx", AInstEmit.Addp_S, typeof(AOpCodeSimd)); - Set("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg)); - Set("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); - Set("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd)); - Set("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg)); - Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg)); - Set("0x10111100000xxx<101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg)); - Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd)); - Set("0>001110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimdReg)); - Set("0>101110<<100000100010xxxxxxxxxx", AInstEmit.Cmge_V, typeof(AOpCodeSimd)); - Set("0>001110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimdReg)); - Set("0>001110<<100000100010xxxxxxxxxx", AInstEmit.Cmgt_V, typeof(AOpCodeSimd)); - Set("0>101110<<1xxxxx001101xxxxxxxxxx", AInstEmit.Cmhi_V, typeof(AOpCodeSimdReg)); - Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg)); - Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd)); - Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd)); - Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd)); - Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns)); - Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns)); - Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns)); - Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg)); - Set("00011110xx100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd)); - Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg)); - Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond)); - Set("00011110xx1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond)); - Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond)); - Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd)); - Set("x0011110xx100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt)); - Set("0>0011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd)); - Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm)); - Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt)); - Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt)); - Set("0>1011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd)); - Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm)); - Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg)); - Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg)); - Set("00011111xx0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg)); - Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg)); - Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg)); - Set("0x0011111<1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg)); - Set("0x0011111<0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg)); - Set("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp, typeof(AOpCodeSimdIns)); - Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns)); - Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs)); - Set("0x001100110xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs)); - Set("0x00110101000000xx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs)); - Set("0x001101110xxxxxxx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs)); - Set("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp, typeof(AOpCodeSimdMemPair)); - Set("xx111100x10xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); - Set("xx111100x10xxxxxxxxx01xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); - Set("xx111100x10xxxxxxxxx11xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); - Set("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm)); - Set("xx111100x11xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemReg)); - Set("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeSimdMemLit)); - Set("0x001110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mla_V, typeof(AOpCodeSimdReg)); - Set("0x101110<<1xxxxx100101xxxxxxxxxx", AInstEmit.Mls_V, typeof(AOpCodeSimdReg)); - Set("0x00111100000xxx0xx001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); - Set("0x00111100000xxx10x001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); - Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); - Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm)); - Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg)); - Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); - Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); - Set("0x10111100000xxx110x01xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm)); - Set("0>101110<<100000101110xxxxxxxxxx", AInstEmit.Neg_V, typeof(AOpCodeSimdReg)); - Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd)); - Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg)); - Set("0x00111100000xxx<>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm)); - Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm)); - Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm)); - Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg)); - Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg)); - Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg)); - Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg)); - Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm)); - Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm)); - Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm)); - Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); - Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs)); - Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); - Set("0x001101100xxxxxxx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs)); - Set("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeSimdMemPair)); - Set("xx111100x00xxxxxxxxx00xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); - Set("xx111100x00xxxxxxxxx01xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); - Set("xx111100x00xxxxxxxxx11xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); - Set("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm)); - Set("xx111100x01xxxxxxxxx10xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemReg)); - Set("01111110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_S, typeof(AOpCodeSimdReg)); - Set("0>101110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V, typeof(AOpCodeSimdReg)); - Set("0x001110000xxxxx0xx000xxxxxxxxxx", AInstEmit.Tbl_V, typeof(AOpCodeSimdTbl)); - Set("001011100x110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); - Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd)); - Set("0x101110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Uaddw_V, typeof(AOpCodeSimdReg)); - Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt)); - Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd)); - Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd)); - Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); - Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); - Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm)); - Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm)); - Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm)); - Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm)); - Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg)); - Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg)); - Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd)); - Set("0x001110xx0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg)); - Set("0x001110xx0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg)); -#endregion - } - - private class TreeNode - { - public int Mask; - public int Value; - - public TreeNode Next; - public TreeNode Child; - - public AInst Inst; - - public TreeNode(int Mask, int Value, AInst Inst) - { - this.Mask = Mask; - this.Value = Value; - this.Inst = Inst; - } - } - - private static TreeNode Root; - - private static void Set(string Encoding, AInstEmitter Emitter, Type Type) - { - Set(Encoding, new AInst(Emitter, Type)); - } - - private static void Set(string Encoding, AInst Inst) - { - int Bit = Encoding.Length - 1; - int Value = 0; - int XMask = 0; - int ZCount = 0; - int OCount = 0; - - int[] ZPos = new int[Encoding.Length]; - int[] OPos = new int[Encoding.Length]; - - for (int Index = 0; Index < Encoding.Length; Index++, Bit--) - { - //Note: < and > are used on special encodings. - //The < means that we should never have ALL bits with the '<' set. - //So, when the encoding has <<, it means that 00, 01, and 10 are valid, - //but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on... - //For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid, - //but 00 isn't. - switch (Encoding[Index]) - { - case '0': /* Do nothing. */ break; - case '1': Value |= 1 << Bit; break; - case 'x': XMask |= 1 << Bit; break; - - case '<': OPos[OCount++] = Bit; break; - case '>': ZPos[ZCount++] = Bit; break; - - default: throw new ArgumentException(nameof(Encoding)); - } - } - - if (ZCount + OCount == 0) - { - InsertTop(XMask, Value, Inst); - } - else if (ZCount != 0 && OCount != 0) - { - //When both the > and the < are used, then a value is blacklisted, - //with > indicating 0, and < indicating 1. So, for example, ><< - //blacklists the pattern 011, but 000, 001, 010, 100, 101, - //110 and 111 are valid. - for (int OCtr = 0; (uint)OCtr < (1 << OCount); OCtr++) - { - int OVal = Value; - - for (int O = 0; O < OCount; O++) - { - OVal |= ((OCtr >> O) & 1) << OPos[O]; - } - - int ZStart = OCtr == (1 << OCount) ? 1 : 0; - - InsertWithCtr(ZStart, 1 << ZCount, ZCount, ZPos, XMask, OVal, Inst); - } - } - else if (ZCount != 0) - { - InsertWithCtr(1, 1 << ZCount, ZCount, ZPos, XMask, Value, Inst); - } - else if (OCount != 0) - { - InsertWithCtr(0, (1 << OCount) - 1, OCount, OPos, XMask, Value, Inst); - } - } - - private static void InsertWithCtr( - int Start, - int End, - int Cnt, - int[] Pos, - int XMask, - int Value, - AInst Inst) - { - for (int Ctr = Start; (uint)Ctr < End; Ctr++) - { - int Val = Value; - - for (int Index = 0; Index < Cnt; Index++) - { - Val |= ((Ctr >> Index) & 1) << Pos[Index]; - } - - InsertTop(XMask, Val, Inst); - } - } - - private static void InsertTop(int XMask, int Value, AInst Inst) - { - TreeNode Next = Root; - - Root = new TreeNode(~XMask, Value, Inst); - - Root.Next = Next; - } - - public static AInst GetInst(int OpCode) - { - TreeNode Node = Root; - - do - { - if ((OpCode & Node.Mask) == Node.Value) - { - return Node.Inst; - } - } - while ((Node = Node.Next) != null); - - return AInst.Undefined; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/AOptimizations.cs b/Ryujinx/Cpu/AOptimizations.cs deleted file mode 100644 index cbfd1ce5..00000000 --- a/Ryujinx/Cpu/AOptimizations.cs +++ /dev/null @@ -1,4 +0,0 @@ -public static class AOptimizations -{ - -} \ No newline at end of file diff --git a/Ryujinx/Cpu/AThread.cs b/Ryujinx/Cpu/AThread.cs deleted file mode 100644 index 5c032289..00000000 --- a/Ryujinx/Cpu/AThread.cs +++ /dev/null @@ -1,72 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using System; -using System.Threading; - -namespace ChocolArm64 -{ - public class AThread - { - public AThreadState ThreadState { get; private set; } - public AMemory Memory { get; private set; } - - public long EntryPoint { get; private set; } - - private ATranslator Translator; - - private ThreadPriority Priority; - - private Thread Work; - - public event EventHandler WorkFinished; - - public int ThreadId => ThreadState.ThreadId; - - public bool IsAlive => Work.IsAlive; - - private bool IsExecuting; - - private object ExecuteLock; - - public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint) - { - this.Memory = Memory; - this.Priority = Priority; - this.EntryPoint = EntryPoint; - - ThreadState = new AThreadState(); - Translator = new ATranslator(this); - ExecuteLock = new object(); - } - - public void StopExecution() => Translator.StopExecution(); - - public bool Execute() - { - lock (ExecuteLock) - { - if (IsExecuting) - { - return false; - } - - IsExecuting = true; - } - - Work = new Thread(delegate() - { - Translator.ExecuteSubroutine(EntryPoint); - - Memory.RemoveMonitor(ThreadId); - - WorkFinished?.Invoke(this, EventArgs.Empty); - }); - - Work.Priority = Priority; - - Work.Start(); - - return true; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/ATranslatedSub.cs b/Ryujinx/Cpu/ATranslatedSub.cs deleted file mode 100644 index 71a6793a..00000000 --- a/Ryujinx/Cpu/ATranslatedSub.cs +++ /dev/null @@ -1,104 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64 -{ - class ATranslatedSub - { - private delegate long AA64Subroutine(AThreadState Register, AMemory Memory); - - private AA64Subroutine ExecDelegate; - - private bool HasDelegate; - - public static Type[] FixedArgTypes { get; private set; } - - public static int StateArgIdx { get; private set; } - public static int MemoryArgIdx { get; private set; } - - public DynamicMethod Method { get; private set; } - - public HashSet SubCalls { get; private set; } - - public List Params { get; private set; } - - public bool NeedsReJit { get; private set; } - - public ATranslatedSub() - { - SubCalls = new HashSet(); - } - - public ATranslatedSub(DynamicMethod Method, List Params) : this() - { - if (Params == null) - { - throw new ArgumentNullException(nameof(Params)); - } - - this.Method = Method; - this.Params = Params; - } - - static ATranslatedSub() - { - MethodInfo MthdInfo = typeof(AA64Subroutine).GetMethod("Invoke"); - - ParameterInfo[] Params = MthdInfo.GetParameters(); - - FixedArgTypes = new Type[Params.Length]; - - for (int Index = 0; Index < Params.Length; Index++) - { - Type ParamType = Params[Index].ParameterType; - - FixedArgTypes[Index] = ParamType; - - if (ParamType == typeof(AThreadState)) - { - StateArgIdx = Index; - } - else if (ParamType == typeof(AMemory)) - { - MemoryArgIdx = Index; - } - } - } - - public long Execute(AThreadState ThreadState, AMemory Memory) - { - if (!HasDelegate) - { - string Name = $"{Method.Name}_Dispatch"; - - DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes); - - ILGenerator Generator = Mthd.GetILGenerator(); - - Generator.EmitLdargSeq(FixedArgTypes.Length); - - foreach (ARegister Reg in Params) - { - Generator.EmitLdarg(StateArgIdx); - - Generator.Emit(OpCodes.Ldfld, Reg.GetField()); - } - - Generator.Emit(OpCodes.Call, Method); - Generator.Emit(OpCodes.Ret); - - ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine)); - - HasDelegate = true; - } - - return ExecDelegate(ThreadState, Memory); - } - - public void MarkForReJit() => NeedsReJit = true; - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/ATranslator.cs b/Ryujinx/Cpu/ATranslator.cs deleted file mode 100644 index 96bbc89e..00000000 --- a/Ryujinx/Cpu/ATranslator.cs +++ /dev/null @@ -1,106 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Instruction; -using ChocolArm64.Translation; -using System.Collections.Generic; -using System.Reflection.Emit; - -namespace ChocolArm64 -{ - class ATranslator - { - public AThread Thread { get; private set; } - - private Dictionary CachedSubs; - - private bool KeepRunning; - - public ATranslator(AThread Parent) - { - this.Thread = Parent; - - CachedSubs = new Dictionary(); - - KeepRunning = true; - } - - public void StopExecution() => KeepRunning = false; - - public void ExecuteSubroutine(long Position) - { - do - { - if (CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) && !Sub.NeedsReJit) - { - Position = Sub.Execute(Thread.ThreadState, Thread.Memory); - } - else - { - Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory); - } - } - while (Position != 0 && KeepRunning); - } - - public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) - { - if (OpCode.Emitter != AInstEmit.Bl) - { - Sub = null; - - return false; - } - - return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub); - } - - public bool TryGetCachedSub(long Position, out ATranslatedSub Sub) - { - return CachedSubs.TryGetValue(Position, out Sub); - } - - public bool HasCachedSub(long Position) - { - return CachedSubs.ContainsKey(Position); - } - - private ATranslatedSub TranslateSubroutine(long Position) - { - (ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Position); - - AILEmitterCtx Context = new AILEmitterCtx( - this, - Cfg.Graph, - Cfg.Root); - - if (Context.CurrBlock.Position != Position) - { - Context.Emit(OpCodes.Br, Context.GetLabel(Position)); - } - - do - { - Context.EmitOpCode(); - } - while (Context.AdvanceOpCode()); - - //Mark all methods that calls this method for ReJiting, - //since we can now call it directly which is faster. - foreach (ATranslatedSub TS in CachedSubs.Values) - { - if (TS.SubCalls.Contains(Position)) - { - TS.MarkForReJit(); - } - } - - ATranslatedSub Subroutine = Context.GetSubroutine(); - - if (!CachedSubs.TryAdd(Position, Subroutine)) - { - CachedSubs[Position] = Subroutine; - } - - return Subroutine; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/ABlock.cs b/Ryujinx/Cpu/Decoder/ABlock.cs deleted file mode 100644 index 32974c1a..00000000 --- a/Ryujinx/Cpu/Decoder/ABlock.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace ChocolArm64.Decoder -{ - class ABlock - { - public long Position { get; set; } - public long EndPosition { get; set; } - - public ABlock Next { get; set; } - public ABlock Branch { get; set; } - - public List OpCodes { get; private set; } - - public ABlock() - { - OpCodes = new List(); - } - - public ABlock(long Position) : this() - { - this.Position = Position; - } - - public AOpCode GetLastOp() - { - if (OpCodes.Count > 0) - { - return OpCodes[OpCodes.Count - 1]; - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/ACond.cs b/Ryujinx/Cpu/Decoder/ACond.cs deleted file mode 100644 index f2da8bd2..00000000 --- a/Ryujinx/Cpu/Decoder/ACond.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace ChocolArm64.Decoder -{ - enum ACond - { - Eq = 0, - Ne = 1, - Ge_Un = 2, - Lt_Un = 3, - Mi = 4, - Pl = 5, - Vs = 6, - Vc = 7, - Gt_Un = 8, - Le_Un = 9, - Ge = 10, - Lt = 11, - Gt = 12, - Le = 13, - Al = 14, - Nv = 15 - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/ADataOp.cs b/Ryujinx/Cpu/Decoder/ADataOp.cs deleted file mode 100644 index a5601a3a..00000000 --- a/Ryujinx/Cpu/Decoder/ADataOp.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.Decoder -{ - enum ADataOp - { - Adr = 0, - Arithmetic = 1, - Logical = 2, - BitField = 3 - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/ADecoder.cs b/Ryujinx/Cpu/Decoder/ADecoder.cs deleted file mode 100644 index 06a535c1..00000000 --- a/Ryujinx/Cpu/Decoder/ADecoder.cs +++ /dev/null @@ -1,207 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.Memory; -using System; -using System.Collections.Generic; -using System.Reflection.Emit; - -namespace ChocolArm64.Decoder -{ - static class ADecoder - { - public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start) - { - Dictionary Visited = new Dictionary(); - Dictionary VisitedEnd = new Dictionary(); - - Queue Blocks = new Queue(); - - ABlock Enqueue(long Position) - { - if (!Visited.TryGetValue(Position, out ABlock Output)) - { - Output = new ABlock(Position); - - Blocks.Enqueue(Output); - - Visited.Add(Position, Output); - } - - return Output; - } - - ABlock Root = Enqueue(Start); - - while (Blocks.Count > 0) - { - ABlock Current = Blocks.Dequeue(); - - FillBlock(Translator.Thread.Memory, Current); - - //Set child blocks. "Branch" is the block the branch instruction - //points to (when taken), "Next" is the block at the next address, - //executed when the branch is not taken. For Unconditional Branches - //(except BL/BLR that are sub calls) or end of executable, Next is null. - if (Current.OpCodes.Count > 0) - { - bool HasCachedSub = false; - - AOpCode LastOp = Current.GetLastOp(); - - if (LastOp is AOpCodeBImm Op) - { - if (Op.Emitter == AInstEmit.Bl) - { - HasCachedSub = Translator.HasCachedSub(Op.Imm); - } - else - { - Current.Branch = Enqueue(Op.Imm); - } - } - - if ((!(LastOp is AOpCodeBImmAl) && - !(LastOp is AOpCodeBReg)) || HasCachedSub) - { - Current.Next = Enqueue(Current.EndPosition); - } - } - - //If we have on the tree two blocks with the same end position, - //then we need to split the bigger block and have two small blocks, - //the end position of the bigger "Current" block should then be == to - //the position of the "Smaller" block. - while (VisitedEnd.TryGetValue(Current.EndPosition, out ABlock Smaller)) - { - if (Current.Position > Smaller.Position) - { - ABlock Temp = Smaller; - - Smaller = Current; - Current = Temp; - } - - Current.EndPosition = Smaller.Position; - Current.Next = Smaller; - Current.Branch = null; - - Current.OpCodes.RemoveRange( - Current.OpCodes.Count - Smaller.OpCodes.Count, - Smaller.OpCodes.Count); - - VisitedEnd[Smaller.EndPosition] = Smaller; - } - - VisitedEnd.Add(Current.EndPosition, Current); - } - - //Make and sort Graph blocks array by position. - ABlock[] Graph = new ABlock[Visited.Count]; - - while (Visited.Count > 0) - { - ulong FirstPos = ulong.MaxValue; - - foreach (ABlock Block in Visited.Values) - { - if (FirstPos > (ulong)Block.Position) - FirstPos = (ulong)Block.Position; - } - - ABlock Current = Visited[(long)FirstPos]; - - do - { - Graph[Graph.Length - Visited.Count] = Current; - - Visited.Remove(Current.Position); - - Current = Current.Next; - } - while (Current != null); - } - - return (Graph, Root); - } - - private static void FillBlock(AMemory Memory, ABlock Block) - { - long Position = Block.Position; - - AOpCode OpCode; - - do - { - OpCode = DecodeOpCode(Memory, Position); - - Block.OpCodes.Add(OpCode); - - Position += 4; - } - while (!(IsBranch(OpCode) || IsException(OpCode))); - - Block.EndPosition = Position; - } - - private static bool IsBranch(AOpCode OpCode) - { - return OpCode is AOpCodeBImm || - OpCode is AOpCodeBReg; - } - - private static bool IsException(AOpCode OpCode) - { - return OpCode.Emitter == AInstEmit.Brk || - OpCode.Emitter == AInstEmit.Svc || - OpCode.Emitter == AInstEmit.Und; - } - - public static AOpCode DecodeOpCode(AMemory Memory, long Position) - { - int OpCode = Memory.ReadInt32(Position); - - AInst Inst = AOpCodeTable.GetInst(OpCode); - - AOpCode DecodedOpCode = new AOpCode(AInst.Undefined, Position, OpCode); - - if (Inst.Type != null) - { - DecodedOpCode = CreateOpCode(Inst.Type, Inst, Position, OpCode); - } - - return DecodedOpCode; - } - - private delegate object OpActivator(AInst Inst, long Position, int OpCode); - - private static Dictionary Activators = new Dictionary(); - - private static AOpCode CreateOpCode(Type Type, AInst Inst, long Position, int OpCode) - { - if (Type == null) - { - throw new ArgumentNullException(nameof(Type)); - } - - if (!Activators.TryGetValue(Type, out OpActivator CreateInstance)) - { - Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) }; - - DynamicMethod Mthd = new DynamicMethod($"{Type.Name}_Create", Type, ArgTypes); - - ILGenerator Generator = Mthd.GetILGenerator(); - - Generator.Emit(OpCodes.Ldarg_0); - Generator.Emit(OpCodes.Ldarg_1); - Generator.Emit(OpCodes.Ldarg_2); - Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes)); - Generator.Emit(OpCodes.Ret); - - CreateInstance = (OpActivator)Mthd.CreateDelegate(typeof(OpActivator)); - - Activators.Add(Type, CreateInstance); - } - - return (AOpCode)CreateInstance(Inst, Position, OpCode); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/ADecoderHelper.cs b/Ryujinx/Cpu/Decoder/ADecoderHelper.cs deleted file mode 100644 index a2179f49..00000000 --- a/Ryujinx/Cpu/Decoder/ADecoderHelper.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; - -namespace ChocolArm64.Decoder -{ - static class ADecoderHelper - { - public struct BitMask - { - public long WMask; - public long TMask; - public int Pos; - public int Shift; - public bool IsUndefined; - - public static BitMask Invalid => new BitMask { IsUndefined = true }; - } - - public static BitMask DecodeBitMask(int OpCode, bool Immediate) - { - int ImmS = (OpCode >> 10) & 0x3f; - int ImmR = (OpCode >> 16) & 0x3f; - - int N = (OpCode >> 22) & 1; - int SF = (OpCode >> 31) & 1; - - int Length = ABitUtils.HighestBitSet32((~ImmS & 0x3f) | (N << 6)); - - if (Length < 1 || (SF == 0 && N != 0)) - { - return BitMask.Invalid; - } - - int Size = 1 << Length; - - int Levels = Size - 1; - - int S = ImmS & Levels; - int R = ImmR & Levels; - - if (Immediate && S == Levels) - { - return BitMask.Invalid; - } - - long WMask = ABitUtils.FillWithOnes(S + 1); - long TMask = ABitUtils.FillWithOnes(((S - R) & Levels) + 1); - - if (R > 0) - { - WMask = ABitUtils.RotateRight(WMask, R, Size); - WMask &= ABitUtils.FillWithOnes(Size); - } - - return new BitMask() - { - WMask = ABitUtils.Replicate(WMask, Size), - TMask = ABitUtils.Replicate(TMask, Size), - - Pos = ImmS, - Shift = ImmR - }; - } - - public static long DecodeImm8Float(long Imm, int Size) - { - int E = 0, F = 0; - - switch (Size) - { - case 0: E = 8; F = 23; break; - case 1: E = 11; F = 52; break; - - default: throw new ArgumentOutOfRangeException(nameof(Size)); - } - - long Value = (Imm & 0x3f) << F - 4; - - long EBit = (Imm >> 6) & 1; - long SBit = (Imm >> 7) & 1; - - if (EBit != 0) - { - Value |= (1L << E - 3) - 1 << F + 2; - } - - Value |= (EBit ^ 1) << F + E - 1; - Value |= SBit << F + E; - - return Value; - } - - public static long DecodeImm26_2(int OpCode) - { - return ((long)OpCode << 38) >> 36; - } - - public static long DecodeImmS19_2(int OpCode) - { - return (((long)OpCode << 40) >> 43) & ~3; - } - - public static long DecodeImmS14_2(int OpCode) - { - return (((long)OpCode << 45) >> 48) & ~3; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AIntType.cs b/Ryujinx/Cpu/Decoder/AIntType.cs deleted file mode 100644 index 242fdada..00000000 --- a/Ryujinx/Cpu/Decoder/AIntType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ChocolArm64.Decoder -{ - enum AIntType - { - UInt8 = 0, - UInt16 = 1, - UInt32 = 2, - UInt64 = 3, - Int8 = 4, - Int16 = 5, - Int32 = 6, - Int64 = 7 - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCode.cs b/Ryujinx/Cpu/Decoder/AOpCode.cs deleted file mode 100644 index 5d127593..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCode.cs +++ /dev/null @@ -1,38 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; -using System; - -namespace ChocolArm64.Decoder -{ - class AOpCode : IAOpCode - { - public long Position { get; private set; } - public int RawOpCode { get; private set; } - - public AInstEmitter Emitter { get; protected set; } - public ARegisterSize RegisterSize { get; protected set; } - - public AOpCode(AInst Inst, long Position, int OpCode) - { - this.Position = Position; - this.RawOpCode = OpCode; - - RegisterSize = ARegisterSize.Int64; - - Emitter = Inst.Emitter; - } - - public int GetBitsCount() - { - switch (RegisterSize) - { - case ARegisterSize.Int32: return 32; - case ARegisterSize.Int64: return 64; - case ARegisterSize.SIMD64: return 64; - case ARegisterSize.SIMD128: return 128; - } - - throw new InvalidOperationException(); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAdr.cs b/Ryujinx/Cpu/Decoder/AOpCodeAdr.cs deleted file mode 100644 index 3396281f..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeAdr.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeAdr : AOpCode - { - public int Rd { get; private set; } - public long Imm { get; private set; } - - public AOpCodeAdr(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rd = OpCode & 0x1f; - - Imm = ADecoderHelper.DecodeImmS19_2(OpCode); - Imm |= ((long)OpCode >> 29) & 3; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAlu.cs b/Ryujinx/Cpu/Decoder/AOpCodeAlu.cs deleted file mode 100644 index e1a44f04..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeAlu.cs +++ /dev/null @@ -1,24 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeAlu : AOpCode, IAOpCodeAlu - { - public int Rd { get; protected set; } - public int Rn { get; private set; } - - public ADataOp DataOp { get; private set; } - - public AOpCodeAlu(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rd = (OpCode >> 0) & 0x1f; - Rn = (OpCode >> 5) & 0x1f; - DataOp = (ADataOp)((OpCode >> 24) & 0x3); - - RegisterSize = (OpCode >> 31) != 0 - ? ARegisterSize.Int64 - : ARegisterSize.Int32; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs deleted file mode 100644 index e913475a..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeAluImm.cs +++ /dev/null @@ -1,39 +0,0 @@ -using ChocolArm64.Instruction; -using System; - -namespace ChocolArm64.Decoder -{ - class AOpCodeAluImm : AOpCodeAlu, IAOpCodeAluImm - { - public long Imm { get; private set; } - - public AOpCodeAluImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - if (DataOp == ADataOp.Arithmetic) - { - Imm = (OpCode >> 10) & 0xfff; - - int Shift = (OpCode >> 22) & 3; - - Imm <<= Shift * 12; - } - else if (DataOp == ADataOp.Logical) - { - var BM = ADecoderHelper.DecodeBitMask(OpCode, true); - - if (BM.IsUndefined) - { - Emitter = AInstEmit.Und; - - return; - } - - Imm = BM.WMask; - } - else - { - throw new ArgumentException(nameof(OpCode)); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs b/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs deleted file mode 100644 index 9c215be3..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeAluRs.cs +++ /dev/null @@ -1,29 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeAluRs : AOpCodeAlu, IAOpCodeAluRs - { - public int Shift { get; private set; } - public int Rm { get; private set; } - - public AShiftType ShiftType { get; private set; } - - public AOpCodeAluRs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Shift = (OpCode >> 10) & 0x3f; - - if (Shift >= GetBitsCount()) - { - Emitter = AInstEmit.Und; - - return; - } - - this.Shift = Shift; - - Rm = (OpCode >> 16) & 0x1f; - ShiftType = (AShiftType)((OpCode >> 22) & 0x3); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeAluRx.cs b/Ryujinx/Cpu/Decoder/AOpCodeAluRx.cs deleted file mode 100644 index 7dd72a68..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeAluRx.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeAluRx : AOpCodeAlu, IAOpCodeAluRx - { - public int Shift { get; private set; } - public int Rm { get; private set; } - - public AIntType IntType { get; private set; } - - public AOpCodeAluRx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Shift = (OpCode >> 10) & 0x7; - IntType = (AIntType)((OpCode >> 13) & 0x7); - Rm = (OpCode >> 16) & 0x1f; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeBImm.cs deleted file mode 100644 index 6519d281..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBImm.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBImm : AOpCode - { - public long Imm { get; protected set; } - - public AOpCodeBImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBImmAl.cs b/Ryujinx/Cpu/Decoder/AOpCodeBImmAl.cs deleted file mode 100644 index a4ff686d..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBImmAl.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBImmAl : AOpCodeBImm - { - public AOpCodeBImmAl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Imm = Position + ADecoderHelper.DecodeImm26_2(OpCode); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBImmCmp.cs b/Ryujinx/Cpu/Decoder/AOpCodeBImmCmp.cs deleted file mode 100644 index 1b6185da..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBImmCmp.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBImmCmp : AOpCodeBImm - { - public int Rt { get; private set; } - - public AOpCodeBImmCmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt = OpCode & 0x1f; - - Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBImmCond.cs b/Ryujinx/Cpu/Decoder/AOpCodeBImmCond.cs deleted file mode 100644 index 1310feb8..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBImmCond.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBImmCond : AOpCodeBImm, IAOpCodeCond - { - public ACond Cond { get; private set; } - - public AOpCodeBImmCond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int O0 = (OpCode >> 4) & 1; - - if (O0 != 0) - { - Emitter = AInstEmit.Und; - - return; - } - - Cond = (ACond)(OpCode & 0xf); - - Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBImmTest.cs b/Ryujinx/Cpu/Decoder/AOpCodeBImmTest.cs deleted file mode 100644 index 73e57b7a..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBImmTest.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBImmTest : AOpCodeBImm - { - public int Rt { get; private set; } - public int Pos { get; private set; } - - public AOpCodeBImmTest(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt = OpCode & 0x1f; - - Imm = Position + ADecoderHelper.DecodeImmS14_2(OpCode); - - Pos = (OpCode >> 19) & 0x1f; - Pos |= (OpCode >> 26) & 0x20; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBReg.cs b/Ryujinx/Cpu/Decoder/AOpCodeBReg.cs deleted file mode 100644 index c9c600af..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBReg.cs +++ /dev/null @@ -1,24 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBReg : AOpCode - { - public int Rn { get; private set; } - - public AOpCodeBReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Op4 = (OpCode >> 0) & 0x1f; - int Op2 = (OpCode >> 16) & 0x1f; - - if (Op2 != 0b11111 || Op4 != 0b00000) - { - Emitter = AInstEmit.Und; - - return; - } - - Rn = (OpCode >> 5) & 0x1f; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeBfm.cs b/Ryujinx/Cpu/Decoder/AOpCodeBfm.cs deleted file mode 100644 index 6498d8ec..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeBfm.cs +++ /dev/null @@ -1,29 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeBfm : AOpCodeAlu - { - public long WMask { get; private set; } - public long TMask { get; private set; } - public int Pos { get; private set; } - public int Shift { get; private set; } - - public AOpCodeBfm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - var BM = ADecoderHelper.DecodeBitMask(OpCode, false); - - if (BM.IsUndefined) - { - Emitter = AInstEmit.Und; - - return; - } - - WMask = BM.WMask; - TMask = BM.TMask; - Pos = BM.Pos; - Shift = BM.Shift; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeCcmp.cs b/Ryujinx/Cpu/Decoder/AOpCodeCcmp.cs deleted file mode 100644 index d0c7f779..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeCcmp.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeCcmp : AOpCodeAlu, IAOpCodeCond - { - public int NZCV { get; private set; } - protected int RmImm; - - public ACond Cond { get; private set; } - - public AOpCodeCcmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int O3 = (OpCode >> 4) & 1; - - if (O3 != 0) - { - Emitter = AInstEmit.Und; - - return; - } - - NZCV = (OpCode >> 0) & 0xf; - Cond = (ACond)((OpCode >> 12) & 0xf); - RmImm = (OpCode >> 16) & 0x1f; - - Rd = AThreadState.ZRIndex; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeCcmpImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeCcmpImm.cs deleted file mode 100644 index 803eefc2..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeCcmpImm.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeCcmpImm : AOpCodeCcmp, IAOpCodeAluImm - { - public long Imm => RmImm; - - public AOpCodeCcmpImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeCcmpReg.cs b/Ryujinx/Cpu/Decoder/AOpCodeCcmpReg.cs deleted file mode 100644 index c364ae68..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeCcmpReg.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeCcmpReg : AOpCodeCcmp, IAOpCodeAluRs - { - public int Rm => RmImm; - - public int Shift => 0; - - public AShiftType ShiftType => AShiftType.Lsl; - - public AOpCodeCcmpReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeCsel.cs b/Ryujinx/Cpu/Decoder/AOpCodeCsel.cs deleted file mode 100644 index cdef3e74..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeCsel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeCsel : AOpCodeAlu, IAOpCodeCond - { - public int Rm { get; private set; } - - public ACond Cond { get; private set; } - - public AOpCodeCsel(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rm = (OpCode >> 16) & 0x1f; - Cond = (ACond)((OpCode >> 12) & 0xf); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeException.cs b/Ryujinx/Cpu/Decoder/AOpCodeException.cs deleted file mode 100644 index 4579c1a7..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeException : AOpCode - { - public int Id { get; private set; } - - public AOpCodeException(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Id = (OpCode >> 5) & 0xffff; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMem.cs b/Ryujinx/Cpu/Decoder/AOpCodeMem.cs deleted file mode 100644 index be5367cf..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMem : AOpCode - { - public int Rt { get; protected set; } - public int Rn { get; protected set; } - public int Size { get; protected set; } - public bool Extend64 { get; protected set; } - - public AOpCodeMem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt = (OpCode >> 0) & 0x1f; - Rn = (OpCode >> 5) & 0x1f; - Size = (OpCode >> 30) & 0x3; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMemEx.cs b/Ryujinx/Cpu/Decoder/AOpCodeMemEx.cs deleted file mode 100644 index 3a28cfd7..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMemEx.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMemEx : AOpCodeMem - { - public int Rt2 { get; private set; } - public int Rs { get; private set; } - - public AOpCodeMemEx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt2 = (OpCode >> 10) & 0x1f; - Rs = (OpCode >> 16) & 0x1f; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMemImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeMemImm.cs deleted file mode 100644 index 14edc514..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMemImm.cs +++ /dev/null @@ -1,53 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMemImm : AOpCodeMem - { - public long Imm { get; protected set; } - public bool WBack { get; protected set; } - public bool PostIdx { get; protected set; } - protected bool Unscaled { get; private set; } - - private enum MemOp - { - Unscaled = 0, - PostIndexed = 1, - Unprivileged = 2, - PreIndexed = 3, - Unsigned - } - - public AOpCodeMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Extend64 = ((OpCode >> 22) & 3) == 2; - WBack = ((OpCode >> 24) & 1) == 0; - - //The type is not valid for the Unsigned Immediate 12-bits encoding, - //because the bits 11:10 are used for the larger Immediate offset. - MemOp Type = WBack ? (MemOp)((OpCode >> 10) & 3) : MemOp.Unsigned; - - PostIdx = Type == MemOp.PostIndexed; - Unscaled = Type == MemOp.Unscaled || - Type == MemOp.Unprivileged; - - //Unscaled and Unprivileged doesn't write back, - //but they do use the 9-bits Signed Immediate. - if (Unscaled) - { - WBack = false; - } - - if (WBack || Unscaled) - { - //9-bits Signed Immediate. - Imm = (OpCode << 43) >> 55; - } - else - { - //12-bits Unsigned Immediate. - Imm = ((OpCode >> 10) & 0xfff) << Size; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMemLit.cs b/Ryujinx/Cpu/Decoder/AOpCodeMemLit.cs deleted file mode 100644 index ad719a19..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMemLit.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMemLit : AOpCode, IAOpCodeLit - { - public int Rt { get; private set; } - public long Imm { get; private set; } - public int Size { get; private set; } - public bool Signed { get; private set; } - public bool Prefetch { get; private set; } - - public AOpCodeMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt = OpCode & 0x1f; - - Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); - - switch ((OpCode >> 30) & 3) - { - case 0: Size = 2; Signed = false; Prefetch = false; break; - case 1: Size = 3; Signed = false; Prefetch = false; break; - case 2: Size = 2; Signed = true; Prefetch = false; break; - case 3: Size = 0; Signed = false; Prefetch = true; break; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMemPair.cs b/Ryujinx/Cpu/Decoder/AOpCodeMemPair.cs deleted file mode 100644 index ec866c84..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMemPair.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMemPair : AOpCodeMemImm - { - public int Rt2 { get; private set; } - - public AOpCodeMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt2 = (OpCode >> 10) & 0x1f; - WBack = ((OpCode >> 23) & 0x1) != 0; - PostIdx = ((OpCode >> 23) & 0x3) == 1; - Extend64 = ((OpCode >> 30) & 0x3) == 1; - Size = ((OpCode >> 31) & 0x1) | 2; - - DecodeImm(OpCode); - } - - protected void DecodeImm(int OpCode) - { - Imm = ((long)(OpCode >> 15) << 57) >> (57 - Size); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMemReg.cs b/Ryujinx/Cpu/Decoder/AOpCodeMemReg.cs deleted file mode 100644 index 98927128..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMemReg.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMemReg : AOpCodeMem - { - public bool Shift { get; private set; } - public int Rm { get; private set; } - - public AIntType IntType { get; private set; } - - public AOpCodeMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Shift = ((OpCode >> 12) & 0x1) != 0; - IntType = (AIntType)((OpCode >> 13) & 0x7); - Rm = (OpCode >> 16) & 0x1f; - Extend64 = ((OpCode >> 22) & 0x3) == 2; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMov.cs b/Ryujinx/Cpu/Decoder/AOpCodeMov.cs deleted file mode 100644 index d5398646..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMov.cs +++ /dev/null @@ -1,36 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMov : AOpCode - { - public int Rd { get; private set; } - public long Imm { get; private set; } - public int Pos { get; private set; } - - public AOpCodeMov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int P1 = (OpCode >> 22) & 1; - int SF = (OpCode >> 31) & 1; - - if (SF == 0 && P1 != 0) - { - Emitter = AInstEmit.Und; - - return; - } - - Rd = (OpCode >> 0) & 0x1f; - Imm = (OpCode >> 5) & 0xffff; - Pos = (OpCode >> 21) & 0x3; - - Pos <<= 4; - Imm <<= Pos; - - RegisterSize = (OpCode >> 31) != 0 - ? ARegisterSize.Int64 - : ARegisterSize.Int32; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeMul.cs b/Ryujinx/Cpu/Decoder/AOpCodeMul.cs deleted file mode 100644 index ca2b0cdb..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeMul.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeMul : AOpCodeAlu - { - public int Rm { get; private set; } - public int Ra { get; private set; } - - public AOpCodeMul(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Ra = (OpCode >> 10) & 0x1f; - Rm = (OpCode >> 16) & 0x1f; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimd.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimd.cs deleted file mode 100644 index 5f940b22..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimd.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimd : AOpCode, IAOpCodeSimd - { - public int Rd { get; private set; } - public int Rn { get; private set; } - public int Opc { get; private set; } - public int Size { get; protected set; } - - public int SizeF => Size & 1; - - public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rd = (OpCode >> 0) & 0x1f; - Rn = (OpCode >> 5) & 0x1f; - Opc = (OpCode >> 15) & 0x3; - Size = (OpCode >> 22) & 0x3; - - RegisterSize = ((OpCode >> 30) & 1) != 0 - ? ARegisterSize.SIMD128 - : ARegisterSize.SIMD64; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdCvt.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdCvt.cs deleted file mode 100644 index 41f4d3b1..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdCvt.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdCvt : AOpCodeSimd - { - public int FBits { get; private set; } - - public AOpCodeSimdCvt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - //TODO: - //Und of Fixed Point variants. - int Scale = (OpCode >> 10) & 0x3f; - int SF = (OpCode >> 31) & 0x1; - - /*if (Type != SF && !(Type == 2 && SF == 1)) - { - Emitter = AInstEmit.Und; - - return; - }*/ - - FBits = 64 - Scale; - - RegisterSize = SF != 0 - ? ARegisterSize.Int64 - : ARegisterSize.Int32; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdFcond.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdFcond.cs deleted file mode 100644 index e38e7424..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdFcond.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdFcond : AOpCodeSimdReg, IAOpCodeCond - { - public int NZCV { get; private set; } - - public ACond Cond { get; private set; } - - public AOpCodeSimdFcond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - NZCV = (OpCode >> 0) & 0xf; - Cond = (ACond)((OpCode >> 12) & 0xf); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdFmov.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdFmov.cs deleted file mode 100644 index 3f888959..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdFmov.cs +++ /dev/null @@ -1,33 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdFmov : AOpCode, IAOpCodeSimd - { - public int Rd { get; private set; } - public long Imm { get; private set; } - public int Size { get; private set; } - - public AOpCodeSimdFmov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Imm5 = (OpCode >> 5) & 0x1f; - int Type = (OpCode >> 22) & 0x3; - - if (Imm5 != 0b00000 || Type > 1) - { - Emitter = AInstEmit.Und; - - return; - } - - Size = Type; - - long Imm; - - Rd = (OpCode >> 0) & 0x1f; - Imm = (OpCode >> 13) & 0xff; - - this.Imm = ADecoderHelper.DecodeImm8Float(Imm, Type); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdImm.cs deleted file mode 100644 index 2959aee6..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdImm.cs +++ /dev/null @@ -1,94 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdImm : AOpCode, IAOpCodeSimd - { - public int Rd { get; private set; } - public long Imm { get; private set; } - public int Size { get; private set; } - - public AOpCodeSimdImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rd = OpCode & 0x1f; - - int CMode = (OpCode >> 12) & 0xf; - int Op = (OpCode >> 29) & 0x1; - - int ModeLow = CMode & 1; - int ModeHigh = CMode >> 1; - - long Imm; - - Imm = ((uint)OpCode >> 5) & 0x1f; - Imm |= ((uint)OpCode >> 11) & 0xe0; - - if (ModeHigh == 0b111) - { - Size = ModeLow != 0 ? Op : 3; - - switch (Op | (ModeLow << 1)) - { - case 0: - //64-bits Immediate. - //Transform abcd efgh into abcd efgh abcd efgh ... - Imm = (long)((ulong)Imm * 0x0101010101010101); - break; - - case 1: - //64-bits Immediate. - //Transform abcd efgh into aaaa aaaa bbbb bbbb ... - Imm = (Imm & 0xf0) >> 4 | (Imm & 0x0f) << 4; - Imm = (Imm & 0xcc) >> 2 | (Imm & 0x33) << 2; - Imm = (Imm & 0xaa) >> 1 | (Imm & 0x55) << 1; - - Imm = (long)((ulong)Imm * 0x8040201008040201); - Imm = (long)((ulong)Imm & 0x8080808080808080); - - Imm |= Imm >> 4; - Imm |= Imm >> 2; - Imm |= Imm >> 1; - break; - - case 2: - case 3: - //Floating point Immediate. - Imm = ADecoderHelper.DecodeImm8Float(Imm, Size); - break; - } - } - else if ((ModeHigh & 0b110) == 0b100) - { - //16-bits shifted Immediate. - Size = 1; Imm <<= (ModeHigh & 1) << 3; - } - else if ((ModeHigh & 0b100) == 0b000) - { - //32-bits shifted Immediate. - Size = 2; Imm <<= ModeHigh << 3; - } - else if ((ModeHigh & 0b111) == 0b110) - { - //32-bits shifted Immediate (fill with ones). - Size = 2; Imm = ShlOnes(Imm, 8 << ModeLow); - } - else - { - //8 bits without shift. - Size = 0; - } - - this.Imm = Imm; - - RegisterSize = ((OpCode >> 30) & 1) != 0 - ? ARegisterSize.SIMD128 - : ARegisterSize.SIMD64; - } - - private static long ShlOnes(long Value, int Shift) - { - return Value << Shift | (long)(ulong.MaxValue >> (64 - Shift)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdIns.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdIns.cs deleted file mode 100644 index 0b60bbe8..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdIns.cs +++ /dev/null @@ -1,36 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdIns : AOpCodeSimd - { - public int SrcIndex { get; private set; } - public int DstIndex { get; private set; } - - public AOpCodeSimdIns(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Imm4 = (OpCode >> 11) & 0xf; - int Imm5 = (OpCode >> 16) & 0x1f; - - if (Imm5 == 0b10000) - { - Emitter = AInstEmit.Und; - - return; - } - - Size = Imm5 & -Imm5; - - switch (Size) - { - case 1: Size = 0; break; - case 2: Size = 1; break; - case 4: Size = 2; break; - case 8: Size = 3; break; - } - - SrcIndex = Imm4 >> Size; - DstIndex = Imm5 >> (Size + 1); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemImm.cs deleted file mode 100644 index 1ef19a5d..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemImm.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemImm : AOpCodeMemImm, IAOpCodeSimd - { - public AOpCodeSimdMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Size |= (OpCode >> 21) & 4; - - if (!WBack && !Unscaled && Size >= 4) - { - Imm <<= 4; - } - - Extend64 = false; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemLit.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemLit.cs deleted file mode 100644 index ea6fe00b..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemLit.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemLit : AOpCode, IAOpCodeSimd, IAOpCodeLit - { - public int Rt { get; private set; } - public long Imm { get; private set; } - public int Size { get; private set; } - public bool Signed => false; - public bool Prefetch => false; - - public AOpCodeSimdMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Opc = (OpCode >> 30) & 3; - - if (Opc == 3) - { - Emitter = AInstEmit.Und; - - return; - } - - Rt = OpCode & 0x1f; - - Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode); - - Size = Opc + 2; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs deleted file mode 100644 index 9ea979ba..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs +++ /dev/null @@ -1,49 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd - { - public int Reps { get; private set; } - public int SElems { get; private set; } - public int Elems { get; private set; } - public bool WBack { get; private set; } - - public AOpCodeSimdMemMs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - switch ((OpCode >> 12) & 0xf) - { - case 0b0000: Reps = 1; SElems = 4; break; - case 0b0010: Reps = 4; SElems = 1; break; - case 0b0100: Reps = 1; SElems = 3; break; - case 0b0110: Reps = 3; SElems = 1; break; - case 0b0111: Reps = 1; SElems = 1; break; - case 0b1000: Reps = 1; SElems = 2; break; - case 0b1010: Reps = 2; SElems = 1; break; - - default: Inst = AInst.Undefined; return; - } - - Size = (OpCode >> 10) & 0x3; - WBack = ((OpCode >> 23) & 0x1) != 0; - - bool Q = ((OpCode >> 30) & 1) != 0; - - if (!Q && Size == 3 && SElems != 1) - { - Inst = AInst.Undefined; - - return; - } - - Extend64 = false; - - RegisterSize = Q - ? ARegisterSize.SIMD128 - : ARegisterSize.SIMD64; - - Elems = (GetBitsCount() >> 3) >> Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemPair.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemPair.cs deleted file mode 100644 index db99e3d4..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemPair.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemPair : AOpCodeMemPair, IAOpCodeSimd - { - public AOpCodeSimdMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Size = ((OpCode >> 30) & 3) + 2; - - Extend64 = false; - - DecodeImm(OpCode); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemReg.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemReg.cs deleted file mode 100644 index aabf4846..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemReg.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemReg : AOpCodeMemReg, IAOpCodeSimd - { - public AOpCodeSimdMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Size |= (OpCode >> 21) & 4; - - Extend64 = false; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs deleted file mode 100644 index be4a8cd9..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs +++ /dev/null @@ -1,97 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd - { - public int SElems { get; private set; } - public int Index { get; private set; } - public bool Replicate { get; private set; } - public bool WBack { get; private set; } - - public AOpCodeSimdMemSs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - int Size = (OpCode >> 10) & 3; - int S = (OpCode >> 12) & 1; - int SElems = (OpCode >> 12) & 2; - int Scale = (OpCode >> 14) & 3; - int L = (OpCode >> 22) & 1; - int Q = (OpCode >> 30) & 1; - - SElems |= (OpCode >> 21) & 1; - - SElems++; - - int Index = (Q << 3) | (S << 2) | Size; - - switch (Scale) - { - case 1: - { - if ((Size & 1) != 0) - { - Inst = AInst.Undefined; - - return; - } - - Index >>= 1; - - break; - } - - case 2: - { - if ((Size & 2) != 0 || - ((Size & 1) != 0 && S != 0)) - { - Inst = AInst.Undefined; - - return; - } - - if ((Size & 1) != 0) - { - Index >>= 3; - - Scale = 3; - } - else - { - Index >>= 2; - } - - break; - } - - case 3: - { - if (L == 0 || S != 0) - { - Inst = AInst.Undefined; - - return; - } - - Scale = Size; - - Replicate = true; - - break; - } - } - - this.SElems = SElems; - this.Size = Scale; - - Extend64 = false; - - WBack = ((OpCode >> 23) & 0x1) != 0; - - RegisterSize = Q != 0 - ? ARegisterSize.SIMD128 - : ARegisterSize.SIMD64; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdReg.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdReg.cs deleted file mode 100644 index 10a4aff8..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdReg.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdReg : AOpCodeSimd - { - public bool Bit3 { get; private set; } - public int Ra { get; private set; } - public int Rm { get; private set; } - - public AOpCodeSimdReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Bit3 = ((OpCode >> 3) & 0x1) != 0; - Ra = (OpCode >> 10) & 0x1f; - Rm = (OpCode >> 16) & 0x1f; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdRegElem.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdRegElem.cs deleted file mode 100644 index d878b12e..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdRegElem.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdRegElem : AOpCodeSimdReg - { - public int Index { get; private set; } - - public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - if ((Size & 1) != 0) - { - Index = (OpCode >> 11) & 1; - } - else - { - Index = (OpCode >> 21) & 1 | - (OpCode >> 10) & 2; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdShImm.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdShImm.cs deleted file mode 100644 index 6c839881..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdShImm.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdShImm : AOpCodeSimd - { - public int Imm { get; private set; } - - public AOpCodeSimdShImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Imm = (OpCode >> 16) & 0x7f; - - Size = ABitUtils.HighestBitSet32(Imm >> 3); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdTbl.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdTbl.cs deleted file mode 100644 index c8ae5bac..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSimdTbl.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSimdTbl : AOpCodeSimdReg - { - public AOpCodeSimdTbl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Size = ((OpCode >> 13) & 3) + 1; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSystem.cs b/Ryujinx/Cpu/Decoder/AOpCodeSystem.cs deleted file mode 100644 index 3d81a5d4..00000000 --- a/Ryujinx/Cpu/Decoder/AOpCodeSystem.cs +++ /dev/null @@ -1,24 +0,0 @@ -using ChocolArm64.Instruction; - -namespace ChocolArm64.Decoder -{ - class AOpCodeSystem : AOpCode - { - public int Rt { get; private set; } - public int Op2 { get; private set; } - public int CRm { get; private set; } - public int CRn { get; private set; } - public int Op1 { get; private set; } - public int Op0 { get; private set; } - - public AOpCodeSystem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) - { - Rt = (OpCode >> 0) & 0x1f; - Op2 = (OpCode >> 5) & 0x7; - CRm = (OpCode >> 8) & 0xf; - CRn = (OpCode >> 12) & 0xf; - Op1 = (OpCode >> 16) & 0x7; - Op0 = ((OpCode >> 19) & 0x1) | 2; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/AShiftType.cs b/Ryujinx/Cpu/Decoder/AShiftType.cs deleted file mode 100644 index 34ceea20..00000000 --- a/Ryujinx/Cpu/Decoder/AShiftType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.Decoder -{ - enum AShiftType - { - Lsl, - Lsr, - Asr, - Ror - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCode.cs b/Ryujinx/Cpu/Decoder/IAOpCode.cs deleted file mode 100644 index 44bf9cb2..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCode.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ChocolArm64.Instruction; -using ChocolArm64.State; - -namespace ChocolArm64.Decoder -{ - interface IAOpCode - { - long Position { get; } - - AInstEmitter Emitter { get; } - ARegisterSize RegisterSize { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeAlu.cs b/Ryujinx/Cpu/Decoder/IAOpCodeAlu.cs deleted file mode 100644 index 22af4c82..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeAlu.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeAlu : IAOpCode - { - int Rd { get; } - int Rn { get; } - - ADataOp DataOp { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeAluImm.cs b/Ryujinx/Cpu/Decoder/IAOpCodeAluImm.cs deleted file mode 100644 index 04b5c5f7..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeAluImm.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeAluImm : IAOpCodeAlu - { - long Imm { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeAluRs.cs b/Ryujinx/Cpu/Decoder/IAOpCodeAluRs.cs deleted file mode 100644 index 5ca9de40..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeAluRs.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeAluRs : IAOpCodeAlu - { - int Shift { get; } - int Rm { get; } - - AShiftType ShiftType { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeAluRx.cs b/Ryujinx/Cpu/Decoder/IAOpCodeAluRx.cs deleted file mode 100644 index b49d5325..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeAluRx.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeAluRx : IAOpCodeAlu - { - int Shift { get; } - int Rm { get; } - - AIntType IntType { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeCond.cs b/Ryujinx/Cpu/Decoder/IAOpCodeCond.cs deleted file mode 100644 index 1655abaa..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeCond.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeCond : IAOpCode - { - ACond Cond { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeLit.cs b/Ryujinx/Cpu/Decoder/IAOpCodeLit.cs deleted file mode 100644 index 0f5092d0..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeLit.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeLit : IAOpCode - { - int Rt { get; } - long Imm { get; } - int Size { get; } - bool Signed { get; } - bool Prefetch { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Decoder/IAOpCodeSimd.cs b/Ryujinx/Cpu/Decoder/IAOpCodeSimd.cs deleted file mode 100644 index 19032ad9..00000000 --- a/Ryujinx/Cpu/Decoder/IAOpCodeSimd.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChocolArm64.Decoder -{ - interface IAOpCodeSimd : IAOpCode - { - int Size { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Exceptions/VmmAccessViolationException.cs b/Ryujinx/Cpu/Exceptions/VmmAccessViolationException.cs deleted file mode 100644 index a557502e..00000000 --- a/Ryujinx/Cpu/Exceptions/VmmAccessViolationException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChocolArm64.Memory; -using System; - -namespace ChocolArm64.Exceptions -{ - public class VmmAccessViolationException : Exception - { - private const string ExMsg = "Address 0x{0:x16} does not have \"{1}\" permission!"; - - public VmmAccessViolationException() { } - - public VmmAccessViolationException(long Position, AMemoryPerm Perm) : base(string.Format(ExMsg, Position, Perm)) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Exceptions/VmmOutOfMemoryException.cs b/Ryujinx/Cpu/Exceptions/VmmOutOfMemoryException.cs deleted file mode 100644 index c11384da..00000000 --- a/Ryujinx/Cpu/Exceptions/VmmOutOfMemoryException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace ChocolArm64.Exceptions -{ - public class VmmOutOfMemoryException : Exception - { - private const string ExMsg = "Failed to allocate {0} bytes of memory!"; - - public VmmOutOfMemoryException() { } - - public VmmOutOfMemoryException(long Size) : base(string.Format(ExMsg, Size)) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Exceptions/VmmPageFaultException.cs b/Ryujinx/Cpu/Exceptions/VmmPageFaultException.cs deleted file mode 100644 index d55c2c1c..00000000 --- a/Ryujinx/Cpu/Exceptions/VmmPageFaultException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace ChocolArm64.Exceptions -{ - public class VmmPageFaultException : Exception - { - private const string ExMsg = "Tried to access unmapped address 0x{0:x16}!"; - - public VmmPageFaultException() { } - - public VmmPageFaultException(long Position) : base(string.Format(ExMsg, Position)) { } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInst.cs b/Ryujinx/Cpu/Instruction/AInst.cs deleted file mode 100644 index cab597d6..00000000 --- a/Ryujinx/Cpu/Instruction/AInst.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace ChocolArm64.Instruction -{ - struct AInst - { - public AInstEmitter Emitter { get; private set; } - public Type Type { get; private set; } - - public static AInst Undefined => new AInst(AInstEmit.Und, null); - - public AInst(AInstEmitter Emitter, Type Type) - { - this.Emitter = Emitter; - this.Type = Type; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs b/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs deleted file mode 100644 index 72903f5b..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitAlu.cs +++ /dev/null @@ -1,364 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitAluHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Adc(AILEmitterCtx Context) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Add); - - Context.EmitLdflg((int)APState.CBit); - - Type[] MthdTypes = new Type[] { typeof(bool) }; - - MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); - - Context.EmitCall(MthdInfo); - - if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_I8); - } - - Context.Emit(OpCodes.Add); - - EmitDataStore(Context); - } - - public static void Add(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Add); - - public static void Adds(AILEmitterCtx Context) - { - Context.TryOptMarkCondWithoutCmp(); - - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Add); - - Context.EmitZNFlagCheck(); - - EmitAddsCCheck(Context); - EmitAddsVCheck(Context); - EmitDataStoreS(Context); - } - - public static void And(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.And); - - public static void Ands(AILEmitterCtx Context) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.And); - - EmitZeroCVFlags(Context); - - Context.EmitZNFlagCheck(); - - EmitDataStoreS(Context); - } - - public static void Asrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr); - - public static void Bic(AILEmitterCtx Context) => EmitBic(Context, false); - public static void Bics(AILEmitterCtx Context) => EmitBic(Context, true); - - private static void EmitBic(AILEmitterCtx Context, bool SetFlags) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - - if (SetFlags) - { - EmitZeroCVFlags(Context); - - Context.EmitZNFlagCheck(); - } - - EmitDataStore(Context, SetFlags); - } - - public static void Clz(AILEmitterCtx Context) - { - AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - if (Op.RegisterSize == ARegisterSize.Int32) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros32)); - } - else - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros64)); - } - - Context.EmitStintzr(Op.Rd); - } - - public static void Eon(AILEmitterCtx Context) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.Xor); - - EmitDataStore(Context); - } - - public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor); - - public static void Extr(AILEmitterCtx Context) - { - //TODO: Ensure that the Shift is valid for the Is64Bits. - AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp; - - Context.EmitLdintzr(Op.Rm); - - if (Op.Shift > 0) - { - Context.EmitLdc_I4(Op.Shift); - - Context.Emit(OpCodes.Shr_Un); - - Context.EmitLdintzr(Op.Rn); - Context.EmitLdc_I4(Op.GetBitsCount() - Op.Shift); - - Context.Emit(OpCodes.Shl); - Context.Emit(OpCodes.Or); - } - - EmitDataStore(Context); - } - - public static void Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl); - public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un); - - public static void Sbc(AILEmitterCtx Context) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Sub); - - Context.EmitLdflg((int)APState.CBit); - - Type[] MthdTypes = new Type[] { typeof(bool) }; - - MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); - - Context.EmitCall(MthdInfo); - - Context.EmitLdc_I4(1); - - Context.Emit(OpCodes.Xor); - - if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_I8); - } - - Context.Emit(OpCodes.Sub); - - EmitDataStore(Context); - } - - public static void Sub(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Sub); - - public static void Subs(AILEmitterCtx Context) - { - Context.TryOptMarkCondWithoutCmp(); - - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Sub); - - Context.EmitZNFlagCheck(); - - EmitSubsCCheck(Context); - EmitSubsVCheck(Context); - EmitDataStoreS(Context); - } - - public static void Orn(AILEmitterCtx Context) - { - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.Or); - - EmitDataStore(Context); - } - - public static void Orr(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Or); - - public static void Rbit(AILEmitterCtx Context) => EmitFallback32_64(Context, - nameof(ASoftFallback.ReverseBits32), - nameof(ASoftFallback.ReverseBits64)); - - public static void Rev16(AILEmitterCtx Context) => EmitFallback32_64(Context, - nameof(ASoftFallback.ReverseBytes16_32), - nameof(ASoftFallback.ReverseBytes16_64)); - - public static void Rev32(AILEmitterCtx Context) => EmitFallback32_64(Context, - nameof(ASoftFallback.ReverseBytes32_32), - nameof(ASoftFallback.ReverseBytes32_64)); - - public static void EmitFallback32_64(AILEmitterCtx Context, string Name32, string Name64) - { - AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - if (Op.RegisterSize == ARegisterSize.Int32) - { - ASoftFallback.EmitCall(Context, Name32); - } - else - { - ASoftFallback.EmitCall(Context, Name64); - } - - Context.EmitStintzr(Op.Rd); - } - - public static void Rev64(AILEmitterCtx Context) - { - AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBytes64)); - - Context.EmitStintzr(Op.Rd); - } - - public static void Rorv(AILEmitterCtx Context) - { - EmitDataLoadRn(Context); - EmitDataLoadShift(Context); - - Context.Emit(OpCodes.Shr_Un); - - EmitDataLoadRn(Context); - - Context.EmitLdc_I4(Context.CurrOp.GetBitsCount()); - - EmitDataLoadShift(Context); - - Context.Emit(OpCodes.Sub); - Context.Emit(OpCodes.Shl); - Context.Emit(OpCodes.Or); - - EmitDataStore(Context); - } - - public static void Sdiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div); - public static void Udiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div_Un); - - private static void EmitDiv(AILEmitterCtx Context, OpCode ILOp) - { - //If Rm == 0, Rd = 0 (division by zero). - Context.EmitLdc_I(0); - - EmitDataLoadRm(Context); - - Context.EmitLdc_I(0); - - AILLabel BadDiv = new AILLabel(); - - Context.Emit(OpCodes.Beq_S, BadDiv); - Context.Emit(OpCodes.Pop); - - if (ILOp == OpCodes.Div) - { - //If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). - long IntMin = 1L << (Context.CurrOp.GetBitsCount() - 1); - - Context.EmitLdc_I(IntMin); - - EmitDataLoadRn(Context); - - Context.EmitLdc_I(IntMin); - - Context.Emit(OpCodes.Ceq); - - EmitDataLoadRm(Context); - - Context.EmitLdc_I(-1); - - Context.Emit(OpCodes.Ceq); - Context.Emit(OpCodes.And); - Context.Emit(OpCodes.Brtrue_S, BadDiv); - Context.Emit(OpCodes.Pop); - } - - EmitDataLoadRn(Context); - EmitDataLoadRm(Context); - - Context.Emit(ILOp); - - Context.MarkLabel(BadDiv); - - EmitDataStore(Context); - } - - private static void EmitDataOp(AILEmitterCtx Context, OpCode ILOp) - { - EmitDataLoadOpers(Context); - - Context.Emit(ILOp); - - EmitDataStore(Context); - } - - private static void EmitDataOpShift(AILEmitterCtx Context, OpCode ILOp) - { - EmitDataLoadRn(Context); - EmitDataLoadShift(Context); - - Context.Emit(ILOp); - - EmitDataStore(Context); - } - - private static void EmitDataLoadShift(AILEmitterCtx Context) - { - EmitDataLoadRm(Context); - - Context.EmitLdc_I(Context.CurrOp.GetBitsCount() - 1); - - Context.Emit(OpCodes.And); - - //Note: Only 32-bits shift values are valid, so when the value is 64-bits - //we need to cast it to a 32-bits integer. This is fine because we - //AND the value and only keep the lower 5 or 6 bits anyway -- it - //could very well fit on a byte. - if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_I4); - } - } - - private static void EmitZeroCVFlags(AILEmitterCtx Context) - { - Context.EmitLdc_I4(0); - - Context.EmitStflg((int)APState.VBit); - - Context.EmitLdc_I4(0); - - Context.EmitStflg((int)APState.CBit); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs deleted file mode 100644 index e848742d..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitAluHelper.cs +++ /dev/null @@ -1,168 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static class AInstEmitAluHelper - { - public static void EmitAddsCCheck(AILEmitterCtx Context) - { - //C = Rd < Rn - Context.Emit(OpCodes.Dup); - - EmitDataLoadRn(Context); - - Context.Emit(OpCodes.Clt_Un); - - Context.EmitStflg((int)APState.CBit); - } - - public static void EmitAddsVCheck(AILEmitterCtx Context) - { - //V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 - Context.Emit(OpCodes.Dup); - - EmitDataLoadRn(Context); - - Context.Emit(OpCodes.Xor); - - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Xor); - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - - Context.EmitLdc_I(0); - - Context.Emit(OpCodes.Clt); - - Context.EmitStflg((int)APState.VBit); - } - - public static void EmitSubsCCheck(AILEmitterCtx Context) - { - //C = Rn == Rm || Rn > Rm = !(Rn < Rm) - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Clt_Un); - - Context.EmitLdc_I4(1); - - Context.Emit(OpCodes.Xor); - - Context.EmitStflg((int)APState.CBit); - } - - public static void EmitSubsVCheck(AILEmitterCtx Context) - { - //V = (Rd ^ Rn) & (Rn ^ Rm) < 0 - Context.Emit(OpCodes.Dup); - - EmitDataLoadRn(Context); - - Context.Emit(OpCodes.Xor); - - EmitDataLoadOpers(Context); - - Context.Emit(OpCodes.Xor); - Context.Emit(OpCodes.And); - - Context.EmitLdc_I(0); - - Context.Emit(OpCodes.Clt); - - Context.EmitStflg((int)APState.VBit); - } - - public static void EmitDataLoadRm(AILEmitterCtx Context) - { - Context.EmitLdintzr(((IAOpCodeAluRs)Context.CurrOp).Rm); - } - - public static void EmitDataLoadOpers(AILEmitterCtx Context) - { - EmitDataLoadRn(Context); - EmitDataLoadOper2(Context); - } - - public static void EmitDataLoadRn(AILEmitterCtx Context) - { - IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp; - - if (Op.DataOp == ADataOp.Logical || Op is IAOpCodeAluRs) - { - Context.EmitLdintzr(Op.Rn); - } - else - { - Context.EmitLdint(Op.Rn); - } - } - - public static void EmitDataLoadOper2(AILEmitterCtx Context) - { - switch (Context.CurrOp) - { - case IAOpCodeAluImm Op: - Context.EmitLdc_I(Op.Imm); - break; - - case IAOpCodeAluRs Op: - Context.EmitLdintzr(Op.Rm); - - switch (Op.ShiftType) - { - case AShiftType.Lsl: Context.EmitLsl(Op.Shift); break; - case AShiftType.Lsr: Context.EmitLsr(Op.Shift); break; - case AShiftType.Asr: Context.EmitAsr(Op.Shift); break; - case AShiftType.Ror: Context.EmitRor(Op.Shift); break; - } - break; - - case IAOpCodeAluRx Op: - Context.EmitLdintzr(Op.Rm); - Context.EmitCast(Op.IntType); - Context.EmitLsl(Op.Shift); - break; - } - } - - public static void EmitDataStore(AILEmitterCtx Context) => EmitDataStore(Context, false); - public static void EmitDataStoreS(AILEmitterCtx Context) => EmitDataStore(Context, true); - - public static void EmitDataStore(AILEmitterCtx Context, bool SetFlags) - { - IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp; - - if (SetFlags || Op is IAOpCodeAluRs) - { - Context.EmitStintzr(Op.Rd); - } - else - { - Context.EmitStint(Op.Rd); - } - } - - public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV) - { - Context.EmitLdc_I4((NZCV >> 0) & 1); - - Context.EmitStflg((int)APState.VBit); - - Context.EmitLdc_I4((NZCV >> 1) & 1); - - Context.EmitStflg((int)APState.CBit); - - Context.EmitLdc_I4((NZCV >> 2) & 1); - - Context.EmitStflg((int)APState.ZBit); - - Context.EmitLdc_I4((NZCV >> 3) & 1); - - Context.EmitStflg((int)APState.NBit); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs b/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs deleted file mode 100644 index 823af738..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitBfm.cs +++ /dev/null @@ -1,217 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Bfm(AILEmitterCtx Context) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - EmitBfmLoadRn(Context); - - Context.EmitLdintzr(Op.Rd); - Context.EmitLdc_I(~Op.WMask & Op.TMask); - - Context.Emit(OpCodes.And); - Context.Emit(OpCodes.Or); - - Context.EmitLdintzr(Op.Rd); - Context.EmitLdc_I(~Op.TMask); - - Context.Emit(OpCodes.And); - Context.Emit(OpCodes.Or); - - Context.EmitStintzr(Op.Rd); - } - - public static void Sbfm(AILEmitterCtx Context) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - int BitsCount = Op.GetBitsCount(); - - if (Op.Pos + 1 == BitsCount) - { - EmitSbfmShift(Context); - } - else if (Op.Pos < Op.Shift) - { - EmitSbfiz(Context); - } - else if (Op.Pos == 7 && Op.Shift == 0) - { - EmitSbfmCast(Context, OpCodes.Conv_I1); - } - else if (Op.Pos == 15 && Op.Shift == 0) - { - EmitSbfmCast(Context, OpCodes.Conv_I2); - } - else if (Op.Pos == 31 && Op.Shift == 0) - { - EmitSbfmCast(Context, OpCodes.Conv_I4); - } - else if (Op.Shift == 0) - { - Context.EmitLdintzr(Op.Rn); - - Context.EmitLsl(BitsCount - 1 - Op.Pos); - Context.EmitAsr(BitsCount - 1); - - Context.EmitStintzr(Op.Rd); - } - else - { - EmitBfmLoadRn(Context); - - Context.EmitLdintzr(Op.Rn); - - Context.EmitLsl(BitsCount - 1 - Op.Pos); - Context.EmitAsr(BitsCount - 1); - - Context.EmitLdc_I(~Op.TMask); - - Context.Emit(OpCodes.And); - Context.Emit(OpCodes.Or); - - Context.EmitStintzr(Op.Rd); - } - } - - public static void Ubfm(AILEmitterCtx Context) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - if (Op.Pos + 1 == Op.GetBitsCount()) - { - EmitUbfmShift(Context); - } - else if (Op.Pos < Op.Shift) - { - EmitUbfiz(Context); - } - else if (Op.Pos + 1 == Op.Shift) - { - EmitBfmLsl(Context); - } - else if (Op.Pos == 7 && Op.Shift == 0) - { - EmitUbfmCast(Context, OpCodes.Conv_U1); - } - else if (Op.Pos == 15 && Op.Shift == 0) - { - EmitUbfmCast(Context, OpCodes.Conv_U2); - } - else - { - EmitBfmLoadRn(Context); - - Context.EmitStintzr(Op.Rd); - } - } - - private static void EmitSbfiz(AILEmitterCtx Context) => EmitBfiz(Context, true); - private static void EmitUbfiz(AILEmitterCtx Context) => EmitBfiz(Context, false); - - private static void EmitBfiz(AILEmitterCtx Context, bool Signed) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - int Width = Op.Pos + 1; - - Context.EmitLdintzr(Op.Rn); - - Context.EmitLsl(Op.GetBitsCount() - Width); - - if (Signed) - { - Context.EmitAsr(Op.Shift - Width); - } - else - { - Context.EmitLsr(Op.Shift - Width); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitSbfmCast(AILEmitterCtx Context, OpCode ILOp) - { - EmitBfmCast(Context, ILOp, true); - } - - private static void EmitUbfmCast(AILEmitterCtx Context, OpCode ILOp) - { - EmitBfmCast(Context, ILOp, false); - } - - private static void EmitBfmCast(AILEmitterCtx Context, OpCode ILOp, bool Signed) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - Context.Emit(ILOp); - - if (Op.RegisterSize != ARegisterSize.Int32) - { - Context.Emit(Signed - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitSbfmShift(AILEmitterCtx Context) - { - EmitBfmShift(Context, true); - } - - private static void EmitUbfmShift(AILEmitterCtx Context) - { - EmitBfmShift(Context, false); - } - - private static void EmitBfmShift(AILEmitterCtx Context, bool Signed) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - Context.EmitLdc_I4(Op.Shift); - - Context.Emit(Signed - ? OpCodes.Shr - : OpCodes.Shr_Un); - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitBfmLsl(AILEmitterCtx Context) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - Context.EmitLsl(Op.GetBitsCount() - Op.Shift); - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitBfmLoadRn(AILEmitterCtx Context) - { - AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - Context.EmitRor(Op.Shift); - - Context.EmitLdc_I(Op.WMask & Op.TMask); - - Context.Emit(OpCodes.And); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitCcmp.cs b/Ryujinx/Cpu/Instruction/AInstEmitCcmp.cs deleted file mode 100644 index 7153a6a0..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitCcmp.cs +++ /dev/null @@ -1,81 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitAluHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - private enum CcmpOp - { - Cmp, - Cmn - } - - public static void Ccmn(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmn); - public static void Ccmp(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmp); - - private static void EmitCcmp(AILEmitterCtx Context, CcmpOp CmpOp) - { - AOpCodeCcmp Op = (AOpCodeCcmp)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - - Context.EmitLdc_I4((Op.NZCV >> 0) & 1); - - Context.EmitStflg((int)APState.VBit); - - Context.EmitLdc_I4((Op.NZCV >> 1) & 1); - - Context.EmitStflg((int)APState.CBit); - - Context.EmitLdc_I4((Op.NZCV >> 2) & 1); - - Context.EmitStflg((int)APState.ZBit); - - Context.EmitLdc_I4((Op.NZCV >> 3) & 1); - - Context.EmitStflg((int)APState.NBit); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - EmitDataLoadOpers(Context); - - if (CmpOp == CcmpOp.Cmp) - { - Context.Emit(OpCodes.Sub); - - Context.EmitZNFlagCheck(); - - EmitSubsCCheck(Context); - EmitSubsVCheck(Context); - } - else if (CmpOp == CcmpOp.Cmn) - { - Context.Emit(OpCodes.Add); - - Context.EmitZNFlagCheck(); - - EmitAddsCCheck(Context); - EmitAddsVCheck(Context); - } - else - { - throw new ArgumentException(nameof(CmpOp)); - } - - Context.Emit(OpCodes.Pop); - - Context.MarkLabel(LblEnd); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitCsel.cs b/Ryujinx/Cpu/Instruction/AInstEmitCsel.cs deleted file mode 100644 index 33080980..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitCsel.cs +++ /dev/null @@ -1,59 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - private enum CselOperation - { - None, - Increment, - Invert, - Negate - } - - public static void Csel(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.None); - public static void Csinc(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Increment); - public static void Csinv(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Invert); - public static void Csneg(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Negate); - - private static void EmitCsel(AILEmitterCtx Context, CselOperation CselOp) - { - AOpCodeCsel Op = (AOpCodeCsel)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - Context.EmitLdintzr(Op.Rm); - - if (CselOp == CselOperation.Increment) - { - Context.EmitLdc_I(1); - - Context.Emit(OpCodes.Add); - } - else if (CselOp == CselOperation.Invert) - { - Context.Emit(OpCodes.Not); - } - else if (CselOp == CselOperation.Negate) - { - Context.Emit(OpCodes.Neg); - } - - Context.EmitStintzr(Op.Rd); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - Context.EmitLdintzr(Op.Rn); - Context.EmitStintzr(Op.Rd); - - Context.MarkLabel(LblEnd); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitException.cs b/Ryujinx/Cpu/Instruction/AInstEmitException.cs deleted file mode 100644 index 209ba56f..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitException.cs +++ /dev/null @@ -1,65 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - private const BindingFlags Binding = BindingFlags.NonPublic | BindingFlags.Instance; - - public static void Brk(AILEmitterCtx Context) - { - EmitExceptionCall(Context, nameof(AThreadState.OnBreak)); - } - - public static void Svc(AILEmitterCtx Context) - { - EmitExceptionCall(Context, nameof(AThreadState.OnSvcCall)); - } - - private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName) - { - AOpCodeException Op = (AOpCodeException)Context.CurrOp; - - Context.EmitStoreState(); - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - - Context.EmitLdc_I4(Op.Id); - - MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); - - Context.EmitCall(MthdInfo); - - if (Context.CurrBlock.Next != null) - { - Context.EmitLoadState(Context.CurrBlock.Next); - } - } - - public static void Und(AILEmitterCtx Context) - { - AOpCode Op = Context.CurrOp; - - Context.EmitStoreState(); - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - - Context.EmitLdc_I8(Op.Position); - Context.EmitLdc_I4(Op.RawOpCode); - - string MthdName = nameof(AThreadState.OnUndefined); - - MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); - - Context.EmitCall(MthdInfo); - - if (Context.CurrBlock.Next != null) - { - Context.EmitLoadState(Context.CurrBlock.Next); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitFlow.cs b/Ryujinx/Cpu/Instruction/AInstEmitFlow.cs deleted file mode 100644 index be68aa6c..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitFlow.cs +++ /dev/null @@ -1,124 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void B(AILEmitterCtx Context) - { - AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; - - Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm)); - } - - public static void B_Cond(AILEmitterCtx Context) - { - AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp; - - Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond); - } - - public static void Bl(AILEmitterCtx Context) - { - AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; - - Context.EmitLdc_I(Op.Position + 4); - Context.EmitStint(AThreadState.LRIndex); - Context.EmitStoreState(); - - if (Context.TryOptEmitSubroutineCall()) - { - //Note: the return value of the called method will be placed - //at the Stack, the return value is always a Int64 with the - //return address of the function. We check if the address is - //correct, if it isn't we keep returning until we reach the dispatcher. - Context.Emit(OpCodes.Dup); - - Context.EmitLdc_I8(Op.Position + 4); - - AILLabel LblContinue = new AILLabel(); - - Context.Emit(OpCodes.Beq_S, LblContinue); - Context.Emit(OpCodes.Ret); - - Context.MarkLabel(LblContinue); - - Context.Emit(OpCodes.Pop); - - if (Context.CurrBlock.Next != null) - { - Context.EmitLoadState(Context.CurrBlock.Next); - } - } - else - { - Context.EmitLdc_I8(Op.Imm); - - Context.Emit(OpCodes.Ret); - } - } - - public static void Blr(AILEmitterCtx Context) - { - AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp; - - Context.EmitLdc_I(Op.Position + 4); - Context.EmitStint(AThreadState.LRIndex); - Context.EmitStoreState(); - Context.EmitLdintzr(Op.Rn); - - Context.Emit(OpCodes.Ret); - } - - public static void Br(AILEmitterCtx Context) - { - AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp; - - Context.EmitStoreState(); - Context.EmitLdintzr(Op.Rn); - - Context.Emit(OpCodes.Ret); - } - - public static void Cbnz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Bne_Un); - public static void Cbz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Beq); - - private static void EmitCb(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeBImmCmp Op = (AOpCodeBImmCmp)Context.CurrOp; - - Context.EmitLdintzr(Op.Rt); - Context.EmitLdc_I(0); - - Context.Emit(ILOp, Context.GetLabel(Op.Imm)); - } - - public static void Ret(AILEmitterCtx Context) - { - Context.EmitStoreState(); - Context.EmitLdint(AThreadState.LRIndex); - - Context.Emit(OpCodes.Ret); - } - - public static void Tbnz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Bne_Un); - public static void Tbz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Beq); - - private static void EmitTb(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeBImmTest Op = (AOpCodeBImmTest)Context.CurrOp; - - Context.EmitLdintzr(Op.Rt); - Context.EmitLdc_I(1L << Op.Pos); - - Context.Emit(OpCodes.And); - - Context.EmitLdc_I(0); - - Context.Emit(ILOp, Context.GetLabel(Op.Imm)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs deleted file mode 100644 index af7de3ba..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs +++ /dev/null @@ -1,252 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitMemoryHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Adr(AILEmitterCtx Context) - { - AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; - - Context.EmitLdc_I(Op.Position + Op.Imm); - Context.EmitStintzr(Op.Rd); - } - - public static void Adrp(AILEmitterCtx Context) - { - AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; - - Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12)); - Context.EmitStintzr(Op.Rd); - } - - public static void Ldr(AILEmitterCtx Context) => EmitLdr(Context, false); - public static void Ldrs(AILEmitterCtx Context) => EmitLdr(Context, true); - - public static void EmitLdr(AILEmitterCtx Context, bool Signed) - { - AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - - EmitLoadAddress(Context); - - if (Signed && Op.Extend64) - { - EmitReadSx64Call(Context, Op.Size); - } - else if (Signed) - { - EmitReadSx32Call(Context, Op.Size); - } - else - { - EmitReadZxCall(Context, Op.Size); - } - - if (Op is IAOpCodeSimd) - { - Context.EmitStvec(Op.Rt); - } - else - { - Context.EmitStintzr(Op.Rt); - } - - EmitWBackIfNeeded(Context); - } - - public static void LdrLit(AILEmitterCtx Context) - { - IAOpCodeLit Op = (IAOpCodeLit)Context.CurrOp; - - if (Op.Prefetch) - { - return; - } - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdc_I8(Op.Imm); - - if (Op.Signed) - { - EmitReadSx64Call(Context, Op.Size); - } - else - { - EmitReadZxCall(Context, Op.Size); - } - - if (Op is IAOpCodeSimd) - { - Context.EmitStvec(Op.Rt); - } - else - { - Context.EmitStint(Op.Rt); - } - } - - public static void Ldp(AILEmitterCtx Context) - { - AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; - - void EmitReadAndStore(int Rt) - { - if (Op.Extend64) - { - EmitReadSx64Call(Context, Op.Size); - } - else - { - EmitReadZxCall(Context, Op.Size); - } - - if (Op is IAOpCodeSimd) - { - Context.EmitStvec(Rt); - } - else - { - Context.EmitStintzr(Rt); - } - } - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - - EmitLoadAddress(Context); - - EmitReadAndStore(Op.Rt); - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdtmp(); - Context.EmitLdc_I8(1 << Op.Size); - - Context.Emit(OpCodes.Add); - - EmitReadAndStore(Op.Rt2); - - EmitWBackIfNeeded(Context); - } - - public static void Str(AILEmitterCtx Context) - { - AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - - EmitLoadAddress(Context); - - if (Op is IAOpCodeSimd) - { - Context.EmitLdvec(Op.Rt); - } - else - { - Context.EmitLdintzr(Op.Rt); - } - - EmitWriteCall(Context, Op.Size); - - EmitWBackIfNeeded(Context); - } - - public static void Stp(AILEmitterCtx Context) - { - AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - - EmitLoadAddress(Context); - - if (Op is IAOpCodeSimd) - { - Context.EmitLdvec(Op.Rt); - } - else - { - Context.EmitLdintzr(Op.Rt); - } - - EmitWriteCall(Context, Op.Size); - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdtmp(); - Context.EmitLdc_I8(1 << Op.Size); - - Context.Emit(OpCodes.Add); - - if (Op is IAOpCodeSimd) - { - Context.EmitLdvec(Op.Rt2); - } - else - { - Context.EmitLdintzr(Op.Rt2); - } - - EmitWriteCall(Context, Op.Size); - - EmitWBackIfNeeded(Context); - } - - private static void EmitLoadAddress(AILEmitterCtx Context) - { - switch (Context.CurrOp) - { - case AOpCodeMemImm Op: - Context.EmitLdint(Op.Rn); - - if (!Op.PostIdx) - { - //Pre-indexing. - Context.EmitLdc_I(Op.Imm); - - Context.Emit(OpCodes.Add); - } - break; - - case AOpCodeMemReg Op: - Context.EmitLdint(Op.Rn); - Context.EmitLdintzr(Op.Rm); - Context.EmitCast(Op.IntType); - - if (Op.Shift) - { - Context.EmitLsl(Op.Size); - } - - Context.Emit(OpCodes.Add); - break; - } - - //Save address to Scratch var since the register value may change. - Context.Emit(OpCodes.Dup); - - Context.EmitSttmp(); - } - - private static void EmitWBackIfNeeded(AILEmitterCtx Context) - { - //Check whenever the current OpCode has post-indexed write back, if so write it. - //Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both. - if (Context.CurrOp is AOpCodeMemImm Op && Op.WBack) - { - Context.EmitLdtmp(); - - if (Op.PostIdx) - { - Context.EmitLdc_I(Op.Imm); - - Context.Emit(OpCodes.Add); - } - - Context.EmitStint(Op.Rn); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemoryEx.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemoryEx.cs deleted file mode 100644 index a339bb69..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitMemoryEx.cs +++ /dev/null @@ -1,180 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Memory; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; -using System.Threading; - -using static ChocolArm64.Instruction.AInstEmitMemoryHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - [Flags] - private enum AccessType - { - None = 0, - Ordered = 1, - Exclusive = 2, - OrderedEx = Ordered | Exclusive - } - - public static void Clrex(AILEmitterCtx Context) - { - EmitMemoryCall(Context, nameof(AMemory.ClearExclusive)); - } - - public static void Dmb(AILEmitterCtx Context) => EmitBarrier(Context); - public static void Dsb(AILEmitterCtx Context) => EmitBarrier(Context); - - public static void Ldar(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Ordered); - public static void Ldaxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.OrderedEx); - public static void Ldxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Exclusive); - public static void Ldxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.Exclusive); - public static void Ldaxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.OrderedEx); - - private static void EmitLdr(AILEmitterCtx Context, AccessType AccType) - { - EmitLoad(Context, AccType, false); - } - - private static void EmitLdp(AILEmitterCtx Context, AccessType AccType) - { - EmitLoad(Context, AccType, true); - } - - private static void EmitLoad(AILEmitterCtx Context, AccessType AccType, bool Pair) - { - AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - - EmitReadZxCall(Context, Op.Size); - - Context.EmitStintzr(Op.Rt); - - if (Pair) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I(8 << Op.Size); - - Context.Emit(OpCodes.Add); - - EmitReadZxCall(Context, Op.Size); - - Context.EmitStintzr(Op.Rt2); - } - - if (AccType.HasFlag(AccessType.Exclusive)) - { - EmitMemoryCall(Context, nameof(AMemory.SetExclusive), Op.Rn); - } - - if (AccType.HasFlag(AccessType.Ordered)) - { - EmitBarrier(Context); - } - } - - public static void Pfrm(AILEmitterCtx Context) - { - //Memory Prefetch, execute as no-op. - } - - public static void Stlr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Ordered); - public static void Stlxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.OrderedEx); - public static void Stxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Exclusive); - public static void Stxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.Exclusive); - public static void Stlxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.OrderedEx); - - private static void EmitStr(AILEmitterCtx Context, AccessType AccType) - { - EmitStore(Context, AccType, false); - } - - private static void EmitStp(AILEmitterCtx Context, AccessType AccType) - { - EmitStore(Context, AccType, true); - } - - private static void EmitStore(AILEmitterCtx Context, AccessType AccType, bool Pair) - { - AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp; - - if (AccType.HasFlag(AccessType.Ordered)) - { - EmitBarrier(Context); - } - - AILLabel LblEx = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - if (AccType.HasFlag(AccessType.Exclusive)) - { - EmitMemoryCall(Context, nameof(AMemory.TestExclusive), Op.Rn); - - Context.Emit(OpCodes.Brtrue_S, LblEx); - - Context.EmitLdc_I8(1); - Context.EmitStintzr(Op.Rs); - - Context.Emit(OpCodes.Br_S, LblEnd); - } - - Context.MarkLabel(LblEx); - - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdintzr(Op.Rt); - - EmitWriteCall(Context, Op.Size); - - if (Pair) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I(8 << Op.Size); - - Context.Emit(OpCodes.Add); - - Context.EmitLdintzr(Op.Rt2); - - EmitWriteCall(Context, Op.Size); - } - - if (AccType.HasFlag(AccessType.Exclusive)) - { - Context.EmitLdc_I8(0); - Context.EmitStintzr(Op.Rs); - - Clrex(Context); - } - - Context.MarkLabel(LblEnd); - } - - private static void EmitMemoryCall(AILEmitterCtx Context, string Name, int Rn = -1) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - - if (Rn != -1) - { - Context.EmitLdint(Rn); - } - - Context.EmitCall(typeof(AMemory), Name); - } - - private static void EmitBarrier(AILEmitterCtx Context) - { - //Note: This barrier is most likely not necessary, and probably - //doesn't make any difference since we need to do a ton of stuff - //(software MMU emulation) to read or write anything anyway. - Context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs deleted file mode 100644 index d5a0051b..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs +++ /dev/null @@ -1,138 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Memory; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static class AInstEmitMemoryHelper - { - private enum Extension - { - Zx, - Sx32, - Sx64 - } - - public static void EmitReadZxCall(AILEmitterCtx Context, int Size) - { - EmitReadCall(Context, Extension.Zx, Size); - } - - public static void EmitReadSx32Call(AILEmitterCtx Context, int Size) - { - EmitReadCall(Context, Extension.Sx32, Size); - } - - public static void EmitReadSx64Call(AILEmitterCtx Context, int Size) - { - EmitReadCall(Context, Extension.Sx64, Size); - } - - private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size) - { - bool IsSimd = GetIsSimd(Context); - - string Name = null; - - if (Size < 0 || Size > (IsSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - if (IsSimd) - { - switch (Size) - { - case 0: Name = nameof(AMemory.ReadVector8); break; - case 1: Name = nameof(AMemory.ReadVector16); break; - case 2: Name = nameof(AMemory.ReadVector32); break; - case 3: Name = nameof(AMemory.ReadVector64); break; - case 4: Name = nameof(AMemory.ReadVector128); break; - } - } - else - { - switch (Size) - { - case 0: Name = nameof(AMemory.ReadByte); break; - case 1: Name = nameof(AMemory.ReadUInt16); break; - case 2: Name = nameof(AMemory.ReadUInt32); break; - case 3: Name = nameof(AMemory.ReadUInt64); break; - } - } - - Context.EmitCall(typeof(AMemory), Name); - - if (!IsSimd) - { - if (Ext == Extension.Sx32 || - Ext == Extension.Sx64) - { - switch (Size) - { - case 0: Context.Emit(OpCodes.Conv_I1); break; - case 1: Context.Emit(OpCodes.Conv_I2); break; - case 2: Context.Emit(OpCodes.Conv_I4); break; - } - } - - if (Size < 3) - { - Context.Emit(Ext == Extension.Sx64 - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); - } - } - } - - public static void EmitWriteCall(AILEmitterCtx Context, int Size) - { - bool IsSimd = GetIsSimd(Context); - - string Name = null; - - if (Size < 0 || Size > (IsSimd ? 4 : 3)) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - if (Size < 3 && !IsSimd) - { - Context.Emit(OpCodes.Conv_I4); - } - - if (IsSimd) - { - switch (Size) - { - case 0: Name = nameof(AMemory.WriteVector8); break; - case 1: Name = nameof(AMemory.WriteVector16); break; - case 2: Name = nameof(AMemory.WriteVector32); break; - case 3: Name = nameof(AMemory.WriteVector64); break; - case 4: Name = nameof(AMemory.WriteVector128); break; - } - } - else - { - switch (Size) - { - case 0: Name = nameof(AMemory.WriteByte); break; - case 1: Name = nameof(AMemory.WriteUInt16); break; - case 2: Name = nameof(AMemory.WriteUInt32); break; - case 3: Name = nameof(AMemory.WriteUInt64); break; - } - } - - Context.EmitCall(typeof(AMemory), Name); - } - - private static bool GetIsSimd(AILEmitterCtx Context) - { - return Context.CurrOp is IAOpCodeSimd && - !(Context.CurrOp is AOpCodeSimdMemMs || - Context.CurrOp is AOpCodeSimdMemSs); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMove.cs b/Ryujinx/Cpu/Instruction/AInstEmitMove.cs deleted file mode 100644 index 719b53d5..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitMove.cs +++ /dev/null @@ -1,41 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Movk(AILEmitterCtx Context) - { - AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; - - Context.EmitLdintzr(Op.Rd); - Context.EmitLdc_I(~(0xffffL << Op.Pos)); - - Context.Emit(OpCodes.And); - - Context.EmitLdc_I(Op.Imm); - - Context.Emit(OpCodes.Or); - - Context.EmitStintzr(Op.Rd); - } - - public static void Movn(AILEmitterCtx Context) - { - AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; - - Context.EmitLdc_I(~Op.Imm); - Context.EmitStintzr(Op.Rd); - } - - public static void Movz(AILEmitterCtx Context) - { - AOpCodeMov Op = (AOpCodeMov)Context.CurrOp; - - Context.EmitLdc_I(Op.Imm); - Context.EmitStintzr(Op.Rd); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMul.cs b/Ryujinx/Cpu/Instruction/AInstEmitMul.cs deleted file mode 100644 index 3713c81f..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitMul.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Translation; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Madd(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Add); - public static void Msub(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Sub); - - private static void EmitMul(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; - - Context.EmitLdintzr(Op.Ra); - Context.EmitLdintzr(Op.Rn); - Context.EmitLdintzr(Op.Rm); - - Context.Emit(OpCodes.Mul); - Context.Emit(ILOp); - - Context.EmitStintzr(Op.Rd); - } - - public static void Smaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, true); - public static void Smsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, true); - public static void Umaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, false); - public static void Umsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, false); - - private static void EmitMull(AILEmitterCtx Context, OpCode AddSubOp, bool Signed) - { - AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; - - OpCode CastOp = Signed - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8; - - Context.EmitLdintzr(Op.Ra); - Context.EmitLdintzr(Op.Rn); - - Context.Emit(OpCodes.Conv_I4); - Context.Emit(CastOp); - - Context.EmitLdintzr(Op.Rm); - - Context.Emit(OpCodes.Conv_I4); - Context.Emit(CastOp); - Context.Emit(OpCodes.Mul); - - Context.Emit(AddSubOp); - - Context.EmitStintzr(Op.Rd); - } - - public static void Smulh(AILEmitterCtx Context) - { - AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - Context.EmitLdintzr(Op.Rm); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SMulHi128)); - - Context.EmitStintzr(Op.Rd); - } - - public static void Umulh(AILEmitterCtx Context) - { - AOpCodeMul Op = (AOpCodeMul)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - Context.EmitLdintzr(Op.Rm); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UMulHi128)); - - Context.EmitStintzr(Op.Rd); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs deleted file mode 100644 index 21ec11a7..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs +++ /dev/null @@ -1,367 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Add_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Addp_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); - EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size); - - Context.Emit(OpCodes.Add); - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void Addp_V(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Elems = Bytes >> Op.Size; - int Half = Elems >> 1; - - for (int Index = 0; Index < Elems; Index++) - { - int Elem = (Index & (Half - 1)) << 1; - - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size); - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size); - - Context.Emit(OpCodes.Add); - - EmitVectorInsertTmp(Context, Index, Op.Size); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Addv_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); - - for (int Index = 1; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); - - Context.Emit(OpCodes.Add); - } - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void Cnt_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, 0); - - Context.Emit(OpCodes.Conv_U1); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8)); - - Context.Emit(OpCodes.Conv_U8); - - EmitVectorInsert(Context, Op.Rd, Index, 0); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Fabs_S(AILEmitterCtx Context) - { - EmitScalarUnaryOpF(Context, () => - { - EmitUnaryMathCall(Context, nameof(Math.Abs)); - }); - } - - public static void Fadd_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Fadd_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Fdiv_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); - } - - public static void Fdiv_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); - } - - public static void Fmadd_S(AILEmitterCtx Context) - { - EmitScalarTernaryRaOpF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Fmax_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => - { - EmitBinaryMathCall(Context, nameof(Math.Max)); - }); - } - - public static void Fmin_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => - { - EmitBinaryMathCall(Context, nameof(Math.Min)); - }); - } - - public static void Fmaxnm_S(AILEmitterCtx Context) - { - Fmax_S(Context); - } - - public static void Fminnm_S(AILEmitterCtx Context) - { - Fmin_S(Context); - } - - public static void Fmla_V(AILEmitterCtx Context) - { - EmitVectorTernaryOpF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Fmla_Ve(AILEmitterCtx Context) - { - EmitVectorTernaryOpByElemF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Fmsub_S(AILEmitterCtx Context) - { - EmitScalarTernaryRaOpF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Sub); - }); - } - - public static void Fmul_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Fmul_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Fmul_Ve(AILEmitterCtx Context) - { - EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Fneg_S(AILEmitterCtx Context) - { - EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg)); - } - - public static void Fnmul_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Neg); - }); - } - - public static void Fnmsub_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int SizeF = Op.Size & 1; - - EmitVectorExtractF(Context, Op.Rn, 0, SizeF); - EmitVectorExtractF(Context, Op.Rm, 0, SizeF); - - Context.Emit(OpCodes.Mul); - - EmitVectorExtractF(Context, Op.Ra, 0, SizeF); - - Context.Emit(OpCodes.Sub); - - EmitScalarSetF(Context, Op.Rd, SizeF); - } - - public static void Frinta_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Frintm_S(AILEmitterCtx Context) - { - EmitScalarUnaryOpF(Context, () => - { - EmitUnaryMathCall(Context, nameof(Math.Floor)); - }); - } - - public static void Fsqrt_S(AILEmitterCtx Context) - { - EmitScalarUnaryOpF(Context, () => - { - EmitUnaryMathCall(Context, nameof(Math.Sqrt)); - }); - } - - public static void Fsub_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Fsub_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Mla_V(AILEmitterCtx Context) - { - EmitVectorTernaryOpZx(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Add); - }); - } - - public static void Mls_V(AILEmitterCtx Context) - { - EmitVectorTernaryOpZx(Context, () => - { - Context.Emit(OpCodes.Mul); - Context.Emit(OpCodes.Sub); - }); - } - - public static void Mul_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Neg_V(AILEmitterCtx Context) - { - EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); - } - - public static void Saddw_V(AILEmitterCtx Context) - { - EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add)); - } - - public static void Smax_V(AILEmitterCtx Context) - { - Type[] Types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types); - - EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); - } - - public static void Smin_V(AILEmitterCtx Context) - { - Type[] Types = new Type[] { typeof(long), typeof(long) }; - - MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); - - EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); - } - - public static void Smull_V(AILEmitterCtx Context) - { - EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul)); - } - - public static void Sub_S(AILEmitterCtx Context) - { - EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Sub_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); - } - - public static void Uaddlv_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); - - for (int Index = 1; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size); - - Context.Emit(OpCodes.Add); - } - - EmitScalarSet(Context, Op.Rd, Op.Size + 1); - } - - public static void Uaddw_V(AILEmitterCtx Context) - { - EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs deleted file mode 100644 index 97ccf0ab..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs +++ /dev/null @@ -1,233 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitAluHelper; -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Cmeq_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Beq_S); - } - - public static void Cmge_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bge_S); - } - - public static void Cmgt_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bgt_S); - } - - public static void Cmhi_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bgt_Un_S); - } - - public static void Cmhs_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Bge_Un_S); - } - - public static void Cmle_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Ble_S); - } - - public static void Cmlt_V(AILEmitterCtx Context) - { - EmitVectorCmp(Context, OpCodes.Blt_S); - } - - public static void Fccmp_S(AILEmitterCtx Context) - { - AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - - EmitSetNZCV(Context, Op.NZCV); - - Context.Emit(OpCodes.Br, LblEnd); - - Context.MarkLabel(LblTrue); - - Fcmp_S(Context); - - Context.MarkLabel(LblEnd); - } - - public static void Fccmpe_S(AILEmitterCtx Context) - { - Fccmp_S(Context); - } - - public static void Fcmp_S(AILEmitterCtx Context) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; - - //Handle NaN case. If any number is NaN, then NZCV = 0011. - if (CmpWithZero) - { - EmitNaNCheck(Context, Op.Rn); - } - else - { - EmitNaNCheck(Context, Op.Rn); - EmitNaNCheck(Context, Op.Rm); - - Context.Emit(OpCodes.Or); - } - - AILLabel LblNaN = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.Emit(OpCodes.Brtrue_S, LblNaN); - - void EmitLoadOpers() - { - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - if (CmpWithZero) - { - EmitLdcImmF(Context, 0, Op.Size); - } - else - { - EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); - } - } - - //Z = Rn == Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Ceq); - Context.Emit(OpCodes.Dup); - - Context.EmitStflg((int)APState.ZBit); - - //C = Rn >= Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Cgt); - Context.Emit(OpCodes.Or); - - Context.EmitStflg((int)APState.CBit); - - //N = Rn < Rm - EmitLoadOpers(); - - Context.Emit(OpCodes.Clt); - - Context.EmitStflg((int)APState.NBit); - - //V = 0 - Context.EmitLdc_I4(0); - - Context.EmitStflg((int)APState.VBit); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblNaN); - - EmitSetNZCV(Context, 0b0011); - - Context.MarkLabel(LblEnd); - } - - public static void Fcmpe_S(AILEmitterCtx Context) - { - Fcmp_S(Context); - } - - private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size) - { - if (Size == 0) - { - Context.EmitLdc_R4((float)ImmF); - } - else if (Size == 1) - { - Context.EmitLdc_R8(ImmF); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - private static void EmitNaNCheck(AILEmitterCtx Context, int Reg) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - EmitVectorExtractF(Context, Reg, 0, Op.Size); - - if (Op.Size == 0) - { - Context.EmitCall(typeof(float), nameof(float.IsNaN)); - } - else if (Op.Size == 1) - { - Context.EmitCall(typeof(double), nameof(double.IsNaN)); - } - else - { - throw new InvalidOperationException(); - } - } - - private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size)); - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size); - - if (Op is AOpCodeSimdReg BinOp) - { - EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size); - } - else - { - Context.EmitLdc_I8(0); - } - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.Emit(ILOp, LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask); - - Context.MarkLabel(LblEnd); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs deleted file mode 100644 index 00c2fe9b..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs +++ /dev/null @@ -1,444 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Fcvt_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - EmitFloatCast(Context, Op.Opc); - - EmitScalarSetF(Context, Op.Rd, Op.Opc); - } - - public static void Fcvtas_Gp(AILEmitterCtx Context) - { - Fcvta__Gp(Context, Signed: true); - } - - public static void Fcvtau_Gp(AILEmitterCtx Context) - { - Fcvta__Gp(Context, Signed: false); - } - - public static void Fcvtms_Gp(AILEmitterCtx Context) - { - EmitFcvt_s_Gp(Context, nameof(Math.Floor)); - } - - public static void Fcvtps_Gp(AILEmitterCtx Context) - { - EmitFcvt_s_Gp(Context, nameof(Math.Ceiling)); - } - - public static void Fcvtzs_Gp(AILEmitterCtx Context) - { - EmitFcvtz__Gp(Context, Signed: true); - } - - public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context) - { - EmitFcvtz__Gp_Fix(Context, Signed: true); - } - - public static void Fcvtzs_V(AILEmitterCtx Context) - { - EmitVectorFcvt(Context, Signed: true); - } - - public static void Fcvtzu_Gp(AILEmitterCtx Context) - { - EmitFcvtz__Gp(Context, Signed: false); - } - - public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context) - { - EmitFcvtz__Gp_Fix(Context, Signed: false); - } - - public static void Fcvtzu_V(AILEmitterCtx Context) - { - EmitVectorFcvt(Context, Signed: false); - } - - public static void Scvtf_Gp(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U4); - } - - EmitFloatCast(Context, Op.Size); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Scvtf_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2); - - EmitFloatCast(Context, Op.Size); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Scvtf_V(AILEmitterCtx Context) - { - EmitVectorCvtf(Context, Signed: true); - } - - public static void Ucvtf_Gp(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U4); - } - - Context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(Context, Op.Size); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Ucvtf_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size + 2); - - Context.Emit(OpCodes.Conv_R_Un); - - EmitFloatCast(Context, Op.Size); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Ucvtf_V(AILEmitterCtx Context) - { - EmitVectorCvtf(Context, Signed: false); - } - - private static int GetFBits(AILEmitterCtx Context) - { - if (Context.CurrOp is AOpCodeSimdShImm Op) - { - return GetImmShr(Op); - } - - return 0; - } - - private static void EmitFloatCast(AILEmitterCtx Context, int Size) - { - if (Size == 0) - { - Context.Emit(OpCodes.Conv_R4); - } - else if (Size == 1) - { - Context.Emit(OpCodes.Conv_R8); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - private static void Fcvta__Gp(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - EmitRoundMathCall(Context, MidpointRounding.AwayFromZero); - - if (Signed) - { - EmitScalarFcvts(Context, Op.Size, 0); - } - else - { - EmitScalarFcvtu(Context, Op.Size, 0); - } - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitFcvt_s_Gp(AILEmitterCtx Context, string Name) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - EmitUnaryMathCall(Context, Name); - - EmitScalarFcvts(Context, Op.Size, 0); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - if (Signed) - { - EmitScalarFcvts(Context, Op.Size, 0); - } - else - { - EmitScalarFcvtu(Context, Op.Size, 0); - } - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - if (Signed) - { - EmitScalarFcvts(Context, Op.Size, Op.FBits); - } - else - { - EmitScalarFcvtu(Context, Op.Size, Op.FBits); - } - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rd); - } - - private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int SizeF = Op.Size & 1; - int SizeI = SizeF + 2; - - int FBits = GetFBits(Context); - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeI); Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed); - - if (!Signed) - { - Context.Emit(OpCodes.Conv_R_Un); - } - - Context.Emit(SizeF == 0 - ? OpCodes.Conv_R4 - : OpCodes.Conv_R8); - - EmitI2fFBitsMul(Context, SizeF, FBits); - - EmitVectorInsertF(Context, Op.Rd, Index, SizeF); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int SizeF = Op.Size & 1; - int SizeI = SizeF + 2; - - int FBits = GetFBits(Context); - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeI); Index++) - { - EmitVectorExtractF(Context, Op.Rn, Index, SizeF); - - EmitF2iFBitsMul(Context, SizeF, FBits); - - if (SizeF == 0) - { - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.SatF32ToS32) - : nameof(ASoftFallback.SatF32ToU32)); - } - else /* if (SizeF == 1) */ - { - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.SatF64ToS64) - : nameof(ASoftFallback.SatF64ToU64)); - } - - if (SizeF == 0) - { - Context.Emit(OpCodes.Conv_U8); - } - - EmitVectorInsert(Context, Op.Rd, Index, SizeI); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitScalarFcvts(AILEmitterCtx Context, int Size, int FBits) - { - if (Size < 0 || Size > 1) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - EmitF2iFBitsMul(Context, Size, FBits); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS32)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS32)); - } - } - else - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS64)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS64)); - } - } - } - - private static void EmitScalarFcvtu(AILEmitterCtx Context, int Size, int FBits) - { - if (Size < 0 || Size > 1) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - EmitF2iFBitsMul(Context, Size, FBits); - - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU32)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU32)); - } - } - else - { - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU64)); - } - else /* if (Size == 1) */ - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU64)); - } - } - } - - private static void EmitF2iFBitsMul(AILEmitterCtx Context, int Size, int FBits) - { - if (FBits != 0) - { - if (Size == 0) - { - Context.EmitLdc_R4(MathF.Pow(2, FBits)); - } - else if (Size == 1) - { - Context.EmitLdc_R8(Math.Pow(2, FBits)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.Emit(OpCodes.Mul); - } - } - - private static void EmitI2fFBitsMul(AILEmitterCtx Context, int Size, int FBits) - { - if (FBits != 0) - { - if (Size == 0) - { - Context.EmitLdc_R4(1f / MathF.Pow(2, FBits)); - } - else if (Size == 1) - { - Context.EmitLdc_R8(1 / Math.Pow(2, FBits)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.Emit(OpCodes.Mul); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs deleted file mode 100644 index 20c8be26..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs +++ /dev/null @@ -1,616 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; - -namespace ChocolArm64.Instruction -{ - static class AInstEmitSimdHelper - { - [Flags] - public enum OperFlags - { - Rd = 1 << 0, - Rn = 1 << 1, - Rm = 1 << 2, - Ra = 1 << 3, - - RnRm = Rn | Rm, - RdRn = Rd | Rn, - RaRnRm = Ra | Rn | Rm, - RdRnRm = Rd | Rn | Rm - } - - public static int GetImmShl(AOpCodeSimdShImm Op) - { - return Op.Imm - (8 << Op.Size); - } - - public static int GetImmShr(AOpCodeSimdShImm Op) - { - return (8 << (Op.Size + 1)) - Op.Imm; - } - - public static void EmitUnaryMathCall(AILEmitterCtx Context, string Name) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) }); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) }); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - } - - public static void EmitBinaryMathCall(AILEmitterCtx Context, string Name) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - MethodInfo MthdInfo; - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - } - - public static void EmitRoundMathCall(AILEmitterCtx Context, MidpointRounding RoundMode) - { - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - Context.EmitLdc_I4((int)RoundMode); - - MethodInfo MthdInfo; - - Type[] Types = new Type[] { null, typeof(MidpointRounding) }; - - Types[0] = Op.Size == 0 - ? typeof(float) - : typeof(double); - - if (Op.Size == 0) - { - MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); - } - else if (Op.Size == 1) - { - MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); - } - else - { - throw new InvalidOperationException(); - } - - Context.EmitCall(MthdInfo); - } - - public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitScalarOp(Context, Emit, OperFlags.Rn, true); - } - - public static void EmitScalarBinaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitScalarOp(Context, Emit, OperFlags.RnRm, true); - } - - public static void EmitScalarUnaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitScalarOp(Context, Emit, OperFlags.Rn, false); - } - - public static void EmitScalarBinaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitScalarOp(Context, Emit, OperFlags.RnRm, false); - } - - public static void EmitScalarTernaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitScalarOp(Context, Emit, OperFlags.RdRnRm, false); - } - - public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - if (Opers.HasFlag(OperFlags.Rd)) - { - EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed); - } - - Emit(); - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void EmitScalarUnaryOpF(AILEmitterCtx Context, Action Emit) - { - EmitScalarOpF(Context, Emit, OperFlags.Rn); - } - - public static void EmitScalarBinaryOpF(AILEmitterCtx Context, Action Emit) - { - EmitScalarOpF(Context, Emit, OperFlags.RnRm); - } - - public static void EmitScalarTernaryRaOpF(AILEmitterCtx Context, Action Emit) - { - EmitScalarOpF(Context, Emit, OperFlags.RaRnRm); - } - - public static void EmitScalarOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int SizeF = Op.Size & 1; - - if (Opers.HasFlag(OperFlags.Ra)) - { - EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtractF(Context, Op.Rn, 0, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF); - } - - Emit(); - - EmitScalarSetF(Context, Op.Rd, SizeF); - } - - public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit) - { - EmitVectorOpF(Context, Emit, OperFlags.RnRm); - } - - public static void EmitVectorTernaryOpF(AILEmitterCtx Context, Action Emit) - { - EmitVectorOpF(Context, Emit, OperFlags.RdRnRm); - } - - public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false); - } - - public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit) - { - AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp; - - EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true); - } - - public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int SizeF = Op.Size & 1; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) - { - if (Opers.HasFlag(OperFlags.Rd)) - { - EmitVectorExtractF(Context, Op.Rd, Index, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtractF(Context, Op.Rn, Index, SizeF); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - EmitVectorExtractF(Context, Op.Rm, Index, SizeF); - } - - Emit(); - - EmitVectorInsertF(Context, Op.Rd, Index, SizeF); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void EmitVectorOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int SizeF = Op.Size & 1; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++) - { - if (Ternary) - { - EmitVectorExtractF(Context, Op.Rd, Index, SizeF); - } - - EmitVectorExtractF(Context, Op.Rn, Index, SizeF); - EmitVectorExtractF(Context, Op.Rm, Elem, SizeF); - - Emit(); - - EmitVectorInsertTmpF(Context, Index, SizeF); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void EmitVectorUnaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.Rn, true); - } - - public static void EmitVectorBinaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RnRm, true); - } - - public static void EmitVectorUnaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.Rn, false); - } - - public static void EmitVectorBinaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RnRm, false); - } - - public static void EmitVectorTernaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false); - } - - public static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - if (Opers.HasFlag(OperFlags.Rd)) - { - EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rn)) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - } - - if (Opers.HasFlag(OperFlags.Rm)) - { - EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); - } - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit) - { - EmitVectorImmOp(Context, Emit, false); - } - - public static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit) - { - EmitVectorImmOp(Context, Emit, true); - } - - public static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary) - { - AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - if (Binary) - { - EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size); - } - - Context.EmitLdc_I8(Op.Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenRmBinaryOp(Context, Emit, true); - } - - public static void EmitVectorWidenRmBinaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenRmBinaryOp(Context, Emit, false); - } - - public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); - EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); - - Emit(); - - EmitVectorInsertTmp(Context, Index, Op.Size + 1); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - } - - public static void EmitVectorWidenRnRmBinaryOpSx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenRnRmBinaryOp(Context, Emit, true); - } - - public static void EmitVectorWidenRnRmBinaryOpZx(AILEmitterCtx Context, Action Emit) - { - EmitVectorWidenRnRmBinaryOp(Context, Emit, false); - } - - public static void EmitVectorWidenRnRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); - EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); - - Emit(); - - EmitVectorInsertTmp(Context, Index, Op.Size + 1); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - } - - public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size) - { - EmitVectorZeroAll(Context, Reg); - EmitVectorInsert(Context, Reg, 0, Size); - } - - public static void EmitScalarSetF(AILEmitterCtx Context, int Reg, int Size) - { - EmitVectorZeroAll(Context, Reg); - EmitVectorInsertF(Context, Reg, 0, Size); - } - - public static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size) - { - EmitVectorExtract(Context, Reg, Index, Size, true); - } - - public static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size) - { - EmitVectorExtract(Context, Reg, Index, Size, false); - } - - public static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; - - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, Signed - ? nameof(ASoftFallback.VectorExtractIntSx) - : nameof(ASoftFallback.VectorExtractIntZx)); - } - - public static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size) - { - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle)); - } - else if (Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } - - public static void EmitVectorZeroAll(AILEmitterCtx Context, int Rd) - { - EmitVectorZeroLower(Context, Rd); - EmitVectorZeroUpper(Context, Rd); - } - - public static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd) - { - EmitVectorInsert(Context, Rd, 0, 3, 0); - } - - public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd) - { - EmitVectorInsert(Context, Rd, 1, 3, 0); - } - - public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); - - Context.EmitStvec(Reg); - } - - public static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdvectmp(); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); - - Context.EmitStvectmp(); - } - - public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value) - { - if (Size < 0 || Size > 3) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitLdc_I8(Value); - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - Context.EmitLdc_I4(Size); - - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt)); - - Context.EmitStvec(Reg); - } - - public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size) - { - Context.EmitLdvec(Reg); - Context.EmitLdc_I4(Index); - - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); - } - else if (Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitStvec(Reg); - } - - public static void EmitVectorInsertTmpF(AILEmitterCtx Context, int Index, int Size) - { - Context.EmitLdvectmp(); - Context.EmitLdc_I4(Index); - - if (Size == 0) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); - } - else if (Size == 1) - { - ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - Context.EmitStvectmp(); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs deleted file mode 100644 index ea4b17b3..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs +++ /dev/null @@ -1,69 +0,0 @@ -using ChocolArm64.Translation; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void And_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.And)); - } - - public static void Bic_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => - { - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - }); - } - - public static void Bic_Vi(AILEmitterCtx Context) - { - EmitVectorImmBinaryOp(Context, () => - { - Context.Emit(OpCodes.Not); - Context.Emit(OpCodes.And); - }); - } - - public static void Bsl_V(AILEmitterCtx Context) - { - EmitVectorTernaryOpZx(Context, () => - { - Context.EmitSttmp(); - Context.EmitLdtmp(); - - Context.Emit(OpCodes.Xor); - Context.Emit(OpCodes.And); - - Context.EmitLdtmp(); - - Context.Emit(OpCodes.Xor); - }); - } - - public static void Eor_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Xor)); - } - - public static void Not_V(AILEmitterCtx Context) - { - EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not)); - } - - public static void Orr_V(AILEmitterCtx Context) - { - EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Or)); - } - - public static void Orr_Vi(AILEmitterCtx Context) - { - EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs deleted file mode 100644 index d98ec012..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs +++ /dev/null @@ -1,184 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitMemoryHelper; -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Ld__Vms(AILEmitterCtx Context) - { - EmitSimdMemMs(Context, IsLoad: true); - } - - public static void Ld__Vss(AILEmitterCtx Context) - { - EmitSimdMemSs(Context, IsLoad: true); - } - - public static void St__Vms(AILEmitterCtx Context) - { - EmitSimdMemMs(Context, IsLoad: false); - } - - public static void St__Vss(AILEmitterCtx Context) - { - EmitSimdMemSs(Context, IsLoad: false); - } - - private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) - { - AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp; - - int Offset = 0; - - for (int Rep = 0; Rep < Op.Reps; Rep++) - for (int Elem = 0; Elem < Op.Elems; Elem++) - for (int SElem = 0; SElem < Op.SElems; SElem++) - { - int Rtt = (Op.Rt + Rep + SElem) & 0x1f; - - if (IsLoad) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - - EmitReadZxCall(Context, Op.Size); - - EmitVectorInsert(Context, Rtt, Elem, Op.Size); - - if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) - { - EmitVectorZeroUpper(Context, Rtt); - } - } - else - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - - EmitVectorExtractZx(Context, Rtt, Elem, Op.Size); - - EmitWriteCall(Context, Op.Size); - } - - Offset += 1 << Op.Size; - } - - if (Op.WBack) - { - EmitSimdMemWBack(Context, Offset); - } - } - - private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad) - { - AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp; - - int Offset = 0; - - void EmitMemAddress() - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rn); - Context.EmitLdc_I8(Offset); - - Context.Emit(OpCodes.Add); - } - - if (Op.Replicate) - { - //Only loads uses the replicate mode. - if (!IsLoad) - { - throw new InvalidOperationException(); - } - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int SElem = 0; SElem < Op.SElems; SElem++) - { - int Rt = (Op.Rt + SElem) & 0x1f; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitMemAddress(); - - EmitReadZxCall(Context, Op.Size); - - EmitVectorInsert(Context, Rt, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Rt); - } - - Offset += 1 << Op.Size; - } - } - else - { - for (int SElem = 0; SElem < Op.SElems; SElem++) - { - int Rt = (Op.Rt + SElem) & 0x1f; - - if (IsLoad) - { - EmitMemAddress(); - - EmitReadZxCall(Context, Op.Size); - - EmitVectorInsert(Context, Rt, Op.Index, Op.Size); - } - else - { - EmitMemAddress(); - - EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); - - EmitWriteCall(Context, Op.Size); - } - - Offset += 1 << Op.Size; - } - } - - if (Op.WBack) - { - EmitSimdMemWBack(Context, Offset); - } - } - - private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) - { - AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; - - Context.EmitLdint(Op.Rn); - - if (Op.Rm != AThreadState.ZRIndex) - { - Context.EmitLdint(Op.Rm); - } - else - { - Context.EmitLdc_I8(Offset); - } - - Context.Emit(OpCodes.Add); - - Context.EmitStint(Op.Rn); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs deleted file mode 100644 index aabb8f34..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs +++ /dev/null @@ -1,333 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Dup_Gp(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - Context.EmitLdintzr(Op.Rn); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Dup_S(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void Dup_V(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Fcsel_S(AILEmitterCtx Context) - { - AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp; - - AILLabel LblTrue = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - Context.EmitCondBranch(LblTrue, Op.Cond); - - EmitVectorExtractF(Context, Op.Rm, 0, Op.Size); - - Context.Emit(OpCodes.Br_S, LblEnd); - - Context.MarkLabel(LblTrue); - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - Context.MarkLabel(LblEnd); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Fmov_Ftoi(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, 0, 3); - - EmitIntZeroHigherIfNeeded(Context); - - Context.EmitStintzr(Op.Rd); - } - - public static void Fmov_Ftoi1(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, 1, 3); - - EmitIntZeroHigherIfNeeded(Context); - - Context.EmitStintzr(Op.Rd); - } - - public static void Fmov_Itof(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - EmitIntZeroHigherIfNeeded(Context); - - EmitScalarSet(Context, Op.Rd, 3); - } - - public static void Fmov_Itof1(AILEmitterCtx Context) - { - AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - EmitIntZeroHigherIfNeeded(Context); - - EmitVectorInsert(Context, Op.Rd, 1, 3); - } - - public static void Fmov_S(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); - - EmitScalarSetF(Context, Op.Rd, Op.Size); - } - - public static void Fmov_Si(AILEmitterCtx Context) - { - AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp; - - Context.EmitLdc_I8(Op.Imm); - - EmitScalarSet(Context, Op.Rd, Op.Size + 2); - } - - public static void Fmov_V(AILEmitterCtx Context) - { - AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp; - - int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 4 : 2; - - for (int Index = 0; Index < (Elems >> Op.Size); Index++) - { - Context.EmitLdc_I8(Op.Imm); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size + 2); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Ins_Gp(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - Context.EmitLdintzr(Op.Rn); - - EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); - } - - public static void Ins_V(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size); - } - - public static void Movi_V(AILEmitterCtx Context) - { - EmitVectorImmUnaryOp(Context, () => { }); - } - - public static void Mvni_V(AILEmitterCtx Context) - { - EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not)); - } - - public static void Tbl_V(AILEmitterCtx Context) - { - AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp; - - Context.EmitLdvec(Op.Rm); - - for (int Index = 0; Index < Op.Size; Index++) - { - Context.EmitLdvec((Op.Rn + Index) & 0x1f); - } - - switch (Op.Size) - { - case 1: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl1_V64), - nameof(ASoftFallback.Tbl1_V128)); break; - - case 2: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl2_V64), - nameof(ASoftFallback.Tbl2_V128)); break; - - case 3: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl3_V64), - nameof(ASoftFallback.Tbl3_V128)); break; - - case 4: ASoftFallback.EmitCall(Context, - nameof(ASoftFallback.Tbl4_V64), - nameof(ASoftFallback.Tbl4_V128)); break; - - default: throw new InvalidOperationException(); - } - - Context.EmitStvec(Op.Rd); - } - - public static void Umov_S(AILEmitterCtx Context) - { - AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size); - - Context.EmitStintzr(Op.Rd); - } - - public static void Uzp1_V(AILEmitterCtx Context) - { - EmitVectorUnzip(Context, Part: 0); - } - - public static void Uzp2_V(AILEmitterCtx Context) - { - EmitVectorUnzip(Context, Part: 1); - } - - public static void Xtn_V(AILEmitterCtx Context) - { - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); - - EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); - } - - if (Part == 0) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - public static void Zip1_V(AILEmitterCtx Context) - { - EmitVectorZip(Context, Part: 0); - } - - public static void Zip2_V(AILEmitterCtx Context) - { - EmitVectorZip(Context, Part: 1); - } - - private static void EmitIntZeroHigherIfNeeded(AILEmitterCtx Context) - { - if (Context.CurrOp.RegisterSize == ARegisterSize.Int32) - { - Context.Emit(OpCodes.Conv_U4); - Context.Emit(OpCodes.Conv_U8); - } - } - - private static void EmitVectorUnzip(AILEmitterCtx Context, int Part) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Elems = Bytes >> Op.Size; - int Half = Elems >> 1; - - for (int Index = 0; Index < Elems; Index++) - { - int Elem = Part + ((Index & (Half - 1)) << 1); - - EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorZip(AILEmitterCtx Context, int Part) - { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - int Elems = Bytes >> Op.Size; - int Half = Elems >> 1; - - for (int Index = 0; Index < Elems; Index++) - { - int Elem = Part * Half + (Index >> 1); - - EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs deleted file mode 100644 index 8740ba4d..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs +++ /dev/null @@ -1,297 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection.Emit; - -using static ChocolArm64.Instruction.AInstEmitSimdHelper; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Shl_S(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size); - - Context.EmitLdc_I4(GetImmShl(Op)); - - Context.Emit(OpCodes.Shl); - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void Shl_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Shrn_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift); - } - - public static void Sshl_V(AILEmitterCtx Context) - { - EmitVectorShl(Context, Signed: true); - } - - public static void Sshll_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Sshr_S(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size); - - Context.EmitLdc_I4(GetImmShr(Op)); - - Context.Emit(OpCodes.Shr); - - EmitScalarSet(Context, Op.Rd, Op.Size); - } - - public static void Sshr_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = (8 << (Op.Size + 1)) - Op.Imm; - - EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift); - } - - public static void Ushl_V(AILEmitterCtx Context) - { - EmitVectorShl(Context, Signed: false); - } - - public static void Ushll_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Shift = Op.Imm - (8 << Op.Size); - - EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift); - } - - public static void Ushr_S(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - EmitScalarUnaryOpZx(Context, () => - { - Context.EmitLdc_I4(GetImmShr(Op)); - - Context.Emit(OpCodes.Shr_Un); - }); - } - - public static void Ushr_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - EmitVectorUnaryOpZx(Context, () => - { - Context.EmitLdc_I4(GetImmShr(Op)); - - Context.Emit(OpCodes.Shr_Un); - }); - } - - public static void Usra_V(AILEmitterCtx Context) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - Action Emit = () => - { - Context.EmitLdc_I4(GetImmShr(Op)); - - Context.Emit(OpCodes.Shr_Un); - Context.Emit(OpCodes.Add); - }; - - EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false); - } - - private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) - { - //This instruction shifts the value on vector A by the number of bits - //specified on the signed, lower 8 bits of vector B. If the shift value - //is greater or equal to the data size of each lane, then the result is zero. - //Additionally, negative shifts produces right shifts by the negated shift value. - AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - - int MaxShift = 8 << Op.Size; - - Action Emit = () => - { - AILLabel LblShl = new AILLabel(); - AILLabel LblZero = new AILLabel(); - AILLabel LblEnd = new AILLabel(); - - void EmitShift(OpCode ILOp) - { - Context.Emit(OpCodes.Dup); - - Context.EmitLdc_I4(MaxShift); - - Context.Emit(OpCodes.Bge_S, LblZero); - Context.Emit(ILOp); - Context.Emit(OpCodes.Br_S, LblEnd); - } - - Context.Emit(OpCodes.Conv_I1); - Context.Emit(OpCodes.Dup); - - Context.EmitLdc_I4(0); - - Context.Emit(OpCodes.Bge_S, LblShl); - Context.Emit(OpCodes.Neg); - - EmitShift(Signed - ? OpCodes.Shr - : OpCodes.Shr_Un); - - Context.MarkLabel(LblShl); - - EmitShift(OpCodes.Shl); - - Context.MarkLabel(LblZero); - - Context.Emit(OpCodes.Pop); - Context.Emit(OpCodes.Pop); - - Context.EmitLdc_I8(0); - - Context.MarkLabel(LblEnd); - }; - - if (Signed) - { - EmitVectorBinaryOpSx(Context, Emit); - } - else - { - EmitVectorBinaryOpZx(Context, Emit); - } - } - - private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Bytes = Context.CurrOp.GetBitsCount() >> 3; - - for (int Index = 0; Index < (Bytes >> Op.Size); Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Index, Op.Size); - } - - if (Op.RegisterSize == ARegisterSize.SIMD64) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); - } - - if (Part == 0) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - } - - private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true); - } - - private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm) - { - EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false); - } - - private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed) - { - AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; - - int Elems = 8 >> Op.Size; - - int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; - - for (int Index = 0; Index < Elems; Index++) - { - EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed); - - Context.EmitLdc_I4(Imm); - - Emit(); - - EmitVectorInsertTmp(Context, Index, Op.Size + 1); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(Op.Rd); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs b/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs deleted file mode 100644 index 6754be7a..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitSystem.cs +++ /dev/null @@ -1,122 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Instruction -{ - static partial class AInstEmit - { - public static void Mrs(AILEmitterCtx Context) - { - AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - - string PropName; - - switch (GetPackedId(Op)) - { - case 0b11_011_0000_0000_001: PropName = nameof(AThreadState.CtrEl0); break; - case 0b11_011_0000_0000_111: PropName = nameof(AThreadState.DczidEl0); break; - case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr); break; - case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr); break; - case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break; - case 0b11_011_1101_0000_011: PropName = nameof(AThreadState.Tpidr); break; - case 0b11_011_1110_0000_001: PropName = nameof(AThreadState.CntpctEl0); break; - - default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}"); - } - - Context.EmitCallPropGet(typeof(AThreadState), PropName); - - PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName); - - if (PropInfo.PropertyType != typeof(long) && - PropInfo.PropertyType != typeof(ulong)) - { - Context.Emit(OpCodes.Conv_U8); - } - - Context.EmitStintzr(Op.Rt); - } - - public static void Msr(AILEmitterCtx Context) - { - AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - Context.EmitLdintzr(Op.Rt); - - string PropName; - - switch (GetPackedId(Op)) - { - case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr); break; - case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr); break; - case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break; - - default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}"); - } - - PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName); - - if (PropInfo.PropertyType != typeof(long) && - PropInfo.PropertyType != typeof(ulong)) - { - Context.Emit(OpCodes.Conv_U4); - } - - Context.EmitCallPropSet(typeof(AThreadState), PropName); - } - - public static void Nop(AILEmitterCtx Context) - { - //Do nothing. - } - - public static void Sys(AILEmitterCtx Context) - { - //This instruction is used to do some operations on the CPU like cache invalidation, - //address translation and the like. - //We treat it as no-op here since we don't have any cache being emulated anyway. - AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp; - - switch (GetPackedId(Op)) - { - case 0b11_011_0111_0100_001: - { - //DC ZVA - for (int Offs = 0; Offs < (4 << AThreadState.DczSizeLog2); Offs += 8) - { - Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); - Context.EmitLdint(Op.Rt); - Context.EmitLdc_I(Offs); - - Context.Emit(OpCodes.Add); - - Context.EmitLdc_I8(0); - - AInstEmitMemoryHelper.EmitWriteCall(Context, 3); - } - break; - } - } - } - - private static int GetPackedId(AOpCodeSystem Op) - { - int Id; - - Id = Op.Op2 << 0; - Id |= Op.CRm << 3; - Id |= Op.CRn << 7; - Id |= Op.Op1 << 11; - Id |= Op.Op0 << 14; - - return Id; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/AInstEmitter.cs b/Ryujinx/Cpu/Instruction/AInstEmitter.cs deleted file mode 100644 index 8712a736..00000000 --- a/Ryujinx/Cpu/Instruction/AInstEmitter.cs +++ /dev/null @@ -1,6 +0,0 @@ -using ChocolArm64.Translation; - -namespace ChocolArm64.Instruction -{ - delegate void AInstEmitter(AILEmitterCtx Context); -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs deleted file mode 100644 index a57966ba..00000000 --- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs +++ /dev/null @@ -1,316 +0,0 @@ -using ChocolArm64.State; -using ChocolArm64.Translation; -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace ChocolArm64.Instruction -{ - static class ASoftFallback - { - public static void EmitCall(AILEmitterCtx Context, string Name64, string Name128) - { - bool IsSimd64 = Context.CurrOp.RegisterSize == ARegisterSize.SIMD64; - - Context.EmitCall(typeof(ASoftFallback), IsSimd64 ? Name64 : Name128); - } - - public static void EmitCall(AILEmitterCtx Context, string MthdName) - { - Context.EmitCall(typeof(ASoftFallback), MthdName); - } - - public static uint CountLeadingZeros32(uint Value) => (uint)CountLeadingZeros(Value, 32); - public static ulong CountLeadingZeros64(ulong Value) => (ulong)CountLeadingZeros(Value, 64); - - private static ulong CountLeadingZeros(ulong Value, int Size) - { - int HighBit = Size - 1; - - for (int Bit = HighBit; Bit >= 0; Bit--) - { - if (((Value >> Bit) & 1) != 0) - { - return (ulong)(HighBit - Bit); - } - } - - return (ulong)Size; - } - - public static uint ReverseBits32(uint Value) - { - Value = ((Value & 0xaaaaaaaa) >> 1) | ((Value & 0x55555555) << 1); - Value = ((Value & 0xcccccccc) >> 2) | ((Value & 0x33333333) << 2); - Value = ((Value & 0xf0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f) << 4); - Value = ((Value & 0xff00ff00) >> 8) | ((Value & 0x00ff00ff) << 8); - - return (Value >> 16) | (Value << 16); - } - - public static ulong ReverseBits64(ulong Value) - { - Value = ((Value & 0xaaaaaaaaaaaaaaaa) >> 1) | ((Value & 0x5555555555555555) << 1); - Value = ((Value & 0xcccccccccccccccc) >> 2) | ((Value & 0x3333333333333333) << 2); - Value = ((Value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f0f0f0f0f) << 4); - Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); - Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16); - - return (Value >> 32) | (Value << 32); - } - - public static uint ReverseBytes16_32(uint Value) => (uint)ReverseBytes16_64(Value); - public static uint ReverseBytes32_32(uint Value) => (uint)ReverseBytes32_64(Value); - - public static ulong ReverseBytes16_64(ulong Value) => ReverseBytes(Value, RevSize.Rev16); - public static ulong ReverseBytes32_64(ulong Value) => ReverseBytes(Value, RevSize.Rev32); - public static ulong ReverseBytes64(ulong Value) => ReverseBytes(Value, RevSize.Rev64); - - private enum RevSize - { - Rev16, - Rev32, - Rev64 - } - - private static ulong ReverseBytes(ulong Value, RevSize Size) - { - Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8); - - if (Size == RevSize.Rev16) - { - return Value; - } - - Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16); - - if (Size == RevSize.Rev32) - { - return Value; - } - - Value = ((Value & 0xffffffff00000000) >> 32) | ((Value & 0x00000000ffffffff) << 32); - - if (Size == RevSize.Rev64) - { - return Value; - } - - throw new ArgumentException(nameof(Size)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SatF32ToS32(float Value) - { - if (float.IsNaN(Value)) return 0; - - return Value > int.MaxValue ? int.MaxValue : - Value < int.MinValue ? int.MinValue : (int)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SatF32ToS64(float Value) - { - if (float.IsNaN(Value)) return 0; - - return Value > long.MaxValue ? long.MaxValue : - Value < long.MinValue ? long.MinValue : (long)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SatF32ToU32(float Value) - { - if (float.IsNaN(Value)) return 0; - - return Value > uint.MaxValue ? uint.MaxValue : - Value < uint.MinValue ? uint.MinValue : (uint)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SatF32ToU64(float Value) - { - if (float.IsNaN(Value)) return 0; - - return Value > ulong.MaxValue ? ulong.MaxValue : - Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SatF64ToS32(double Value) - { - if (double.IsNaN(Value)) return 0; - - return Value > int.MaxValue ? int.MaxValue : - Value < int.MinValue ? int.MinValue : (int)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long SatF64ToS64(double Value) - { - if (double.IsNaN(Value)) return 0; - - return Value > long.MaxValue ? long.MaxValue : - Value < long.MinValue ? long.MinValue : (long)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SatF64ToU32(double Value) - { - if (double.IsNaN(Value)) return 0; - - return Value > uint.MaxValue ? uint.MaxValue : - Value < uint.MinValue ? uint.MinValue : (uint)Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong SatF64ToU64(double Value) - { - if (double.IsNaN(Value)) return 0; - - return Value > ulong.MaxValue ? ulong.MaxValue : - Value < ulong.MinValue ? ulong.MinValue : (ulong)Value; - } - - public static long SMulHi128(long LHS, long RHS) - { - return (long)(BigInteger.Multiply(LHS, RHS) >> 64); - } - - public static ulong UMulHi128(ulong LHS, ulong RHS) - { - return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64); - } - - public static int CountSetBits8(byte Value) - { - return (Value >> 0) & 1 + (Value >> 1) & 1 + - (Value >> 2) & 1 + (Value >> 3) & 1 + - (Value >> 4) & 1 + (Value >> 5) & 1 + - (Value >> 6) & 1 + (Value >> 7); - } - - public static AVec Tbl1_V64(AVec Vector, AVec Tb0) - { - return Tbl(Vector, 8, Tb0); - } - - public static AVec Tbl1_V128(AVec Vector, AVec Tb0) - { - return Tbl(Vector, 16, Tb0); - } - - public static AVec Tbl2_V64(AVec Vector, AVec Tb0, AVec Tb1) - { - return Tbl(Vector, 8, Tb0, Tb1); - } - - public static AVec Tbl2_V128(AVec Vector, AVec Tb0, AVec Tb1) - { - return Tbl(Vector, 16, Tb0, Tb1); - } - - public static AVec Tbl3_V64(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2) - { - return Tbl(Vector, 8, Tb0, Tb1, Tb2); - } - - public static AVec Tbl3_V128(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2) - { - return Tbl(Vector, 16, Tb0, Tb1, Tb2); - } - - public static AVec Tbl4_V64(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2, AVec Tb3) - { - return Tbl(Vector, 8, Tb0, Tb1, Tb2, Tb3); - } - - public static AVec Tbl4_V128(AVec Vector, AVec Tb0, AVec Tb1, AVec Tb2, AVec Tb3) - { - return Tbl(Vector, 16, Tb0, Tb1, Tb2, Tb3); - } - - private static AVec Tbl(AVec Vector, int Bytes, params AVec[] Tb) - { - AVec Res = new AVec(); - - byte[] Table = new byte[Tb.Length * 16]; - - for (int Index = 0; Index < Tb.Length; Index++) - for (int Index2 = 0; Index2 < 16; Index2++) - { - Table[Index * 16 + Index2] = (byte)VectorExtractIntZx(Tb[Index], Index2, 0); - } - - for (int Index = 0; Index < Bytes; Index++) - { - byte TblIdx = (byte)VectorExtractIntZx(Vector, Index, 0); - - if (TblIdx < Table.Length) - { - Res = VectorInsertInt(Table[TblIdx], Res, Index, 0); - } - } - - return Res; - } - - public static ulong VectorExtractIntZx(AVec Vector, int Index, int Size) - { - switch (Size) - { - case 0: return Vector.ExtractByte (Index); - case 1: return Vector.ExtractUInt16(Index); - case 2: return Vector.ExtractUInt32(Index); - case 3: return Vector.ExtractUInt64(Index); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - public static long VectorExtractIntSx(AVec Vector, int Index, int Size) - { - switch (Size) - { - case 0: return (sbyte)Vector.ExtractByte (Index); - case 1: return (short)Vector.ExtractUInt16(Index); - case 2: return (int)Vector.ExtractUInt32(Index); - case 3: return (long)Vector.ExtractUInt64(Index); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - public static float VectorExtractSingle(AVec Vector, int Index) - { - return Vector.ExtractSingle(Index); - } - - public static double VectorExtractDouble(AVec Vector, int Index) - { - return Vector.ExtractDouble(Index); - } - - public static AVec VectorInsertSingle(float Value, AVec Vector, int Index) - { - return AVec.InsertSingle(Vector, Index, Value); - } - - public static AVec VectorInsertDouble(double Value, AVec Vector, int Index) - { - return AVec.InsertDouble(Vector, Index, Value); - } - - public static AVec VectorInsertInt(ulong Value, AVec Vector, int Index, int Size) - { - switch (Size) - { - case 0: return AVec.InsertByte (Vector, Index, (byte)Value); - case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value); - case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value); - case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value); - } - - throw new ArgumentOutOfRangeException(nameof(Size)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemory.cs b/Ryujinx/Cpu/Memory/AMemory.cs deleted file mode 100644 index f2abffbf..00000000 --- a/Ryujinx/Cpu/Memory/AMemory.cs +++ /dev/null @@ -1,345 +0,0 @@ -using ChocolArm64.Exceptions; -using ChocolArm64.State; -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace ChocolArm64.Memory -{ - public unsafe class AMemory - { - private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; - - public AMemoryMgr Manager { get; private set; } - - private struct ExMonitor - { - public long Position { get; private set; } - - private bool ExState; - - public ExMonitor(long Position, bool ExState) - { - this.Position = Position; - this.ExState = ExState; - } - - public bool HasExclusiveAccess(long Position) - { - return this.Position == Position && ExState; - } - - public void Reset() - { - ExState = false; - } - } - - private Dictionary Monitors; - - private HashSet ExAddrs; - - private byte* RamPtr; - - public AMemory(IntPtr Ram, AMemoryAlloc Allocator) - { - Manager = new AMemoryMgr(Allocator); - - Monitors = new Dictionary(); - - ExAddrs = new HashSet(); - - RamPtr = (byte*)Ram; - } - - public void RemoveMonitor(int ThreadId) - { - lock (Monitors) - { - if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor)) - { - ExAddrs.Remove(Monitor.Position); - } - - Monitors.Remove(ThreadId); - } - } - - public void SetExclusive(AThreadState ThreadState, long Position) - { - Position &= ~ErgMask; - - lock (Monitors) - { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) - { - ExAddrs.Remove(Monitor.Position); - } - - bool ExState = ExAddrs.Add(Position); - - Monitor = new ExMonitor(Position, ExState); - - if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor)) - { - Monitors[ThreadState.ThreadId] = Monitor; - } - } - } - - public bool TestExclusive(AThreadState ThreadState, long Position) - { - Position &= ~ErgMask; - - lock (Monitors) - { - if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) - { - return false; - } - - return Monitor.HasExclusiveAccess(Position); - } - } - - public void ClearExclusive(AThreadState ThreadState) - { - lock (Monitors) - { - if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) - { - Monitor.Reset(); - ExAddrs.Remove(Monitor.Position); - } - } - } - - public bool AcquireAddress(long Position) - { - Position &= ~ErgMask; - - lock (Monitors) - { - return ExAddrs.Add(Position); - } - } - - public void ReleaseAddress(long Position) - { - Position &= ~ErgMask; - - lock (Monitors) - { - ExAddrs.Remove(Position); - } - } - - public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position); - public short ReadInt16(long Position) => (short)ReadUInt16(Position); - public int ReadInt32(long Position) => (int)ReadUInt32(Position); - public long ReadInt64(long Position) => (long)ReadUInt64(Position); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte ReadByte(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return *((byte*)(RamPtr + (uint)Position)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ushort ReadUInt16(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return *((ushort*)(RamPtr + (uint)Position)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint ReadUInt32(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return *((uint*)(RamPtr + (uint)Position)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ulong ReadUInt64(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return *((ulong*)(RamPtr + (uint)Position)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AVec ReadVector8(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return new AVec() { B0 = ReadByte(Position) }; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AVec ReadVector16(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return new AVec() { H0 = ReadUInt16(Position) }; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AVec ReadVector32(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return new AVec() { W0 = ReadUInt32(Position) }; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AVec ReadVector64(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return new AVec() { X0 = ReadUInt64(Position) }; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public AVec ReadVector128(long Position) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Read); -#endif - - return new AVec() - { - X0 = ReadUInt64(Position + 0), - X1 = ReadUInt64(Position + 8) - }; - } - - public void WriteSByte(long Position, sbyte Value) => WriteByte (Position, (byte)Value); - public void WriteInt16(long Position, short Value) => WriteUInt16(Position, (ushort)Value); - public void WriteInt32(long Position, int Value) => WriteUInt32(Position, (uint)Value); - public void WriteInt64(long Position, long Value) => WriteUInt64(Position, (ulong)Value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteByte(long Position, byte Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - *((byte*)(RamPtr + (uint)Position)) = Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteUInt16(long Position, ushort Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - *((ushort*)(RamPtr + (uint)Position)) = Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteUInt32(long Position, uint Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - *((uint*)(RamPtr + (uint)Position)) = Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteUInt64(long Position, ulong Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - *((ulong*)(RamPtr + (uint)Position)) = Value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector8(long Position, AVec Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - WriteByte(Position, Value.B0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector16(long Position, AVec Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - WriteUInt16(Position, Value.H0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector32(long Position, AVec Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - WriteUInt32(Position, Value.W0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector64(long Position, AVec Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - WriteUInt64(Position, Value.X0); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector128(long Position, AVec Value) - { -#if DEBUG - EnsureAccessIsValid(Position, AMemoryPerm.Write); -#endif - - WriteUInt64(Position + 0, Value.X0); - WriteUInt64(Position + 8, Value.X1); - } - - private void EnsureAccessIsValid(long Position, AMemoryPerm Perm) - { - if (!Manager.IsMapped(Position)) - { - throw new VmmPageFaultException(Position); - } - - if (!Manager.HasPermission(Position, Perm)) - { - throw new VmmAccessViolationException(Position, Perm); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemoryAlloc.cs b/Ryujinx/Cpu/Memory/AMemoryAlloc.cs deleted file mode 100644 index b11e7793..00000000 --- a/Ryujinx/Cpu/Memory/AMemoryAlloc.cs +++ /dev/null @@ -1,35 +0,0 @@ -using ChocolArm64.Exceptions; - -namespace ChocolArm64.Memory -{ - public class AMemoryAlloc - { - private long PhysPos; - - public long Alloc(long Size) - { - long Position = PhysPos; - - Size = AMemoryHelper.PageRoundUp(Size); - - PhysPos += Size; - - if (PhysPos > AMemoryMgr.RamSize || PhysPos < 0) - { - throw new VmmOutOfMemoryException(Size); - } - - return Position; - } - - public void Free(long Position) - { - //TODO - } - - public long GetFreeMem() - { - return AMemoryMgr.RamSize - PhysPos; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemoryHelper.cs b/Ryujinx/Cpu/Memory/AMemoryHelper.cs deleted file mode 100644 index 219aeebf..00000000 --- a/Ryujinx/Cpu/Memory/AMemoryHelper.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.IO; -using System.Text; - -namespace ChocolArm64.Memory -{ - public static class AMemoryHelper - { - public static void FillWithZeros(AMemory Memory, long Position, int Size) - { - int Size8 = Size & ~(8 - 1); - - for (int Offs = 0; Offs < Size8; Offs += 8) - { - Memory.WriteInt64(Position + Offs, 0); - } - - for (int Offs = Size8; Offs < (Size - Size8); Offs++) - { - Memory.WriteByte(Position + Offs, 0); - } - } - - public static byte[] ReadBytes(AMemory Memory, long Position, int Size) - { - byte[] Data = new byte[Size]; - - for (int Offs = 0; Offs < Size; Offs++) - { - Data[Offs] = (byte)Memory.ReadByte(Position + Offs); - } - - return Data; - } - - public static void WriteBytes(AMemory Memory, long Position, byte[] Data) - { - for (int Offs = 0; Offs < Data.Length; Offs++) - { - Memory.WriteByte(Position + Offs, Data[Offs]); - } - } - - public static string ReadAsciiString(AMemory Memory, long Position, int MaxSize = -1) - { - using (MemoryStream MS = new MemoryStream()) - { - for (int Offs = 0; Offs < MaxSize || MaxSize == -1; Offs++) - { - byte Value = (byte)Memory.ReadByte(Position + Offs); - - if (Value == 0) - { - break; - } - - MS.WriteByte(Value); - } - - return Encoding.ASCII.GetString(MS.ToArray()); - } - } - - public static long PageRoundUp(long Value) - { - return (Value + AMemoryMgr.PageMask) & ~AMemoryMgr.PageMask; - } - - public static long PageRoundDown(long Value) - { - return Value & ~AMemoryMgr.PageMask; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemoryMapInfo.cs b/Ryujinx/Cpu/Memory/AMemoryMapInfo.cs deleted file mode 100644 index 44b2cc07..00000000 --- a/Ryujinx/Cpu/Memory/AMemoryMapInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace ChocolArm64.Memory -{ - public struct AMemoryMapInfo - { - public long Position { get; private set; } - public long Size { get; private set; } - public int Type { get; private set; } - public int Attr { get; private set; } - - public AMemoryPerm Perm { get; private set; } - - public AMemoryMapInfo(long Position, long Size, int Type, int Attr, AMemoryPerm Perm) - { - this.Position = Position; - this.Size = Size; - this.Type = Type; - this.Attr = Attr; - this.Perm = Perm; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemoryMgr.cs b/Ryujinx/Cpu/Memory/AMemoryMgr.cs deleted file mode 100644 index 05284059..00000000 --- a/Ryujinx/Cpu/Memory/AMemoryMgr.cs +++ /dev/null @@ -1,286 +0,0 @@ -namespace ChocolArm64.Memory -{ - public class AMemoryMgr - { - public const long AddrSize = RamSize; - public const long RamSize = 4L * 1024 * 1024 * 1024; - - private const int PTLvl0Bits = 11; - private const int PTLvl1Bits = 13; - private const int PTPageBits = 12; - - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - public const int PageSize = 1 << PTPageBits; - - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - public const int PageMask = PageSize - 1; - - private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; - private const int PTLvl1Bit = PTPageBits; - - private AMemoryAlloc Allocator; - - private enum PTMap - { - Unmapped, - Mapped - } - - private struct PTEntry - { - public PTMap Map; - public AMemoryPerm Perm; - - public int Type; - public int Attr; - - public PTEntry(PTMap Map, AMemoryPerm Perm, int Type, int Attr) - { - this.Map = Map; - this.Perm = Perm; - this.Type = Type; - this.Attr = Attr; - } - } - - private PTEntry[][] PageTable; - - private bool IsHeapInitialized; - - public long HeapAddr { get; private set; } - public long HeapSize { get; private set; } - - public AMemoryMgr(AMemoryAlloc Allocator) - { - this.Allocator = Allocator; - - PageTable = new PTEntry[PTLvl0Size][]; - } - - public long GetTotalMemorySize() - { - return Allocator.GetFreeMem() + GetUsedMemorySize(); - } - - public long GetUsedMemorySize() - { - long Size = 0; - - for (int L0 = 0; L0 < PageTable.Length; L0++) - { - if (PageTable[L0] == null) - { - continue; - } - - for (int L1 = 0; L1 < PageTable[L0].Length; L1++) - { - Size += PageTable[L0][L1].Map != PTMap.Unmapped ? PageSize : 0; - } - } - - return Size; - } - - public bool SetHeapAddr(long Position) - { - if (!IsHeapInitialized) - { - HeapAddr = Position; - - IsHeapInitialized = true; - - return true; - } - - return false; - } - - public void SetHeapSize(long Size, int Type) - { - //TODO: Return error when theres no enough space to allocate heap. - Size = AMemoryHelper.PageRoundUp(Size); - - long Position = HeapAddr; - - if ((ulong)Size < (ulong)HeapSize) - { - //Try to free now free area if size is smaller than old size. - Position += Size; - - while ((ulong)Size < (ulong)HeapSize) - { - Allocator.Free(Position); - - Position += PageSize; - } - } - else - { - //Allocate extra needed size. - Position += HeapSize; - Size -= HeapSize; - - MapPhys(Position, Size, Type, AMemoryPerm.RW); - } - - HeapSize = Size; - } - - public void MapPhys(long Position, long Size, int Type, AMemoryPerm Perm) - { - while (Size > 0) - { - if (!IsMapped(Position)) - { - SetPTEntry(Position, new PTEntry(PTMap.Mapped, Perm, Type, 0)); - } - - long CPgSize = PageSize - (Position & PageMask); - - Position += CPgSize; - Size -= CPgSize; - } - } - - public void MapMirror(long Src, long Dst, long Size, int Type) - { - Src = AMemoryHelper.PageRoundDown(Src); - Dst = AMemoryHelper.PageRoundDown(Dst); - - Size = AMemoryHelper.PageRoundUp(Size); - - long PagesCount = Size / PageSize; - - while (PagesCount-- > 0) - { - PTEntry SrcEntry = GetPTEntry(Src); - PTEntry DstEntry = GetPTEntry(Dst); - - DstEntry.Map = PTMap.Mapped; - DstEntry.Type = Type; - DstEntry.Perm = SrcEntry.Perm; - - SrcEntry.Perm = AMemoryPerm.None; - - SrcEntry.Attr |= 1; - - SetPTEntry(Src, SrcEntry); - SetPTEntry(Dst, DstEntry); - - Src += PageSize; - Dst += PageSize; - } - } - - public void Reprotect(long Position, long Size, AMemoryPerm Perm) - { - Position = AMemoryHelper.PageRoundDown(Position); - - Size = AMemoryHelper.PageRoundUp(Size); - - long PagesCount = Size / PageSize; - - while (PagesCount-- > 0) - { - PTEntry Entry = GetPTEntry(Position); - - Entry.Perm = Perm; - - SetPTEntry(Position, Entry); - - Position += PageSize; - } - } - - public AMemoryMapInfo GetMapInfo(long Position) - { - Position = AMemoryHelper.PageRoundDown(Position); - - PTEntry BaseEntry = GetPTEntry(Position); - - bool IsSameSegment(long Pos) - { - PTEntry Entry = GetPTEntry(Pos); - - return Entry.Map == BaseEntry.Map && - Entry.Perm == BaseEntry.Perm && - Entry.Type == BaseEntry.Type && - Entry.Attr == BaseEntry.Attr; - } - - long Start = Position; - long End = Position + PageSize; - - while (Start > 0 && IsSameSegment(Start - PageSize)) - { - Start -= PageSize; - } - - while (End < AddrSize && IsSameSegment(End)) - { - End += PageSize; - } - - long Size = End - Start; - - return new AMemoryMapInfo( - Start, - Size, - BaseEntry.Type, - BaseEntry.Attr, - BaseEntry.Perm); - } - - public bool HasPermission(long Position, AMemoryPerm Perm) - { - return GetPTEntry(Position).Perm.HasFlag(Perm); - } - - public bool IsMapped(long Position) - { - if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1].Map != PTMap.Unmapped; - } - - private PTEntry GetPTEntry(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return default(PTEntry); - } - - return PageTable[L0][L1]; - } - - private void SetPTEntry(long Position, PTEntry Entry) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - PageTable[L0] = new PTEntry[PTLvl1Size]; - } - - PageTable[L0][L1] = Entry; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Memory/AMemoryPerm.cs b/Ryujinx/Cpu/Memory/AMemoryPerm.cs deleted file mode 100644 index b425eb94..00000000 --- a/Ryujinx/Cpu/Memory/AMemoryPerm.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ChocolArm64.Memory -{ - [Flags] - public enum AMemoryPerm - { - None = 0, - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - RW = Read | Write, - RX = Read | Execute - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/AInstExceptEventArgs.cs b/Ryujinx/Cpu/State/AInstExceptEventArgs.cs deleted file mode 100644 index f2ee039b..00000000 --- a/Ryujinx/Cpu/State/AInstExceptEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace ChocolArm64.State -{ - public class AInstExceptEventArgs : EventArgs - { - public int Id { get; private set; } - - public AInstExceptEventArgs(int Id) - { - this.Id = Id; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/AInstUndEventArgs.cs b/Ryujinx/Cpu/State/AInstUndEventArgs.cs deleted file mode 100644 index 53de65a3..00000000 --- a/Ryujinx/Cpu/State/AInstUndEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace ChocolArm64.State -{ - public class AInstUndEventArgs : EventArgs - { - public long Position { get; private set; } - public int RawOpCode { get; private set; } - - public AInstUndEventArgs(long Position, int RawOpCode) - { - this.Position = Position; - this.RawOpCode = RawOpCode; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/APState.cs b/Ryujinx/Cpu/State/APState.cs deleted file mode 100644 index f55431a6..00000000 --- a/Ryujinx/Cpu/State/APState.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace ChocolArm64.State -{ - [Flags] - public enum APState - { - VBit = 28, - CBit = 29, - ZBit = 30, - NBit = 31, - - V = 1 << VBit, - C = 1 << CBit, - Z = 1 << ZBit, - N = 1 << NBit, - - NZ = N | Z, - CV = C | V, - - NZCV = NZ | CV - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/ARegister.cs b/Ryujinx/Cpu/State/ARegister.cs deleted file mode 100644 index 5861db8c..00000000 --- a/Ryujinx/Cpu/State/ARegister.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Reflection; - -namespace ChocolArm64.State -{ - struct ARegister - { - public int Index; - - public ARegisterType Type; - - public ARegister(int Index, ARegisterType Type) - { - this.Index = Index; - this.Type = Type; - } - - public override int GetHashCode() - { - return (ushort)Index | ((ushort)Type << 16); - } - - public override bool Equals(object Obj) - { - return Obj is ARegister Reg && - Reg.Index == Index && - Reg.Type == Type; - } - - public FieldInfo GetField() - { - switch (Type) - { - case ARegisterType.Flag: return GetFieldFlag(); - case ARegisterType.Int: return GetFieldInt(); - case ARegisterType.Vector: return GetFieldVector(); - } - - throw new InvalidOperationException(); - } - - private FieldInfo GetFieldFlag() - { - switch ((APState)Index) - { - case APState.VBit: return GetField(nameof(AThreadState.Overflow)); - case APState.CBit: return GetField(nameof(AThreadState.Carry)); - case APState.ZBit: return GetField(nameof(AThreadState.Zero)); - case APState.NBit: return GetField(nameof(AThreadState.Negative)); - } - - throw new InvalidOperationException(); - } - - private FieldInfo GetFieldInt() - { - switch (Index) - { - case 0: return GetField(nameof(AThreadState.X0)); - case 1: return GetField(nameof(AThreadState.X1)); - case 2: return GetField(nameof(AThreadState.X2)); - case 3: return GetField(nameof(AThreadState.X3)); - case 4: return GetField(nameof(AThreadState.X4)); - case 5: return GetField(nameof(AThreadState.X5)); - case 6: return GetField(nameof(AThreadState.X6)); - case 7: return GetField(nameof(AThreadState.X7)); - case 8: return GetField(nameof(AThreadState.X8)); - case 9: return GetField(nameof(AThreadState.X9)); - case 10: return GetField(nameof(AThreadState.X10)); - case 11: return GetField(nameof(AThreadState.X11)); - case 12: return GetField(nameof(AThreadState.X12)); - case 13: return GetField(nameof(AThreadState.X13)); - case 14: return GetField(nameof(AThreadState.X14)); - case 15: return GetField(nameof(AThreadState.X15)); - case 16: return GetField(nameof(AThreadState.X16)); - case 17: return GetField(nameof(AThreadState.X17)); - case 18: return GetField(nameof(AThreadState.X18)); - case 19: return GetField(nameof(AThreadState.X19)); - case 20: return GetField(nameof(AThreadState.X20)); - case 21: return GetField(nameof(AThreadState.X21)); - case 22: return GetField(nameof(AThreadState.X22)); - case 23: return GetField(nameof(AThreadState.X23)); - case 24: return GetField(nameof(AThreadState.X24)); - case 25: return GetField(nameof(AThreadState.X25)); - case 26: return GetField(nameof(AThreadState.X26)); - case 27: return GetField(nameof(AThreadState.X27)); - case 28: return GetField(nameof(AThreadState.X28)); - case 29: return GetField(nameof(AThreadState.X29)); - case 30: return GetField(nameof(AThreadState.X30)); - case 31: return GetField(nameof(AThreadState.X31)); - } - - throw new InvalidOperationException(); - } - - private FieldInfo GetFieldVector() - { - switch (Index) - { - case 0: return GetField(nameof(AThreadState.V0)); - case 1: return GetField(nameof(AThreadState.V1)); - case 2: return GetField(nameof(AThreadState.V2)); - case 3: return GetField(nameof(AThreadState.V3)); - case 4: return GetField(nameof(AThreadState.V4)); - case 5: return GetField(nameof(AThreadState.V5)); - case 6: return GetField(nameof(AThreadState.V6)); - case 7: return GetField(nameof(AThreadState.V7)); - case 8: return GetField(nameof(AThreadState.V8)); - case 9: return GetField(nameof(AThreadState.V9)); - case 10: return GetField(nameof(AThreadState.V10)); - case 11: return GetField(nameof(AThreadState.V11)); - case 12: return GetField(nameof(AThreadState.V12)); - case 13: return GetField(nameof(AThreadState.V13)); - case 14: return GetField(nameof(AThreadState.V14)); - case 15: return GetField(nameof(AThreadState.V15)); - case 16: return GetField(nameof(AThreadState.V16)); - case 17: return GetField(nameof(AThreadState.V17)); - case 18: return GetField(nameof(AThreadState.V18)); - case 19: return GetField(nameof(AThreadState.V19)); - case 20: return GetField(nameof(AThreadState.V20)); - case 21: return GetField(nameof(AThreadState.V21)); - case 22: return GetField(nameof(AThreadState.V22)); - case 23: return GetField(nameof(AThreadState.V23)); - case 24: return GetField(nameof(AThreadState.V24)); - case 25: return GetField(nameof(AThreadState.V25)); - case 26: return GetField(nameof(AThreadState.V26)); - case 27: return GetField(nameof(AThreadState.V27)); - case 28: return GetField(nameof(AThreadState.V28)); - case 29: return GetField(nameof(AThreadState.V29)); - case 30: return GetField(nameof(AThreadState.V30)); - case 31: return GetField(nameof(AThreadState.V31)); - } - - throw new InvalidOperationException(); - } - - private FieldInfo GetField(string Name) - { - return typeof(AThreadState).GetField(Name); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/ARegisterSize.cs b/Ryujinx/Cpu/State/ARegisterSize.cs deleted file mode 100644 index 144f36b9..00000000 --- a/Ryujinx/Cpu/State/ARegisterSize.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChocolArm64.State -{ - enum ARegisterSize - { - Int32, - Int64, - SIMD64, - SIMD128 - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/ARegisterType.cs b/Ryujinx/Cpu/State/ARegisterType.cs deleted file mode 100644 index f9776bb7..00000000 --- a/Ryujinx/Cpu/State/ARegisterType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChocolArm64.State -{ - enum ARegisterType - { - Flag, - Int, - Vector - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/AThreadState.cs b/Ryujinx/Cpu/State/AThreadState.cs deleted file mode 100644 index cdab4034..00000000 --- a/Ryujinx/Cpu/State/AThreadState.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; - -namespace ChocolArm64.State -{ - public class AThreadState - { - internal const int LRIndex = 30; - internal const int ZRIndex = 31; - - internal const int ErgSizeLog2 = 4; - internal const int DczSizeLog2 = 4; - - public ulong X0, X1, X2, X3, X4, X5, X6, X7, - X8, X9, X10, X11, X12, X13, X14, X15, - X16, X17, X18, X19, X20, X21, X22, X23, - X24, X25, X26, X27, X28, X29, X30, X31; - - public AVec V0, V1, V2, V3, V4, V5, V6, V7, - V8, V9, V10, V11, V12, V13, V14, V15, - V16, V17, V18, V19, V20, V21, V22, V23, - V24, V25, V26, V27, V28, V29, V30, V31; - - public bool Overflow; - public bool Carry; - public bool Zero; - public bool Negative; - - public int ProcessId; - public int ThreadId; - - public long TpidrEl0 { get; set; } - public long Tpidr { get; set; } - - public int Fpcr { get; set; } - public int Fpsr { get; set; } - - public uint CtrEl0 => 0x8444c004; - public uint DczidEl0 => 0x00000004; - - private const long TicksPerS = 19_200_000; - private const long TicksPerMS = TicksPerS / 1_000; - - public long CntpctEl0 => Environment.TickCount * TicksPerMS; - - public event EventHandler Break; - public event EventHandler SvcCall; - public event EventHandler Undefined; - - internal void OnBreak(int Imm) - { - Break?.Invoke(this, new AInstExceptEventArgs(Imm)); - } - - internal void OnSvcCall(int Imm) - { - SvcCall?.Invoke(this, new AInstExceptEventArgs(Imm)); - } - - internal void OnUndefined(long Position, int RawOpCode) - { - Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/State/AVec.cs b/Ryujinx/Cpu/State/AVec.cs deleted file mode 100644 index f7eb2e22..00000000 --- a/Ryujinx/Cpu/State/AVec.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ChocolArm64.State -{ - [StructLayout(LayoutKind.Explicit, Size = 16)] - public struct AVec - { - [FieldOffset(0x0)] public byte B0; - [FieldOffset(0x1)] public byte B1; - [FieldOffset(0x2)] public byte B2; - [FieldOffset(0x3)] public byte B3; - [FieldOffset(0x4)] public byte B4; - [FieldOffset(0x5)] public byte B5; - [FieldOffset(0x6)] public byte B6; - [FieldOffset(0x7)] public byte B7; - [FieldOffset(0x8)] public byte B8; - [FieldOffset(0x9)] public byte B9; - [FieldOffset(0xa)] public byte B10; - [FieldOffset(0xb)] public byte B11; - [FieldOffset(0xc)] public byte B12; - [FieldOffset(0xd)] public byte B13; - [FieldOffset(0xe)] public byte B14; - [FieldOffset(0xf)] public byte B15; - - [FieldOffset(0x0)] public ushort H0; - [FieldOffset(0x2)] public ushort H1; - [FieldOffset(0x4)] public ushort H2; - [FieldOffset(0x6)] public ushort H3; - [FieldOffset(0x8)] public ushort H4; - [FieldOffset(0xa)] public ushort H5; - [FieldOffset(0xc)] public ushort H6; - [FieldOffset(0xe)] public ushort H7; - - [FieldOffset(0x0)] public uint W0; - [FieldOffset(0x4)] public uint W1; - [FieldOffset(0x8)] public uint W2; - [FieldOffset(0xc)] public uint W3; - - [FieldOffset(0x0)] public float S0; - [FieldOffset(0x4)] public float S1; - [FieldOffset(0x8)] public float S2; - [FieldOffset(0xc)] public float S3; - - [FieldOffset(0x0)] public ulong X0; - [FieldOffset(0x8)] public ulong X1; - - [FieldOffset(0x0)] public double D0; - [FieldOffset(0x8)] public double D1; - - public byte ExtractByte(int Index) - { - switch (Index) - { - case 0: return B0; - case 1: return B1; - case 2: return B2; - case 3: return B3; - case 4: return B4; - case 5: return B5; - case 6: return B6; - case 7: return B7; - case 8: return B8; - case 9: return B9; - case 10: return B10; - case 11: return B11; - case 12: return B12; - case 13: return B13; - case 14: return B14; - case 15: return B15; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public ushort ExtractUInt16(int Index) - { - switch (Index) - { - case 0: return H0; - case 1: return H1; - case 2: return H2; - case 3: return H3; - case 4: return H4; - case 5: return H5; - case 6: return H6; - case 7: return H7; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public uint ExtractUInt32(int Index) - { - switch (Index) - { - case 0: return W0; - case 1: return W1; - case 2: return W2; - case 3: return W3; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public float ExtractSingle(int Index) - { - switch (Index) - { - case 0: return S0; - case 1: return S1; - case 2: return S2; - case 3: return S3; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public ulong ExtractUInt64(int Index) - { - switch (Index) - { - case 0: return X0; - case 1: return X1; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public double ExtractDouble(int Index) - { - switch (Index) - { - case 0: return D0; - case 1: return D1; - } - - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - public static AVec InsertByte(AVec Vec, int Index, byte Value) - { - switch (Index) - { - case 0: Vec.B0 = Value; break; - case 1: Vec.B1 = Value; break; - case 2: Vec.B2 = Value; break; - case 3: Vec.B3 = Value; break; - case 4: Vec.B4 = Value; break; - case 5: Vec.B5 = Value; break; - case 6: Vec.B6 = Value; break; - case 7: Vec.B7 = Value; break; - case 8: Vec.B8 = Value; break; - case 9: Vec.B9 = Value; break; - case 10: Vec.B10 = Value; break; - case 11: Vec.B11 = Value; break; - case 12: Vec.B12 = Value; break; - case 13: Vec.B13 = Value; break; - case 14: Vec.B14 = Value; break; - case 15: Vec.B15 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - - public static AVec InsertUInt16(AVec Vec, int Index, ushort Value) - { - switch (Index) - { - case 0: Vec.H0 = Value; break; - case 1: Vec.H1 = Value; break; - case 2: Vec.H2 = Value; break; - case 3: Vec.H3 = Value; break; - case 4: Vec.H4 = Value; break; - case 5: Vec.H5 = Value; break; - case 6: Vec.H6 = Value; break; - case 7: Vec.H7 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - - public static AVec InsertUInt32(AVec Vec, int Index, uint Value) - { - switch (Index) - { - case 0: Vec.W0 = Value; break; - case 1: Vec.W1 = Value; break; - case 2: Vec.W2 = Value; break; - case 3: Vec.W3 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - - public static AVec InsertSingle(AVec Vec, int Index, float Value) - { - switch (Index) - { - case 0: Vec.S0 = Value; break; - case 1: Vec.S1 = Value; break; - case 2: Vec.S2 = Value; break; - case 3: Vec.S3 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - - public static AVec InsertUInt64(AVec Vec, int Index, ulong Value) - { - switch (Index) - { - case 0: Vec.X0 = Value; break; - case 1: Vec.X1 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - - public static AVec InsertDouble(AVec Vec, int Index, double Value) - { - switch (Index) - { - case 0: Vec.D0 = Value; break; - case 1: Vec.D1 = Value; break; - - default: throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Vec; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILBlock.cs b/Ryujinx/Cpu/Translation/AILBlock.cs deleted file mode 100644 index bed195aa..00000000 --- a/Ryujinx/Cpu/Translation/AILBlock.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; - -namespace ChocolArm64.Translation -{ - class AILBlock : IAILEmit - { - public long IntInputs { get; private set; } - public long IntOutputs { get; private set; } - - public long VecInputs { get; private set; } - public long VecOutputs { get; private set; } - - public bool HasStateStore { get; private set; } - - public List ILEmitters { get; private set; } - - public AILBlock Next { get; set; } - public AILBlock Branch { get; set; } - - public AILBlock() - { - ILEmitters = new List(); - } - - public void Add(IAILEmit ILEmitter) - { - if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index)) - { - switch (Ld.IoType) - { - case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntOutputs; break; - case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntOutputs; break; - case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecOutputs; break; - } - } - else if (ILEmitter is AILOpCodeStore St) - { - if (AILEmitter.IsRegIndex(St.Index)) - { - switch (St.IoType) - { - case AIoType.Flag: IntOutputs |= (1L << St.Index) << 32; break; - case AIoType.Int: IntOutputs |= 1L << St.Index; break; - case AIoType.Vector: VecOutputs |= 1L << St.Index; break; - } - } - - if (St.IoType == AIoType.Fields) - { - HasStateStore = true; - } - } - - ILEmitters.Add(ILEmitter); - } - - public void Emit(AILEmitter Context) - { - foreach (IAILEmit ILEmitter in ILEmitters) - { - ILEmitter.Emit(Context); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILEmitter.cs b/Ryujinx/Cpu/Translation/AILEmitter.cs deleted file mode 100644 index 8f6e1210..00000000 --- a/Ryujinx/Cpu/Translation/AILEmitter.cs +++ /dev/null @@ -1,187 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.State; -using System; -using System.Collections.Generic; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - class AILEmitter - { - public ALocalAlloc LocalAlloc { get; private set; } - - public ILGenerator Generator { get; private set; } - - private Dictionary Locals; - - private AILBlock[] ILBlocks; - - private AILBlock Root; - - private ATranslatedSub Subroutine; - - private string SubName; - - private int LocalsCount; - - public AILEmitter(ABlock[] Graph, ABlock Root, string SubName) - { - this.SubName = SubName; - - Locals = new Dictionary(); - - ILBlocks = new AILBlock[Graph.Length]; - - AILBlock GetBlock(int Index) - { - if (Index < 0 || Index >= ILBlocks.Length) - { - return null; - } - - if (ILBlocks[Index] == null) - { - ILBlocks[Index] = new AILBlock(); - } - - return ILBlocks[Index]; - } - - for (int Index = 0; Index < ILBlocks.Length; Index++) - { - AILBlock Block = GetBlock(Index); - - Block.Next = GetBlock(Array.IndexOf(Graph, Graph[Index].Next)); - Block.Branch = GetBlock(Array.IndexOf(Graph, Graph[Index].Branch)); - } - - this.Root = ILBlocks[Array.IndexOf(Graph, Root)]; - } - - public ATranslatedSub GetSubroutine() - { - LocalAlloc = new ALocalAlloc(ILBlocks, Root); - - InitSubroutine(); - InitLocals(); - - foreach (AILBlock ILBlock in ILBlocks) - { - ILBlock.Emit(this); - } - - return Subroutine; - } - - public AILBlock GetILBlock(int Index) => ILBlocks[Index]; - - private void InitLocals() - { - int ParamsStart = ATranslatedSub.FixedArgTypes.Length; - - Locals = new Dictionary(); - - for (int Index = 0; Index < Subroutine.Params.Count; Index++) - { - ARegister Reg = Subroutine.Params[Index]; - - Generator.EmitLdarg(Index + ParamsStart); - Generator.EmitStloc(GetLocalIndex(Reg)); - } - } - - private void InitSubroutine() - { - List Params = new List(); - - void SetParams(long Inputs, ARegisterType BaseType) - { - for (int Bit = 0; Bit < 64; Bit++) - { - long Mask = 1L << Bit; - - if ((Inputs & Mask) != 0) - { - Params.Add(GetRegFromBit(Bit, BaseType)); - } - } - } - - SetParams(LocalAlloc.GetIntInputs(Root), ARegisterType.Int); - SetParams(LocalAlloc.GetVecInputs(Root), ARegisterType.Vector); - - DynamicMethod Mthd = new DynamicMethod(SubName, typeof(long), GetParamTypes(Params)); - - Generator = Mthd.GetILGenerator(); - - Subroutine = new ATranslatedSub(Mthd, Params); - } - - private Type[] GetParamTypes(IList Params) - { - Type[] FixedArgs = ATranslatedSub.FixedArgTypes; - - Type[] Output = new Type[Params.Count + FixedArgs.Length]; - - FixedArgs.CopyTo(Output, 0); - - int TypeIdx = FixedArgs.Length; - - for (int Index = 0; Index < Params.Count; Index++) - { - Output[TypeIdx++] = GetFieldType(Params[Index].Type); - } - - return Output; - } - - public int GetLocalIndex(ARegister Reg) - { - if (!Locals.TryGetValue(Reg, out int Index)) - { - Generator.DeclareLocal(GetLocalType(Reg)); - - Index = LocalsCount++; - - Locals.Add(Reg, Index); - } - - return Index; - } - - public Type GetLocalType(ARegister Reg) => GetFieldType(Reg.Type); - - public Type GetFieldType(ARegisterType RegType) - { - switch (RegType) - { - case ARegisterType.Flag: return typeof(bool); - case ARegisterType.Int: return typeof(ulong); - case ARegisterType.Vector: return typeof(AVec); - } - - throw new ArgumentException(nameof(RegType)); - } - - public static ARegister GetRegFromBit(int Bit, ARegisterType BaseType) - { - if (Bit < 32) - { - return new ARegister(Bit, BaseType); - } - else if (BaseType == ARegisterType.Int) - { - return new ARegister(Bit & 0x1f, ARegisterType.Flag); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Bit)); - } - } - - public static bool IsRegIndex(int Index) - { - return Index >= 0 && Index < 32; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs deleted file mode 100644 index cf644540..00000000 --- a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs +++ /dev/null @@ -1,487 +0,0 @@ -using ChocolArm64.Decoder; -using ChocolArm64.Instruction; -using ChocolArm64.State; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - class AILEmitterCtx - { - private ATranslator Translator; - - private Dictionary Labels; - - private AILEmitter Emitter; - - private AILBlock ILBlock; - - private AOpCode LastCmpOp; - private AOpCode LastFlagOp; - - private int BlkIndex; - private int OpcIndex; - - private ABlock[] Graph; - private ABlock Root; - public ABlock CurrBlock => Graph[BlkIndex]; - public AOpCode CurrOp => Graph[BlkIndex].OpCodes[OpcIndex]; - - //This is the index of the temporary register, used to store temporary - //values needed by some functions, since IL doesn't have a swap instruction. - //You can use any value here as long it doesn't conflict with the indices - //for the other registers. Any value >= 64 or < 0 will do. - private const int Tmp1Index = -1; - private const int Tmp2Index = -2; - private const int Tmp3Index = -3; - private const int Tmp4Index = -4; - private const int Tmp5Index = -5; - - public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root) - { - this.Translator = Translator; - this.Graph = Graph; - this.Root = Root; - - string SubName = $"Sub{Root.Position:X16}"; - - Labels = new Dictionary(); - - Emitter = new AILEmitter(Graph, Root, SubName); - - ILBlock = Emitter.GetILBlock(0); - - OpcIndex = -1; - - if (!AdvanceOpCode()) - { - throw new ArgumentException(nameof(Graph)); - } - } - - public ATranslatedSub GetSubroutine() => Emitter.GetSubroutine(); - - public bool AdvanceOpCode() - { - while (++OpcIndex >= (CurrBlock?.OpCodes.Count ?? 0)) - { - if (BlkIndex + 1 >= Graph.Length) - { - return false; - } - - BlkIndex++; - OpcIndex = -1; - - ILBlock = Emitter.GetILBlock(BlkIndex); - } - - return true; - } - - public void EmitOpCode() - { - if (OpcIndex == 0) - { - MarkLabel(GetLabel(CurrBlock.Position)); - } - - CurrOp.Emitter(this); - } - - public bool TryOptEmitSubroutineCall() - { - if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub)) - { - return false; - } - - for (int Index = 0; Index < ATranslatedSub.FixedArgTypes.Length; Index++) - { - EmitLdarg(Index); - } - - foreach (ARegister Reg in Sub.Params) - { - switch (Reg.Type) - { - case ARegisterType.Flag: Ldloc(Reg.Index, AIoType.Flag); break; - case ARegisterType.Int: Ldloc(Reg.Index, AIoType.Int); break; - case ARegisterType.Vector: Ldloc(Reg.Index, AIoType.Vector); break; - } - } - - EmitCall(Sub.Method); - - return true; - } - - public void TryOptMarkCondWithoutCmp() - { - LastCmpOp = CurrOp; - - AInstEmitAluHelper.EmitDataLoadOpers(this); - - Stloc(Tmp4Index, AIoType.Int); - Stloc(Tmp3Index, AIoType.Int); - } - - private Dictionary BranchOps = new Dictionary() - { - { ACond.Eq, OpCodes.Beq }, - { ACond.Ne, OpCodes.Bne_Un }, - { ACond.Ge_Un, OpCodes.Bge_Un }, - { ACond.Lt_Un, OpCodes.Blt_Un }, - { ACond.Gt_Un, OpCodes.Bgt_Un }, - { ACond.Le_Un, OpCodes.Ble_Un }, - { ACond.Ge, OpCodes.Bge }, - { ACond.Lt, OpCodes.Blt }, - { ACond.Gt, OpCodes.Bgt }, - { ACond.Le, OpCodes.Ble } - }; - - public void EmitCondBranch(AILLabel Target, ACond Cond) - { - OpCode ILOp; - - int IntCond = (int)Cond; - - if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond)) - { - Ldloc(Tmp3Index, AIoType.Int, LastCmpOp.RegisterSize); - Ldloc(Tmp4Index, AIoType.Int, LastCmpOp.RegisterSize); - - if (LastCmpOp.Emitter == AInstEmit.Adds) - { - Emit(OpCodes.Neg); - } - - ILOp = BranchOps[Cond]; - } - else if (IntCond < 14) - { - int CondTrue = IntCond >> 1; - - switch (CondTrue) - { - case 0: EmitLdflg((int)APState.ZBit); break; - case 1: EmitLdflg((int)APState.CBit); break; - case 2: EmitLdflg((int)APState.NBit); break; - case 3: EmitLdflg((int)APState.VBit); break; - - case 4: - EmitLdflg((int)APState.CBit); - EmitLdflg((int)APState.ZBit); - - Emit(OpCodes.Not); - Emit(OpCodes.And); - break; - - case 5: - case 6: - EmitLdflg((int)APState.NBit); - EmitLdflg((int)APState.VBit); - - Emit(OpCodes.Ceq); - - if (CondTrue == 6) - { - EmitLdflg((int)APState.ZBit); - - Emit(OpCodes.Not); - Emit(OpCodes.And); - } - break; - } - - ILOp = (IntCond & 1) != 0 - ? OpCodes.Brfalse - : OpCodes.Brtrue; - } - else - { - ILOp = OpCodes.Br; - } - - Emit(ILOp, Target); - } - - public void EmitCast(AIntType IntType) - { - switch (IntType) - { - case AIntType.UInt8: Emit(OpCodes.Conv_U1); break; - case AIntType.UInt16: Emit(OpCodes.Conv_U2); break; - case AIntType.UInt32: Emit(OpCodes.Conv_U4); break; - case AIntType.UInt64: Emit(OpCodes.Conv_U8); break; - case AIntType.Int8: Emit(OpCodes.Conv_I1); break; - case AIntType.Int16: Emit(OpCodes.Conv_I2); break; - case AIntType.Int32: Emit(OpCodes.Conv_I4); break; - case AIntType.Int64: Emit(OpCodes.Conv_I8); break; - } - - if (IntType == AIntType.UInt64 || - IntType == AIntType.Int64) - { - return; - } - - if (CurrOp.RegisterSize != ARegisterSize.Int32) - { - Emit(IntType >= AIntType.Int8 - ? OpCodes.Conv_I8 - : OpCodes.Conv_U8); - } - } - - public void EmitLsl(int Amount) => EmitILShift(Amount, OpCodes.Shl); - public void EmitLsr(int Amount) => EmitILShift(Amount, OpCodes.Shr_Un); - public void EmitAsr(int Amount) => EmitILShift(Amount, OpCodes.Shr); - - private void EmitILShift(int Amount, OpCode ILOp) - { - if (Amount > 0) - { - EmitLdc_I4(Amount); - - Emit(ILOp); - } - } - - public void EmitRor(int Amount) - { - if (Amount > 0) - { - Stloc(Tmp2Index, AIoType.Int); - Ldloc(Tmp2Index, AIoType.Int); - - EmitLdc_I4(Amount); - - Emit(OpCodes.Shr_Un); - - Ldloc(Tmp2Index, AIoType.Int); - - EmitLdc_I4(CurrOp.GetBitsCount() - Amount); - - Emit(OpCodes.Shl); - Emit(OpCodes.Or); - } - } - - public AILLabel GetLabel(long Position) - { - if (!Labels.TryGetValue(Position, out AILLabel Output)) - { - Output = new AILLabel(); - - Labels.Add(Position, Output); - } - - return Output; - } - - public void MarkLabel(AILLabel Label) - { - ILBlock.Add(Label); - } - - public void Emit(OpCode ILOp) - { - ILBlock.Add(new AILOpCode(ILOp)); - } - - public void Emit(OpCode ILOp, AILLabel Label) - { - ILBlock.Add(new AILOpCodeBranch(ILOp, Label)); - } - - public void Emit(string Text) - { - ILBlock.Add(new AILOpCodeLog(Text)); - } - - public void EmitLdarg(int Index) - { - ILBlock.Add(new AILOpCodeLoad(Index, AIoType.Arg)); - } - - public void EmitLdintzr(int Index) - { - if (Index != AThreadState.ZRIndex) - { - EmitLdint(Index); - } - else - { - EmitLdc_I(0); - } - } - - public void EmitStintzr(int Index) - { - if (Index != AThreadState.ZRIndex) - { - EmitStint(Index); - } - else - { - Emit(OpCodes.Pop); - } - } - - public void EmitLoadState(ABlock RetBlk) - { - ILBlock.Add(new AILOpCodeLoad(Array.IndexOf(Graph, RetBlk), AIoType.Fields)); - } - - public void EmitStoreState() - { - ILBlock.Add(new AILOpCodeStore(Array.IndexOf(Graph, CurrBlock), AIoType.Fields)); - } - - public void EmitLdtmp() => EmitLdint(Tmp1Index); - public void EmitSttmp() => EmitStint(Tmp1Index); - - public void EmitLdvectmp() => EmitLdvec(Tmp5Index); - public void EmitStvectmp() => EmitStvec(Tmp5Index); - - public void EmitLdint(int Index) => Ldloc(Index, AIoType.Int); - public void EmitStint(int Index) => Stloc(Index, AIoType.Int); - - public void EmitLdvec(int Index) => Ldloc(Index, AIoType.Vector); - public void EmitStvec(int Index) => Stloc(Index, AIoType.Vector); - - public void EmitLdflg(int Index) => Ldloc(Index, AIoType.Flag); - public void EmitStflg(int Index) - { - LastFlagOp = CurrOp; - - Stloc(Index, AIoType.Flag); - } - - private void Ldloc(int Index, AIoType IoType) - { - ILBlock.Add(new AILOpCodeLoad(Index, IoType, CurrOp.RegisterSize)); - } - - private void Ldloc(int Index, AIoType IoType, ARegisterSize RegisterSize) - { - ILBlock.Add(new AILOpCodeLoad(Index, IoType, RegisterSize)); - } - - private void Stloc(int Index, AIoType IoType) - { - ILBlock.Add(new AILOpCodeStore(Index, IoType, CurrOp.RegisterSize)); - } - - public void EmitCallPropGet(Type ObjType, string PropName) - { - if (ObjType == null) - { - throw new ArgumentNullException(nameof(ObjType)); - } - - if (PropName == null) - { - throw new ArgumentNullException(nameof(PropName)); - } - - EmitCall(ObjType.GetMethod($"get_{PropName}")); - } - - public void EmitCallPropSet(Type ObjType, string PropName) - { - if (ObjType == null) - { - throw new ArgumentNullException(nameof(ObjType)); - } - - if (PropName == null) - { - throw new ArgumentNullException(nameof(PropName)); - } - - EmitCall(ObjType.GetMethod($"set_{PropName}")); - } - - public void EmitCall(Type ObjType, string MthdName) - { - if (ObjType == null) - { - throw new ArgumentNullException(nameof(ObjType)); - } - - if (MthdName == null) - { - throw new ArgumentNullException(nameof(MthdName)); - } - - EmitCall(ObjType.GetMethod(MthdName)); - } - - public void EmitCall(MethodInfo MthdInfo) - { - if (MthdInfo == null) - { - throw new ArgumentNullException(nameof(MthdInfo)); - } - - ILBlock.Add(new AILOpCodeCall(MthdInfo)); - } - - public void EmitLdc_I(long Value) - { - if (CurrOp.RegisterSize == ARegisterSize.Int32) - { - EmitLdc_I4((int)Value); - } - else - { - EmitLdc_I8(Value); - } - } - - public void EmitLdc_I4(int Value) - { - ILBlock.Add(new AILOpCodeConst(Value)); - } - - public void EmitLdc_I8(long Value) - { - ILBlock.Add(new AILOpCodeConst(Value)); - } - - public void EmitLdc_R4(float Value) - { - ILBlock.Add(new AILOpCodeConst(Value)); - } - - public void EmitLdc_R8(double Value) - { - ILBlock.Add(new AILOpCodeConst(Value)); - } - - public void EmitZNFlagCheck() - { - EmitZNCheck(OpCodes.Ceq, (int)APState.ZBit); - EmitZNCheck(OpCodes.Clt, (int)APState.NBit); - } - - private void EmitZNCheck(OpCode ILCmpOp, int Flag) - { - Emit(OpCodes.Dup); - Emit(OpCodes.Ldc_I4_0); - - if (CurrOp.RegisterSize != ARegisterSize.Int32) - { - Emit(OpCodes.Conv_I8); - } - - Emit(ILCmpOp); - - EmitStflg(Flag); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILLabel.cs b/Ryujinx/Cpu/Translation/AILLabel.cs deleted file mode 100644 index 0ee39ad7..00000000 --- a/Ryujinx/Cpu/Translation/AILLabel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - class AILLabel : IAILEmit - { - private bool HasLabel; - - private Label Lbl; - - public void Emit(AILEmitter Context) - { - Context.Generator.MarkLabel(GetLabel(Context)); - } - - public Label GetLabel(AILEmitter Context) - { - if (!HasLabel) - { - Lbl = Context.Generator.DefineLabel(); - - HasLabel = true; - } - - return Lbl; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCode.cs b/Ryujinx/Cpu/Translation/AILOpCode.cs deleted file mode 100644 index a4bc93a0..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCode.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - struct AILOpCode : IAILEmit - { - private OpCode ILOp; - - public AILOpCode(OpCode ILOp) - { - this.ILOp = ILOp; - } - - public void Emit(AILEmitter Context) - { - Context.Generator.Emit(ILOp); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeBranch.cs b/Ryujinx/Cpu/Translation/AILOpCodeBranch.cs deleted file mode 100644 index e4caad1f..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeBranch.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - struct AILOpCodeBranch : IAILEmit - { - private OpCode ILOp; - private AILLabel Label; - - public AILOpCodeBranch(OpCode ILOp, AILLabel Label) - { - this.ILOp = ILOp; - this.Label = Label; - } - - public void Emit(AILEmitter Context) - { - Context.Generator.Emit(ILOp, Label.GetLabel(Context)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeCall.cs b/Ryujinx/Cpu/Translation/AILOpCodeCall.cs deleted file mode 100644 index 8cd944eb..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeCall.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - struct AILOpCodeCall : IAILEmit - { - private MethodInfo MthdInfo; - - public AILOpCodeCall(MethodInfo MthdInfo) - { - this.MthdInfo = MthdInfo; - } - - public void Emit(AILEmitter Context) - { - Context.Generator.Emit(OpCodes.Call, MthdInfo); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeConst.cs b/Ryujinx/Cpu/Translation/AILOpCodeConst.cs deleted file mode 100644 index 80150ec5..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeConst.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Reflection.Emit; -using System.Runtime.InteropServices; - -namespace ChocolArm64.Translation -{ - class AILOpCodeConst : IAILEmit - { - [StructLayout(LayoutKind.Explicit, Size = 8)] - private struct ImmVal - { - [FieldOffset(0)] public int I4; - [FieldOffset(0)] public long I8; - [FieldOffset(0)] public float R4; - [FieldOffset(0)] public double R8; - } - - private ImmVal Value; - - private enum ConstType - { - Int32, - Int64, - Single, - Double - } - - private ConstType Type; - - private AILOpCodeConst(ConstType Type) - { - this.Type = Type; - } - - public AILOpCodeConst(int Value) : this(ConstType.Int32) - { - this.Value = new ImmVal { I4 = Value }; - } - - public AILOpCodeConst(long Value) : this(ConstType.Int64) - { - this.Value = new ImmVal { I8 = Value }; - } - - public AILOpCodeConst(float Value) : this(ConstType.Single) - { - this.Value = new ImmVal { R4 = Value }; - } - - public AILOpCodeConst(double Value) : this(ConstType.Double) - { - this.Value = new ImmVal { R8 = Value }; - } - - public void Emit(AILEmitter Context) - { - switch (Type) - { - case ConstType.Int32: Context.Generator.EmitLdc_I4(Value.I4); break; - - case ConstType.Int64: - { - if (Value.I8 >= int.MinValue && - Value.I8 <= int.MaxValue) - { - Context.Generator.EmitLdc_I4(Value.I4); - - Context.Generator.Emit(OpCodes.Conv_I8); - } - else - { - Context.Generator.Emit(OpCodes.Ldc_I8, Value.I8); - } - break; - } - - case ConstType.Single: Context.Generator.Emit(OpCodes.Ldc_R4, Value.R4); break; - case ConstType.Double: Context.Generator.Emit(OpCodes.Ldc_R8, Value.R8); break; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs b/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs deleted file mode 100644 index 7cb431e2..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs +++ /dev/null @@ -1,77 +0,0 @@ -using ChocolArm64.State; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - struct AILOpCodeLoad : IAILEmit - { - public int Index { get; private set; } - - public AIoType IoType { get; private set; } - - public ARegisterSize RegisterSize { get; private set; } - - public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { } - - public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize) - { - this.IoType = IoType; - this.Index = Index; - this.RegisterSize = RegisterSize; - } - - public void Emit(AILEmitter Context) - { - switch (IoType) - { - case AIoType.Arg: Context.Generator.EmitLdarg(Index); break; - - case AIoType.Fields: - { - long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index)); - long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index)); - - LoadLocals(Context, IntInputs, ARegisterType.Int); - LoadLocals(Context, VecInputs, ARegisterType.Vector); - - break; - } - - case AIoType.Flag: EmitLdloc(Context, Index, ARegisterType.Flag); break; - case AIoType.Int: EmitLdloc(Context, Index, ARegisterType.Int); break; - case AIoType.Vector: EmitLdloc(Context, Index, ARegisterType.Vector); break; - } - } - - private void LoadLocals(AILEmitter Context, long Inputs, ARegisterType BaseType) - { - for (int Bit = 0; Bit < 64; Bit++) - { - long Mask = 1L << Bit; - - if ((Inputs & Mask) != 0) - { - ARegister Reg = AILEmitter.GetRegFromBit(Bit, BaseType); - - Context.Generator.EmitLdarg(ATranslatedSub.StateArgIdx); - Context.Generator.Emit(OpCodes.Ldfld, Reg.GetField()); - - Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); - } - } - } - - private void EmitLdloc(AILEmitter Context, int Index, ARegisterType RegisterType) - { - ARegister Reg = new ARegister(Index, RegisterType); - - Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); - - if (RegisterType == ARegisterType.Int && - RegisterSize == ARegisterSize.Int32) - { - Context.Generator.Emit(OpCodes.Conv_U4); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeLog.cs b/Ryujinx/Cpu/Translation/AILOpCodeLog.cs deleted file mode 100644 index 1338ca1f..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeLog.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace ChocolArm64.Translation -{ - struct AILOpCodeLog : IAILEmit - { - private string Text; - - public AILOpCodeLog(string Text) - { - this.Text = Text; - } - - public void Emit(AILEmitter Context) - { - Context.Generator.EmitWriteLine(Text); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs b/Ryujinx/Cpu/Translation/AILOpCodeStore.cs deleted file mode 100644 index c4ea53ab..00000000 --- a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs +++ /dev/null @@ -1,75 +0,0 @@ -using ChocolArm64.State; -using System.Reflection.Emit; - -namespace ChocolArm64.Translation -{ - struct AILOpCodeStore : IAILEmit - { - public int Index { get; private set; } - - public AIoType IoType { get; private set; } - - public ARegisterSize RegisterSize { get; private set; } - - public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = ARegisterSize.Int64) - { - this.IoType = IoType; - this.Index = Index; - this.RegisterSize = RegisterSize; - } - - public void Emit(AILEmitter Context) - { - switch (IoType) - { - case AIoType.Arg: Context.Generator.EmitStarg(Index); break; - - case AIoType.Fields: - { - long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index)); - long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index)); - - StoreLocals(Context, IntOutputs, ARegisterType.Int); - StoreLocals(Context, VecOutputs, ARegisterType.Vector); - - break; - } - - case AIoType.Flag: EmitStloc(Context, Index, ARegisterType.Flag); break; - case AIoType.Int: EmitStloc(Context, Index, ARegisterType.Int); break; - case AIoType.Vector: EmitStloc(Context, Index, ARegisterType.Vector); break; - } - } - - private void StoreLocals(AILEmitter Context, long Outputs, ARegisterType BaseType) - { - for (int Bit = 0; Bit < 64; Bit++) - { - long Mask = 1L << Bit; - - if ((Outputs & Mask) != 0) - { - ARegister Reg = AILEmitter.GetRegFromBit(Bit, BaseType); - - Context.Generator.EmitLdarg(ATranslatedSub.StateArgIdx); - Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg)); - - Context.Generator.Emit(OpCodes.Stfld, Reg.GetField()); - } - } - } - - private void EmitStloc(AILEmitter Context, int Index, ARegisterType RegisterType) - { - ARegister Reg = new ARegister(Index, RegisterType); - - if (RegisterType == ARegisterType.Int && - RegisterSize == ARegisterSize.Int32) - { - Context.Generator.Emit(OpCodes.Conv_U8); - } - - Context.Generator.EmitStloc(Context.GetLocalIndex(Reg)); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/AIoType.cs b/Ryujinx/Cpu/Translation/AIoType.cs deleted file mode 100644 index 94f89081..00000000 --- a/Ryujinx/Cpu/Translation/AIoType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ChocolArm64.Translation -{ - [Flags] - enum AIoType - { - Arg, - Fields, - Flag, - Int, - Float, - Vector - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/ALocalAlloc.cs b/Ryujinx/Cpu/Translation/ALocalAlloc.cs deleted file mode 100644 index 0661ddc8..00000000 --- a/Ryujinx/Cpu/Translation/ALocalAlloc.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System.Collections.Generic; - -namespace ChocolArm64.Translation -{ - class ALocalAlloc - { - private class PathIo - { - private Dictionary AllInputs; - private Dictionary CmnOutputs; - - private long AllOutputs; - - public PathIo() - { - AllInputs = new Dictionary(); - CmnOutputs = new Dictionary(); - } - - public PathIo(AILBlock Root, long Inputs, long Outputs) : this() - { - Set(Root, Inputs, Outputs); - } - - public void Set(AILBlock Root, long Inputs, long Outputs) - { - if (!AllInputs.TryAdd(Root, Inputs)) - { - AllInputs[Root] |= Inputs; - } - - if (!CmnOutputs.TryAdd(Root, Outputs)) - { - CmnOutputs[Root] &= Outputs; - } - - AllOutputs |= Outputs; - } - - public long GetInputs(AILBlock Root) - { - if (AllInputs.TryGetValue(Root, out long Inputs)) - { - return Inputs | (AllOutputs & ~CmnOutputs[Root]); - } - - return 0; - } - - public long GetOutputs() - { - return AllOutputs; - } - } - - private Dictionary IntPaths; - private Dictionary VecPaths; - - private struct BlockIo - { - public AILBlock Block; - public AILBlock Entry; - - public long IntInputs; - public long VecInputs; - public long IntOutputs; - public long VecOutputs; - } - - private const int MaxOptGraphLength = 120; - - public ALocalAlloc(AILBlock[] Graph, AILBlock Root) - { - IntPaths = new Dictionary(); - VecPaths = new Dictionary(); - - if (Graph.Length < MaxOptGraphLength) - { - InitializeOptimal(Graph, Root); - } - else - { - InitializeFast(Graph); - } - } - - private void InitializeOptimal(AILBlock[] Graph, AILBlock Root) - { - //This will go through all possible paths on the graph, - //and store all inputs/outputs for each block. A register - //that was previously written to already is not considered an input. - //When a block can be reached by more than one path, then the - //output from all paths needs to be set for this block, and - //only outputs present in all of the parent blocks can be considered - //when doing input elimination. Each block chain have a root, that's where - //the code starts executing. They are present on the subroutine start point, - //and on call return points too (address written to X30 by BL). - HashSet Visited = new HashSet(); - - Queue Unvisited = new Queue(); - - void Enqueue(BlockIo Block) - { - if (!Visited.Contains(Block)) - { - Unvisited.Enqueue(Block); - - Visited.Add(Block); - } - } - - Enqueue(new BlockIo() - { - Block = Root, - Entry = Root - }); - - while (Unvisited.Count > 0) - { - BlockIo Current = Unvisited.Dequeue(); - - Current.IntInputs |= Current.Block.IntInputs & ~Current.IntOutputs; - Current.VecInputs |= Current.Block.VecInputs & ~Current.VecOutputs; - Current.IntOutputs |= Current.Block.IntOutputs; - Current.VecOutputs |= Current.Block.VecOutputs; - - //Check if this is a exit block - //(a block that returns or calls another sub). - if ((Current.Block.Next == null && - Current.Block.Branch == null) || Current.Block.HasStateStore) - { - if (!IntPaths.TryGetValue(Current.Block, out PathIo IntPath)) - { - IntPaths.Add(Current.Block, IntPath = new PathIo()); - } - - if (!VecPaths.TryGetValue(Current.Block, out PathIo VecPath)) - { - VecPaths.Add(Current.Block, VecPath = new PathIo()); - } - - IntPath.Set(Current.Entry, Current.IntInputs, Current.IntOutputs); - VecPath.Set(Current.Entry, Current.VecInputs, Current.VecOutputs); - } - - void EnqueueFromCurrent(AILBlock Block, bool RetTarget) - { - BlockIo BlkIO = new BlockIo() { Block = Block }; - - if (RetTarget) - { - BlkIO.Entry = Block; - BlkIO.IntInputs = 0; - BlkIO.VecInputs = 0; - BlkIO.IntOutputs = 0; - BlkIO.VecOutputs = 0; - } - else - { - BlkIO.Entry = Current.Entry; - BlkIO.IntInputs = Current.IntInputs; - BlkIO.VecInputs = Current.VecInputs; - BlkIO.IntOutputs = Current.IntOutputs; - BlkIO.VecOutputs = Current.VecOutputs; - } - - Enqueue(BlkIO); - } - - if (Current.Block.Next != null) - { - EnqueueFromCurrent(Current.Block.Next, Current.Block.HasStateStore); - } - - if (Current.Block.Branch != null) - { - EnqueueFromCurrent(Current.Block.Branch, false); - } - } - } - - private void InitializeFast(AILBlock[] Graph) - { - //This is WAY faster than InitializeOptimal, but results in - //uneeded loads and stores, so the resulting code will be slower. - long IntInputs = 0; - long IntOutputs = 0; - long VecInputs = 0; - long VecOutputs = 0; - - foreach (AILBlock Block in Graph) - { - IntInputs |= Block.IntInputs; - IntOutputs |= Block.IntOutputs; - VecInputs |= Block.VecInputs; - VecOutputs |= Block.VecOutputs; - } - - //It's possible that not all code paths writes to those output registers, - //in those cases if we attempt to write an output registers that was - //not written, we will be just writing zero and messing up the old register value. - //So we just need to ensure that all outputs are loaded. - IntInputs |= IntOutputs; - VecInputs |= VecOutputs; - - foreach (AILBlock Block in Graph) - { - IntPaths.Add(Block, new PathIo(Block, IntInputs, IntOutputs)); - VecPaths.Add(Block, new PathIo(Block, VecInputs, VecOutputs)); - } - } - - public long GetIntInputs(AILBlock Root) => GetInputsImpl(Root, IntPaths.Values); - public long GetVecInputs(AILBlock Root) => GetInputsImpl(Root, VecPaths.Values); - - private long GetInputsImpl(AILBlock Root, IEnumerable Values) - { - long Inputs = 0; - - foreach (PathIo Path in Values) - { - Inputs |= Path.GetInputs(Root); - } - - return Inputs; - } - - public long GetIntOutputs(AILBlock Block) => IntPaths[Block].GetOutputs(); - public long GetVecOutputs(AILBlock Block) => VecPaths[Block].GetOutputs(); - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/IAILEmit.cs b/Ryujinx/Cpu/Translation/IAILEmit.cs deleted file mode 100644 index 6e4e9a78..00000000 --- a/Ryujinx/Cpu/Translation/IAILEmit.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChocolArm64.Translation -{ - interface IAILEmit - { - void Emit(AILEmitter Context); - } -} \ No newline at end of file diff --git a/Ryujinx/Cpu/Translation/ILGeneratorEx.cs b/Ryujinx/Cpu/Translation/ILGeneratorEx.cs deleted file mode 100644 index abb35ec3..00000000 --- a/Ryujinx/Cpu/Translation/ILGeneratorEx.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; - -namespace ChocolArm64 -{ - using System.Reflection.Emit; - - static class ILGeneratorEx - { - public static void EmitLdc_I4(this ILGenerator Generator,int Value) - { - switch (Value) - { - case 0: Generator.Emit(OpCodes.Ldc_I4_0); break; - case 1: Generator.Emit(OpCodes.Ldc_I4_1); break; - case 2: Generator.Emit(OpCodes.Ldc_I4_2); break; - case 3: Generator.Emit(OpCodes.Ldc_I4_3); break; - case 4: Generator.Emit(OpCodes.Ldc_I4_4); break; - case 5: Generator.Emit(OpCodes.Ldc_I4_5); break; - case 6: Generator.Emit(OpCodes.Ldc_I4_6); break; - case 7: Generator.Emit(OpCodes.Ldc_I4_7); break; - case 8: Generator.Emit(OpCodes.Ldc_I4_8); break; - case -1: Generator.Emit(OpCodes.Ldc_I4_M1); break; - default: Generator.Emit(OpCodes.Ldc_I4, Value); break; - } - } - - public static void EmitLdarg(this ILGenerator Generator, int Index) - { - switch (Index) - { - case 0: Generator.Emit(OpCodes.Ldarg_0); break; - case 1: Generator.Emit(OpCodes.Ldarg_1); break; - case 2: Generator.Emit(OpCodes.Ldarg_2); break; - case 3: Generator.Emit(OpCodes.Ldarg_3); break; - - default: - if ((uint)Index <= byte.MaxValue) - { - Generator.Emit(OpCodes.Ldarg_S, (byte)Index); - } - else if ((uint)Index < ushort.MaxValue) - { - Generator.Emit(OpCodes.Ldarg, (short)Index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - break; - } - } - - public static void EmitStarg(this ILGenerator Generator, int Index) - { - if ((uint)Index <= byte.MaxValue) - { - Generator.Emit(OpCodes.Starg_S, (byte)Index); - } - else if ((uint)Index < ushort.MaxValue) - { - Generator.Emit(OpCodes.Starg, (short)Index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - } - - public static void EmitLdloc(this ILGenerator Generator, int Index) - { - switch (Index) - { - case 0: Generator.Emit(OpCodes.Ldloc_0); break; - case 1: Generator.Emit(OpCodes.Ldloc_1); break; - case 2: Generator.Emit(OpCodes.Ldloc_2); break; - case 3: Generator.Emit(OpCodes.Ldloc_3); break; - - default: - if ((uint)Index <= byte.MaxValue) - { - Generator.Emit(OpCodes.Ldloc_S, (byte)Index); - } - else if ((uint)Index < ushort.MaxValue) - { - Generator.Emit(OpCodes.Ldloc, (short)Index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - break; - } - } - - public static void EmitStloc(this ILGenerator Generator, int Index) - { - switch (Index) - { - case 0: Generator.Emit(OpCodes.Stloc_0); break; - case 1: Generator.Emit(OpCodes.Stloc_1); break; - case 2: Generator.Emit(OpCodes.Stloc_2); break; - case 3: Generator.Emit(OpCodes.Stloc_3); break; - - default: - if ((uint)Index <= byte.MaxValue) - { - Generator.Emit(OpCodes.Stloc_S, (byte)Index); - } - else if ((uint)Index < ushort.MaxValue) - { - Generator.Emit(OpCodes.Stloc, (short)Index); - } - else - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - break; - } - } - - public static void EmitLdargSeq(this ILGenerator Generator, int Count) - { - for (int Index = 0; Index < Count; Index++) - { - Generator.EmitLdarg(Index); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/GalPrimitiveType.cs b/Ryujinx/Gal/GalPrimitiveType.cs deleted file mode 100644 index 7b6d99a0..00000000 --- a/Ryujinx/Gal/GalPrimitiveType.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Gal -{ - public enum GalPrimitiveType - { - Points = 0x0, - Lines = 0x1, - LineLoop = 0x2, - LineStrip = 0x3, - Triangles = 0x4, - TriangleStrip = 0x5, - TriangleFan = 0x6, - Quads = 0x7, - QuadStrip = 0x8, - Polygon = 0x9, - LinesAdjacency = 0xa, - LineStripAdjacency = 0xb, - TrianglesAdjacency = 0xc, - TriangleStripAdjacency = 0xd, - Patches = 0xe - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/GalVertexAttrib.cs b/Ryujinx/Gal/GalVertexAttrib.cs deleted file mode 100644 index bbc32633..00000000 --- a/Ryujinx/Gal/GalVertexAttrib.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Gal -{ - public struct GalVertexAttrib - { - public int Index { get; private set; } - public int Buffer { get; private set; } - public bool IsConst { get; private set; } - public int Offset { get; private set; } - - public GalVertexAttribSize Size { get; private set; } - public GalVertexAttribType Type { get; private set; } - - public bool IsBgra { get; private set; } - - public GalVertexAttrib( - int Index, - int Buffer, - bool IsConst, - int Offset, - GalVertexAttribSize Size, - GalVertexAttribType Type, - bool IsBgra) - { - this.Index = Index; - this.Buffer = Buffer; - this.IsConst = IsConst; - this.Offset = Offset; - this.Size = Size; - this.Type = Type; - this.IsBgra = IsBgra; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/GalVertexAttribSize.cs b/Ryujinx/Gal/GalVertexAttribSize.cs deleted file mode 100644 index 11f0470c..00000000 --- a/Ryujinx/Gal/GalVertexAttribSize.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Gal -{ - public enum GalVertexAttribSize - { - _32_32_32_32 = 0x1, - _32_32_32 = 0x2, - _16_16_16_16 = 0x3, - _32_32 = 0x4, - _16_16_16 = 0x5, - _8_8_8_8 = 0xa, - _16_16 = 0xf, - _32 = 0x12, - _8_8_8 = 0x13, - _8_8 = 0x18, - _16 = 0x1b, - _8 = 0x1d, - _10_10_10_2 = 0x30, - _11_11_10 = 0x31 - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/GalVertexAttribType.cs b/Ryujinx/Gal/GalVertexAttribType.cs deleted file mode 100644 index c0ed59fb..00000000 --- a/Ryujinx/Gal/GalVertexAttribType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Gal -{ - public enum GalVertexAttribType - { - Snorm = 1, - Unorm = 2, - Sint = 3, - Uint = 4, - Uscaled = 5, - Sscaled = 6, - Float = 7 - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/IGalRenderer.cs b/Ryujinx/Gal/IGalRenderer.cs deleted file mode 100644 index 306d0d51..00000000 --- a/Ryujinx/Gal/IGalRenderer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Gal -{ - public interface IGalRenderer - { - long FrameBufferPtr { get; set; } - - void QueueAction(Action ActionMthd); - void RunActions(); - - void Render(); - void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs); - void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height); - void BindTexture(int Index); - } -} \ No newline at end of file diff --git a/Ryujinx/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx/Gal/OpenGL/OpenGLRenderer.cs deleted file mode 100644 index 72ad6f70..00000000 --- a/Ryujinx/Gal/OpenGL/OpenGLRenderer.cs +++ /dev/null @@ -1,282 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; -using System.Collections.Generic; - -namespace Gal.OpenGL -{ - public class OpenGLRenderer : IGalRenderer - { - private struct VertexBuffer - { - public int VaoHandle; - public int VboHandle; - - public int PrimCount; - } - - private struct Texture - { - public int Handle; - } - - private List VertexBuffers; - - private Texture[] Textures; - - private Queue ActionsQueue; - - public long FrameBufferPtr { get; set; } - - public OpenGLRenderer() - { - VertexBuffers = new List(); - - Textures = new Texture[8]; - - ActionsQueue = new Queue(); - } - - public void QueueAction(Action ActionMthd) - { - ActionsQueue.Enqueue(ActionMthd); - } - - public void RunActions() - { - while (ActionsQueue.Count > 0) - { - ActionsQueue.Dequeue()(); - } - } - - public void Render() - { - for (int Index = 0; Index < VertexBuffers.Count; Index++) - { - VertexBuffer Vb = VertexBuffers[Index]; - - if (Vb.VaoHandle != 0 && - Vb.PrimCount != 0) - { - GL.BindVertexArray(Vb.VaoHandle); - GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount); - } - } - - } - - public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs) - { - if (Index < 0) - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - if (Buffer.Length == 0 || Stride == 0) - { - return; - } - - EnsureVbInitialized(Index); - - VertexBuffer Vb = VertexBuffers[Index]; - - Vb.PrimCount = Buffer.Length / Stride; - - VertexBuffers[Index] = Vb; - - IntPtr Length = new IntPtr(Buffer.Length); - - GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); - GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); - GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - - GL.BindVertexArray(Vb.VaoHandle); - - for (int Attr = 0; Attr < 16; Attr++) - { - GL.DisableVertexAttribArray(Attr); - } - - foreach (GalVertexAttrib Attrib in Attribs) - { - if (Attrib.Index >= 3) break; - - GL.EnableVertexAttribArray(Attrib.Index); - - GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle); - - int Size = 0; - - switch (Attrib.Size) - { - case GalVertexAttribSize._8: - case GalVertexAttribSize._16: - case GalVertexAttribSize._32: - Size = 1; - break; - case GalVertexAttribSize._8_8: - case GalVertexAttribSize._16_16: - case GalVertexAttribSize._32_32: - Size = 2; - break; - case GalVertexAttribSize._8_8_8: - case GalVertexAttribSize._11_11_10: - case GalVertexAttribSize._16_16_16: - case GalVertexAttribSize._32_32_32: - Size = 3; - break; - case GalVertexAttribSize._8_8_8_8: - case GalVertexAttribSize._10_10_10_2: - case GalVertexAttribSize._16_16_16_16: - case GalVertexAttribSize._32_32_32_32: - Size = 4; - break; - } - - bool Signed = - Attrib.Type == GalVertexAttribType.Snorm || - Attrib.Type == GalVertexAttribType.Sint || - Attrib.Type == GalVertexAttribType.Sscaled; - - bool Normalize = - Attrib.Type == GalVertexAttribType.Snorm || - Attrib.Type == GalVertexAttribType.Unorm; - - VertexAttribPointerType Type = 0; - - switch (Attrib.Type) - { - case GalVertexAttribType.Snorm: - case GalVertexAttribType.Unorm: - case GalVertexAttribType.Sint: - case GalVertexAttribType.Uint: - case GalVertexAttribType.Uscaled: - case GalVertexAttribType.Sscaled: - { - switch (Attrib.Size) - { - case GalVertexAttribSize._8: - case GalVertexAttribSize._8_8: - case GalVertexAttribSize._8_8_8: - case GalVertexAttribSize._8_8_8_8: - { - Type = Signed - ? VertexAttribPointerType.Byte - : VertexAttribPointerType.UnsignedByte; - - break; - } - - case GalVertexAttribSize._16: - case GalVertexAttribSize._16_16: - case GalVertexAttribSize._16_16_16: - case GalVertexAttribSize._16_16_16_16: - { - Type = Signed - ? VertexAttribPointerType.Short - : VertexAttribPointerType.UnsignedShort; - - break; - } - - case GalVertexAttribSize._10_10_10_2: - case GalVertexAttribSize._11_11_10: - case GalVertexAttribSize._32: - case GalVertexAttribSize._32_32: - case GalVertexAttribSize._32_32_32: - case GalVertexAttribSize._32_32_32_32: - { - Type = Signed - ? VertexAttribPointerType.Int - : VertexAttribPointerType.UnsignedInt; - - break; - } - } - - break; - } - - case GalVertexAttribType.Float: - { - Type = VertexAttribPointerType.Float; - - break; - } - } - - GL.VertexAttribPointer( - Attrib.Index, - Size, - Type, - Normalize, - Stride, - Attrib.Offset); - } - - GL.BindVertexArray(0); - } - - public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height) - { - EnsureTexInitialized(Index); - - GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - GL.TexImage2D(TextureTarget.Texture2D, - 0, - PixelInternalFormat.Rgba, - Width, - Height, - 0, - PixelFormat.Rgba, - PixelType.UnsignedByte, - Buffer); - } - - public void BindTexture(int Index) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle); - } - - private void EnsureVbInitialized(int VbIndex) - { - while (VbIndex >= VertexBuffers.Count) - { - VertexBuffers.Add(new VertexBuffer()); - } - - VertexBuffer Vb = VertexBuffers[VbIndex]; - - if (Vb.VaoHandle == 0) - { - Vb.VaoHandle = GL.GenVertexArray(); - } - - if (Vb.VboHandle == 0) - { - Vb.VboHandle = GL.GenBuffer(); - } - - VertexBuffers[VbIndex] = Vb; - } - - private void EnsureTexInitialized(int TexIndex) - { - Texture Tex = Textures[TexIndex]; - - if (Tex.Handle == 0) - { - Tex.Handle = GL.GenTexture(); - } - - Textures[TexIndex] = Tex; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/BCn.cs b/Ryujinx/Gpu/BCn.cs deleted file mode 100644 index bf782d16..00000000 --- a/Ryujinx/Gpu/BCn.cs +++ /dev/null @@ -1,468 +0,0 @@ -using System; -using System.Drawing; - -namespace Ryujinx.Gpu -{ - static class BCn - { - public static byte[] DecodeBC1(NsGpuTexture Tex, int Offset) - { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; - - byte[] Output = new byte[W * H * 64]; - - SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8); - - for (int Y = 0; Y < H; Y++) - { - for (int X = 0; X < W; X++) - { - int IOffs = Offset + Swizzle.GetSwizzledAddress64(X, Y) * 8; - - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs, true); - - int TOffset = 0; - - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - Output[OOffset + 0] = Tile[TOffset + 0]; - Output[OOffset + 1] = Tile[TOffset + 1]; - Output[OOffset + 2] = Tile[TOffset + 2]; - Output[OOffset + 3] = Tile[TOffset + 3]; - - TOffset += 4; - } - } - } - } - - return Output; - } - - public static byte[] DecodeBC2(NsGpuTexture Tex, int Offset) - { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; - - byte[] Output = new byte[W * H * 64]; - - SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); - - for (int Y = 0; Y < H; Y++) - { - for (int X = 0; X < W; X++) - { - int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; - - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); - - int AlphaLow = Get32(Tex.Data, IOffs + 0); - int AlphaHigh = Get32(Tex.Data, IOffs + 4); - - ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; - - int TOffset = 0; - - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - ulong Alpha = (AlphaCh >> (TY * 16 + TX * 4)) & 0xf; - - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - Output[OOffset + 0] = Tile[TOffset + 0]; - Output[OOffset + 1] = Tile[TOffset + 1]; - Output[OOffset + 2] = Tile[TOffset + 2]; - Output[OOffset + 3] = (byte)(Alpha | (Alpha << 4)); - - TOffset += 4; - } - } - } - } - - return Output; - } - - public static byte[] DecodeBC3(NsGpuTexture Tex, int Offset) - { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; - - byte[] Output = new byte[W * H * 64]; - - SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); - - for (int Y = 0; Y < H; Y++) - { - for (int X = 0; X < W; X++) - { - int IOffs = Offset + Swizzle.GetSwizzledAddress128(X, Y) * 16; - - byte[] Tile = BCnDecodeTile(Tex.Data, IOffs + 8, false); - - byte[] Alpha = new byte[8]; - - Alpha[0] = Tex.Data[IOffs + 0]; - Alpha[1] = Tex.Data[IOffs + 1]; - - CalculateBC3Alpha(Alpha); - - int AlphaLow = Get32(Tex.Data, IOffs + 2); - int AlphaHigh = Get16(Tex.Data, IOffs + 6); - - ulong AlphaCh = (uint)AlphaLow | (ulong)AlphaHigh << 32; - - int TOffset = 0; - - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - byte AlphaPx = Alpha[(AlphaCh >> (TY * 12 + TX * 3)) & 7]; - - Output[OOffset + 0] = Tile[TOffset + 0]; - Output[OOffset + 1] = Tile[TOffset + 1]; - Output[OOffset + 2] = Tile[TOffset + 2]; - Output[OOffset + 3] = AlphaPx; - - TOffset += 4; - } - } - } - } - - return Output; - } - - public static byte[] DecodeBC4(NsGpuTexture Tex, int Offset) - { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; - - byte[] Output = new byte[W * H * 64]; - - SwizzleAddr Swizzle = new SwizzleAddr(W, H, 8); - - for (int Y = 0; Y < H; Y++) - { - for (int X = 0; X < W; X++) - { - int IOffs = Swizzle.GetSwizzledAddress64(X, Y) * 8; - - byte[] Red = new byte[8]; - - Red[0] = Tex.Data[IOffs + 0]; - Red[1] = Tex.Data[IOffs + 1]; - - CalculateBC3Alpha(Red); - - int RedLow = Get32(Tex.Data, IOffs + 2); - int RedHigh = Get16(Tex.Data, IOffs + 6); - - ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; - - int TOffset = 0; - - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - byte RedPx = Red[(RedCh >> (TY * 12 + TX * 3)) & 7]; - - Output[OOffset + 0] = RedPx; - Output[OOffset + 1] = RedPx; - Output[OOffset + 2] = RedPx; - Output[OOffset + 3] = 0xff; - - TOffset += 4; - } - } - } - } - - return Output; - } - - public static byte[] DecodeBC5(NsGpuTexture Tex, int Offset, bool SNorm) - { - int W = (Tex.Width + 3) / 4; - int H = (Tex.Height + 3) / 4; - - byte[] Output = new byte[W * H * 64]; - - SwizzleAddr Swizzle = new SwizzleAddr(W, H, 4); - - for (int Y = 0; Y < H; Y++) - { - for (int X = 0; X < W; X++) - { - int IOffs = Swizzle.GetSwizzledAddress128(X, Y) * 16; - - byte[] Red = new byte[8]; - byte[] Green = new byte[8]; - - Red[0] = Tex.Data[IOffs + 0]; - Red[1] = Tex.Data[IOffs + 1]; - - Green[0] = Tex.Data[IOffs + 8]; - Green[1] = Tex.Data[IOffs + 9]; - - if (SNorm) - { - CalculateBC3AlphaS(Red); - CalculateBC3AlphaS(Green); - } - else - { - CalculateBC3Alpha(Red); - CalculateBC3Alpha(Green); - } - - int RedLow = Get32(Tex.Data, IOffs + 2); - int RedHigh = Get16(Tex.Data, IOffs + 6); - - int GreenLow = Get32(Tex.Data, IOffs + 10); - int GreenHigh = Get16(Tex.Data, IOffs + 14); - - ulong RedCh = (uint)RedLow | (ulong)RedHigh << 32; - ulong GreenCh = (uint)GreenLow | (ulong)GreenHigh << 32; - - int TOffset = 0; - - if (SNorm) - { - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int Shift = TY * 12 + TX * 3; - - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - byte RedPx = Red [(RedCh >> Shift) & 7]; - byte GreenPx = Green[(GreenCh >> Shift) & 7]; - - RedPx += 0x80; - GreenPx += 0x80; - - float NX = (RedPx / 255f) * 2 - 1; - float NY = (GreenPx / 255f) * 2 - 1; - - float NZ = (float)Math.Sqrt(1 - (NX * NX + NY * NY)); - - Output[OOffset + 0] = Clamp((NZ + 1) * 0.5f); - Output[OOffset + 1] = Clamp((NY + 1) * 0.5f); - Output[OOffset + 2] = Clamp((NX + 1) * 0.5f); - Output[OOffset + 3] = 0xff; - - TOffset += 4; - } - } - } - else - { - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int Shift = TY * 12 + TX * 3; - - int OOffset = (X * 4 + TX + (Y * 4 + TY) * W * 4) * 4; - - byte RedPx = Red [(RedCh >> Shift) & 7]; - byte GreenPx = Green[(GreenCh >> Shift) & 7]; - - Output[OOffset + 0] = RedPx; - Output[OOffset + 1] = RedPx; - Output[OOffset + 2] = RedPx; - Output[OOffset + 3] = GreenPx; - - TOffset += 4; - } - } - } - } - } - - return Output; - } - - private static byte Clamp(float Value) - { - if (Value > 1) - { - return 0xff; - } - else if (Value < 0) - { - return 0; - } - else - { - return (byte)(Value * 0xff); - } - } - - private static void CalculateBC3Alpha(byte[] Alpha) - { - for (int i = 2; i < 8; i++) - { - if (Alpha[0] > Alpha[1]) - { - Alpha[i] = (byte)(((8 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7); - } - else if (i < 6) - { - Alpha[i] = (byte)(((6 - i) * Alpha[0] + (i - 1) * Alpha[1]) / 7); - } - else if (i == 6) - { - Alpha[i] = 0; - } - else /* i == 7 */ - { - Alpha[i] = 0xff; - } - } - } - - private static void CalculateBC3AlphaS(byte[] Alpha) - { - for (int i = 2; i < 8; i++) - { - if ((sbyte)Alpha[0] > (sbyte)Alpha[1]) - { - Alpha[i] = (byte)(((8 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7); - } - else if (i < 6) - { - Alpha[i] = (byte)(((6 - i) * (sbyte)Alpha[0] + (i - 1) * (sbyte)Alpha[1]) / 7); - } - else if (i == 6) - { - Alpha[i] = 0x80; - } - else /* i == 7 */ - { - Alpha[i] = 0x7f; - } - } - } - - private static byte[] BCnDecodeTile( - byte[] Input, - int Offset, - bool IsBC1) - { - Color[] CLUT = new Color[4]; - - int c0 = Get16(Input, Offset + 0); - int c1 = Get16(Input, Offset + 2); - - CLUT[0] = DecodeRGB565(c0); - CLUT[1] = DecodeRGB565(c1); - CLUT[2] = CalculateCLUT2(CLUT[0], CLUT[1], c0, c1, IsBC1); - CLUT[3] = CalculateCLUT3(CLUT[0], CLUT[1], c0, c1, IsBC1); - - int Indices = Get32(Input, Offset + 4); - - int IdxShift = 0; - - byte[] Output = new byte[4 * 4 * 4]; - - int OOffset = 0; - - for (int TY = 0; TY < 4; TY++) - { - for (int TX = 0; TX < 4; TX++) - { - int Idx = (Indices >> IdxShift) & 3; - - IdxShift += 2; - - Color Pixel = CLUT[Idx]; - - Output[OOffset + 0] = Pixel.R; - Output[OOffset + 1] = Pixel.G; - Output[OOffset + 2] = Pixel.B; - Output[OOffset + 3] = Pixel.A; - - OOffset += 4; - } - } - - return Output; - } - - private static Color CalculateCLUT2(Color C0, Color C1, int c0, int c1, bool IsBC1) - { - if (c0 > c1 || !IsBC1) - { - return Color.FromArgb( - (2 * C0.R + C1.R) / 3, - (2 * C0.G + C1.G) / 3, - (2 * C0.B + C1.B) / 3); - } - else - { - return Color.FromArgb( - (C0.R + C1.R) / 2, - (C0.G + C1.G) / 2, - (C0.B + C1.B) / 2); - } - } - - private static Color CalculateCLUT3(Color C0, Color C1, int c0, int c1, bool IsBC1) - { - if (c0 > c1 || !IsBC1) - { - return - Color.FromArgb( - (2 * C1.R + C0.R) / 3, - (2 * C1.G + C0.G) / 3, - (2 * C1.B + C0.B) / 3); - } - - return Color.Transparent; - } - - private static Color DecodeRGB565(int Value) - { - int B = ((Value >> 0) & 0x1f) << 3; - int G = ((Value >> 5) & 0x3f) << 2; - int R = ((Value >> 11) & 0x1f) << 3; - - return Color.FromArgb( - R | (R >> 5), - G | (G >> 6), - B | (B >> 5)); - } - - private static int Get16(byte[] Data, int Address) - { - return - Data[Address + 0] << 0 | - Data[Address + 1] << 8; - } - - private static int Get32(byte[] Data, int Address) - { - return - Data[Address + 0] << 0 | - Data[Address + 1] << 8 | - Data[Address + 2] << 16 | - Data[Address + 3] << 24; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpu.cs b/Ryujinx/Gpu/NsGpu.cs deleted file mode 100644 index 6aa7332c..00000000 --- a/Ryujinx/Gpu/NsGpu.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Gal; - -namespace Ryujinx.Gpu -{ - class NsGpu - { - public IGalRenderer Renderer { get; private set; } - - public NsGpuMemoryMgr MemoryMgr { get; private set; } - - public NsGpuPGraph PGraph { get; private set; } - - public NsGpu(IGalRenderer Renderer) - { - this.Renderer = Renderer; - - MemoryMgr = new NsGpuMemoryMgr(); - - PGraph = new NsGpuPGraph(this); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuEngine.cs b/Ryujinx/Gpu/NsGpuEngine.cs deleted file mode 100644 index bf104569..00000000 --- a/Ryujinx/Gpu/NsGpuEngine.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.Gpu -{ - enum NsGpuEngine - { - None = 0, - _2d = 0x902d, - _3d = 0xb197, - Compute = 0xb1c0, - Kepler = 0xa140, - Dma = 0xb0b5, - GpFifo = 0xb06f - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuMemoryMgr.cs b/Ryujinx/Gpu/NsGpuMemoryMgr.cs deleted file mode 100644 index 563a5c09..00000000 --- a/Ryujinx/Gpu/NsGpuMemoryMgr.cs +++ /dev/null @@ -1,204 +0,0 @@ -namespace Ryujinx.Gpu -{ - class NsGpuMemoryMgr - { - private const long AddrSize = 1L << 40; - - private const int PTLvl0Bits = 14; - private const int PTLvl1Bits = 14; - private const int PTPageBits = 12; - - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - private const int PageSize = 1 << PTPageBits; - - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - private const int PageMask = PageSize - 1; - - private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; - private const int PTLvl1Bit = PTPageBits; - - private const long PteUnmapped = -1; - private const long PteReserved = -2; - - private long[][] PageTable; - - public NsGpuMemoryMgr() - { - PageTable = new long[PTLvl0Size][]; - } - - public long Map(long CpuAddr, long GpuAddr, long Size) - { - CpuAddr &= ~PageMask; - GpuAddr &= ~PageMask; - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - if (GetPTAddr(GpuAddr + Offset) != PteReserved) - { - return Map(CpuAddr, Size); - } - } - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(GpuAddr + Offset, CpuAddr + Offset); - } - - return GpuAddr; - } - - public long Map(long CpuAddr, long Size) - { - CpuAddr &= ~PageMask; - - long Position = GetFreePosition(Size); - - if (Position != -1) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(Position + Offset, CpuAddr + Offset); - } - } - - return Position; - } - - public long Reserve(long GpuAddr, long Size, long Align) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - if (HasPTAddr(GpuAddr + Offset)) - { - return Reserve(Size, Align); - } - } - - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(GpuAddr + Offset, PteReserved); - } - - return GpuAddr; - } - - public long Reserve(long Size, long Align) - { - long Position = GetFreePosition(Size, Align); - - if (Position != -1) - { - for (long Offset = 0; Offset < Size; Offset += PageSize) - { - SetPTAddr(Position + Offset, PteReserved); - } - } - - return Position; - } - - private long GetFreePosition(long Size, long Align = 1) - { - long Position = 0; - long FreeSize = 0; - - if (Align < 1) - { - Align = 1; - } - - Align = (Align + PageMask) & ~PageMask; - - while (Position + FreeSize < AddrSize) - { - if (!HasPTAddr(Position + FreeSize)) - { - FreeSize += PageSize; - - if (FreeSize >= Size) - { - return Position; - } - } - else - { - Position += FreeSize + PageSize; - FreeSize = 0; - - long Remainder = Position % Align; - - if (Remainder != 0) - { - Position = (Position - Remainder) + Align; - } - } - } - - return -1; - } - - public long GetCpuAddr(long Position) - { - long BasePos = GetPTAddr(Position); - - if (BasePos < 0) - { - return -1; - } - - return BasePos + (Position & PageMask); - } - - private bool HasPTAddr(long Position) - { - if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1] != PteUnmapped; - } - - private long GetPTAddr(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return -1; - } - - return PageTable[L0][L1]; - } - - private void SetPTAddr(long Position, long TgtAddr) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - PageTable[L0] = new long[PTLvl1Size]; - - for (int Index = 0; Index < PTLvl1Size; Index++) - { - PageTable[L0][Index] = PteUnmapped; - } - } - - PageTable[L0][L1] = TgtAddr; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuPBEntry.cs b/Ryujinx/Gpu/NsGpuPBEntry.cs deleted file mode 100644 index 226a7f61..00000000 --- a/Ryujinx/Gpu/NsGpuPBEntry.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; - -namespace Ryujinx.Gpu -{ - struct NsGpuPBEntry - { - public NsGpuRegister Register { get; private set; } - - public int SubChannel { get; private set; } - - private int[] m_Arguments; - - public ReadOnlyCollection Arguments => Array.AsReadOnly(m_Arguments); - - public NsGpuPBEntry(NsGpuRegister Register, int SubChannel, params int[] Arguments) - { - this.Register = Register; - this.SubChannel = SubChannel; - this.m_Arguments = Arguments; - } - - public static NsGpuPBEntry[] DecodePushBuffer(byte[] Data) - { - using (MemoryStream MS = new MemoryStream(Data)) - { - BinaryReader Reader = new BinaryReader(MS); - - List GpFifos = new List(); - - bool CanRead() => MS.Position + 4 <= MS.Length; - - while (CanRead()) - { - int Packed = Reader.ReadInt32(); - - int Reg = (Packed << 2) & 0x7ffc; - int SubC = (Packed >> 13) & 7; - int Args = (Packed >> 16) & 0x1fff; - int Mode = (Packed >> 29) & 7; - - if (Mode == 4) - { - //Inline Mode. - GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Args)); - } - else - { - //Word mode. - if (Mode == 1) - { - //Sequential Mode. - for (int Index = 0; Index < Args && CanRead(); Index++, Reg += 4) - { - GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Reader.ReadInt32())); - } - } - else - { - //Non-Sequential Mode. - int[] Arguments = new int[Args]; - - for (int Index = 0; Index < Args && CanRead(); Index++) - { - Arguments[Index] = Reader.ReadInt32(); - } - - GpFifos.Add(new NsGpuPBEntry((NsGpuRegister)Reg, SubC, Arguments)); - } - } - } - - return GpFifos.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuPGraph.cs b/Ryujinx/Gpu/NsGpuPGraph.cs deleted file mode 100644 index e40b6283..00000000 --- a/Ryujinx/Gpu/NsGpuPGraph.cs +++ /dev/null @@ -1,276 +0,0 @@ -using ChocolArm64.Memory; -using Gal; -using System.Collections.Generic; - -namespace Ryujinx.Gpu -{ - class NsGpuPGraph - { - private NsGpu Gpu; - - private int[] Registers; - - public NsGpuEngine[] SubChannels; - - private Dictionary CurrentVertexBuffers; - - public NsGpuPGraph(NsGpu Gpu) - { - this.Gpu = Gpu; - - Registers = new int[0x1000]; - - SubChannels = new NsGpuEngine[8]; - - CurrentVertexBuffers = new Dictionary(); - } - - public void ProcessPushBuffer(NsGpuPBEntry[] PushBuffer, AMemory Memory) - { - bool HasQuery = false; - - foreach (NsGpuPBEntry Entry in PushBuffer) - { - if (Entry.Arguments.Count == 1) - { - SetRegister(Entry.Register, Entry.Arguments[0]); - } - - switch (Entry.Register) - { - case NsGpuRegister.BindChannel: - if (Entry.Arguments.Count > 0) - { - SubChannels[Entry.SubChannel] = (NsGpuEngine)Entry.Arguments[0]; - } - break; - - case NsGpuRegister._3dVertexArray0Fetch: - SendVertexBuffers(Memory); - break; - - case NsGpuRegister._3dCbData0: - if (GetRegister(NsGpuRegister._3dCbPos) == 0x20) - { - SendTexture(Memory); - } - break; - - case NsGpuRegister._3dQueryAddressHigh: - case NsGpuRegister._3dQueryAddressLow: - case NsGpuRegister._3dQuerySequence: - case NsGpuRegister._3dQueryGet: - HasQuery = true; - break; - } - } - - if (HasQuery) - { - long Position = - (long)GetRegister(NsGpuRegister._3dQueryAddressHigh) << 32 | - (long)GetRegister(NsGpuRegister._3dQueryAddressLow) << 0; - - int Seq = GetRegister(NsGpuRegister._3dQuerySequence); - int Get = GetRegister(NsGpuRegister._3dQueryGet); - - int Mode = Get & 3; - - if (Mode == 0) - { - //Write - Position = Gpu.MemoryMgr.GetCpuAddr(Position); - - if (Position != -1) - { - Gpu.Renderer.QueueAction(delegate() - { - Memory.WriteInt32(Position, Seq); - }); - } - } - } - } - - private void SendVertexBuffers(AMemory Memory) - { - long Position = - (long)GetRegister(NsGpuRegister._3dVertexArray0StartHigh) << 32 | - (long)GetRegister(NsGpuRegister._3dVertexArray0StartLow) << 0; - - long Limit = - (long)GetRegister(NsGpuRegister._3dVertexArray0LimitHigh) << 32 | - (long)GetRegister(NsGpuRegister._3dVertexArray0LimitLow) << 0; - - int VbIndex = CurrentVertexBuffers.Count; - - if (!CurrentVertexBuffers.TryAdd(Position, VbIndex)) - { - VbIndex = CurrentVertexBuffers[Position]; - } - - if (Limit != 0) - { - long Size = (Limit - Position) + 1; - - Position = Gpu.MemoryMgr.GetCpuAddr(Position); - - if (Position != -1) - { - byte[] Buffer = AMemoryHelper.ReadBytes(Memory, Position, (int)Size); - - int Stride = GetRegister(NsGpuRegister._3dVertexArray0Fetch) & 0xfff; - - List Attribs = new List(); - - for (int Attr = 0; Attr < 16; Attr++) - { - int Packed = GetRegister(NsGpuRegister._3dVertexAttrib0Format + Attr * 4); - - GalVertexAttrib Attrib = new GalVertexAttrib(Attr, - (Packed >> 0) & 0x1f, - ((Packed >> 6) & 0x1) != 0, - (Packed >> 7) & 0x3fff, - (GalVertexAttribSize)((Packed >> 21) & 0x3f), - (GalVertexAttribType)((Packed >> 27) & 0x7), - ((Packed >> 31) & 0x1) != 0); - - if (Attrib.Offset < Stride) - { - Attribs.Add(Attrib); - } - } - - Gpu.Renderer.QueueAction(delegate() - { - Gpu.Renderer.SendVertexBuffer(VbIndex, Buffer, Stride, Attribs.ToArray()); - }); - } - } - } - - private void SendTexture(AMemory Memory) - { - long TicPos = (long)GetRegister(NsGpuRegister._3dTicAddressHigh) << 32 | - (long)GetRegister(NsGpuRegister._3dTicAddressLow) << 0; - - int CbData = GetRegister(NsGpuRegister._3dCbData0); - - int TicIndex = (CbData >> 0) & 0xfffff; - int TscIndex = (CbData >> 20) & 0xfff; //I guess? - - TicPos = Gpu.MemoryMgr.GetCpuAddr(TicPos + TicIndex * 0x20); - - if (TicPos != -1) - { - int Word0 = Memory.ReadInt32(TicPos + 0x0); - int Word1 = Memory.ReadInt32(TicPos + 0x4); - int Word2 = Memory.ReadInt32(TicPos + 0x8); - int Word3 = Memory.ReadInt32(TicPos + 0xc); - int Word4 = Memory.ReadInt32(TicPos + 0x10); - int Word5 = Memory.ReadInt32(TicPos + 0x14); - int Word6 = Memory.ReadInt32(TicPos + 0x18); - int Word7 = Memory.ReadInt32(TicPos + 0x1c); - - long TexAddress = Word1; - - TexAddress |= (long)(Word2 & 0xff) << 32; - - TexAddress = Gpu.MemoryMgr.GetCpuAddr(TexAddress); - - if (TexAddress != -1) - { - NsGpuTextureFormat Format = (NsGpuTextureFormat)(Word0 & 0x7f); - - int Width = (Word4 & 0xffff) + 1; - int Height = (Word5 & 0xffff) + 1; - - byte[] Buffer = GetDecodedTexture(Memory, Format, TexAddress, Width, Height); - - if (Buffer != null) - { - Gpu.Renderer.QueueAction(delegate() - { - Gpu.Renderer.SendR8G8B8A8Texture(0, Buffer, Width, Height); - }); - } - } - } - } - - private static byte[] GetDecodedTexture( - AMemory Memory, - NsGpuTextureFormat Format, - long Position, - int Width, - int Height) - { - byte[] Data = null; - - switch (Format) - { - case NsGpuTextureFormat.BC1: - { - int Size = (Width * Height) >> 1; - - Data = AMemoryHelper.ReadBytes(Memory, Position, Size); - - Data = BCn.DecodeBC1(new NsGpuTexture() - { - Width = Width, - Height = Height, - Data = Data - }, 0); - - break; - } - - case NsGpuTextureFormat.BC2: - { - int Size = Width * Height; - - Data = AMemoryHelper.ReadBytes(Memory, Position, Size); - - Data = BCn.DecodeBC2(new NsGpuTexture() - { - Width = Width, - Height = Height, - Data = Data - }, 0); - - break; - } - - case NsGpuTextureFormat.BC3: - { - int Size = Width * Height; - - Data = AMemoryHelper.ReadBytes(Memory, Position, Size); - - Data = BCn.DecodeBC3(new NsGpuTexture() - { - Width = Width, - Height = Height, - Data = Data - }, 0); - - break; - } - - //default: throw new NotImplementedException(Format.ToString()); - } - - return Data; - } - - public int GetRegister(NsGpuRegister Register) - { - return Registers[((int)Register >> 2) & 0xfff]; - } - - public void SetRegister(NsGpuRegister Register, int Value) - { - Registers[((int)Register >> 2) & 0xfff] = Value; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuRegister.cs b/Ryujinx/Gpu/NsGpuRegister.cs deleted file mode 100644 index 740ca9fe..00000000 --- a/Ryujinx/Gpu/NsGpuRegister.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Ryujinx.Gpu -{ - enum NsGpuRegister - { - BindChannel = 0, - - _2dClipEnable = 0x0290, - _2dOperation = 0x02ac, - - _3dGlobalBase = 0x02c8, - _3dRt0AddressHigh = 0x0800, - _3dRt0AddressLow = 0x0804, - _3dRt0Horiz = 0x0808, - _3dRt0Vert = 0x080c, - _3dRt0Format = 0x0810, - _3dRt0BlockDimensions = 0x0814, - _3dRt0ArrayMode = 0x0818, - _3dRt0LayerStride = 0x081c, - _3dRt0BaseLayer = 0x0820, - _3dViewportScaleX = 0x0a00, - _3dViewportScaleY = 0x0a04, - _3dViewportScaleZ = 0x0a08, - _3dViewportTranslateX = 0x0a0c, - _3dViewportTranslateY = 0x0a10, - _3dViewportTranslateZ = 0x0a14, - _3dViewportHoriz = 0x0c00, - _3dViewportVert = 0x0c04, - _3dDepthRangeNear = 0x0c08, - _3dDepthRangeFar = 0x0c0c, - _3dClearColorR = 0x0d80, - _3dClearColorG = 0x0d84, - _3dClearColorB = 0x0d88, - _3dClearColorA = 0x0d8c, - _3dScreenScissorHoriz = 0x0ff4, - _3dScreenScissorVert = 0x0ff8, - _3dVertexAttrib0Format = 0x1160, - _3dVertexAttrib1Format = 0x1164, - _3dVertexAttrib2Format = 0x1168, - _3dVertexAttrib3Format = 0x116c, - _3dVertexAttrib4Format = 0x1170, - _3dVertexAttrib5Format = 0x1174, - _3dVertexAttrib6Format = 0x1178, - _3dVertexAttrib7Format = 0x117c, - _3dVertexAttrib8Format = 0x1180, - _3dVertexAttrib9Format = 0x1184, - _3dVertexAttrib10Format = 0x1188, - _3dVertexAttrib11Format = 0x118c, - _3dVertexAttrib12Format = 0x1190, - _3dVertexAttrib13Format = 0x1194, - _3dVertexAttrib14Format = 0x1198, - _3dVertexAttrib15Format = 0x119c, - _3dScreenYControl = 0x13ac, - _3dTscAddressHigh = 0x155c, - _3dTscAddressLow = 0x1560, - _3dTscLimit = 0x1564, - _3dTicAddressHigh = 0x1574, - _3dTicAddressLow = 0x1578, - _3dTicLimit = 0x157c, - _3dMultiSampleMode = 0x15d0, - _3dVertexEndGl = 0x1614, - _3dVertexBeginGl = 0x1618, - _3dQueryAddressHigh = 0x1b00, - _3dQueryAddressLow = 0x1b04, - _3dQuerySequence = 0x1b08, - _3dQueryGet = 0x1b0c, - _3dVertexArray0Fetch = 0x1c00, - _3dVertexArray0StartHigh = 0x1c04, - _3dVertexArray0StartLow = 0x1c08, - _3dVertexArray1Fetch = 0x1c10, //todo: the rest - _3dVertexArray0LimitHigh = 0x1f00, - _3dVertexArray0LimitLow = 0x1f04, - _3dCbSize = 0x2380, - _3dCbAddressHigh = 0x2384, - _3dCbAddressLow = 0x2388, - _3dCbPos = 0x238c, - _3dCbData0 = 0x2390, - _3dCbData1 = 0x2394, - _3dCbData2 = 0x2398, - _3dCbData3 = 0x239c, - _3dCbData4 = 0x23a0, - _3dCbData5 = 0x23a4, - _3dCbData6 = 0x23a8, - _3dCbData7 = 0x23ac, - _3dCbData8 = 0x23b0, - _3dCbData9 = 0x23b4, - _3dCbData10 = 0x23b8, - _3dCbData11 = 0x23bc, - _3dCbData12 = 0x23c0, - _3dCbData13 = 0x23c4, - _3dCbData14 = 0x23c8, - _3dCbData15 = 0x23cc, - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuTexture.cs b/Ryujinx/Gpu/NsGpuTexture.cs deleted file mode 100644 index 26500c04..00000000 --- a/Ryujinx/Gpu/NsGpuTexture.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Gpu -{ - struct NsGpuTexture - { - public int Width; - public int Height; - - public byte[] Data; - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/NsGpuTextureFormat.cs b/Ryujinx/Gpu/NsGpuTextureFormat.cs deleted file mode 100644 index 9bb12281..00000000 --- a/Ryujinx/Gpu/NsGpuTextureFormat.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Gpu -{ - enum NsGpuTextureFormat - { - BC1 = 0x24, - BC2 = 0x25, - BC3 = 0x26 - } -} \ No newline at end of file diff --git a/Ryujinx/Gpu/SwizzleAddr.cs b/Ryujinx/Gpu/SwizzleAddr.cs deleted file mode 100644 index 5ad35a53..00000000 --- a/Ryujinx/Gpu/SwizzleAddr.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; - -namespace Ryujinx.Gpu -{ - class SwizzleAddr - { - private int Width; - - private int XB; - private int YB; - - public SwizzleAddr(int Width, int Height, int Pad) - { - int W = Pow2RoundUp(Width); - int H = Pow2RoundUp(Height); - - XB = CountZeros(W); - YB = CountZeros(H); - - int HH = H >> 1; - - if (!IsPow2(Height) && Height <= HH + HH / 3 && YB > 3) - { - YB--; - } - - this.Width = RoundSize(Width, Pad); - } - - private static int Pow2RoundUp(int Value) - { - Value--; - - Value |= (Value >> 1); - Value |= (Value >> 2); - Value |= (Value >> 4); - Value |= (Value >> 8); - Value |= (Value >> 16); - - return ++Value; - } - - private static bool IsPow2(int Value) - { - return Value != 0 && (Value & (Value - 1)) == 0; - } - - private static int CountZeros(int Value) - { - int Count = 0; - - for (int i = 0; i < 32; i++) - { - if ((Value & (1 << i)) != 0) - { - break; - } - - Count++; - } - - return Count; - } - - private static int RoundSize(int Size, int Pad) - { - int Mask = Pad - 1; - - if ((Size & Mask) != 0) - { - Size &= ~Mask; - Size += Pad; - } - - return Size; - } - - public int GetSwizzledAddress8(int X, int Y) - { - return GetSwizzledAddress(X, Y, 4); - } - - public int GetSwizzledAddress16(int X, int Y) - { - return GetSwizzledAddress(X, Y, 3); - } - - public int GetSwizzledAddress32(int X, int Y) - { - return GetSwizzledAddress(X, Y, 2); - } - - public int GetSwizzledAddress64(int X, int Y) - { - return GetSwizzledAddress(X, Y, 1); - } - - public int GetSwizzledAddress128(int X, int Y) - { - return GetSwizzledAddress(X, Y, 0); - } - - private int GetSwizzledAddress(int X, int Y, int XBase) - { - /* - * Examples of patterns: - * x x y x y y x y 0 0 0 0 64 x 64 dxt5 - * x x x x x y y y y x y y x y 0 0 0 0 512 x 512 dxt5 - * y x x x x x x y y y y x y y x y 0 0 0 0 1024 x 1024 dxt5 - * y y x x x x x x y y y y x y y x y x 0 0 0 2048 x 2048 dxt1 - * y y y x x x x x x y y y y x y y x y x x 0 0 1024 x 1024 rgba8888 - * - * Read from right to left, LSB first. - */ - int XCnt = XBase; - int YCnt = 1; - int XUsed = 0; - int YUsed = 0; - int Address = 0; - - while (XUsed < XBase + 2 && XUsed + XCnt < XB) - { - int XMask = (1 << XCnt) - 1; - int YMask = (1 << YCnt) - 1; - - Address |= (X & XMask) << XUsed + YUsed; - Address |= (Y & YMask) << XUsed + YUsed + XCnt; - - X >>= XCnt; - Y >>= YCnt; - - XUsed += XCnt; - YUsed += YCnt; - - XCnt = Math.Min(XB - XUsed, 1); - YCnt = Math.Min(YB - YUsed, YCnt << 1); - } - - Address |= (X + Y * (Width >> XUsed)) << (XUsed + YUsed); - - return Address; - } - } -} diff --git a/Ryujinx/Hid.cs b/Ryujinx/Hid.cs deleted file mode 100644 index c344ec58..00000000 --- a/Ryujinx/Hid.cs +++ /dev/null @@ -1,185 +0,0 @@ -using Ryujinx.OsHle; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - public class Hid - { - /* - Thanks to: - https://github.com/reswitched/libtransistor/blob/development/lib/hid.c - https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h - https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c - https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h - - struct HidSharedMemory - { - header[0x400]; - touchscreen[0x3000]; - mouse[0x400]; - keyboard[0x400]; - unkSection1[0x400]; - unkSection2[0x400]; - unkSection3[0x400]; - unkSection4[0x400]; - unkSection5[0x200]; - unkSection6[0x200]; - unkSection7[0x200]; - unkSection8[0x800]; - controllerSerials[0x4000]; - controllers[0x5000 * 10]; - unkSection9[0x4600]; - } - */ - - private const int Hid_Num_Entries = 16; - private Switch Ns; - private long SharedMemOffset; - - public Hid(Switch Ns) - { - this.Ns = Ns; - } - - public void Init(long HidOffset) - { - unsafe - { - if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue) - { - return; - } - - SharedMemOffset = HidOffset; - - uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)); - - IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidTouchScreen TouchScreen = new HidTouchScreen(); - TouchScreen.Header.TimestampTicks = (ulong)Environment.TickCount; - TouchScreen.Header.NumEntries = (ulong)Hid_Num_Entries; - TouchScreen.Header.LatestEntry = 0; - TouchScreen.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - TouchScreen.Header.Timestamp = (ulong)Environment.TickCount; - - //TODO: Write this structure when the input is implemented - //Marshal.StructureToPtr(TouchScreen, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreen)); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidMouse Mouse = new HidMouse(); - Mouse.Header.TimestampTicks = (ulong)Environment.TickCount; - Mouse.Header.NumEntries = (ulong)Hid_Num_Entries; - Mouse.Header.LatestEntry = 0; - Mouse.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - - //TODO: Write this structure when the input is implemented - //Marshal.StructureToPtr(Mouse, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidMouse)); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidKeyboard Keyboard = new HidKeyboard(); - Keyboard.Header.TimestampTicks = (ulong)Environment.TickCount; - Keyboard.Header.NumEntries = (ulong)Hid_Num_Entries; - Keyboard.Header.LatestEntry = 0; - Keyboard.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1; - - //TODO: Write this structure when the input is implemented - //Marshal.StructureToPtr(Keyboard, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidKeyboard)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + - (uint)Marshal.SizeOf(typeof(HidControllerSerials)); - - //Increase the loop to initialize more controller. - for (int i = 8; i < Enum.GetNames(typeof(HidControllerID)).Length - 1; i++) - { - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset + (uint)(Marshal.SizeOf(typeof(HidController)) * i)); - - HidController Controller = new HidController(); - Controller.Header.Type = (uint)(HidControllerType.ControllerType_Handheld | HidControllerType.ControllerType_JoyconPair); - Controller.Header.IsHalf = 0; - Controller.Header.SingleColorsDescriptor = (uint)(HidControllerColorDescription.ColorDesc_ColorsNonexistent); - Controller.Header.SingleColorBody = 0; - Controller.Header.SingleColorButtons = 0; - Controller.Header.SplitColorsDescriptor = 0; - Controller.Header.LeftColorBody = (uint)JoyConColor.Body_Neon_Red; - Controller.Header.LeftColorButtons = (uint)JoyConColor.Buttons_Neon_Red; - Controller.Header.RightColorBody = (uint)JoyConColor.Body_Neon_Blue; - Controller.Header.RightColorButtons = (uint)JoyConColor.Buttons_Neon_Blue; - - Controller.Layouts = new HidControllerLayout[Enum.GetNames(typeof(HidControllerLayouts)).Length]; - Controller.Layouts[(int)HidControllerLayouts.Main] = new HidControllerLayout(); - Controller.Layouts[(int)HidControllerLayouts.Main].Header.LatestEntry = (ulong)Hid_Num_Entries; - - Marshal.StructureToPtr(Controller, HidPtr, false); - } - - Logging.Info("HID Initialized!"); - } - } - - public void SendControllerButtons(HidControllerID ControllerId, - HidControllerLayouts Layout, - HidControllerKeys Buttons, - JoystickPosition LeftJoystick, - JoystickPosition RightJoystick) - { - uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)) + - (uint)Marshal.SizeOf(typeof(HidTouchScreen)) + - (uint)Marshal.SizeOf(typeof(HidMouse)) + - (uint)Marshal.SizeOf(typeof(HidKeyboard)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection1)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection2)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection3)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection4)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection5)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection6)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection7)) + - (uint)Marshal.SizeOf(typeof(HidUnknownSection8)) + - (uint)Marshal.SizeOf(typeof(HidControllerSerials)) + - ((uint)(Marshal.SizeOf(typeof(HidController)) * (int)ControllerId)) + - (uint)Marshal.SizeOf(typeof(HidControllerHeader)) + - (uint)Layout * (uint)Marshal.SizeOf(typeof(HidControllerLayout)); - - IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidControllerLayoutHeader OldControllerHeaderLayout = (HidControllerLayoutHeader)Marshal.PtrToStructure(HidPtr, typeof(HidControllerLayoutHeader)); - - HidControllerLayoutHeader ControllerLayoutHeader = new HidControllerLayoutHeader - { - TimestampTicks = (ulong)Environment.TickCount, - NumEntries = (ulong)Hid_Num_Entries, - MaxEntryIndex = (ulong)Hid_Num_Entries - 1, - LatestEntry = (OldControllerHeaderLayout.LatestEntry < (ulong)Hid_Num_Entries ? OldControllerHeaderLayout.LatestEntry + 1 : 0) - }; - - Marshal.StructureToPtr(ControllerLayoutHeader, HidPtr, false); - - InnerOffset += (uint)Marshal.SizeOf(typeof(HidControllerLayoutHeader)) + (uint)((uint)(ControllerLayoutHeader.LatestEntry) * Marshal.SizeOf(typeof(HidControllerInputEntry))); - HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset); - - HidControllerInputEntry ControllerInputEntry = new HidControllerInputEntry(); - ControllerInputEntry.Timestamp = (ulong)Environment.TickCount; - ControllerInputEntry.Timestamp_2 = (ulong)Environment.TickCount; - ControllerInputEntry.Buttons = (ulong)Buttons; - ControllerInputEntry.Joysticks = new JoystickPosition[(int)HidControllerJoystick.Joystick_Num_Sticks]; - ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Left] = LeftJoystick; - ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Right] = RightJoystick; - ControllerInputEntry.ConnectionState = (ulong)(HidControllerConnectionState.Controller_State_Connected | HidControllerConnectionState.Controller_State_Wired); - - Marshal.StructureToPtr(ControllerInputEntry, HidPtr, false); - } - } -} diff --git a/Ryujinx/Hid/HidController.cs b/Ryujinx/Hid/HidController.cs deleted file mode 100644 index 7dd19841..00000000 --- a/Ryujinx/Hid/HidController.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - [Flags] - public enum HidControllerKeys - { - KEY_A = (1 << 0), - KEY_B = (1 << 1), - KEY_X = (1 << 2), - KEY_Y = (1 << 3), - KEY_LSTICK = (1 << 4), - KEY_RSTICK = (1 << 5), - KEY_L = (1 << 6), - KEY_R = (1 << 7), - KEY_ZL = (1 << 8), - KEY_ZR = (1 << 9), - KEY_PLUS = (1 << 10), - KEY_MINUS = (1 << 11), - KEY_DLEFT = (1 << 12), - KEY_DUP = (1 << 13), - KEY_DRIGHT = (1 << 14), - KEY_DDOWN = (1 << 15), - KEY_LSTICK_LEFT = (1 << 16), - KEY_LSTICK_UP = (1 << 17), - KEY_LSTICK_RIGHT = (1 << 18), - KEY_LSTICK_DOWN = (1 << 19), - KEY_RSTICK_LEFT = (1 << 20), - KEY_RSTICK_UP = (1 << 21), - KEY_RSTICK_RIGHT = (1 << 22), - KEY_RSTICK_DOWN = (1 << 23), - KEY_SL = (1 << 24), - KEY_SR = (1 << 25), - - // Pseudo-key for at least one finger on the touch screen - KEY_TOUCH = (1 << 26), - - // Buttons by orientation (for single Joy-Con), also works with Joy-Con pairs, Pro Controller - KEY_JOYCON_RIGHT = (1 << 0), - KEY_JOYCON_DOWN = (1 << 1), - KEY_JOYCON_UP = (1 << 2), - KEY_JOYCON_LEFT = (1 << 3), - - // Generic catch-all directions, also works for single Joy-Con - KEY_UP = KEY_DUP | KEY_LSTICK_UP | KEY_RSTICK_UP, - KEY_DOWN = KEY_DDOWN | KEY_LSTICK_DOWN | KEY_RSTICK_DOWN, - KEY_LEFT = KEY_DLEFT | KEY_LSTICK_LEFT | KEY_RSTICK_LEFT, - KEY_RIGHT = KEY_DRIGHT | KEY_LSTICK_RIGHT | KEY_RSTICK_RIGHT, - } - - public enum HidControllerID - { - CONTROLLER_PLAYER_1 = 0, - CONTROLLER_PLAYER_2 = 1, - CONTROLLER_PLAYER_3 = 2, - CONTROLLER_PLAYER_4 = 3, - CONTROLLER_PLAYER_5 = 4, - CONTROLLER_PLAYER_6 = 5, - CONTROLLER_PLAYER_7 = 6, - CONTROLLER_PLAYER_8 = 7, - CONTROLLER_HANDHELD = 8, - CONTROLLER_UNKNOWN = 9 - } - - public enum HidControllerJoystick - { - Joystick_Left = 0, - Joystick_Right = 1, - Joystick_Num_Sticks = 2 - } - - public enum HidControllerLayouts - { - Pro_Controller, - Handheld_Joined, - Joined, - Left, - Right, - Main_No_Analog, - Main - } - - [Flags] - public enum HidControllerConnectionState - { - Controller_State_Connected = (1 << 0), - Controller_State_Wired = (1 << 1) - } - - [Flags] - public enum HidControllerType - { - ControllerType_ProController = (1 << 0), - ControllerType_Handheld = (1 << 1), - ControllerType_JoyconPair = (1 << 2), - ControllerType_JoyconLeft = (1 << 3), - ControllerType_JoyconRight = (1 << 4) - } - - public enum HidControllerColorDescription - { - ColorDesc_ColorsNonexistent = (1 << 1), - } - - [StructLayout(LayoutKind.Sequential, Size = 0x8)] - public struct JoystickPosition - { - public int DX; - public int DY; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidControllerMAC - { - public ulong Timestamp; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] MAC; - public ulong Unknown; - public ulong Timestamp_2; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidControllerHeader - { - public uint Type; - public uint IsHalf; - public uint SingleColorsDescriptor; - public uint SingleColorBody; - public uint SingleColorButtons; - public uint SplitColorsDescriptor; - public uint LeftColorBody; - public uint LeftColorButtons; - public uint RightColorBody; - public uint RightColorButtons; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidControllerLayoutHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x30)] - public struct HidControllerInputEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public ulong Buttons; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)HidControllerJoystick.Joystick_Num_Sticks)] - public JoystickPosition[] Joysticks; - public ulong ConnectionState; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x350)] - public struct HidControllerLayout - { - public HidControllerLayoutHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidControllerInputEntry[] Entries; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x5000)] - public struct HidController - { - public HidControllerHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public HidControllerLayout[] Layouts; - /* - pro_controller - handheld_joined - joined - left - right - main_no_analog - main - */ - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2A70)] - public byte[] Unknown_1; - public HidControllerMAC MacLeft; - public HidControllerMAC MacRight; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xDF8)] - public byte[] Unknown_2; - } -} diff --git a/Ryujinx/Hid/HidKeyboard.cs b/Ryujinx/Hid/HidKeyboard.cs deleted file mode 100644 index 2ee51bfa..00000000 --- a/Ryujinx/Hid/HidKeyboard.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidKeyboardHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x38)] - public struct HidKeyboardEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public ulong Modifier; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public uint[] Keys; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidKeyboard - { - public HidKeyboardHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidKeyboardEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)] - public byte[] Padding; - } -} diff --git a/Ryujinx/Hid/HidMouse.cs b/Ryujinx/Hid/HidMouse.cs deleted file mode 100644 index db01e649..00000000 --- a/Ryujinx/Hid/HidMouse.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - public struct HidMouseHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x30)] - public struct HidMouseEntry - { - public ulong Timestamp; - public ulong Timestamp_2; - public uint X; - public uint Y; - public uint VelocityX; - public uint VelocityY; - public uint ScrollVelocityX; - public uint ScrollVelocityY; - public ulong Buttons; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidMouse - { - public HidMouseHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidMouseEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xB0)] - public byte[] Padding; - } -} diff --git a/Ryujinx/Hid/HidTouchScreen.cs b/Ryujinx/Hid/HidTouchScreen.cs deleted file mode 100644 index 7fb02289..00000000 --- a/Ryujinx/Hid/HidTouchScreen.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidTouchScreenHeader - { - public ulong TimestampTicks; - public ulong NumEntries; - public ulong LatestEntry; - public ulong MaxEntryIndex; - public ulong Timestamp; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - public struct HidTouchScreenEntryHeader - { - public ulong Timestamp; - public ulong NumTouches; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x28)] - public struct HidTouchScreenEntryTouch - { - public ulong Timestamp; - public uint Padding; - public uint TouchIndex; - public uint X; - public uint Y; - public uint DiameterX; - public uint DiameterY; - public uint Angle; - public uint Padding_2; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x298)] - public struct HidTouchScreenEntry - { - public HidTouchScreenEntryHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public HidTouchScreenEntryTouch[] Touches; - public ulong Unknown; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x3000)] - public struct HidTouchScreen - { - public HidTouchScreenHeader Header; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public HidTouchScreenEntry[] Entries; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3C0)] - public byte[] Padding; - } -} diff --git a/Ryujinx/Hid/HidUnknown.cs b/Ryujinx/Hid/HidUnknown.cs deleted file mode 100644 index ef2172d5..00000000 --- a/Ryujinx/Hid/HidUnknown.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidSharedMemHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection1 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection2 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection3 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x400)] - public struct HidUnknownSection4 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection5 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection6 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x200)] - public struct HidUnknownSection7 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x800)] - public struct HidUnknownSection8 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x4000)] - public struct HidControllerSerials - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)] - public byte[] Padding; - } - - [StructLayout(LayoutKind.Sequential, Size = 0x4600)] - public struct HidUnknownSection9 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4600)] - public byte[] Padding; - } -} diff --git a/Ryujinx/Hid/JoyCon.cs b/Ryujinx/Hid/JoyCon.cs deleted file mode 100644 index 8c9518e5..00000000 --- a/Ryujinx/Hid/JoyCon.cs +++ /dev/null @@ -1,66 +0,0 @@ -namespace Ryujinx -{ - /// - /// Common RGB color hex codes for JoyCon coloring. - /// - public enum JoyConColor //Thanks to CTCaer - { - Body_Grey = 0x828282, - Body_Neon_Blue = 0x0AB9E6, - Body_Neon_Red = 0xFF3C28, - Body_Neon_Yellow = 0xE6FF00, - Body_Neon_Pink = 0xFF3278, - Body_Neon_Green = 0x1EDC00, - Body_Red = 0xE10F00, - - Buttons_Grey = 0x0F0F0F, - Buttons_Neon_Blue = 0x001E1E, - Buttons_Neon_Red = 0x1E0A0A, - Buttons_Neon_Yellow = 0x142800, - Buttons_Neon_Pink = 0x28001E, - Buttons_Neon_Green = 0x002800, - Buttons_Red = 0x280A0A - } - - public struct JoyConLeft - { - public int StickUp; - public int StickDown; - public int StickLeft; - public int StickRight; - public int StickButton; - public int DPadUp; - public int DPadDown; - public int DPadLeft; - public int DPadRight; - public int ButtonMinus; - public int ButtonL; - public int ButtonZL; - public int ButtonSL; - public int ButtonSR; - } - - public struct JoyConRight - { - public int StickUp; - public int StickDown; - public int StickLeft; - public int StickRight; - public int StickButton; - public int ButtonA; - public int ButtonB; - public int ButtonX; - public int ButtonY; - public int ButtonPlus; - public int ButtonR; - public int ButtonZR; - public int ButtonSL; - public int ButtonSR; - } - - public struct JoyCon - { - public JoyConLeft Left; - public JoyConRight Right; - } -} diff --git a/Ryujinx/Loaders/Compression/Lz4.cs b/Ryujinx/Loaders/Compression/Lz4.cs deleted file mode 100644 index aace200c..00000000 --- a/Ryujinx/Loaders/Compression/Lz4.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; - -namespace Ryujinx.Loaders.Compression -{ - static class Lz4 - { - public static byte[] Decompress(byte[] Cmp, int DecLength) - { - byte[] Dec = new byte[DecLength]; - - int CmpPos = 0; - int DecPos = 0; - - int GetLength(int Length) - { - byte Sum; - - if (Length == 0xf) - { - do - { - Length += (Sum = Cmp[CmpPos++]); - } - while (Sum == 0xff); - } - - return Length; - } - - do - { - byte Token = Cmp[CmpPos++]; - - int EncCount = (Token >> 0) & 0xf; - int LitCount = (Token >> 4) & 0xf; - - //Copy literal chunck - LitCount = GetLength(LitCount); - - Buffer.BlockCopy(Cmp, CmpPos, Dec, DecPos, LitCount); - - CmpPos += LitCount; - DecPos += LitCount; - - if (CmpPos >= Cmp.Length) - { - break; - } - - //Copy compressed chunck - int Back = Cmp[CmpPos++] << 0 | - Cmp[CmpPos++] << 8; - - EncCount = GetLength(EncCount) + 4; - - int EncPos = DecPos - Back; - - if (EncCount <= Back) - { - Buffer.BlockCopy(Dec, EncPos, Dec, DecPos, EncCount); - - DecPos += EncCount; - } - else - { - while (EncCount-- > 0) - { - Dec[DecPos++] = Dec[EncPos++]; - } - } - } - while (CmpPos < Cmp.Length && - DecPos < Dec.Length); - - return Dec; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfDyn.cs b/Ryujinx/Loaders/ElfDyn.cs deleted file mode 100644 index 595d6cfb..00000000 --- a/Ryujinx/Loaders/ElfDyn.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ryujinx.Loaders -{ - struct ElfDyn - { - public ElfDynTag Tag { get; private set; } - - public long Value { get; private set; } - - public ElfDyn(ElfDynTag Tag, long Value) - { - this.Tag = Tag; - this.Value = Value; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfDynTag.cs b/Ryujinx/Loaders/ElfDynTag.cs deleted file mode 100644 index fb6cab3f..00000000 --- a/Ryujinx/Loaders/ElfDynTag.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Ryujinx.Loaders -{ - enum ElfDynTag - { - DT_NULL = 0, - DT_NEEDED = 1, - DT_PLTRELSZ = 2, - DT_PLTGOT = 3, - DT_HASH = 4, - DT_STRTAB = 5, - DT_SYMTAB = 6, - DT_RELA = 7, - DT_RELASZ = 8, - DT_RELAENT = 9, - DT_STRSZ = 10, - DT_SYMENT = 11, - DT_INIT = 12, - DT_FINI = 13, - DT_SONAME = 14, - DT_RPATH = 15, - DT_SYMBOLIC = 16, - DT_REL = 17, - DT_RELSZ = 18, - DT_RELENT = 19, - DT_PLTREL = 20, - DT_DEBUG = 21, - DT_TEXTREL = 22, - DT_JMPREL = 23, - DT_BIND_NOW = 24, - DT_INIT_ARRAY = 25, - DT_FINI_ARRAY = 26, - DT_INIT_ARRAYSZ = 27, - DT_FINI_ARRAYSZ = 28, - DT_RUNPATH = 29, - DT_FLAGS = 30, - DT_ENCODING = 32, - DT_PREINIT_ARRAY = 32, - DT_PREINIT_ARRAYSZ = 33, - DT_GNU_PRELINKED = 0x6ffffdf5, - DT_GNU_CONFLICTSZ = 0x6ffffdf6, - DT_GNU_LIBLISTSZ = 0x6ffffdf7, - DT_CHECKSUM = 0x6ffffdf8, - DT_PLTPADSZ = 0x6ffffdf9, - DT_MOVEENT = 0x6ffffdfa, - DT_MOVESZ = 0x6ffffdfb, - DT_FEATURE_1 = 0x6ffffdfc, - DT_POSFLAG_1 = 0x6ffffdfd, - DT_SYMINSZ = 0x6ffffdfe, - DT_SYMINENT = 0x6ffffdff, - DT_GNU_HASH = 0x6ffffef5, - DT_TLSDESC_PLT = 0x6ffffef6, - DT_TLSDESC_GOT = 0x6ffffef7, - DT_GNU_CONFLICT = 0x6ffffef8, - DT_GNU_LIBLIST = 0x6ffffef9, - DT_CONFIG = 0x6ffffefa, - DT_DEPAUDIT = 0x6ffffefb, - DT_AUDIT = 0x6ffffefc, - DT_PLTPAD = 0x6ffffefd, - DT_MOVETAB = 0x6ffffefe, - DT_SYMINFO = 0x6ffffeff, - DT_VERSYM = 0x6ffffff0, - DT_RELACOUNT = 0x6ffffff9, - DT_RELCOUNT = 0x6ffffffa, - DT_FLAGS_1 = 0x6ffffffb, - DT_VERDEF = 0x6ffffffc, - DT_VERDEFNUM = 0x6ffffffd, - DT_VERNEED = 0x6ffffffe, - DT_VERNEEDNUM = 0x6fffffff, - DT_AUXILIARY = 0x7ffffffd, - DT_FILTER = 0x7fffffff - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfRel.cs b/Ryujinx/Loaders/ElfRel.cs deleted file mode 100644 index 8b691d99..00000000 --- a/Ryujinx/Loaders/ElfRel.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.Loaders -{ - struct ElfRel - { - public long Offset { get; private set; } - public long Addend { get; private set; } - - public ElfSym Symbol { get; private set; } - public ElfRelType Type { get; private set; } - - public ElfRel(long Offset, long Addend, ElfSym Symbol, ElfRelType Type) - { - this.Offset = Offset; - this.Addend = Addend; - this.Symbol = Symbol; - this.Type = Type; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfRelType.cs b/Ryujinx/Loaders/ElfRelType.cs deleted file mode 100644 index cc638b19..00000000 --- a/Ryujinx/Loaders/ElfRelType.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace Ryujinx.Loaders -{ - enum ElfRelType - { - R_AARCH64_NONE = 0, - R_AARCH64_ABS64 = 257, - R_AARCH64_ABS32 = 258, - R_AARCH64_ABS16 = 259, - R_AARCH64_PREL64 = 260, - R_AARCH64_PREL32 = 261, - R_AARCH64_PREL16 = 262, - R_AARCH64_MOVW_UABS_G0 = 263, - R_AARCH64_MOVW_UABS_G0_NC = 264, - R_AARCH64_MOVW_UABS_G1 = 265, - R_AARCH64_MOVW_UABS_G1_NC = 266, - R_AARCH64_MOVW_UABS_G2 = 267, - R_AARCH64_MOVW_UABS_G2_NC = 268, - R_AARCH64_MOVW_UABS_G3 = 269, - R_AARCH64_MOVW_SABS_G0 = 270, - R_AARCH64_MOVW_SABS_G1 = 271, - R_AARCH64_MOVW_SABS_G2 = 272, - R_AARCH64_LD_PREL_LO19 = 273, - R_AARCH64_ADR_PREL_LO21 = 274, - R_AARCH64_ADR_PREL_PG_HI21 = 275, - R_AARCH64_ADR_PREL_PG_HI21_NC = 276, - R_AARCH64_ADD_ABS_LO12_NC = 277, - R_AARCH64_LDST8_ABS_LO12_NC = 278, - R_AARCH64_TSTBR14 = 279, - R_AARCH64_CONDBR19 = 280, - R_AARCH64_JUMP26 = 282, - R_AARCH64_CALL26 = 283, - R_AARCH64_LDST16_ABS_LO12_NC = 284, - R_AARCH64_LDST32_ABS_LO12_NC = 285, - R_AARCH64_LDST64_ABS_LO12_NC = 286, - R_AARCH64_MOVW_PREL_G0 = 287, - R_AARCH64_MOVW_PREL_G0_NC = 288, - R_AARCH64_MOVW_PREL_G1 = 289, - R_AARCH64_MOVW_PREL_G1_NC = 290, - R_AARCH64_MOVW_PREL_G2 = 291, - R_AARCH64_MOVW_PREL_G2_NC = 292, - R_AARCH64_MOVW_PREL_G3 = 293, - R_AARCH64_LDST128_ABS_LO12_NC = 299, - R_AARCH64_MOVW_GOTOFF_G0 = 300, - R_AARCH64_MOVW_GOTOFF_G0_NC = 301, - R_AARCH64_MOVW_GOTOFF_G1 = 302, - R_AARCH64_MOVW_GOTOFF_G1_NC = 303, - R_AARCH64_MOVW_GOTOFF_G2 = 304, - R_AARCH64_MOVW_GOTOFF_G2_NC = 305, - R_AARCH64_MOVW_GOTOFF_G3 = 306, - R_AARCH64_GOTREL64 = 307, - R_AARCH64_GOTREL32 = 308, - R_AARCH64_GOT_LD_PREL19 = 309, - R_AARCH64_LD64_GOTOFF_LO15 = 310, - R_AARCH64_ADR_GOT_PAGE = 311, - R_AARCH64_LD64_GOT_LO12_NC = 312, - R_AARCH64_LD64_GOTPAGE_LO15 = 313, - R_AARCH64_TLSGD_ADR_PREL21 = 512, - R_AARCH64_TLSGD_ADR_PAGE21 = 513, - R_AARCH64_TLSGD_ADD_LO12_NC = 514, - R_AARCH64_TLSGD_MOVW_G1 = 515, - R_AARCH64_TLSGD_MOVW_G0_NC = 516, - R_AARCH64_TLSLD_ADR_PREL21 = 517, - R_AARCH64_TLSLD_ADR_PAGE21 = 518, - R_AARCH64_TLSLD_ADD_LO12_NC = 519, - R_AARCH64_TLSLD_MOVW_G1 = 520, - R_AARCH64_TLSLD_MOVW_G0_NC = 521, - R_AARCH64_TLSLD_LD_PREL19 = 522, - R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523, - R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524, - R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525, - R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526, - R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527, - R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528, - R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529, - R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530, - R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531, - R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532, - R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533, - R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534, - R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535, - R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536, - R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537, - R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538, - R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539, - R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540, - R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541, - R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542, - R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543, - R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544, - R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545, - R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546, - R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547, - R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548, - R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549, - R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550, - R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551, - R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552, - R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553, - R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554, - R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555, - R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556, - R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557, - R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558, - R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559, - R_AARCH64_TLSDESC_LD_PREL19 = 560, - R_AARCH64_TLSDESC_ADR_PREL21 = 561, - R_AARCH64_TLSDESC_ADR_PAGE21 = 562, - R_AARCH64_TLSDESC_LD64_LO12 = 563, - R_AARCH64_TLSDESC_ADD_LO12 = 564, - R_AARCH64_TLSDESC_OFF_G1 = 565, - R_AARCH64_TLSDESC_OFF_G0_NC = 566, - R_AARCH64_TLSDESC_LDR = 567, - R_AARCH64_TLSDESC_ADD = 568, - R_AARCH64_TLSDESC_CALL = 569, - R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570, - R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571, - R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572, - R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573, - R_AARCH64_COPY = 1024, - R_AARCH64_GLOB_DAT = 1025, - R_AARCH64_JUMP_SLOT = 1026, - R_AARCH64_RELATIVE = 1027, - R_AARCH64_TLS_DTPMOD64 = 1028, - R_AARCH64_TLS_DTPREL64 = 1029, - R_AARCH64_TLS_TPREL64 = 1030, - R_AARCH64_TLSDESC = 1031 - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfSym.cs b/Ryujinx/Loaders/ElfSym.cs deleted file mode 100644 index c4ed810c..00000000 --- a/Ryujinx/Loaders/ElfSym.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Ryujinx.Loaders -{ - struct ElfSym - { - public string Name { get; private set; } - - public ElfSymType Type { get; private set; } - public ElfSymBinding Binding { get; private set; } - public ElfSymVisibility Visibility { get; private set; } - - public bool IsFuncOrObject => - Type == ElfSymType.STT_FUNC || - Type == ElfSymType.STT_OBJECT; - - public bool IsGlobalOrWeak => - Binding == ElfSymBinding.STB_GLOBAL || - Binding == ElfSymBinding.STB_WEAK; - - public int SHIdx { get; private set; } - public long ValueAbs { get; private set; } - public long Value { get; private set; } - public long Size { get; private set; } - - public ElfSym( - string Name, - int Info, - int Other, - int SHIdx, - long ImageBase, - long Value, - long Size) - { - this.Name = Name; - this.Type = (ElfSymType)(Info & 0xf); - this.Binding = (ElfSymBinding)(Info >> 4); - this.Visibility = (ElfSymVisibility)Other; - this.SHIdx = SHIdx; - this.ValueAbs = Value + ImageBase; - this.Value = Value; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfSymBinding.cs b/Ryujinx/Loaders/ElfSymBinding.cs deleted file mode 100644 index 8bbc6d4e..00000000 --- a/Ryujinx/Loaders/ElfSymBinding.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Loaders -{ - enum ElfSymBinding - { - STB_LOCAL = 0, - STB_GLOBAL = 1, - STB_WEAK = 2 - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfSymType.cs b/Ryujinx/Loaders/ElfSymType.cs deleted file mode 100644 index e504411e..00000000 --- a/Ryujinx/Loaders/ElfSymType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.Loaders -{ - enum ElfSymType - { - STT_NOTYPE = 0, - STT_OBJECT = 1, - STT_FUNC = 2, - STT_SECTION = 3, - STT_FILE = 4, - STT_COMMON = 5, - STT_TLS = 6 - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/ElfSymVisibility.cs b/Ryujinx/Loaders/ElfSymVisibility.cs deleted file mode 100644 index a308ef79..00000000 --- a/Ryujinx/Loaders/ElfSymVisibility.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Loaders -{ - enum ElfSymVisibility - { - STV_DEFAULT = 0, - STV_INTERNAL = 1, - STV_HIDDEN = 2, - STV_PROTECTED = 3 - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/Executable.cs b/Ryujinx/Loaders/Executable.cs deleted file mode 100644 index 65043658..00000000 --- a/Ryujinx/Loaders/Executable.cs +++ /dev/null @@ -1,149 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Loaders.Executables; -using Ryujinx.OsHle; -using System.Collections.Generic; - -namespace Ryujinx.Loaders -{ - class Executable - { - private AMemory Memory; - - private ElfDyn[] Dynamic; - - public long ImageBase { get; private set; } - public long ImageEnd { get; private set; } - - public Executable(IExecutable Exe, AMemory Memory, long ImageBase) - { - this.Memory = Memory; - this.ImageBase = ImageBase; - this.ImageEnd = ImageBase; - - WriteData(ImageBase + Exe.TextOffset, Exe.Text, MemoryType.CodeStatic, AMemoryPerm.RX); - WriteData(ImageBase + Exe.ROOffset, Exe.RO, MemoryType.Normal, AMemoryPerm.Read); - WriteData(ImageBase + Exe.DataOffset, Exe.Data, MemoryType.Normal, AMemoryPerm.RW); - - if (Exe.Mod0Offset == 0) - { - MapBss(ImageBase + Exe.DataOffset + Exe.Data.Count, Exe.BssSize); - - return; - } - - long Mod0Offset = ImageBase + Exe.Mod0Offset; - - int Mod0Magic = Memory.ReadInt32(Mod0Offset + 0x0); - long DynamicOffset = Memory.ReadInt32(Mod0Offset + 0x4) + Mod0Offset; - long BssStartOffset = Memory.ReadInt32(Mod0Offset + 0x8) + Mod0Offset; - long BssEndOffset = Memory.ReadInt32(Mod0Offset + 0xc) + Mod0Offset; - long EhHdrStartOffset = Memory.ReadInt32(Mod0Offset + 0x10) + Mod0Offset; - long EhHdrEndOffset = Memory.ReadInt32(Mod0Offset + 0x14) + Mod0Offset; - long ModObjOffset = Memory.ReadInt32(Mod0Offset + 0x18) + Mod0Offset; - - MapBss(BssStartOffset, BssEndOffset - BssStartOffset); - - ImageEnd = BssEndOffset; - - List Dynamic = new List(); - - while (true) - { - long TagVal = Memory.ReadInt64(DynamicOffset + 0); - long Value = Memory.ReadInt64(DynamicOffset + 8); - - DynamicOffset += 0x10; - - ElfDynTag Tag = (ElfDynTag)TagVal; - - if (Tag == ElfDynTag.DT_NULL) - { - break; - } - - Dynamic.Add(new ElfDyn(Tag, Value)); - } - - this.Dynamic = Dynamic.ToArray(); - } - - private void WriteData( - long Position, - IList Data, - MemoryType Type, - AMemoryPerm Perm) - { - Memory.Manager.MapPhys(Position, Data.Count, (int)Type, AMemoryPerm.Write); - - for (int Index = 0; Index < Data.Count; Index++) - { - Memory.WriteByte(Position + Index, Data[Index]); - } - - Memory.Manager.Reprotect(Position, Data.Count, Perm); - } - - private void MapBss(long Position, long Size) - { - Memory.Manager.MapPhys(Position, Size, (int)MemoryType.Normal, AMemoryPerm.RW); - } - - private ElfRel GetRelocation(long Position) - { - long Offset = Memory.ReadInt64(Position + 0); - long Info = Memory.ReadInt64(Position + 8); - long Addend = Memory.ReadInt64(Position + 16); - - int RelType = (int)(Info >> 0); - int SymIdx = (int)(Info >> 32); - - ElfSym Symbol = GetSymbol(SymIdx); - - return new ElfRel(Offset, Addend, Symbol, (ElfRelType)RelType); - } - - private ElfSym GetSymbol(int Index) - { - long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB); - long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB); - - long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT); - - long Position = SymTblAddr + Index * SymEntSize; - - return GetSymbol(Position, StrTblAddr); - } - - private ElfSym GetSymbol(long Position, long StrTblAddr) - { - int NameIndex = Memory.ReadInt32(Position + 0); - int Info = Memory.ReadByte(Position + 4); - int Other = Memory.ReadByte(Position + 5); - int SHIdx = Memory.ReadInt16(Position + 6); - long Value = Memory.ReadInt64(Position + 8); - long Size = Memory.ReadInt64(Position + 16); - - string Name = string.Empty; - - for (int Chr; (Chr = Memory.ReadByte(StrTblAddr + NameIndex++)) != 0;) - { - Name += (char)Chr; - } - - return new ElfSym(Name, Info, Other, SHIdx, ImageBase, Value, Size); - } - - private long GetFirstValue(ElfDynTag Tag) - { - foreach (ElfDyn Entry in Dynamic) - { - if (Entry.Tag == Tag) - { - return Entry.Value; - } - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/Executables/IExecutable.cs b/Ryujinx/Loaders/Executables/IExecutable.cs deleted file mode 100644 index 3e42a834..00000000 --- a/Ryujinx/Loaders/Executables/IExecutable.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.ObjectModel; - -namespace Ryujinx.Loaders.Executables -{ - interface IExecutable - { - ReadOnlyCollection Text { get; } - ReadOnlyCollection RO { get; } - ReadOnlyCollection Data { get; } - - int Mod0Offset { get; } - int TextOffset { get; } - int ROOffset { get; } - int DataOffset { get; } - int BssSize { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/Executables/Nro.cs b/Ryujinx/Loaders/Executables/Nro.cs deleted file mode 100644 index 2217f331..00000000 --- a/Ryujinx/Loaders/Executables/Nro.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.IO; - -namespace Ryujinx.Loaders.Executables -{ - class Nro : IExecutable - { - private byte[] m_Text; - private byte[] m_RO; - private byte[] m_Data; - - public ReadOnlyCollection Text => Array.AsReadOnly(m_Text); - public ReadOnlyCollection RO => Array.AsReadOnly(m_RO); - public ReadOnlyCollection Data => Array.AsReadOnly(m_Data); - - public int Mod0Offset { get; private set; } - public int TextOffset { get; private set; } - public int ROOffset { get; private set; } - public int DataOffset { get; private set; } - public int BssSize { get; private set; } - - public Nro(Stream Input) - { - BinaryReader Reader = new BinaryReader(Input); - - Input.Seek(4, SeekOrigin.Begin); - - int Mod0Offset = Reader.ReadInt32(); - int Padding8 = Reader.ReadInt32(); - int Paddingc = Reader.ReadInt32(); - int NroMagic = Reader.ReadInt32(); - int Unknown14 = Reader.ReadInt32(); - int FileSize = Reader.ReadInt32(); - int Unknown1c = Reader.ReadInt32(); - int TextOffset = Reader.ReadInt32(); - int TextSize = Reader.ReadInt32(); - int ROOffset = Reader.ReadInt32(); - int ROSize = Reader.ReadInt32(); - int DataOffset = Reader.ReadInt32(); - int DataSize = Reader.ReadInt32(); - int BssSize = Reader.ReadInt32(); - - this.Mod0Offset = Mod0Offset; - this.TextOffset = TextOffset; - this.ROOffset = ROOffset; - this.DataOffset = DataOffset; - this.BssSize = BssSize; - - byte[] Read(long Position, int Size) - { - Input.Seek(Position, SeekOrigin.Begin); - - return Reader.ReadBytes(Size); - } - - m_Text = Read(TextOffset, TextSize); - m_RO = Read(ROOffset, ROSize); - m_Data = Read(DataOffset, DataSize); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Loaders/Executables/Nso.cs b/Ryujinx/Loaders/Executables/Nso.cs deleted file mode 100644 index ead1baf1..00000000 --- a/Ryujinx/Loaders/Executables/Nso.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Ryujinx.Loaders.Compression; -using System; -using System.Collections.ObjectModel; -using System.IO; - -namespace Ryujinx.Loaders.Executables -{ - class Nso : IExecutable - { - private byte[] m_Text; - private byte[] m_RO; - private byte[] m_Data; - - public ReadOnlyCollection Text => Array.AsReadOnly(m_Text); - public ReadOnlyCollection RO => Array.AsReadOnly(m_RO); - public ReadOnlyCollection Data => Array.AsReadOnly(m_Data); - - public int Mod0Offset { get; private set; } - public int TextOffset { get; private set; } - public int ROOffset { get; private set; } - public int DataOffset { get; private set; } - public int BssSize { get; private set; } - - [Flags] - private enum NsoFlags - { - IsTextCompressed = 1 << 0, - IsROCompressed = 1 << 1, - IsDataCompressed = 1 << 2, - HasTextHash = 1 << 3, - HasROHash = 1 << 4, - HasDataHash = 1 << 5 - } - - public Nso(Stream Input) - { - BinaryReader Reader = new BinaryReader(Input); - - Input.Seek(0, SeekOrigin.Begin); - - int NsoMagic = Reader.ReadInt32(); - int Version = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - int FlagsMsk = Reader.ReadInt32(); - int TextOffset = Reader.ReadInt32(); - int TextMemOffset = Reader.ReadInt32(); - int TextDecSize = Reader.ReadInt32(); - int ModNameOffset = Reader.ReadInt32(); - int ROOffset = Reader.ReadInt32(); - int ROMemOffset = Reader.ReadInt32(); - int RODecSize = Reader.ReadInt32(); - int ModNameSize = Reader.ReadInt32(); - int DataOffset = Reader.ReadInt32(); - int DataMemOffset = Reader.ReadInt32(); - int DataDecSize = Reader.ReadInt32(); - int BssSize = Reader.ReadInt32(); - - byte[] BuildId = Reader.ReadBytes(0x20); - - int TextSize = Reader.ReadInt32(); - int ROSize = Reader.ReadInt32(); - int DataSize = Reader.ReadInt32(); - - Input.Seek(0x24, SeekOrigin.Current); - - int DynStrOffset = Reader.ReadInt32(); - int DynStrSize = Reader.ReadInt32(); - int DynSymOffset = Reader.ReadInt32(); - int DynSymSize = Reader.ReadInt32(); - - byte[] TextHash = Reader.ReadBytes(0x20); - byte[] ROHash = Reader.ReadBytes(0x20); - byte[] DataHash = Reader.ReadBytes(0x20); - - NsoFlags Flags = (NsoFlags)FlagsMsk; - - this.TextOffset = TextMemOffset; - this.ROOffset = ROMemOffset; - this.DataOffset = DataMemOffset; - this.BssSize = BssSize; - - //Text segment - Input.Seek(TextOffset, SeekOrigin.Begin); - - m_Text = Reader.ReadBytes(TextSize); - - if (Flags.HasFlag(NsoFlags.IsTextCompressed) || true) - { - m_Text = Lz4.Decompress(m_Text, TextDecSize); - } - - //Read-only data segment - Input.Seek(ROOffset, SeekOrigin.Begin); - - m_RO = Reader.ReadBytes(ROSize); - - if (Flags.HasFlag(NsoFlags.IsROCompressed) || true) - { - m_RO = Lz4.Decompress(m_RO, RODecSize); - } - - //Data segment - Input.Seek(DataOffset, SeekOrigin.Begin); - - m_Data = Reader.ReadBytes(DataSize); - - if (Flags.HasFlag(NsoFlags.IsDataCompressed) || true) - { - m_Data = Lz4.Decompress(m_Data, DataDecSize); - } - - using (MemoryStream Text = new MemoryStream(m_Text)) - { - BinaryReader TextReader = new BinaryReader(Text); - - Text.Seek(4, SeekOrigin.Begin); - - Mod0Offset = TextReader.ReadInt32(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/Logging.cs b/Ryujinx/Logging.cs deleted file mode 100644 index 2ae858b4..00000000 --- a/Ryujinx/Logging.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace Ryujinx -{ - public static class Logging - { - private static Stopwatch ExecutionTime = new Stopwatch(); - private const string LogFileName = "Ryujinx.log"; - - public static bool EnableInfo = Config.LoggingEnableInfo; - public static bool EnableTrace = Config.LoggingEnableTrace; - public static bool EnableDebug = Config.LoggingEnableDebug; - public static bool EnableWarn = Config.LoggingEnableWarn; - public static bool EnableError = Config.LoggingEnableError; - public static bool EnableFatal = Config.LoggingEnableFatal; - public static bool EnableLogFile = Config.LoggingEnableLogFile; - - static Logging() - { - ExecutionTime.Start(); - - if (File.Exists(LogFileName)) File.Delete(LogFileName); - } - - public static string GetExecutionTime() - { - return ExecutionTime.ElapsedMilliseconds.ToString().PadLeft(8, '0') + "ms"; - } - - private static string WhoCalledMe() - { - return new StackTrace().GetFrame(2).GetMethod().Name; - } - - private static void LogFile(string Message) - { - if (EnableLogFile) - { - using (StreamWriter Writer = File.AppendText(LogFileName)) - { - Writer.WriteLine(Message); - } - } - } - - public static void Info(string Message) - { - if (EnableInfo) - { - string Text = $"{GetExecutionTime()} | INFO > {Message}"; - - Console.ForegroundColor = ConsoleColor.White; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - - public static void Trace(string Message) - { - if (EnableTrace) - { - string Text = $"{GetExecutionTime()} | TRACE > {WhoCalledMe()} - {Message}"; - - Console.ForegroundColor = ConsoleColor.DarkGray; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - - public static void Debug(string Message) - { - if (EnableDebug) - { - string Text = $"{GetExecutionTime()} | DEBUG > {WhoCalledMe()} - {Message}"; - - Console.ForegroundColor = ConsoleColor.Gray; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - - public static void Warn(string Message) - { - if (EnableWarn) - { - string Text = $"{GetExecutionTime()} | WARN > {WhoCalledMe()} - {Message}"; - - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - - public static void Error(string Message) - { - if (EnableError) - { - string Text = $"{GetExecutionTime()} | ERROR > {WhoCalledMe()} - {Message}"; - - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - - public static void Fatal(string Message) - { - if (EnableFatal) - { - string Text = $"{GetExecutionTime()} | FATAL > {WhoCalledMe()} - {Message}"; - - Console.ForegroundColor = ConsoleColor.Magenta; - Console.WriteLine(Text.PadLeft(Text.Length + 1, ' ')); - Console.ResetColor(); - - LogFile(Text); - } - } - } -} diff --git a/Ryujinx/OsHle/CondVar.cs b/Ryujinx/OsHle/CondVar.cs deleted file mode 100644 index 91ea37bd..00000000 --- a/Ryujinx/OsHle/CondVar.cs +++ /dev/null @@ -1,138 +0,0 @@ -using Ryujinx.OsHle.Handles; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.OsHle -{ - class CondVar - { - private Process Process; - - private long CondVarAddress; - private long Timeout; - - private bool OwnsCondVarValue; - - private List WaitingThreads; - - public CondVar(Process Process, long CondVarAddress, long Timeout) - { - this.Process = Process; - this.CondVarAddress = CondVarAddress; - this.Timeout = Timeout; - - WaitingThreads = new List(); - } - - public void WaitForSignal(HThread Thread) - { - int Count = Process.Memory.ReadInt32(CondVarAddress); - - if (Count <= 0) - { - lock (WaitingThreads) - { - WaitingThreads.Add(Thread); - } - - if (Timeout == -1) - { - Process.Scheduler.WaitForSignal(Thread); - } - else - { - Process.Scheduler.WaitForSignal(Thread, (int)(Timeout / 1000000)); - - lock (WaitingThreads) - { - WaitingThreads.Remove(Thread); - } - } - } - - AcquireCondVarValue(); - - Count = Process.Memory.ReadInt32(CondVarAddress); - - if (Count > 0) - { - Process.Memory.WriteInt32(CondVarAddress, Count - 1); - } - - ReleaseCondVarValue(); - } - - public void SetSignal(HThread Thread, int Count) - { - lock (WaitingThreads) - { - if (Count == -1) - { - Process.Scheduler.Signal(WaitingThreads.ToArray()); - - AcquireCondVarValue(); - - Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count); - - ReleaseCondVarValue(); - - WaitingThreads.Clear(); - } - else - { - if (WaitingThreads.Count > 0) - { - int HighestPriority = WaitingThreads[0].Priority; - int HighestPrioIndex = 0; - - for (int Index = 1; Index < WaitingThreads.Count; Index++) - { - if (HighestPriority > WaitingThreads[Index].Priority) - { - HighestPriority = WaitingThreads[Index].Priority; - - HighestPrioIndex = Index; - } - } - - Process.Scheduler.Signal(WaitingThreads[HighestPrioIndex]); - - WaitingThreads.RemoveAt(HighestPrioIndex); - } - - AcquireCondVarValue(); - - Process.Memory.WriteInt32(CondVarAddress, Count); - - ReleaseCondVarValue(); - } - } - - Process.Scheduler.Suspend(Thread.ProcessorId); - Process.Scheduler.Resume(Thread); - } - - private void AcquireCondVarValue() - { - if (!OwnsCondVarValue) - { - while (!Process.Memory.AcquireAddress(CondVarAddress)) - { - Thread.Yield(); - } - - OwnsCondVarValue = true; - } - } - - private void ReleaseCondVarValue() - { - if (OwnsCondVarValue) - { - OwnsCondVarValue = false; - - Process.Memory.ReleaseAddress(CondVarAddress); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Display.cs b/Ryujinx/OsHle/Display.cs deleted file mode 100644 index f62430fa..00000000 --- a/Ryujinx/OsHle/Display.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.OsHle -{ - class Display - { - public string Name { get; private set; } - - public Display(string Name) - { - this.Name = Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Exceptions/GuestBrokeExecutionException.cs b/Ryujinx/OsHle/Exceptions/GuestBrokeExecutionException.cs deleted file mode 100644 index 1369c57b..00000000 --- a/Ryujinx/OsHle/Exceptions/GuestBrokeExecutionException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Ryujinx.OsHle.Exceptions -{ - public class GuestBrokeExecutionException : Exception - { - private const string ExMsg = "The guest program broke execution!"; - - public GuestBrokeExecutionException() : base(ExMsg) { } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Exceptions/UndefinedInstructionException.cs b/Ryujinx/OsHle/Exceptions/UndefinedInstructionException.cs deleted file mode 100644 index 86033a82..00000000 --- a/Ryujinx/OsHle/Exceptions/UndefinedInstructionException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Ryujinx.OsHle.Exceptions -{ - public class UndefinedInstructionException : Exception - { - private const string ExMsg = "The instruction at 0x{0:x16} (opcode 0x{1:x8}) is undefined!"; - - public UndefinedInstructionException() : base() { } - - public UndefinedInstructionException(long Position, int OpCode) : base(string.Format(ExMsg, Position, OpCode)) { } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/FileDesc.cs b/Ryujinx/OsHle/FileDesc.cs deleted file mode 100644 index 2a21f500..00000000 --- a/Ryujinx/OsHle/FileDesc.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.OsHle -{ - class FileDesc - { - public string Name { get; private set; } - - public FileDesc(string Name) - { - this.Name = Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HDomain.cs b/Ryujinx/OsHle/Handles/HDomain.cs deleted file mode 100644 index e781602a..00000000 --- a/Ryujinx/OsHle/Handles/HDomain.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Ryujinx.OsHle.Utilities; -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Handles -{ - class HDomain : HSession - { - private Dictionary Objects; - - private IdPool ObjIds; - - public HDomain(HSession Session) : base(Session) - { - Objects = new Dictionary(); - - ObjIds = new IdPool(); - } - - public int GenerateObjectId(object Obj) - { - int Id = ObjIds.GenerateId(); - - if (Id == -1) - { - throw new InvalidOperationException(); - } - - Objects.Add(Id, Obj); - - return Id; - } - - public void DeleteObject(int Id) - { - if (Objects.TryGetValue(Id, out object Obj)) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - - ObjIds.DeleteId(Id); - Objects.Remove(Id); - } - } - - public object GetObject(int Id) - { - if (Objects.TryGetValue(Id, out object Obj)) - { - return Obj; - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HEvent.cs b/Ryujinx/OsHle/Handles/HEvent.cs deleted file mode 100644 index d9d0ff4c..00000000 --- a/Ryujinx/OsHle/Handles/HEvent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.OsHle.Handles -{ - class HEvent - { - - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HNvMap.cs b/Ryujinx/OsHle/Handles/HNvMap.cs deleted file mode 100644 index 3e15eda3..00000000 --- a/Ryujinx/OsHle/Handles/HNvMap.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ryujinx.OsHle.Handles -{ - class HNvMap - { - public int Id { get; private set; } - public int Size { get; private set; } - - public int Align { get; set; } - public int Kind { get; set; } - public long Address { get; set; } - - public HNvMap(int Id, int Size) - { - this.Id = Id; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HSession.cs b/Ryujinx/OsHle/Handles/HSession.cs deleted file mode 100644 index 6b901659..00000000 --- a/Ryujinx/OsHle/Handles/HSession.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ryujinx.OsHle.Handles -{ - class HSession - { - public string ServiceName { get; private set; } - - public bool IsInitialized { get; private set; } - - public int State { get; set; } - - public HSession(string ServiceName) - { - this.ServiceName = ServiceName; - } - - public HSession(HSession Session) - { - ServiceName = Session.ServiceName; - IsInitialized = Session.IsInitialized; - } - - public void Initialize() - { - IsInitialized = true; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HSessionObj.cs b/Ryujinx/OsHle/Handles/HSessionObj.cs deleted file mode 100644 index a871a11f..00000000 --- a/Ryujinx/OsHle/Handles/HSessionObj.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Ryujinx.OsHle.Handles -{ - class HSessionObj : HSession, IDisposable - { - public object Obj { get; private set; } - - public HSessionObj(HSession Session, object Obj) : base(Session) - { - this.Obj = Obj; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && Obj != null) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HSharedMem.cs b/Ryujinx/OsHle/Handles/HSharedMem.cs deleted file mode 100644 index 4f943ebc..00000000 --- a/Ryujinx/OsHle/Handles/HSharedMem.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Handles -{ - class HSharedMem - { - private List Positions; - - public int PositionsCount => Positions.Count; - - public EventHandler MemoryMapped; - public EventHandler MemoryUnmapped; - - public HSharedMem(long PhysPos) - { - Positions = new List(); - } - - public void AddVirtualPosition(long Position) - { - lock (Positions) - { - Positions.Add(Position); - - MemoryMapped?.Invoke(this, EventArgs.Empty); - } - } - - public void RemoveVirtualPosition(long Position) - { - lock (Positions) - { - Positions.Remove(Position); - - MemoryUnmapped?.Invoke(this, EventArgs.Empty); - } - } - - public long GetVirtualPosition(int Index) - { - lock (Positions) - { - if (Index < 0 || Index >= Positions.Count) - { - throw new ArgumentOutOfRangeException(nameof(Index)); - } - - return Positions[Index]; - } - } - - public bool TryGetLastVirtualPosition(out long Position) - { - lock (Positions) - { - if (Positions.Count > 0) - { - Position = Positions[Positions.Count - 1]; - - return true; - } - - Position = 0; - - return false; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HThread.cs b/Ryujinx/OsHle/Handles/HThread.cs deleted file mode 100644 index fef2faf2..00000000 --- a/Ryujinx/OsHle/Handles/HThread.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ChocolArm64; - -namespace Ryujinx.OsHle.Handles -{ - class HThread - { - public AThread Thread { get; private set; } - - public int ProcessorId { get; private set; } - public int Priority { get; private set; } - - public int ThreadId => Thread.ThreadId; - - public HThread(AThread Thread, int ProcessorId, int Priority) - { - this.Thread = Thread; - this.ProcessorId = ProcessorId; - this.Priority = Priority; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/HTransferMem.cs b/Ryujinx/OsHle/Handles/HTransferMem.cs deleted file mode 100644 index b24e1412..00000000 --- a/Ryujinx/OsHle/Handles/HTransferMem.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.OsHle.Handles -{ - class HTransferMem - { - public AMemory Memory { get; private set; } - public AMemoryPerm Perm { get; private set; } - - public long Position { get; private set; } - public long Size { get; private set; } - - public HTransferMem(AMemory Memory, AMemoryPerm Perm, long Position, long Size) - { - this.Memory = Memory; - this.Perm = Perm; - this.Position = Position; - this.Size = Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Handles/KProcessScheduler.cs b/Ryujinx/OsHle/Handles/KProcessScheduler.cs deleted file mode 100644 index 9044987f..00000000 --- a/Ryujinx/OsHle/Handles/KProcessScheduler.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.OsHle.Handles -{ - class KProcessScheduler : IDisposable - { - private class SchedulerThread : IDisposable - { - public HThread Thread { get; private set; } - - public AutoResetEvent WaitEvent { get; private set; } - - public SchedulerThread(HThread Thread) - { - this.Thread = Thread; - - WaitEvent = new AutoResetEvent(false); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - WaitEvent.Dispose(); - } - } - } - - private class ThreadQueue - { - private List Threads; - - public ThreadQueue() - { - Threads = new List(); - } - - public void Push(SchedulerThread Thread) - { - lock (Threads) - { - Threads.Add(Thread); - } - } - - public SchedulerThread Pop(int MinPriority = 0x40) - { - lock (Threads) - { - SchedulerThread SchedThread; - - int HighestPriority = MinPriority; - - int HighestPrioIndex = -1; - - for (int Index = 0; Index < Threads.Count; Index++) - { - SchedThread = Threads[Index]; - - if (HighestPriority > SchedThread.Thread.Priority) - { - HighestPriority = SchedThread.Thread.Priority; - - HighestPrioIndex = Index; - } - } - - if (HighestPrioIndex == -1) - { - return null; - } - - SchedThread = Threads[HighestPrioIndex]; - - Threads.RemoveAt(HighestPrioIndex); - - return SchedThread; - } - } - - public bool HasThread(SchedulerThread SchedThread) - { - lock (Threads) - { - return Threads.Contains(SchedThread); - } - } - } - - private ConcurrentDictionary AllThreads; - - private ThreadQueue[] WaitingToRun; - - private HashSet ActiveProcessors; - - private object SchedLock; - - public KProcessScheduler() - { - AllThreads = new ConcurrentDictionary(); - - WaitingToRun = new ThreadQueue[4]; - - for (int Index = 0; Index < 4; Index++) - { - WaitingToRun[Index] = new ThreadQueue(); - } - - ActiveProcessors = new HashSet(); - - SchedLock = new object(); - } - - public void StartThread(HThread Thread) - { - lock (SchedLock) - { - SchedulerThread SchedThread = new SchedulerThread(Thread); - - if (!AllThreads.TryAdd(Thread, SchedThread)) - { - return; - } - - if (!ActiveProcessors.Contains(Thread.ProcessorId)) - { - ActiveProcessors.Add(Thread.ProcessorId); - - Thread.Thread.Execute(); - - Logging.Debug($"{GetDbgThreadInfo(Thread)} running."); - } - else - { - WaitingToRun[Thread.ProcessorId].Push(SchedThread); - - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run."); - } - } - } - - public void Suspend(int ProcessorId) - { - lock (SchedLock) - { - SchedulerThread SchedThread = WaitingToRun[ProcessorId].Pop(); - - if (SchedThread != null) - { - RunThread(SchedThread); - } - else - { - ActiveProcessors.Remove(ProcessorId); - } - } - } - - public void Resume(HThread CurrThread) - { - SchedulerThread SchedThread; - - Logging.Debug($"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state."); - - lock (SchedLock) - { - if (!AllThreads.TryGetValue(CurrThread, out SchedThread)) - { - Logging.Error($"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!"); - - return; - } - } - - TryResumingExecution(SchedThread); - } - - public void WaitForSignal(HThread Thread, int Timeout = -1) - { - SchedulerThread SchedThread; - - Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state."); - - lock (SchedLock) - { - SchedThread = WaitingToRun[Thread.ProcessorId].Pop(); - - if (SchedThread != null) - { - RunThread(SchedThread); - } - else - { - ActiveProcessors.Remove(Thread.ProcessorId); - } - - if (!AllThreads.TryGetValue(Thread, out SchedThread)) - { - Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); - - return; - } - } - - if (Timeout >= 0) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms."); - - SchedThread.WaitEvent.WaitOne(Timeout); - } - else - { - SchedThread.WaitEvent.WaitOne(); - } - - TryResumingExecution(SchedThread); - } - - private void TryResumingExecution(SchedulerThread SchedThread) - { - HThread Thread = SchedThread.Thread; - - lock (SchedLock) - { - if (ActiveProcessors.Add(Thread.ProcessorId)) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); - - return; - } - - WaitingToRun[Thread.ProcessorId].Push(SchedThread); - } - - SchedThread.WaitEvent.WaitOne(); - - Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); - } - - public void Yield(HThread Thread) - { - SchedulerThread SchedThread; - - Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution."); - - lock (SchedLock) - { - SchedThread = WaitingToRun[Thread.ProcessorId].Pop(Thread.Priority); - - if (SchedThread == null) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run."); - - return; - } - - RunThread(SchedThread); - - if (!AllThreads.TryGetValue(Thread, out SchedThread)) - { - Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!"); - - return; - } - - WaitingToRun[Thread.ProcessorId].Push(SchedThread); - } - - SchedThread.WaitEvent.WaitOne(); - - Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution..."); - } - - private void RunThread(SchedulerThread SchedThread) - { - if (!SchedThread.Thread.Thread.Execute()) - { - SchedThread.WaitEvent.Set(); - } - else - { - Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running."); - } - } - - public void Signal(params HThread[] Threads) - { - lock (SchedLock) - { - foreach (HThread Thread in Threads) - { - if (AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread)) - { - if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread)) - { - Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled."); - - SchedThread.WaitEvent.Set(); - } - } - } - } - } - - private string GetDbgThreadInfo(HThread Thread) - { - return $"Thread {Thread.ThreadId} (core {Thread.ProcessorId}) prio {Thread.Priority}"; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - foreach (SchedulerThread SchedThread in AllThreads.Values) - { - SchedThread.Dispose(); - } - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Horizon.cs b/Ryujinx/OsHle/Horizon.cs deleted file mode 100644 index b9af69c2..00000000 --- a/Ryujinx/OsHle/Horizon.cs +++ /dev/null @@ -1,197 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Loaders.Executables; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Utilities; -using System.Collections.Concurrent; -using System.IO; -using System; - -namespace Ryujinx.OsHle -{ - class Horizon - { - internal const int HidSize = 0x40000; - internal const int FontSize = 0x50; - - internal int HidHandle { get; private set; } - internal int FontHandle { get; private set; } - - public long HidOffset { get; private set; } - public long FontOffset { get; private set; } - - internal IdPool IdGen { get; private set; } - internal IdPool NvMapIds { get; private set; } - - internal IdPoolWithObj Handles { get; private set; } - internal IdPoolWithObj Fds { get; private set; } - internal IdPoolWithObj Displays { get; private set; } - - public ConcurrentDictionary Mutexes { get; private set; } - public ConcurrentDictionary CondVars { get; private set; } - - private ConcurrentDictionary Processes; - - private HSharedMem HidSharedMem; - - private AMemoryAlloc Allocator; - - private Switch Ns; - - public Horizon(Switch Ns) - { - this.Ns = Ns; - - IdGen = new IdPool(); - NvMapIds = new IdPool(); - - Handles = new IdPoolWithObj(); - Fds = new IdPoolWithObj(); - Displays = new IdPoolWithObj(); - - Mutexes = new ConcurrentDictionary(); - CondVars = new ConcurrentDictionary(); - - Processes = new ConcurrentDictionary(); - - Allocator = new AMemoryAlloc(); - - HidOffset = Allocator.Alloc(HidSize); - FontOffset = Allocator.Alloc(FontSize); - - HidSharedMem = new HSharedMem(HidOffset); - - HidSharedMem.MemoryMapped += HidInit; - - HidHandle = Handles.GenerateId(HidSharedMem); - - FontHandle = Handles.GenerateId(new HSharedMem(FontOffset)); - } - - public void LoadCart(string ExeFsDir, string RomFsFile = null) - { - if (RomFsFile != null) - { - Ns.VFs.LoadRomFs(RomFsFile); - } - - int ProcessId = IdGen.GenerateId(); - - Process MainProcess = new Process(Ns, Allocator, ProcessId); - - void LoadNso(string FileName) - { - foreach (string File in Directory.GetFiles(ExeFsDir, FileName)) - { - if (Path.GetExtension(File) != string.Empty) - { - continue; - } - - Logging.Info($"Loading {Path.GetFileNameWithoutExtension(File)}..."); - - using (FileStream Input = new FileStream(File, FileMode.Open)) - { - Nso Program = new Nso(Input); - - MainProcess.LoadProgram(Program); - } - } - } - - LoadNso("rtld"); - - MainProcess.SetEmptyArgs(); - - LoadNso("main"); - LoadNso("subsdk*"); - LoadNso("sdk"); - - MainProcess.InitializeHeap(); - MainProcess.Run(); - - Processes.TryAdd(ProcessId, MainProcess); - } - - public void LoadProgram(string FileName) - { - int ProcessId = IdGen.GenerateId(); - - Process MainProcess = new Process(Ns, Allocator, ProcessId); - - using (FileStream Input = new FileStream(FileName, FileMode.Open)) - { - if (Path.GetExtension(FileName).ToLower() == ".nro") - { - MainProcess.LoadProgram(new Nro(Input)); - } - else - { - MainProcess.LoadProgram(new Nso(Input)); - } - } - - MainProcess.SetEmptyArgs(); - MainProcess.InitializeHeap(); - MainProcess.Run(); - - Processes.TryAdd(ProcessId, MainProcess); - } - - public void FinalizeAllProcesses() - { - foreach (Process Process in Processes.Values) - { - Process.StopAllThreads(); - Process.Dispose(); - } - } - - internal bool ExitProcess(int ProcessId) - { - bool Success = Processes.TryRemove(ProcessId, out Process Process); - - if (Success) - { - Process.StopAllThreads(); - } - - if (Processes.Count == 0) - { - Ns.OnFinish(EventArgs.Empty); - } - - return Success; - } - - internal bool TryGetProcess(int ProcessId, out Process Process) - { - return Processes.TryGetValue(ProcessId, out Process); - } - - internal void CloseHandle(int Handle) - { - object HndData = Handles.GetData(Handle); - - if (HndData is HTransferMem TransferMem) - { - TransferMem.Memory.Manager.Reprotect( - TransferMem.Position, - TransferMem.Size, - TransferMem.Perm); - } - - Handles.Delete(Handle); - } - - private void HidInit(object sender, EventArgs e) - { - HSharedMem SharedMem = (HSharedMem)sender; - - if (SharedMem.TryGetLastVirtualPosition(out long Position)) - { - Logging.Info($"HID shared memory successfully mapped to {Position:x16}!"); - Ns.Hid.Init(Position); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcBuffDesc.cs b/Ryujinx/OsHle/Ipc/IpcBuffDesc.cs deleted file mode 100644 index 41b1efe0..00000000 --- a/Ryujinx/OsHle/Ipc/IpcBuffDesc.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - struct IpcBuffDesc - { - public long Position { get; private set; } - public long Size { get; private set; } - public int Flags { get; private set; } - - public IpcBuffDesc(BinaryReader Reader) - { - long Word0 = Reader.ReadUInt32(); - long Word1 = Reader.ReadUInt32(); - long Word2 = Reader.ReadUInt32(); - - Position = Word1; - Position |= (Word2 << 4) & 0x0f00000000; - Position |= (Word2 << 34) & 0x7000000000; - - Size = Word0; - Size |= (Word2 << 8) & 0xf00000000; - - Flags = (int)Word2 & 3; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcDomCmd.cs b/Ryujinx/OsHle/Ipc/IpcDomCmd.cs deleted file mode 100644 index 03567185..00000000 --- a/Ryujinx/OsHle/Ipc/IpcDomCmd.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.OsHle.Ipc -{ - enum IpcDomCmd - { - SendMsg = 1, - DeleteObj = 2 - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcHandleDesc.cs b/Ryujinx/OsHle/Ipc/IpcHandleDesc.cs deleted file mode 100644 index fa5d7e1d..00000000 --- a/Ryujinx/OsHle/Ipc/IpcHandleDesc.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - class IpcHandleDesc - { - public bool HasPId { get; private set; } - - public long PId { get; private set; } - - public int[] ToCopy { get; private set; } - public int[] ToMove { get; private set; } - - public IpcHandleDesc(BinaryReader Reader) - { - int Word = Reader.ReadInt32(); - - HasPId = (Word & 1) != 0; - - ToCopy = new int[(Word >> 1) & 0xf]; - ToMove = new int[(Word >> 5) & 0xf]; - - PId = HasPId ? Reader.ReadInt64() : 0; - - for (int Index = 0; Index < ToCopy.Length; Index++) - { - ToCopy[Index] = Reader.ReadInt32(); - } - - for (int Index = 0; Index < ToMove.Length; Index++) - { - ToMove[Index] = Reader.ReadInt32(); - } - } - - public IpcHandleDesc(int[] Copy, int[] Move) - { - ToCopy = Copy ?? throw new ArgumentNullException(nameof(Copy)); - ToMove = Move ?? throw new ArgumentNullException(nameof(Move)); - } - - public IpcHandleDesc(int[] Copy, int[] Move, long PId) : this(Copy, Move) - { - this.PId = PId; - - HasPId = true; - } - - public static IpcHandleDesc MakeCopy(int Handle) => new IpcHandleDesc( - new int[] { Handle }, - new int[0]); - - public static IpcHandleDesc MakeMove(int Handle) => new IpcHandleDesc( - new int[0], - new int[] { Handle }); - - public byte[] GetBytes() - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - int Word = HasPId ? 1 : 0; - - Word |= (ToCopy.Length & 0xf) << 1; - Word |= (ToMove.Length & 0xf) << 5; - - Writer.Write(Word); - - if (HasPId) - { - Writer.Write((long)PId); - } - - foreach (int Handle in ToCopy) - { - Writer.Write(Handle); - } - - foreach (int Handle in ToMove) - { - Writer.Write(Handle); - } - - return MS.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcHandler.cs b/Ryujinx/OsHle/Ipc/IpcHandler.cs deleted file mode 100644 index f1278914..00000000 --- a/Ryujinx/OsHle/Ipc/IpcHandler.cs +++ /dev/null @@ -1,277 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Objects; -using Ryujinx.OsHle.Services; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - static class IpcHandler - { - private static Dictionary<(string, int), ServiceProcessRequest> ServiceCmds = - new Dictionary<(string, int), ServiceProcessRequest>() - { - { ( "acc:u0", 3), Service.AccU0ListOpenUsers }, - { ( "acc:u0", 5), Service.AccU0GetProfile }, - { ( "acc:u0", 100), Service.AccU0InitializeApplicationInfo }, - { ( "acc:u0", 101), Service.AccU0GetBaasAccountManagerForApplication }, - { ( "apm", 0), Service.ApmOpenSession }, - { ( "apm:p", 0), Service.ApmOpenSession }, - { ( "appletOE", 0), Service.AppletOpenApplicationProxy }, - { ( "audout:u", 0), Service.AudOutListAudioOuts }, - { ( "audout:u", 1), Service.AudOutOpenAudioOut }, - { ( "audren:u", 0), Service.AudRenOpenAudioRenderer }, - { ( "audren:u", 1), Service.AudRenGetAudioRendererWorkBufferSize }, - { ( "friend:a", 0), Service.FriendCreateFriendService }, - { ( "fsp-srv", 1), Service.FspSrvInitialize }, - { ( "fsp-srv", 18), Service.FspSrvMountSdCard }, - { ( "fsp-srv", 51), Service.FspSrvMountSaveData }, - { ( "fsp-srv", 200), Service.FspSrvOpenDataStorageByCurrentProcess }, - { ( "fsp-srv", 203), Service.FspSrvOpenRomStorage }, - { ( "fsp-srv", 1005), Service.FspSrvGetGlobalAccessLogMode }, - { ( "hid", 0), Service.HidCreateAppletResource }, - { ( "hid", 11), Service.HidActivateTouchScreen }, - { ( "hid", 100), Service.HidSetSupportedNpadStyleSet }, - { ( "hid", 102), Service.HidSetSupportedNpadIdType }, - { ( "hid", 103), Service.HidActivateNpad }, - { ( "hid", 120), Service.HidSetNpadJoyHoldType }, - { ( "lm", 0), Service.LmInitialize }, - { ( "nvdrv", 0), Service.NvDrvOpen }, - { ( "nvdrv", 1), Service.NvDrvIoctl }, - { ( "nvdrv", 2), Service.NvDrvClose }, - { ( "nvdrv", 3), Service.NvDrvInitialize }, - { ( "nvdrv", 4), Service.NvDrvQueryEvent }, - { ( "nvdrv", 8), Service.NvDrvSetClientPid }, - { ( "nvdrv:a", 0), Service.NvDrvOpen }, - { ( "nvdrv:a", 1), Service.NvDrvIoctl }, - { ( "nvdrv:a", 2), Service.NvDrvClose }, - { ( "nvdrv:a", 3), Service.NvDrvInitialize }, - { ( "nvdrv:a", 4), Service.NvDrvQueryEvent }, - { ( "nvdrv:a", 8), Service.NvDrvSetClientPid }, - { ( "pctl:a", 0), Service.PctlCreateService }, - { ( "pl:u", 1), Service.PlGetLoadState }, - { ( "pl:u", 2), Service.PlGetFontSize }, - { ( "pl:u", 3), Service.PlGetSharedMemoryAddressOffset }, - { ( "pl:u", 4), Service.PlGetSharedMemoryNativeHandle }, - { ( "set", 1), Service.SetGetAvailableLanguageCodes }, - { ( "sm:", 0), Service.SmInitialize }, - { ( "sm:", 1), Service.SmGetService }, - { ( "time:u", 0), Service.TimeGetStandardUserSystemClock }, - { ( "time:u", 1), Service.TimeGetStandardNetworkSystemClock }, - { ( "time:u", 2), Service.TimeGetStandardSteadyClock }, - { ( "time:u", 3), Service.TimeGetTimeZoneService }, - { ( "time:u", 4), Service.TimeGetStandardLocalSystemClock }, - { ( "time:s", 0), Service.TimeGetStandardUserSystemClock }, - { ( "time:s", 1), Service.TimeGetStandardNetworkSystemClock }, - { ( "time:s", 2), Service.TimeGetStandardSteadyClock }, - { ( "time:s", 3), Service.TimeGetTimeZoneService }, - { ( "time:s", 4), Service.TimeGetStandardLocalSystemClock }, - { ( "vi:m", 2), Service.ViGetDisplayService }, - }; - - private const long SfciMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'I' << 24; - private const long SfcoMagic = 'S' << 0 | 'F' << 8 | 'C' << 16 | 'O' << 24; - - public static void IpcCall( - Switch Ns, - AMemory Memory, - HSession Session, - IpcMessage Request, - long CmdPtr, - int HndId) - { - IpcMessage Response = new IpcMessage(Request.IsDomain); - - using (MemoryStream Raw = new MemoryStream(Request.RawData)) - { - BinaryReader ReqReader = new BinaryReader(Raw); - - if (Request.Type == IpcMessageType.Request) - { - string ServiceName = Session.ServiceName; - - ServiceProcessRequest ProcReq = null; - - bool IgnoreNullPR = false; - - string DbgServiceName = string.Empty; - - if (Session is HDomain Dom) - { - if (Request.DomCmd == IpcDomCmd.SendMsg) - { - long Magic = ReqReader.ReadInt64(); - int CmdId = (int)ReqReader.ReadInt64(); - - object Obj = Dom.GetObject(Request.DomObjId); - - if (Obj is HDomain) - { - ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); - - DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - else if (Obj != null) - { - ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq); - - DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - } - else if (Request.DomCmd == IpcDomCmd.DeleteObj) - { - Dom.DeleteObject(Request.DomObjId); - - Response = FillResponse(Response, 0); - - IgnoreNullPR = true; - } - } - else - { - long Magic = ReqReader.ReadInt64(); - int CmdId = (int)ReqReader.ReadInt64(); - - if (Session is HSessionObj) - { - object Obj = ((HSessionObj)Session).Obj; - - ((IIpcInterface)Obj).Commands.TryGetValue(CmdId, out ProcReq); - - DbgServiceName = $"{ServiceName} {Obj.GetType().Name} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - else - { - ServiceCmds.TryGetValue((ServiceName, CmdId), out ProcReq); - - DbgServiceName = $"{ServiceName} {ProcReq?.Method.Name ?? CmdId.ToString()}"; - } - } - - Logging.Debug($"IpcMessage: {DbgServiceName}"); - - if (ProcReq != null) - { - using (MemoryStream ResMS = new MemoryStream()) - { - BinaryWriter ResWriter = new BinaryWriter(ResMS); - - ServiceCtx Context = new ServiceCtx( - Ns, - Memory, - Session, - Request, - Response, - ReqReader, - ResWriter); - - long Result = ProcReq(Context); - - Response = FillResponse(Response, Result, ResMS.ToArray()); - } - } - else if (!IgnoreNullPR) - { - throw new NotImplementedException(DbgServiceName); - } - } - else if (Request.Type == IpcMessageType.Control) - { - long Magic = ReqReader.ReadInt64(); - long CmdId = ReqReader.ReadInt64(); - - switch (CmdId) - { - case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break; - case 3: Request = IpcQueryBufferPointerSize(Response); break; - case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break; - - default: throw new NotImplementedException(CmdId.ToString()); - } - } - else if (Request.Type == IpcMessageType.Unknown2) - { - //TODO - } - else - { - throw new NotImplementedException(Request.Type.ToString()); - } - - AMemoryHelper.WriteBytes(Memory, CmdPtr, Response.GetBytes(CmdPtr)); - } - } - - private static IpcMessage IpcConvertSessionToDomain( - Switch Ns, - HSession Session, - IpcMessage Response, - int HndId) - { - HDomain Dom = new HDomain(Session); - - Ns.Os.Handles.ReplaceData(HndId, Dom); - - return FillResponse(Response, 0, Dom.GenerateObjectId(Dom)); - } - - private static IpcMessage IpcDuplicateSessionEx( - Switch Ns, - HSession Session, - IpcMessage Response, - BinaryReader ReqReader) - { - int Unknown = ReqReader.ReadInt32(); - - int Handle = Ns.Os.Handles.GenerateId(Session); - - Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return FillResponse(Response, 0); - } - - private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response) - { - return FillResponse(Response, 0, 0x500); - } - - private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values) - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - foreach (int Value in Values) - { - Writer.Write(Value); - } - - return FillResponse(Response, Result, MS.ToArray()); - } - } - - private static IpcMessage FillResponse(IpcMessage Response, long Result, byte[] Data = null) - { - Response.Type = IpcMessageType.Response; - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write(SfcoMagic); - Writer.Write(Result); - - if (Data != null) - { - Writer.Write(Data); - } - - Response.RawData = MS.ToArray(); - } - - return Response; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcMessage.cs b/Ryujinx/OsHle/Ipc/IpcMessage.cs deleted file mode 100644 index 407fd65f..00000000 --- a/Ryujinx/OsHle/Ipc/IpcMessage.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - class IpcMessage - { - public IpcMessageType Type { get; set; } - - public IpcHandleDesc HandleDesc { get; set; } - - public List PtrBuff { get; private set; } - public List SendBuff { get; private set; } - public List ReceiveBuff { get; private set; } - public List ExchangeBuff { get; private set; } - public List RecvListBuff { get; private set; } - - public List ResponseObjIds { get; private set; } - - public bool IsDomain { get; private set; } - public IpcDomCmd DomCmd { get; private set; } - public int DomObjId { get; private set; } - - public byte[] RawData { get; set; } - - public IpcMessage() - { - PtrBuff = new List(); - SendBuff = new List(); - ReceiveBuff = new List(); - ExchangeBuff = new List(); - RecvListBuff = new List(); - - ResponseObjIds = new List(); - } - - public IpcMessage(bool Domain) : this() - { - IsDomain = Domain; - } - - public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this() - { - using (MemoryStream MS = new MemoryStream(Data)) - { - BinaryReader Reader = new BinaryReader(MS); - - Initialize(Reader, CmdPtr, Domain); - } - } - - private void Initialize(BinaryReader Reader, long CmdPtr, bool Domain) - { - IsDomain = Domain; - - int Word0 = Reader.ReadInt32(); - int Word1 = Reader.ReadInt32(); - - Type = (IpcMessageType)(Word0 & 0xffff); - - int PtrBuffCount = (Word0 >> 16) & 0xf; - int SendBuffCount = (Word0 >> 20) & 0xf; - int RecvBuffCount = (Word0 >> 24) & 0xf; - int XchgBuffCount = (Word0 >> 28) & 0xf; - - int RawDataSize = (Word1 >> 0) & 0x3ff; - int RecvListFlags = (Word1 >> 10) & 0xf; - bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0; - - if (HndDescEnable) - { - HandleDesc = new IpcHandleDesc(Reader); - } - - for (int Index = 0; Index < PtrBuffCount; Index++) - { - PtrBuff.Add(new IpcPtrBuffDesc(Reader)); - } - - void ReadBuff(List Buff, int Count) - { - for (int Index = 0; Index < Count; Index++) - { - Buff.Add(new IpcBuffDesc(Reader)); - } - } - - ReadBuff(SendBuff, SendBuffCount); - ReadBuff(ReceiveBuff, RecvBuffCount); - ReadBuff(ExchangeBuff, XchgBuffCount); - - RawDataSize *= 4; - - long RecvListPos = Reader.BaseStream.Position + RawDataSize; - - long Pad0 = GetPadSize16(Reader.BaseStream.Position + CmdPtr); - - Reader.BaseStream.Seek(Pad0, SeekOrigin.Current); - - int RecvListCount = RecvListFlags - 2; - - if (RecvListCount == 0) - { - RecvListCount = 1; - } - else if (RecvListCount < 0) - { - RecvListCount = 0; - } - - if (Domain) - { - int DomWord0 = Reader.ReadInt32(); - - DomCmd = (IpcDomCmd)(DomWord0 & 0xff); - - RawDataSize = (DomWord0 >> 16) & 0xffff; - - DomObjId = Reader.ReadInt32(); - - Reader.ReadInt64(); //Padding - } - - RawData = Reader.ReadBytes(RawDataSize); - - Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin); - - for (int Index = 0; Index < RecvListCount; Index++) - { - RecvListBuff.Add(new IpcRecvListBuffDesc(Reader)); - } - } - - public byte[] GetBytes(long CmdPtr) - { - //todo - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - int Word0; - int Word1; - - Word0 = (int)Type; - Word0 |= (PtrBuff.Count & 0xf) << 16; - Word0 |= (SendBuff.Count & 0xf) << 20; - Word0 |= (ReceiveBuff.Count & 0xf) << 24; - Word0 |= (ExchangeBuff.Count & 0xf) << 28; - - byte[] HandleData = new byte[0]; - - if (HandleDesc != null) - { - HandleData = HandleDesc.GetBytes(); - } - - int DataLength = RawData?.Length ?? 0; - - int Pad0 = (int)GetPadSize16(CmdPtr + 8 + HandleData.Length); - - //Apparently, padding after Raw Data is 16 bytes, however when there is - //padding before Raw Data too, we need to subtract the size of this padding. - //This is the weirdest padding I've seen so far... - int Pad1 = 0x10 - Pad0; - - DataLength = (DataLength + Pad0 + Pad1 + (IsDomain ? 0x10 : 0)) / 4; - - DataLength += ResponseObjIds.Count; - - Word1 = DataLength & 0x3ff; - - if (HandleDesc != null) - { - Word1 |= 1 << 31; - } - - Writer.Write(Word0); - Writer.Write(Word1); - Writer.Write(HandleData); - - MS.Seek(Pad0, SeekOrigin.Current); - - if (IsDomain) - { - Writer.Write(ResponseObjIds.Count); - Writer.Write(0); - Writer.Write(0L); - } - - if (RawData != null) - { - Writer.Write(RawData); - } - - foreach (int Id in ResponseObjIds) - { - Writer.Write(Id); - } - - Writer.Write(new byte[Pad1]); - - return MS.ToArray(); - } - } - - private long GetPadSize16(long Position) - { - if ((Position & 0xf) != 0) - { - return 0x10 - (Position & 0xf); - } - - return 0; - } - - public long GetSendBuffPtr() - { - if (SendBuff.Count > 0 && SendBuff[0].Position != 0) - { - return SendBuff[0].Position; - } - - if (PtrBuff.Count > 0 && PtrBuff[0].Position != 0) - { - return PtrBuff[0].Position; - } - - return -1; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcMessageType.cs b/Ryujinx/OsHle/Ipc/IpcMessageType.cs deleted file mode 100644 index b0e283de..00000000 --- a/Ryujinx/OsHle/Ipc/IpcMessageType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.OsHle.Ipc -{ - enum IpcMessageType - { - Response = 0, - Unknown2 = 2, - Request = 4, - Control = 5 - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs b/Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs deleted file mode 100644 index 414d71f4..00000000 --- a/Ryujinx/OsHle/Ipc/IpcPtrBuffDesc.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - struct IpcPtrBuffDesc - { - public long Position { get; private set; } - public int Index { get; private set; } - public short Size { get; private set; } - - public IpcPtrBuffDesc(BinaryReader Reader) - { - long Word0 = Reader.ReadUInt32(); - long Word1 = Reader.ReadUInt32(); - - Position = Word1; - Position |= (Word0 << 20) & 0x0f00000000; - Position |= (Word0 << 30) & 0x7000000000; - - Index = ((int)Word0 >> 0) & 0x03f; - Index |= ((int)Word0 >> 3) & 0x1c0; - - Size = (short)(Word0 >> 16); - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs b/Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs deleted file mode 100644 index 8180b8dd..00000000 --- a/Ryujinx/OsHle/Ipc/IpcRecvListBuffDesc.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.IO; - -namespace Ryujinx.OsHle.Ipc -{ - struct IpcRecvListBuffDesc - { - public long Position { get; private set; } - public short Size { get; private set; } - - public IpcRecvListBuffDesc(BinaryReader Reader) - { - long Value = Reader.ReadInt64(); - - Position = Value & 0xffffffffffff; - - Size = (short)(Value >> 48); - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Ipc/ServiceProcessRequest.cs b/Ryujinx/OsHle/Ipc/ServiceProcessRequest.cs deleted file mode 100644 index 838a6aea..00000000 --- a/Ryujinx/OsHle/Ipc/ServiceProcessRequest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.OsHle.Ipc -{ - delegate long ServiceProcessRequest(ServiceCtx Context); -} \ No newline at end of file diff --git a/Ryujinx/OsHle/MemoryInfo.cs b/Ryujinx/OsHle/MemoryInfo.cs deleted file mode 100644 index 395ccf73..00000000 --- a/Ryujinx/OsHle/MemoryInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.OsHle -{ - struct MemoryInfo - { - public long BaseAddress; - public long Size; - public int MemType; - public int MemAttr; - public int MemPerm; - public int IpcRefCount; - public int DeviceRefCount; - public int Padding; //SBZ - - public MemoryInfo(AMemoryMapInfo MapInfo) - { - BaseAddress = MapInfo.Position; - Size = MapInfo.Size; - MemType = MapInfo.Type; - MemAttr = MapInfo.Attr; - MemPerm = (int)MapInfo.Perm; - IpcRefCount = 0; - DeviceRefCount = 0; - Padding = 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/MemoryType.cs b/Ryujinx/OsHle/MemoryType.cs deleted file mode 100644 index b1ac330a..00000000 --- a/Ryujinx/OsHle/MemoryType.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Ryujinx.OsHle -{ - enum MemoryType - { - Unmapped = 0, - Io = 1, - Normal = 2, - CodeStatic = 3, - CodeMutable = 4, - Heap = 5, - SharedMemory = 6, - ModCodeStatic = 8, - ModCodeMutable = 9, - IpcBuffer0 = 10, - MappedMemory = 11, - ThreadLocal = 12, - TransferMemoryIsolated = 13, - TransferMemory = 14, - ProcessMemory = 15, - Reserved = 16, - IpcBuffer1 = 17, - IpcBuffer3 = 18, - KernelStack = 19 - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Mutex.cs b/Ryujinx/OsHle/Mutex.cs deleted file mode 100644 index 43862d7b..00000000 --- a/Ryujinx/OsHle/Mutex.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Ryujinx.OsHle.Handles; -using System.Collections.Concurrent; -using System.Threading; - -namespace Ryujinx.OsHle -{ - class Mutex - { - private const int MutexHasListenersMask = 0x40000000; - - private Process Process; - - private long MutexAddress; - - private bool OwnsMutexValue; - - private object EnterWaitLock; - - private ConcurrentQueue WaitingThreads; - - public Mutex(Process Process, long MutexAddress, int OwnerThreadHandle) - { - this.Process = Process; - this.MutexAddress = MutexAddress; - - //Process.Memory.WriteInt32(MutexAddress, OwnerThreadHandle); - - EnterWaitLock = new object(); - - WaitingThreads = new ConcurrentQueue(); - } - - public void WaitForLock(HThread RequestingThread, int RequestingThreadHandle) - { - AcquireMutexValue(); - - lock (EnterWaitLock) - { - int CurrentThreadHandle = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; - - if (CurrentThreadHandle == RequestingThreadHandle || - CurrentThreadHandle == 0) - { - return; - } - - Process.Memory.WriteInt32(MutexAddress, CurrentThreadHandle | MutexHasListenersMask); - - ReleaseMutexValue(); - - WaitingThreads.Enqueue(RequestingThread); - } - - Process.Scheduler.WaitForSignal(RequestingThread); - } - - public void GiveUpLock(int ThreadHandle) - { - AcquireMutexValue(); - - lock (EnterWaitLock) - { - int CurrentThread = Process.Memory.ReadInt32(MutexAddress) & ~MutexHasListenersMask; - - if (CurrentThread == ThreadHandle) - { - Unlock(); - } - } - - ReleaseMutexValue(); - } - - public void Unlock() - { - AcquireMutexValue(); - - lock (EnterWaitLock) - { - int HasListeners = WaitingThreads.Count > 1 ? MutexHasListenersMask : 0; - - Process.Memory.WriteInt32(MutexAddress, HasListeners); - - ReleaseMutexValue(); - - HThread[] UnlockedThreads = new HThread[WaitingThreads.Count]; - - int Index = 0; - - while (WaitingThreads.TryDequeue(out HThread Thread)) - { - UnlockedThreads[Index++] = Thread; - } - - Process.Scheduler.Signal(UnlockedThreads); - } - } - - private void AcquireMutexValue() - { - if (!OwnsMutexValue) - { - while (!Process.Memory.AcquireAddress(MutexAddress)) - { - Thread.Yield(); - } - - OwnsMutexValue = true; - } - } - - private void ReleaseMutexValue() - { - if (OwnsMutexValue) - { - OwnsMutexValue = false; - - Process.Memory.ReleaseAddress(MutexAddress); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Acc/IManagerForApplication.cs b/Ryujinx/OsHle/Objects/Acc/IManagerForApplication.cs deleted file mode 100644 index 404ee7da..00000000 --- a/Ryujinx/OsHle/Objects/Acc/IManagerForApplication.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Acc -{ - class IManagerForApplication : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IManagerForApplication() - { - m_Commands = new Dictionary() - { - { 0, CheckAvailability }, - { 1, GetAccountId } - }; - } - - public long CheckAvailability(ServiceCtx Context) - { - return 0; - } - - public long GetAccountId(ServiceCtx Context) - { - Context.ResponseData.Write(0xcafeL); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Acc/IProfile.cs b/Ryujinx/OsHle/Objects/Acc/IProfile.cs deleted file mode 100644 index c84c7ae2..00000000 --- a/Ryujinx/OsHle/Objects/Acc/IProfile.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Acc -{ - class IProfile : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IProfile() - { - m_Commands = new Dictionary() - { - { 1, GetBase } - }; - } - - public long GetBase(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - Context.ResponseData.Write(0L); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IApplicationFunctions.cs b/Ryujinx/OsHle/Objects/Am/IApplicationFunctions.cs deleted file mode 100644 index 138d9084..00000000 --- a/Ryujinx/OsHle/Objects/Am/IApplicationFunctions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IApplicationFunctions : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IApplicationFunctions() - { - m_Commands = new Dictionary() - { - { 1, PopLaunchParameter }, - { 20, EnsureSaveData }, - { 21, GetDesiredLanguage }, - { 40, NotifyRunning } - }; - } - - private const uint LaunchParamsMagic = 0xc79497ca; - - public long PopLaunchParameter(ServiceCtx Context) - { - //Only the first 0x18 bytes of the Data seems to be actually used. - MakeObject(Context, new IStorage(MakeLaunchParams())); - - return 0; - } - - public long EnsureSaveData(ServiceCtx Context) - { - long UIdLow = Context.RequestData.ReadInt64(); - long UIdHigh = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(0L); - - return 0; - } - - public long GetDesiredLanguage(ServiceCtx Context) - { - //This is an enumerator where each number is a differnet language. - //0 is Japanese and 1 is English, need to figure out the other codes. - Context.ResponseData.Write(1L); - - return 0; - } - - public long NotifyRunning(ServiceCtx Context) - { - Context.ResponseData.Write(1); - - return 0; - } - - private byte[] MakeLaunchParams() - { - //Size needs to be at least 0x88 bytes otherwise application errors. - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - MS.SetLength(0x88); - - Writer.Write(LaunchParamsMagic); - Writer.Write(1); //IsAccountSelected? Only lower 8 bits actually used. - Writer.Write(1L); //User Id Low (note: User Id needs to be != 0) - Writer.Write(0L); //User Id High - - return MS.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IApplicationProxy.cs b/Ryujinx/OsHle/Objects/Am/IApplicationProxy.cs deleted file mode 100644 index 3d692d6b..00000000 --- a/Ryujinx/OsHle/Objects/Am/IApplicationProxy.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IApplicationProxy : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IApplicationProxy() - { - m_Commands = new Dictionary() - { - { 0, GetCommonStateGetter }, - { 1, GetSelfController }, - { 2, GetWindowController }, - { 3, GetAudioController }, - { 4, GetDisplayController }, - { 11, GetLibraryAppletCreator }, - { 20, GetApplicationFunctions }, - { 1000, GetDebugFunctions } - }; - } - - public long GetCommonStateGetter(ServiceCtx Context) - { - MakeObject(Context, new ICommonStateGetter()); - - return 0; - } - - public long GetSelfController(ServiceCtx Context) - { - MakeObject(Context, new ISelfController()); - - return 0; - } - - public long GetWindowController(ServiceCtx Context) - { - MakeObject(Context, new IWindowController()); - - return 0; - } - - public long GetAudioController(ServiceCtx Context) - { - MakeObject(Context, new IAudioController()); - - return 0; - } - - public long GetDisplayController(ServiceCtx Context) - { - MakeObject(Context, new IDisplayController()); - - return 0; - } - - public long GetLibraryAppletCreator(ServiceCtx Context) - { - MakeObject(Context, new ILibraryAppletCreator()); - - return 0; - } - - public long GetApplicationFunctions(ServiceCtx Context) - { - MakeObject(Context, new IApplicationFunctions()); - - return 0; - } - - public long GetDebugFunctions(ServiceCtx Context) - { - MakeObject(Context, new IDebugFunctions()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IAudioController.cs b/Ryujinx/OsHle/Objects/Am/IAudioController.cs deleted file mode 100644 index 0ca49f89..00000000 --- a/Ryujinx/OsHle/Objects/Am/IAudioController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IAudioController : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/ICommonStateGetter.cs b/Ryujinx/OsHle/Objects/Am/ICommonStateGetter.cs deleted file mode 100644 index 5a3af8e1..00000000 --- a/Ryujinx/OsHle/Objects/Am/ICommonStateGetter.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class ICommonStateGetter : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ICommonStateGetter() - { - m_Commands = new Dictionary() - { - { 0, GetEventHandle }, - { 1, ReceiveMessage }, - { 5, GetOperationMode }, - { 6, GetPerformanceMode }, - { 9, GetCurrentFocusState }, - }; - } - - private enum FocusState - { - InFocus = 1, - OutOfFocus = 2 - } - - private enum OperationMode - { - Handheld = 0, - Docked = 1 - } - - public long GetEventHandle(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - return 0; - } - - public long ReceiveMessage(ServiceCtx Context) - { - //Program expects 0xF at 0x17ae70 on puyo sdk, - //otherwise runs on a infinite loop until it reads said value. - //What it means is still unknown. - Context.ResponseData.Write(0xfL); - - return 0; //0x680; - } - - public long GetOperationMode(ServiceCtx Context) - { - Context.ResponseData.Write((byte)OperationMode.Handheld); - - return 0; - } - - public long GetPerformanceMode(ServiceCtx Context) - { - Context.ResponseData.Write((byte)0); - - return 0; - } - - public long GetCurrentFocusState(ServiceCtx Context) - { - Context.ResponseData.Write((byte)FocusState.InFocus); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IDebugFunctions.cs b/Ryujinx/OsHle/Objects/Am/IDebugFunctions.cs deleted file mode 100644 index dc57e8e6..00000000 --- a/Ryujinx/OsHle/Objects/Am/IDebugFunctions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IDebugFunctions : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IDebugFunctions() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IDisplayController.cs b/Ryujinx/OsHle/Objects/Am/IDisplayController.cs deleted file mode 100644 index 88612086..00000000 --- a/Ryujinx/OsHle/Objects/Am/IDisplayController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IDisplayController : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IDisplayController() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/ILibraryAppletCreator.cs b/Ryujinx/OsHle/Objects/Am/ILibraryAppletCreator.cs deleted file mode 100644 index 91fae3dd..00000000 --- a/Ryujinx/OsHle/Objects/Am/ILibraryAppletCreator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class ILibraryAppletCreator : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ILibraryAppletCreator() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IParentalControlService.cs b/Ryujinx/OsHle/Objects/Am/IParentalControlService.cs deleted file mode 100644 index c462ff07..00000000 --- a/Ryujinx/OsHle/Objects/Am/IParentalControlService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IParentalControlService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IParentalControlService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/ISelfController.cs b/Ryujinx/OsHle/Objects/Am/ISelfController.cs deleted file mode 100644 index c46396c5..00000000 --- a/Ryujinx/OsHle/Objects/Am/ISelfController.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class ISelfController : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISelfController() - { - m_Commands = new Dictionary() - { - { 11, SetOperationModeChangedNotification }, - { 12, SetPerformanceModeChangedNotification }, - { 13, SetFocusHandlingMode }, - { 16, SetOutOfFocusSuspendingEnabled } - }; - } - - public long SetOperationModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - - public long SetPerformanceModeChangedNotification(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - - public long SetFocusHandlingMode(ServiceCtx Context) - { - bool Flag1 = Context.RequestData.ReadByte() != 0 ? true : false; - bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false; - bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - - public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context) - { - bool Enable = Context.RequestData.ReadByte() != 0 ? true : false; - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IStorage.cs b/Ryujinx/OsHle/Objects/Am/IStorage.cs deleted file mode 100644 index d5a7ee61..00000000 --- a/Ryujinx/OsHle/Objects/Am/IStorage.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IStorage : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public byte[] Data { get; private set; } - - public IStorage(byte[] Data) - { - m_Commands = new Dictionary() - { - { 0, Open } - }; - - this.Data = Data; - } - - public long Open(ServiceCtx Context) - { - MakeObject(Context, new IStorageAccessor(this)); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IStorageAccessor.cs b/Ryujinx/OsHle/Objects/Am/IStorageAccessor.cs deleted file mode 100644 index bcf0fc01..00000000 --- a/Ryujinx/OsHle/Objects/Am/IStorageAccessor.cs +++ /dev/null @@ -1,62 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IStorageAccessor : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private IStorage Storage; - - public IStorageAccessor(IStorage Storage) - { - m_Commands = new Dictionary() - { - { 0, GetSize }, - { 11, Read } - }; - - this.Storage = Storage; - } - - public long GetSize(ServiceCtx Context) - { - Context.ResponseData.Write((long)Storage.Data.Length); - - return 0; - } - - public long Read(ServiceCtx Context) - { - long ReadPosition = Context.RequestData.ReadInt64(); - - if (Context.Request.RecvListBuff.Count > 0) - { - long Position = Context.Request.RecvListBuff[0].Position; - short Size = Context.Request.RecvListBuff[0].Size; - - byte[] Data; - - if (Storage.Data.Length > Size) - { - Data = new byte[Size]; - - Buffer.BlockCopy(Storage.Data, 0, Data, 0, Size); - } - else - { - Data = Storage.Data; - } - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Am/IWindowController.cs b/Ryujinx/OsHle/Objects/Am/IWindowController.cs deleted file mode 100644 index 1796644e..00000000 --- a/Ryujinx/OsHle/Objects/Am/IWindowController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Am -{ - class IWindowController : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IWindowController() - { - m_Commands = new Dictionary() - { - { 1, GetAppletResourceUserId }, - { 10, AcquireForegroundRights } - }; - } - - public long GetAppletResourceUserId(ServiceCtx Context) - { - Context.ResponseData.Write(0L); - - return 0; - } - - public long AcquireForegroundRights(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Apm/ISession.cs b/Ryujinx/OsHle/Objects/Apm/ISession.cs deleted file mode 100644 index f3965b48..00000000 --- a/Ryujinx/OsHle/Objects/Apm/ISession.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Apm -{ - class ISession : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISession() - { - m_Commands = new Dictionary() - { - { 0, SetPerformanceConfiguration } - }; - } - - public long SetPerformanceConfiguration(ServiceCtx Context) - { - int PerfMode = Context.RequestData.ReadInt32(); - int PerfConfig = Context.RequestData.ReadInt32(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Aud/IAudioOut.cs b/Ryujinx/OsHle/Objects/Aud/IAudioOut.cs deleted file mode 100644 index 9e55e30e..00000000 --- a/Ryujinx/OsHle/Objects/Aud/IAudioOut.cs +++ /dev/null @@ -1,180 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using OpenTK.Audio; -using OpenTK.Audio.OpenAL; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.OsHle.Objects.Aud -{ - class IAudioOut : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioOut() - { - m_Commands = new Dictionary() - { - { 0, GetAudioOutState }, - { 1, StartAudioOut }, - { 2, StopAudioOut }, - { 3, AppendAudioOutBuffer }, - { 4, RegisterBufferEvent }, - { 5, GetReleasedAudioOutBuffer }, - { 6, ContainsAudioOutBuffer }, - { 7, AppendAudioOutBuffer_ex }, - { 8, GetReleasedAudioOutBuffer_ex } - }; - } - - enum AudioOutState - { - Started, - Stopped - }; - - //IAudioOut - private AudioOutState State = AudioOutState.Stopped; - private Queue KeysQueue = new Queue(); - - //OpenAL - private bool OpenALInstalled = true; - private AudioContext AudioCtx; - private int Source; - private int Buffer; - - //Return State of IAudioOut - public long GetAudioOutState(ServiceCtx Context) - { - Context.ResponseData.Write((int)State); - - return 0; - } - - public long StartAudioOut(ServiceCtx Context) - { - if (State == AudioOutState.Stopped) - { - State = AudioOutState.Started; - - try - { - AudioCtx = new AudioContext(); //Create the audio context - } - catch (Exception) - { - Logging.Warn("OpenAL Error! PS: Install OpenAL Core SDK!"); - OpenALInstalled = false; - } - - if (OpenALInstalled) AL.Listener(ALListenerf.Gain, (float)8.0); //Add more gain to it - } - - return 0; - } - - public long StopAudioOut(ServiceCtx Context) - { - if (State == AudioOutState.Started) - { - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - AL.SourceStop(Source); - AL.DeleteSource(Source); - } - State = AudioOutState.Stopped; - } - - return 0; - } - - public long AppendAudioOutBuffer(ServiceCtx Context) - { - long BufferId = Context.RequestData.ReadInt64(); - - KeysQueue.Enqueue(BufferId); - - byte[] AudioOutBuffer = AMemoryHelper.ReadBytes(Context.Memory, Context.Request.SendBuff[0].Position, sizeof(long) * 5); - using (MemoryStream MS = new MemoryStream(AudioOutBuffer)) - { - BinaryReader Reader = new BinaryReader(MS); - long PointerNextBuffer = Reader.ReadInt64(); - long PointerSampleBuffer = Reader.ReadInt64(); - long CapacitySampleBuffer = Reader.ReadInt64(); - long SizeDataInSampleBuffer = Reader.ReadInt64(); - long OffsetDataInSampleBuffer = Reader.ReadInt64(); - - byte[] AudioSampleBuffer = AMemoryHelper.ReadBytes(Context.Memory, PointerSampleBuffer + OffsetDataInSampleBuffer, (int)SizeDataInSampleBuffer); - - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - Buffer = AL.GenBuffer(); - AL.BufferData(Buffer, ALFormat.Stereo16, AudioSampleBuffer, AudioSampleBuffer.Length, 48000); - - Source = AL.GenSource(); - AL.SourceQueueBuffer(Source, Buffer); - } - } - - return 0; - } - - public long RegisterBufferEvent(ServiceCtx Context) - { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - public long GetReleasedAudioOutBuffer(ServiceCtx Context) - { - long TempKey = 0; - - if (KeysQueue.Count > 0) TempKey = KeysQueue.Dequeue(); - - AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, BitConverter.GetBytes(TempKey)); - - int ReleasedBuffersCount = 1; - Context.ResponseData.Write(ReleasedBuffersCount); - - if (OpenALInstalled) - { - if (AudioCtx == null) //Needed to call the instance of AudioContext() - return 0; - - AL.SourcePlay(Source); - int[] FreeBuffers = AL.SourceUnqueueBuffers(Source, 1); - AL.DeleteBuffers(FreeBuffers); - } - - return 0; - } - - public long ContainsAudioOutBuffer(ServiceCtx Context) - { - return 0; - } - - public long AppendAudioOutBuffer_ex(ServiceCtx Context) - { - return 0; - } - - public long GetReleasedAudioOutBuffer_ex(ServiceCtx Context) - { - return 0; - } - } -} diff --git a/Ryujinx/OsHle/Objects/Aud/IAudioRenderer.cs b/Ryujinx/OsHle/Objects/Aud/IAudioRenderer.cs deleted file mode 100644 index a953d82a..00000000 --- a/Ryujinx/OsHle/Objects/Aud/IAudioRenderer.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Aud -{ - class IAudioRenderer : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IAudioRenderer() - { - m_Commands = new Dictionary() - { - { 4, RequestUpdateAudioRenderer }, - { 5, StartAudioRenderer }, - { 6, StopAudioRenderer }, - { 7, QuerySystemEvent } - }; - } - - public long RequestUpdateAudioRenderer(ServiceCtx Context) - { - //(buffer) -> (buffer, buffer) - - long Position = Context.Request.ReceiveBuff[0].Position; - - //0x40 bytes header - Context.Memory.WriteInt32(Position + 0x4, 0xb0); //Behavior Out State Size? (note: this is the last section) - Context.Memory.WriteInt32(Position + 0x8, 0x18e0); //Memory Pool Out State Size? - Context.Memory.WriteInt32(Position + 0xc, 0x600); //Voice Out State Size? - Context.Memory.WriteInt32(Position + 0x14, 0xe0); //Effect Out State Size? - Context.Memory.WriteInt32(Position + 0x1c, 0x20); //Sink Out State Size? - Context.Memory.WriteInt32(Position + 0x20, 0x10); //Performance Out State Size? - Context.Memory.WriteInt32(Position + 0x3c, 0x20e0); //Total Size (including 0x40 bytes header) - - for (int Offset = 0x40; Offset < 0x40 + 0x18e0; Offset += 0x10) - { - Context.Memory.WriteInt32(Position + Offset, 5); - } - - return 0; - } - - public long StartAudioRenderer(ServiceCtx Context) - { - return 0; - } - - public long StopAudioRenderer(ServiceCtx Context) - { - return 0; - } - - public long QuerySystemEvent(ServiceCtx Context) - { - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Friend/IFriendService.cs b/Ryujinx/OsHle/Objects/Friend/IFriendService.cs deleted file mode 100644 index 41084f8d..00000000 --- a/Ryujinx/OsHle/Objects/Friend/IFriendService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Friend -{ - class IFriendService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IFriendService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs b/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs deleted file mode 100644 index 82867451..00000000 --- a/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs +++ /dev/null @@ -1,133 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; - -namespace Ryujinx.OsHle.Objects.FspSrv -{ - [StructLayout(LayoutKind.Sequential, Size = 0x310)] - struct DirectoryEntry - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x300)] - public byte[] Name; - public int Unknown; - public byte Type; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] - public byte[] Padding; - public long Size; - } - - enum DirectoryEntryType - { - Directory, - File - } - - class IDirectory : IIpcInterface - { - private List DirectoryEntries = new List(); - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private string HostPath; - - public IDirectory(string HostPath, int flags) - { - m_Commands = new Dictionary() - { - { 0, Read }, - { 1, GetEntryCount } - }; - - this.HostPath = HostPath; - - if ((flags & 1) == 1) - { - string[] Directories = Directory.GetDirectories(HostPath, "*", SearchOption.TopDirectoryOnly). - Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray(); - - foreach (string Directory in Directories) - { - DirectoryEntry Info = new DirectoryEntry - { - Name = Encoding.UTF8.GetBytes(Directory), - Type = (byte)DirectoryEntryType.Directory, - Size = 0 - }; - - Array.Resize(ref Info.Name, 0x300); - DirectoryEntries.Add(Info); - } - } - - if ((flags & 2) == 2) - { - string[] Files = Directory.GetFiles(HostPath, "*", SearchOption.TopDirectoryOnly). - Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray(); - - foreach (string FileName in Files) - { - DirectoryEntry Info = new DirectoryEntry - { - Name = Encoding.UTF8.GetBytes(Path.GetFileName(FileName)), - Type = (byte)DirectoryEntryType.File, - Size = new FileInfo(Path.Combine(HostPath, FileName)).Length - }; - - Array.Resize(ref Info.Name, 0x300); - DirectoryEntries.Add(Info); - } - } - } - - private int LastItem = 0; - public long Read(ServiceCtx Context) - { - long BufferPosition = Context.Request.ReceiveBuff[0].Position; - long BufferLen = Context.Request.ReceiveBuff[0].Size; - long MaxDirectories = BufferLen / Marshal.SizeOf(typeof(DirectoryEntry)); - - if (MaxDirectories > DirectoryEntries.Count - LastItem) - { - MaxDirectories = DirectoryEntries.Count - LastItem; - } - - int CurrentIndex; - for (CurrentIndex = 0; CurrentIndex < MaxDirectories; CurrentIndex++) - { - int CurrentItem = LastItem + CurrentIndex; - - byte[] DirectoryEntry = new byte[Marshal.SizeOf(typeof(DirectoryEntry))]; - IntPtr Ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DirectoryEntry))); - Marshal.StructureToPtr(DirectoryEntries[CurrentItem], Ptr, true); - Marshal.Copy(Ptr, DirectoryEntry, 0, Marshal.SizeOf(typeof(DirectoryEntry))); - Marshal.FreeHGlobal(Ptr); - - AMemoryHelper.WriteBytes(Context.Memory, BufferPosition + Marshal.SizeOf(typeof(DirectoryEntry)) * CurrentIndex, DirectoryEntry); - } - - if (LastItem < DirectoryEntries.Count) - { - LastItem += CurrentIndex; - Context.ResponseData.Write((long)CurrentIndex); // index = number of entries written this call. - } - else - { - Context.ResponseData.Write((long)0); - } - - return 0; - } - - public long GetEntryCount(ServiceCtx Context) - { - Context.ResponseData.Write((long)DirectoryEntries.Count); - return 0; - } - } -} diff --git a/Ryujinx/OsHle/Objects/FspSrv/IFile.cs b/Ryujinx/OsHle/Objects/FspSrv/IFile.cs deleted file mode 100644 index 2f389990..00000000 --- a/Ryujinx/OsHle/Objects/FspSrv/IFile.cs +++ /dev/null @@ -1,93 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Ipc; -using System; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.OsHle.Objects.FspSrv -{ - class IFile : IIpcInterface, IDisposable - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private Stream BaseStream; - - public IFile(Stream BaseStream) - { - m_Commands = new Dictionary() - { - { 0, Read }, - { 1, Write }, - // { 2, Flush }, - { 3, SetSize }, - { 4, GetSize } - }; - - this.BaseStream = BaseStream; - } - - public long Read(ServiceCtx Context) - { - long Position = Context.Request.ReceiveBuff[0].Position; - - long Zero = Context.RequestData.ReadInt64(); - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - byte[] Data = new byte[Size]; - - BaseStream.Seek(Offset, SeekOrigin.Begin); - int ReadSize = BaseStream.Read(Data, 0, (int)Size); - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); - - Context.ResponseData.Write((long)ReadSize); - - return 0; - } - - public long Write(ServiceCtx Context) - { - long Position = Context.Request.SendBuff[0].Position; - - long Zero = Context.RequestData.ReadInt64(); - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, Position, (int)Size); - - BaseStream.Seek(Offset, SeekOrigin.Begin); - BaseStream.Write(Data, 0, (int)Size); - - return 0; - } - - public long GetSize(ServiceCtx Context) - { - Context.ResponseData.Write(BaseStream.Length); - return 0; - } - - public long SetSize(ServiceCtx Context) - { - long Size = Context.RequestData.ReadInt64(); - BaseStream.SetLength(Size); - return 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing && BaseStream != null) - { - BaseStream.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs b/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs deleted file mode 100644 index c3edf271..00000000 --- a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs +++ /dev/null @@ -1,247 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Objects.FspSrv -{ - class IFileSystem : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private string Path; - - public IFileSystem(string Path) - { - //TODO: implement. - m_Commands = new Dictionary() - { - { 0, CreateFile }, - { 1, DeleteFile }, - { 2, CreateDirectory }, - { 3, DeleteDirectory }, - { 4, DeleteDirectoryRecursively }, - { 5, RenameFile }, - { 6, RenameDirectory }, - { 7, GetEntryType }, - { 8, OpenFile }, - { 9, OpenDirectory }, - { 10, Commit }, - //{ 11, GetFreeSpaceSize }, - //{ 12, GetTotalSpaceSize }, - //{ 13, CleanDirectoryRecursively }, - //{ 14, GetFileTimeStampRaw } - }; - - this.Path = Path; - } - - public long CreateFile(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - ulong Mode = Context.RequestData.ReadUInt64(); - uint Size = Context.RequestData.ReadUInt32(); - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName != null) - { - FileStream NewFile = File.Create(FileName); - NewFile.SetLength(Size); - NewFile.Close(); - return 0; - } - - //TODO: Correct error code. - return -1; - } - - public long DeleteFile(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName != null) - { - File.Delete(FileName); - return 0; - } - - //TODO: Correct error code. - return -1; - } - - public long CreateDirectory(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName != null) - { - Directory.CreateDirectory(FileName); - return 0; - } - - //TODO: Correct error code. - return -1; - } - - public long DeleteDirectory(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName != null) - { - Directory.Delete(FileName); - return 0; - } - - // TODO: Correct error code. - return -1; - } - - public long DeleteDirectoryRecursively(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName != null) - { - Directory.Delete(FileName, true); // recursive = true - return 0; - } - - // TODO: Correct error code. - return -1; - } - - public long RenameFile(ServiceCtx Context) - { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); - string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); - string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); - - if (OldFileName != null && NewFileName != null) - { - File.Move(OldFileName, NewFileName); - return 0; - } - - // TODO: Correct error code. - return -1; - } - - public long RenameDirectory(ServiceCtx Context) - { - long OldPosition = Context.Request.PtrBuff[0].Position; - long NewPosition = Context.Request.PtrBuff[0].Position; - string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); - string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); - string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); - string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); - - if (OldDirName != null && NewDirName != null) - { - Directory.Move(OldDirName, NewDirName); - return 0; - } - - // TODO: Correct error code. - return -1; - } - - public long GetEntryType(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName == null) - { - //TODO: Correct error code. - return -1; - } - - bool IsFile = File.Exists(FileName); - - Context.ResponseData.Write(IsFile ? 1 : 0); - - return 0; - } - - public long OpenFile(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - string FileName = Context.Ns.VFs.GetFullPath(Path, Name); - - if (FileName == null) - { - //TODO: Correct error code. - return -1; - } - - if (File.Exists(FileName)) - { - FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate); - MakeObject(Context, new IFile(Stream)); - - return 0; - } - - //TODO: Correct error code. - return -1; - } - - public long OpenDirectory(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int FilterFlags = Context.RequestData.ReadInt32(); - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); - - string DirName = Context.Ns.VFs.GetFullPath(Path, Name); - - if(DirName != null) - { - if (Directory.Exists(DirName)) - { - MakeObject(Context, new IDirectory(DirName, FilterFlags)); - return 0; - } - else - { - // TODO: correct error code. - return -1; - } - } - - // TODO: Correct error code. - return -1; - } - - public long Commit(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/FspSrv/IStorage.cs b/Ryujinx/OsHle/Objects/FspSrv/IStorage.cs deleted file mode 100644 index 40fb87ca..00000000 --- a/Ryujinx/OsHle/Objects/FspSrv/IStorage.cs +++ /dev/null @@ -1,52 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -namespace Ryujinx.OsHle.Objects.FspSrv -{ - class IStorage : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private Stream BaseStream; - - public IStorage(Stream BaseStream) - { - m_Commands = new Dictionary() - { - { 0, Read } - }; - - this.BaseStream = BaseStream; - } - - public long Read(ServiceCtx Context) - { - long Offset = Context.RequestData.ReadInt64(); - long Size = Context.RequestData.ReadInt64(); - - if (Context.Request.ReceiveBuff.Count > 0) - { - IpcBuffDesc BuffDesc = Context.Request.ReceiveBuff[0]; - - //Use smaller length to avoid overflows. - if (Size > BuffDesc.Size) - { - Size = BuffDesc.Size; - } - - byte[] Data = new byte[Size]; - - BaseStream.Seek(Offset, SeekOrigin.Begin); - BaseStream.Read(Data, 0, Data.Length); - - AMemoryHelper.WriteBytes(Context.Memory, BuffDesc.Position, Data); - } - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Hid/IAppletResource.cs b/Ryujinx/OsHle/Objects/Hid/IAppletResource.cs deleted file mode 100644 index ac7ccf56..00000000 --- a/Ryujinx/OsHle/Objects/Hid/IAppletResource.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Hid -{ - class IAppletResource : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public HSharedMem Handle; - - public IAppletResource(HSharedMem Handle) - { - m_Commands = new Dictionary() - { - { 0, GetSharedMemoryHandle } - }; - - this.Handle = Handle; - } - - public static long GetSharedMemoryHandle(ServiceCtx Context) - { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/IIpcInterface.cs b/Ryujinx/OsHle/Objects/IIpcInterface.cs deleted file mode 100644 index af0594cc..00000000 --- a/Ryujinx/OsHle/Objects/IIpcInterface.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects -{ - interface IIpcInterface - { - IReadOnlyDictionary Commands { get; } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/ObjHelper.cs b/Ryujinx/OsHle/Objects/ObjHelper.cs deleted file mode 100644 index bab22203..00000000 --- a/Ryujinx/OsHle/Objects/ObjHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; - -namespace Ryujinx.OsHle.Objects -{ - static class ObjHelper - { - public static void MakeObject(ServiceCtx Context, object Obj) - { - if (Context.Session is HDomain Dom) - { - Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj)); - } - else - { - HSessionObj HndData = new HSessionObj(Context.Session, Obj); - - int VHandle = Context.Ns.Os.Handles.GenerateId(HndData); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Parcel.cs b/Ryujinx/OsHle/Objects/Parcel.cs deleted file mode 100644 index 0d322bab..00000000 --- a/Ryujinx/OsHle/Objects/Parcel.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx.OsHle.Objects.Android -{ - static class Parcel - { - public static byte[] GetParcelData(byte[] Parcel) - { - if (Parcel == null) - { - throw new ArgumentNullException(nameof(Parcel)); - } - - using (MemoryStream MS = new MemoryStream(Parcel)) - { - BinaryReader Reader = new BinaryReader(MS); - - int DataSize = Reader.ReadInt32(); - int DataOffset = Reader.ReadInt32(); - int ObjsSize = Reader.ReadInt32(); - int ObjsOffset = Reader.ReadInt32(); - - MS.Seek(DataOffset - 0x10, SeekOrigin.Current); - - return Reader.ReadBytes(DataSize); - } - } - - public static byte[] MakeParcel(byte[] Data, byte[] Objs) - { - if (Data == null) - { - throw new ArgumentNullException(nameof(Data)); - } - - if (Objs == null) - { - throw new ArgumentNullException(nameof(Objs)); - } - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - Writer.Write(Data.Length); - Writer.Write(0x10); - Writer.Write(Objs.Length); - Writer.Write(Data.Length + 0x10); - - Writer.Write(Data); - Writer.Write(Objs); - - return MS.ToArray(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Time/ISteadyClock.cs b/Ryujinx/OsHle/Objects/Time/ISteadyClock.cs deleted file mode 100644 index a5139bab..00000000 --- a/Ryujinx/OsHle/Objects/Time/ISteadyClock.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Time -{ - class ISteadyClock : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISteadyClock() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Time/ISystemClock.cs b/Ryujinx/OsHle/Objects/Time/ISystemClock.cs deleted file mode 100644 index 1d9bae3b..00000000 --- a/Ryujinx/OsHle/Objects/Time/ISystemClock.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Time -{ - class ISystemClock : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - private SystemClockType ClockType; - - public ISystemClock(SystemClockType ClockType) - { - m_Commands = new Dictionary() - { - { 0, GetCurrentTime } - }; - - this.ClockType = ClockType; - } - - public long GetCurrentTime(ServiceCtx Context) - { - DateTime CurrentTime = DateTime.Now; - - if (ClockType == SystemClockType.User || - ClockType == SystemClockType.Network) - { - CurrentTime = CurrentTime.ToUniversalTime(); - } - - Context.ResponseData.Write((long)(DateTime.Now - Epoch).TotalSeconds); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Time/ITimeZoneService.cs b/Ryujinx/OsHle/Objects/Time/ITimeZoneService.cs deleted file mode 100644 index 29e7ec92..00000000 --- a/Ryujinx/OsHle/Objects/Time/ITimeZoneService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Time -{ - class ITimeZoneService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ITimeZoneService() - { - m_Commands = new Dictionary() - { - //... - }; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Time/SystemClockType.cs b/Ryujinx/OsHle/Objects/Time/SystemClockType.cs deleted file mode 100644 index ad9675aa..00000000 --- a/Ryujinx/OsHle/Objects/Time/SystemClockType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.OsHle.Objects.Time -{ - enum SystemClockType - { - User, - Network, - Local - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Vi/IApplicationDisplayService.cs b/Ryujinx/OsHle/Objects/Vi/IApplicationDisplayService.cs deleted file mode 100644 index 4fa35928..00000000 --- a/Ryujinx/OsHle/Objects/Vi/IApplicationDisplayService.cs +++ /dev/null @@ -1,176 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; -using System.IO; - -using static Ryujinx.OsHle.Objects.Android.Parcel; -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Objects.Vi -{ - class IApplicationDisplayService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IApplicationDisplayService() - { - m_Commands = new Dictionary() - { - { 100, GetRelayService }, - { 101, GetSystemDisplayService }, - { 102, GetManagerDisplayService }, - { 103, GetIndirectDisplayTransactionService }, - { 1010, OpenDisplay }, - { 2020, OpenLayer }, - { 2030, CreateStrayLayer }, - { 2101, SetLayerScalingMode }, - { 5202, GetDisplayVSyncEvent } - }; - } - - public long GetRelayService(ServiceCtx Context) - { - MakeObject(Context, new IHOSBinderDriver()); - - return 0; - } - - public long GetSystemDisplayService(ServiceCtx Context) - { - MakeObject(Context, new ISystemDisplayService()); - - return 0; - } - - public long GetManagerDisplayService(ServiceCtx Context) - { - MakeObject(Context, new IManagerDisplayService()); - - return 0; - } - - public long GetIndirectDisplayTransactionService(ServiceCtx Context) - { - MakeObject(Context, new IHOSBinderDriver()); - - return 0; - } - - public long OpenDisplay(ServiceCtx Context) - { - string Name = GetDisplayName(Context); - - long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name)); - - Context.ResponseData.Write(DisplayId); - - return 0; - } - - public long OpenLayer(ServiceCtx Context) - { - long LayerId = Context.RequestData.ReadInt64(); - long UserId = Context.RequestData.ReadInt64(); - - long ParcelPtr = Context.Request.ReceiveBuff[0].Position; - - byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); - - AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); - - Context.ResponseData.Write((long)Parcel.Length); - - return 0; - } - - public long CreateStrayLayer(ServiceCtx Context) - { - long LayerFlags = Context.RequestData.ReadInt64(); - long DisplayId = Context.RequestData.ReadInt64(); - - long ParcelPtr = Context.Request.ReceiveBuff[0].Position; - - Display Disp = Context.Ns.Os.Displays.GetData((int)DisplayId); - - byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr); - - AMemoryHelper.WriteBytes(Context.Memory, ParcelPtr, Parcel); - - Context.ResponseData.Write(0L); - Context.ResponseData.Write((long)Parcel.Length); - - return 0; - } - - public long SetLayerScalingMode(ServiceCtx Context) - { - int ScalingMode = Context.RequestData.ReadInt32(); - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public long GetDisplayVSyncEvent(ServiceCtx Context) - { - string Name = GetDisplayName(Context); - - int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent()); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); - - return 0; - } - - private byte[] MakeIGraphicsBufferProducer(long BasePtr) - { - long Id = 0x20; - long CookiePtr = 0L; - - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - //flat_binder_object (size is 0x28) - Writer.Write(2); //Type (BINDER_TYPE_WEAK_BINDER) - Writer.Write(0); //Flags - Writer.Write((int)(Id >> 0)); - Writer.Write((int)(Id >> 32)); - Writer.Write((int)(CookiePtr >> 0)); - Writer.Write((int)(CookiePtr >> 32)); - Writer.Write((byte)'d'); - Writer.Write((byte)'i'); - Writer.Write((byte)'s'); - Writer.Write((byte)'p'); - Writer.Write((byte)'d'); - Writer.Write((byte)'r'); - Writer.Write((byte)'v'); - Writer.Write((byte)'\0'); - Writer.Write(0L); //Pad - - return MakeParcel(MS.ToArray(), new byte[] { 0, 0, 0, 0 }); - } - } - - private string GetDisplayName(ServiceCtx Context) - { - string Name = string.Empty; - - for (int Index = 0; Index < 8 && - Context.RequestData.BaseStream.Position < - Context.RequestData.BaseStream.Length; Index++) - { - byte Chr = Context.RequestData.ReadByte(); - - if (Chr >= 0x20 && Chr < 0x7f) - { - Name += (char)Chr; - } - } - - return Name; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Vi/IHOSBinderDriver.cs b/Ryujinx/OsHle/Objects/Vi/IHOSBinderDriver.cs deleted file mode 100644 index 157d600f..00000000 --- a/Ryujinx/OsHle/Objects/Vi/IHOSBinderDriver.cs +++ /dev/null @@ -1,214 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using Ryujinx.OsHle.Utilities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using static Ryujinx.OsHle.Objects.Android.Parcel; - -namespace Ryujinx.OsHle.Objects.Vi -{ - class IHOSBinderDriver : IIpcInterface - { - private delegate long ServiceProcessParcel(ServiceCtx Context, byte[] ParcelData); - - private Dictionary m_Commands; - - private Dictionary<(string, int), ServiceProcessParcel> m_Methods; - - public IReadOnlyDictionary Commands => m_Commands; - - private class BufferObj - { - - } - - private IdPoolWithObj BufferSlots; - - private byte[] Gbfr; - - public IHOSBinderDriver() - { - m_Commands = new Dictionary() - { - { 0, TransactParcel }, - { 1, AdjustRefcount }, - { 2, GetNativeHandle } - }; - - m_Methods = new Dictionary<(string, int), ServiceProcessParcel>() - { - { ("android.gui.IGraphicBufferProducer", 0x1), GraphicBufferProducerRequestBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x3), GraphicBufferProducerDequeueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x7), GraphicBufferProducerQueueBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x8), GraphicBufferProducerCancelBuffer }, - { ("android.gui.IGraphicBufferProducer", 0x9), GraphicBufferProducerQuery }, - { ("android.gui.IGraphicBufferProducer", 0xa), GraphicBufferProducerConnect }, - { ("android.gui.IGraphicBufferProducer", 0xe), GraphicBufferPreallocateBuffer } - }; - - BufferSlots = new IdPoolWithObj(); - } - - public long TransactParcel(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - int Code = Context.RequestData.ReadInt32(); - - long DataPos = Context.Request.SendBuff[0].Position; - long DataSize = Context.Request.SendBuff[0].Size; - - byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, DataPos, (int)DataSize); - - Data = GetParcelData(Data); - - using (MemoryStream MS = new MemoryStream(Data)) - { - BinaryReader Reader = new BinaryReader(MS); - - MS.Seek(4, SeekOrigin.Current); - - int StrSize = Reader.ReadInt32(); - - string InterfaceName = Encoding.Unicode.GetString(Data, 8, StrSize * 2); - - if (m_Methods.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq)) - { - return ProcReq(Context, Data); - } - else - { - throw new NotImplementedException($"{InterfaceName} {Code}"); - } - } - } - - private long GraphicBufferProducerRequestBuffer(ServiceCtx Context, byte[] ParcelData) - { - int GbfrSize = Gbfr?.Length ?? 0; - - byte[] Data = new byte[GbfrSize + 4]; - - if (Gbfr != null) - { - Buffer.BlockCopy(Gbfr, 0, Data, 0, GbfrSize); - } - - return MakeReplyParcel(Context, Data); - } - - private long GraphicBufferProducerDequeueBuffer(ServiceCtx Context, byte[] ParcelData) - { - //Note: It seems that the maximum number of slots is 64, because if we return - //a Slot number > 63, it seems to cause a buffer overrun and it reads garbage. - //Note 2: The size of each object associated with the slot is 0x30. - int Slot = BufferSlots.GenerateId(new BufferObj()); - - return MakeReplyParcel(Context, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - - private long GraphicBufferProducerQueueBuffer(ServiceCtx Context, byte[] ParcelData) - { - return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); - } - - private long GraphicBufferProducerCancelBuffer(ServiceCtx Context, byte[] ParcelData) - { - using (MemoryStream MS = new MemoryStream(ParcelData)) - { - BinaryReader Reader = new BinaryReader(MS); - - MS.Seek(0x50, SeekOrigin.Begin); - - int Slot = Reader.ReadInt32(); - - BufferSlots.Delete(Slot); - - return MakeReplyParcel(Context, 0); - } - } - - private long GraphicBufferProducerQuery(ServiceCtx Context, byte[] ParcelData) - { - return MakeReplyParcel(Context, 0, 0); - } - - private long GraphicBufferProducerConnect(ServiceCtx Context, byte[] ParcelData) - { - return MakeReplyParcel(Context, 1280, 720, 0, 0, 0); - } - - private long GraphicBufferPreallocateBuffer(ServiceCtx Context, byte[] ParcelData) - { - int GbfrSize = ParcelData.Length - 0x54; - - Gbfr = new byte[GbfrSize]; - - Buffer.BlockCopy(ParcelData, 0x54, Gbfr, 0, GbfrSize); - - using (MemoryStream MS = new MemoryStream(ParcelData)) - { - BinaryReader Reader = new BinaryReader(MS); - - MS.Seek(0xd4, SeekOrigin.Begin); - - int Handle = Reader.ReadInt32(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - Context.Ns.Gpu.Renderer.FrameBufferPtr = NvMap.Address; - } - - return MakeReplyParcel(Context, 0); - } - - private long MakeReplyParcel(ServiceCtx Context, params int[] Ints) - { - using (MemoryStream MS = new MemoryStream()) - { - BinaryWriter Writer = new BinaryWriter(MS); - - foreach (int Int in Ints) - { - Writer.Write(Int); - } - - return MakeReplyParcel(Context, MS.ToArray()); - } - } - - private long MakeReplyParcel(ServiceCtx Context, byte[] Data) - { - long ReplyPos = Context.Request.ReceiveBuff[0].Position; - long ReplySize = Context.Request.ReceiveBuff[0].Position; - - byte[] Reply = MakeParcel(Data, new byte[0]); - - AMemoryHelper.WriteBytes(Context.Memory, ReplyPos, Reply); - - return 0; - } - - public long AdjustRefcount(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - int AddVal = Context.RequestData.ReadInt32(); - int Type = Context.RequestData.ReadInt32(); - - return 0; - } - - public long GetNativeHandle(ServiceCtx Context) - { - int Id = Context.RequestData.ReadInt32(); - uint Unk = Context.RequestData.ReadUInt32(); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(0xbadcafe); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Vi/IManagerDisplayService.cs b/Ryujinx/OsHle/Objects/Vi/IManagerDisplayService.cs deleted file mode 100644 index c2bbf43b..00000000 --- a/Ryujinx/OsHle/Objects/Vi/IManagerDisplayService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Vi -{ - class IManagerDisplayService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public IManagerDisplayService() - { - m_Commands = new Dictionary() - { - { 2010, CreateManagedLayer }, - { 6000, AddToLayerStack } - }; - } - - public static long CreateManagedLayer(ServiceCtx Context) - { - Context.ResponseData.Write(0L); //LayerId - - return 0; - } - - public static long AddToLayerStack(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/Vi/ISystemDisplayService.cs b/Ryujinx/OsHle/Objects/Vi/ISystemDisplayService.cs deleted file mode 100644 index 39d19786..00000000 --- a/Ryujinx/OsHle/Objects/Vi/ISystemDisplayService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Ryujinx.OsHle.Ipc; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Objects.Vi -{ - class ISystemDisplayService : IIpcInterface - { - private Dictionary m_Commands; - - public IReadOnlyDictionary Commands => m_Commands; - - public ISystemDisplayService() - { - m_Commands = new Dictionary() - { - { 2205, SetLayerZ } - }; - } - - public static long SetLayerZ(ServiceCtx Context) - { - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs deleted file mode 100644 index 4d07b94b..00000000 --- a/Ryujinx/OsHle/Process.cs +++ /dev/null @@ -1,257 +0,0 @@ -using ChocolArm64; -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.Loaders; -using Ryujinx.Loaders.Executables; -using Ryujinx.OsHle.Exceptions; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Svc; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Threading; - -namespace Ryujinx.OsHle -{ - class Process : IDisposable - { - private const int MaxStackSize = 8 * 1024 * 1024; - - private const int TlsSize = 0x200; - private const int TotalTlsSlots = 32; - private const int TlsTotalSize = TotalTlsSlots * TlsSize; - private const long TlsPageAddr = (AMemoryMgr.AddrSize - TlsTotalSize) & ~AMemoryMgr.PageMask; - - private Switch Ns; - - public int ProcessId { get; private set; } - - public AMemory Memory { get; private set; } - - public KProcessScheduler Scheduler { get; private set; } - - private SvcHandler SvcHandler; - - private ConcurrentDictionary TlsSlots; - - private ConcurrentDictionary ThreadsByTpidr; - - private List Executables; - - private HThread MainThread; - - private long ImageBase; - - public Process(Switch Ns, AMemoryAlloc Allocator, int ProcessId) - { - this.Ns = Ns; - this.ProcessId = ProcessId; - - Memory = new AMemory(Ns.Ram, Allocator); - - Scheduler = new KProcessScheduler(); - - SvcHandler = new SvcHandler(Ns, this); - - TlsSlots = new ConcurrentDictionary(); - - ThreadsByTpidr = new ConcurrentDictionary(); - - Executables = new List(); - - ImageBase = 0x8000000; - - Memory.Manager.MapPhys( - TlsPageAddr, - TlsTotalSize, - (int)MemoryType.ThreadLocal, - AMemoryPerm.RW); - } - - public void LoadProgram(IExecutable Program) - { - Logging.Info($"Image base at 0x{ImageBase:x16}."); - - Executable Executable = new Executable(Program, Memory, ImageBase); - - Executables.Add(Executable); - - ImageBase = AMemoryHelper.PageRoundUp(Executable.ImageEnd); - } - - public void SetEmptyArgs() - { - ImageBase += AMemoryMgr.PageSize; - } - - public void InitializeHeap() - { - Memory.Manager.SetHeapAddr((ImageBase + 0x3fffffff) & ~0x3fffffff); - } - - public bool Run() - { - if (Executables.Count == 0) - { - return false; - } - - long StackBot = TlsPageAddr - MaxStackSize; - - Memory.Manager.MapPhys(StackBot, MaxStackSize, (int)MemoryType.Normal, AMemoryPerm.RW); - - int Handle = MakeThread(Executables[0].ImageBase, TlsPageAddr, 0, 0, 0); - - if (Handle == -1) - { - return false; - } - - MainThread = Ns.Os.Handles.GetData(Handle); - - Scheduler.StartThread(MainThread); - - return true; - } - - public void StopAllThreads() - { - if (MainThread != null) - { - while (MainThread.Thread.IsAlive) - { - MainThread.Thread.StopExecution(); - } - } - - foreach (AThread Thread in TlsSlots.Values) - { - while (Thread.IsAlive) - { - Thread.StopExecution(); - } - } - } - - public int MakeThread( - long EntryPoint, - long StackTop, - long ArgsPtr, - int Priority, - int ProcessorId) - { - ThreadPriority ThreadPrio; - - if (Priority < 12) - { - ThreadPrio = ThreadPriority.Highest; - } - else if (Priority < 24) - { - ThreadPrio = ThreadPriority.AboveNormal; - } - else if (Priority < 36) - { - ThreadPrio = ThreadPriority.Normal; - } - else if (Priority < 48) - { - ThreadPrio = ThreadPriority.BelowNormal; - } - else - { - ThreadPrio = ThreadPriority.Lowest; - } - - AThread Thread = new AThread(Memory, ThreadPrio, EntryPoint); - - HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority); - - int Handle = Ns.Os.Handles.GenerateId(ThreadHnd); - - int TlsSlot = GetFreeTlsSlot(Thread); - - if (TlsSlot == -1 || Handle == -1) - { - return -1; - } - - Thread.ThreadState.Break += BreakHandler; - Thread.ThreadState.SvcCall += SvcHandler.SvcCall; - Thread.ThreadState.Undefined += UndefinedHandler; - Thread.ThreadState.ProcessId = ProcessId; - Thread.ThreadState.ThreadId = Ns.Os.IdGen.GenerateId(); - Thread.ThreadState.Tpidr = TlsPageAddr + TlsSlot * TlsSize; - Thread.ThreadState.X0 = (ulong)ArgsPtr; - Thread.ThreadState.X1 = (ulong)Handle; - Thread.ThreadState.X31 = (ulong)StackTop; - - Thread.WorkFinished += ThreadFinished; - - ThreadsByTpidr.TryAdd(Thread.ThreadState.Tpidr, ThreadHnd); - - return Handle; - } - - private void BreakHandler(object sender, AInstExceptEventArgs e) - { - throw new GuestBrokeExecutionException(); - } - - private void UndefinedHandler(object sender, AInstUndEventArgs e) - { - throw new UndefinedInstructionException(e.Position, e.RawOpCode); - } - - private int GetFreeTlsSlot(AThread Thread) - { - for (int Index = 1; Index < TotalTlsSlots; Index++) - { - if (TlsSlots.TryAdd(Index, Thread)) - { - return Index; - } - } - - return -1; - } - - private void ThreadFinished(object sender, EventArgs e) - { - if (sender is AThread Thread) - { - TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _); - - Ns.Os.IdGen.DeleteId(Thread.ThreadId); - } - } - - private int GetTlsSlot(long Position) - { - return (int)((Position - TlsPageAddr) / TlsSize); - } - - public HThread GetThread(long Tpidr) - { - if (!ThreadsByTpidr.TryGetValue(Tpidr, out HThread Thread)) - { - Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!"); - } - - return Thread; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing) - { - Scheduler.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/ServiceCtx.cs b/Ryujinx/OsHle/ServiceCtx.cs deleted file mode 100644 index 501d8d0f..00000000 --- a/Ryujinx/OsHle/ServiceCtx.cs +++ /dev/null @@ -1,36 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using System.IO; - -namespace Ryujinx.OsHle -{ - class ServiceCtx - { - public Switch Ns { get; private set; } - public AMemory Memory { get; private set; } - public HSession Session { get; private set; } - public IpcMessage Request { get; private set; } - public IpcMessage Response { get; private set; } - public BinaryReader RequestData { get; private set; } - public BinaryWriter ResponseData { get; private set; } - - public ServiceCtx( - Switch Ns, - AMemory Memory, - HSession Session, - IpcMessage Request, - IpcMessage Response, - BinaryReader RequestData, - BinaryWriter ResponseData) - { - this.Ns = Ns; - this.Memory = Memory; - this.Session = Session; - this.Request = Request; - this.Response = Response; - this.RequestData = RequestData; - this.ResponseData = ResponseData; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceAcc.cs b/Ryujinx/OsHle/Services/ServiceAcc.cs deleted file mode 100644 index 632fb41c..00000000 --- a/Ryujinx/OsHle/Services/ServiceAcc.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Ryujinx.OsHle.Objects.Acc; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long AccU0ListOpenUsers(ServiceCtx Context) - { - return 0; - } - - public static long AccU0GetProfile(ServiceCtx Context) - { - MakeObject(Context, new IProfile()); - - return 0; - } - - public static long AccU0InitializeApplicationInfo(ServiceCtx Context) - { - return 0; - } - - public static long AccU0GetBaasAccountManagerForApplication(ServiceCtx Context) - { - MakeObject(Context, new IManagerForApplication()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceApm.cs b/Ryujinx/OsHle/Services/ServiceApm.cs deleted file mode 100644 index 81e68680..00000000 --- a/Ryujinx/OsHle/Services/ServiceApm.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Ryujinx.OsHle.Objects.Apm; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long ApmOpenSession(ServiceCtx Context) - { - MakeObject(Context, new ISession()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceAppletOE.cs b/Ryujinx/OsHle/Services/ServiceAppletOE.cs deleted file mode 100644 index 9f2391df..00000000 --- a/Ryujinx/OsHle/Services/ServiceAppletOE.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Ryujinx.OsHle.Objects.Am; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long AppletOpenApplicationProxy(ServiceCtx Context) - { - MakeObject(Context, new IApplicationProxy()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceAud.cs b/Ryujinx/OsHle/Services/ServiceAud.cs deleted file mode 100644 index 6d1367cf..00000000 --- a/Ryujinx/OsHle/Services/ServiceAud.cs +++ /dev/null @@ -1,71 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.OsHle.Objects.Aud; -using System.Text; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long AudOutListAudioOuts(ServiceCtx Context) - { - long Position = Context.Request.ReceiveBuff[0].Position; - - AMemoryHelper.WriteBytes(Context.Memory, Position, Encoding.ASCII.GetBytes("iface")); - - Context.ResponseData.Write(1); - - return 0; - } - - public static long AudOutOpenAudioOut(ServiceCtx Context) - { - MakeObject(Context, new IAudioOut()); - - Context.ResponseData.Write(48000); //Sample Rate - Context.ResponseData.Write(2); //Channel Count - Context.ResponseData.Write(2); //PCM Format - /* - 0 - Invalid - 1 - INT8 - 2 - INT16 - 3 - INT24 - 4 - INT32 - 5 - PCM Float - 6 - ADPCM - */ - Context.ResponseData.Write(0); //Unknown - - return 0; - } - - public static long AudRenOpenAudioRenderer(ServiceCtx Context) - { - MakeObject(Context, new IAudioRenderer()); - - return 0; - } - - public static long AudRenGetAudioRendererWorkBufferSize(ServiceCtx Context) - { - int SampleRate = Context.RequestData.ReadInt32(); - int Unknown4 = Context.RequestData.ReadInt32(); - int Unknown8 = Context.RequestData.ReadInt32(); - int UnknownC = Context.RequestData.ReadInt32(); - int Unknown10 = Context.RequestData.ReadInt32(); - int Unknown14 = Context.RequestData.ReadInt32(); - int Unknown18 = Context.RequestData.ReadInt32(); - int Unknown1c = Context.RequestData.ReadInt32(); - int Unknown20 = Context.RequestData.ReadInt32(); - int Unknown24 = Context.RequestData.ReadInt32(); - int Unknown28 = Context.RequestData.ReadInt32(); - int Unknown2c = Context.RequestData.ReadInt32(); - int Rev1Magic = Context.RequestData.ReadInt32(); - - Context.ResponseData.Write(0x400L); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceFriend.cs b/Ryujinx/OsHle/Services/ServiceFriend.cs deleted file mode 100644 index 10c23aae..00000000 --- a/Ryujinx/OsHle/Services/ServiceFriend.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Ryujinx.OsHle.Objects.Friend; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long FriendCreateFriendService(ServiceCtx Context) - { - MakeObject(Context, new IFriendService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceFspSrv.cs b/Ryujinx/OsHle/Services/ServiceFspSrv.cs deleted file mode 100644 index 17aa3bda..00000000 --- a/Ryujinx/OsHle/Services/ServiceFspSrv.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Ryujinx.OsHle.Objects.FspSrv; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long FspSrvInitialize(ServiceCtx Context) - { - return 0; - } - - public static long FspSrvMountSdCard(ServiceCtx Context) - { - MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath())); - - return 0; - } - - public static long FspSrvMountSaveData(ServiceCtx Context) - { - MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetGameSavesPath())); - - return 0; - } - - public static long FspSrvOpenDataStorageByCurrentProcess(ServiceCtx Context) - { - MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); - - return 0; - } - - public static long FspSrvOpenRomStorage(ServiceCtx Context) - { - MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs)); - - return 0; - } - - public static long FspSrvGetGlobalAccessLogMode(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceHid.cs b/Ryujinx/OsHle/Services/ServiceHid.cs deleted file mode 100644 index 176c7842..00000000 --- a/Ryujinx/OsHle/Services/ServiceHid.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Objects.Hid; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long HidCreateAppletResource(ServiceCtx Context) - { - HSharedMem HidHndData = Context.Ns.Os.Handles.GetData(Context.Ns.Os.HidHandle); - - MakeObject(Context, new IAppletResource(HidHndData)); - - return 0; - } - - public static long HidActivateTouchScreen(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public static long HidSetSupportedNpadStyleSet(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - return 0; - } - - public static long HidSetSupportedNpadIdType(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public static long HidActivateNpad(ServiceCtx Context) - { - long Unknown = Context.RequestData.ReadInt64(); - - return 0; - } - - public static long HidSetNpadJoyHoldType(ServiceCtx Context) - { - long Unknown0 = Context.RequestData.ReadInt64(); - long Unknown8 = Context.RequestData.ReadInt64(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceLm.cs b/Ryujinx/OsHle/Services/ServiceLm.cs deleted file mode 100644 index dc6acad9..00000000 --- a/Ryujinx/OsHle/Services/ServiceLm.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long LmInitialize(ServiceCtx Context) - { - Context.Session.Initialize(); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceNvDrv.cs b/Ryujinx/OsHle/Services/ServiceNvDrv.cs deleted file mode 100644 index 405eace2..00000000 --- a/Ryujinx/OsHle/Services/ServiceNvDrv.cs +++ /dev/null @@ -1,610 +0,0 @@ -using ChocolArm64.Memory; -using Ryujinx.Gpu; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using Ryujinx.OsHle.Utilities; -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - private delegate long ServiceProcessRequest(ServiceCtx Context); - - private static Dictionary<(string, int), ServiceProcessRequest> IoctlCmds = - new Dictionary<(string, int), ServiceProcessRequest>() - { - { ("/dev/nvhost-as-gpu", 0x4101), NvGpuAsIoctlBindChannel }, - { ("/dev/nvhost-as-gpu", 0x4102), NvGpuAsIoctlAllocSpace }, - { ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx }, - { ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions }, - { ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx }, - { ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig }, - { ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait }, - { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize }, - { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo }, - { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics }, - { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks }, - { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask }, - { ("/dev/nvhost-gpu", 0x4714), NvMapIoctlChannelSetUserData }, - { ("/dev/nvhost-gpu", 0x4801), NvMapIoctlChannelSetNvMap }, - { ("/dev/nvhost-gpu", 0x4808), NvMapIoctlChannelSubmitGpFifo }, - { ("/dev/nvhost-gpu", 0x4809), NvMapIoctlChannelAllocObjCtx }, - { ("/dev/nvhost-gpu", 0x480b), NvMapIoctlChannelZcullBind }, - { ("/dev/nvhost-gpu", 0x480c), NvMapIoctlChannelSetErrorNotifier }, - { ("/dev/nvhost-gpu", 0x480d), NvMapIoctlChannelSetPriority }, - { ("/dev/nvhost-gpu", 0x481a), NvMapIoctlChannelAllocGpFifoEx2 }, - { ("/dev/nvmap", 0x0101), NvMapIocCreate }, - { ("/dev/nvmap", 0x0103), NvMapIocFromId }, - { ("/dev/nvmap", 0x0104), NvMapIocAlloc }, - { ("/dev/nvmap", 0x0109), NvMapIocParam }, - { ("/dev/nvmap", 0x010e), NvMapIocGetId }, - }; - - public static long NvDrvOpen(ServiceCtx Context) - { - long NamePtr = Context.Request.SendBuff[0].Position; - - string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr); - - int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name)); - - Context.ResponseData.Write(Fd); - Context.ResponseData.Write(0); - - return 0; - } - - public static long NvDrvIoctl(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int Cmd = Context.RequestData.ReadInt32() & 0xffff; - - FileDesc FdData = Context.Ns.Os.Fds.GetData(Fd); - - long Position = Context.Request.PtrBuff[0].Position; - - Context.ResponseData.Write(0); - - if (IoctlCmds.TryGetValue((FdData.Name, Cmd), out ServiceProcessRequest ProcReq)) - { - return ProcReq(Context); - } - else - { - throw new NotImplementedException($"{FdData.Name} {Cmd:x4}"); - } - } - - public static long NvDrvClose(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - - Context.Ns.Os.Fds.Delete(Fd); - - Context.ResponseData.Write(0); - - return 0; - } - - public static long NvDrvInitialize(ServiceCtx Context) - { - long TransferMemSize = Context.RequestData.ReadInt64(); - int TransferMemHandle = Context.Request.HandleDesc.ToCopy[0]; - - Context.ResponseData.Write(0); - - return 0; - } - - public static long NvDrvQueryEvent(ServiceCtx Context) - { - int Fd = Context.RequestData.ReadInt32(); - int EventId = Context.RequestData.ReadInt32(); - - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(0xcafe); - - Context.ResponseData.Write(0); - - return 0; - } - - public static long NvDrvSetClientPid(ServiceCtx Context) - { - long Pid = Context.RequestData.ReadInt64(); - - Context.ResponseData.Write(0); - - return 0; - } - - private static long NvGpuAsIoctlBindChannel(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Pages = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - long Align = Reader.ReadInt64(); - - if ((Flags & 1) != 0) - { - Align = Context.Ns.Gpu.MemoryMgr.Reserve(Align, (long)Pages * PageSize, 1); - } - else - { - Align = Context.Ns.Gpu.MemoryMgr.Reserve((long)Pages * PageSize, Align); - } - - Context.Memory.WriteInt64(Position + 0x10, Align); - - return 0; - } - - private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Flags = Reader.ReadInt32(); - int Kind = Reader.ReadInt32(); - int Handle = Reader.ReadInt32(); - int PageSize = Reader.ReadInt32(); - long BuffAddr = Reader.ReadInt64(); - long MapSize = Reader.ReadInt64(); - long Offset = Reader.ReadInt64(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - if (NvMap != null) - { - if ((Flags & 1) != 0) - { - Offset = Context.Ns.Gpu.MemoryMgr.Map(NvMap.Address, Offset, NvMap.Size); - } - else - { - Offset = Context.Ns.Gpu.MemoryMgr.Map(NvMap.Address, NvMap.Size); - } - } - - Context.Memory.WriteInt64(Position + 0x20, Offset); - - return 0; - } - - private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - long Unused = Reader.ReadInt64(); - int BuffSize = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - BuffSize = 0x30; - - Writer.WriteInt64(Unused); - Writer.WriteInt32(BuffSize); - Writer.WriteInt32(Padding); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - Writer.WriteInt64(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt64(0); - - return 0; - } - - private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int BigPageSize = Reader.ReadInt32(); - int AsFd = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long Unknown10 = Reader.ReadInt64(); - long Unknown18 = Reader.ReadInt64(); - long Unknown20 = Reader.ReadInt64(); - - return 0; - } - - private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x82); - - for (int Index = 0; Index < 0x101; Index++) - { - Writer.WriteByte(0); - } - - return 0; - } - - private static long NvHostIoctlCtrlEventWait(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int SyncPtId = Reader.ReadInt32(); - int Threshold = Reader.ReadInt32(); - int Timeout = Reader.ReadInt32(); - int Value = Reader.ReadInt32(); - - Context.Memory.WriteInt32(Position + 0xc, 0xcafe); - - return 0; - } - - private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - Context.Memory.WriteInt32(Position, 1); - - return 0; - } - - private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemWriter Writer = new MemWriter(Context.Memory, Position); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position); - - //Note: We should just ignore the BuffAddr, because official code - //does __memcpy_device from Position + 0x10 to BuffAddr. - long BuffSize = Reader.ReadInt64(); - long BuffAddr = Reader.ReadInt64(); - - BuffSize = 0xa0; - - Writer.WriteInt64(BuffSize); - Writer.WriteInt64(BuffAddr); - Writer.WriteInt32(0x120); //NVGPU_GPU_ARCH_GM200 - Writer.WriteInt32(0xb); //NVGPU_GPU_IMPL_GM20B - Writer.WriteInt32(0xa1); - Writer.WriteInt32(1); - Writer.WriteInt64(0x40000); - Writer.WriteInt64(0); - Writer.WriteInt32(2); - Writer.WriteInt32(0x20); //NVGPU_GPU_BUS_TYPE_AXI - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x20000); - Writer.WriteInt32(0x1b); - Writer.WriteInt32(0x30000); - Writer.WriteInt32(1); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x503); - Writer.WriteInt32(0x80); - Writer.WriteInt32(0x28); - Writer.WriteInt32(0); - Writer.WriteInt64(0x55); - Writer.WriteInt32(0x902d); //FERMI_TWOD_A - Writer.WriteInt32(0xb197); //MAXWELL_B - Writer.WriteInt32(0xb1c0); //MAXWELL_COMPUTE_B - Writer.WriteInt32(0xb06f); //MAXWELL_CHANNEL_GPFIFO_A - Writer.WriteInt32(0xa140); //KEPLER_INLINE_TO_MEMORY_B - Writer.WriteInt32(0xb0b5); //MAXWELL_DMA_COPY_A - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(2); - Writer.WriteInt32(1); - Writer.WriteInt32(0); - Writer.WriteInt32(1); - Writer.WriteInt32(0x21d70); - Writer.WriteInt32(0); - Writer.WriteByte((byte)'g'); - Writer.WriteByte((byte)'m'); - Writer.WriteByte((byte)'2'); - Writer.WriteByte((byte)'0'); - Writer.WriteByte((byte)'b'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteByte((byte)'\0'); - Writer.WriteInt64(0); - - return 0; - } - - private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - int MaskBuffSize = Reader.ReadInt32(); - int Reserved = Reader.ReadInt32(); - long MaskBuffAddr = Reader.ReadInt64(); - long Unknown = Reader.ReadInt64(); - - return 0; - } - - private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - Context.Memory.WriteInt32(Position + 0, 7); - Context.Memory.WriteInt32(Position + 4, 1); - - return 0; - } - - private static long NvMapIoctlChannelSetUserData(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - return 0; - } - - private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Fd = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0x10); - - long GpFifo = Reader.ReadInt64(); - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int FenceId = Reader.ReadInt32(); - int FenceVal = Reader.ReadInt32(); - - for (int Index = 0; Index < Count; Index++) - { - long GpFifoHdr = Reader.ReadInt64(); - - long GpuAddr = GpFifoHdr & 0xffffffffff; - - int Size = (int)(GpFifoHdr >> 40) & 0x7ffffc; - - long CpuAddr = Context.Ns.Gpu.MemoryMgr.GetCpuAddr(GpuAddr); - - if (CpuAddr != -1) - { - byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size); - - NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data); - - Context.Ns.Gpu.PGraph.ProcessPushBuffer(PushBuffer, Context.Memory); - } - } - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int ClassNum = Context.Memory.ReadInt32(Position + 0); - int Flags = Context.Memory.ReadInt32(Position + 4); - - Context.Memory.WriteInt32(Position + 8, 0); - - return 0; - } - - private static long NvMapIoctlChannelZcullBind(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - long GpuVa = Reader.ReadInt64(); - int Mode = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - - long Offset = Reader.ReadInt64(); - long Size = Reader.ReadInt64(); - int Mem = Reader.ReadInt32(); - int Padding = Reader.ReadInt32(); - - return 0; - } - - private static long NvMapIoctlChannelSetPriority(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - int Priority = Context.Memory.ReadInt32(Position); - - return 0; - } - - private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context) - { - long Position = Context.Request.PtrBuff[0].Position; - - MemReader Reader = new MemReader(Context.Memory, Position); - MemWriter Writer = new MemWriter(Context.Memory, Position + 0xc); - - int Count = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Unknown8 = Reader.ReadInt32(); - long Fence = Reader.ReadInt64(); - int Unknown14 = Reader.ReadInt32(); - int Unknown18 = Reader.ReadInt32(); - - Writer.WriteInt32(0); - Writer.WriteInt32(0); - - return 0; - } - - private static long NvMapIocCreate(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Size = Context.Memory.ReadInt32(Position); - - int Id = Context.Ns.Os.NvMapIds.GenerateId(); - - int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size)); - - Context.Memory.WriteInt32(Position + 4, Handle); - - return 0; - } - - private static long NvMapIocFromId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Id = Context.Memory.ReadInt32(Position); - - int Handle = -1; - - foreach (KeyValuePair KV in Context.Ns.Os.Handles) - { - if (KV.Value is HNvMap NvMap && NvMap.Id == Id) - { - Handle = KV.Key; - - break; - } - } - - Context.Memory.WriteInt32(Position + 4, Handle); - - return 0; - } - - private static long NvMapIocAlloc(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int HeapMask = Reader.ReadInt32(); - int Flags = Reader.ReadInt32(); - int Align = Reader.ReadInt32(); - byte Kind = (byte)Reader.ReadInt64(); - long Addr = Reader.ReadInt64(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - if (NvMap != null) - { - NvMap.Address = Addr; - NvMap.Align = Align; - NvMap.Kind = Kind; - } - - Logging.Debug($"NvMapIocAlloc at {NvMap.Address:x16}"); - - return 0; - } - - private static long NvMapIocParam(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - MemReader Reader = new MemReader(Context.Memory, Position); - - int Handle = Reader.ReadInt32(); - int Param = Reader.ReadInt32(); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - int Response = 0; - - switch (Param) - { - case 1: Response = NvMap.Size; break; - case 2: Response = NvMap.Align; break; - case 4: Response = 0x40000000; break; - case 5: Response = NvMap.Kind; break; - } - - Context.Memory.WriteInt32(Position + 8, Response); - - return 0; - } - - private static long NvMapIocGetId(ServiceCtx Context) - { - long Position = Context.Request.GetSendBuffPtr(); - - int Handle = Context.Memory.ReadInt32(Position + 4); - - HNvMap NvMap = Context.Ns.Os.Handles.GetData(Handle); - - Context.Memory.WriteInt32(Position, NvMap.Id); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServicePctl.cs b/Ryujinx/OsHle/Services/ServicePctl.cs deleted file mode 100644 index a0a5aaf3..00000000 --- a/Ryujinx/OsHle/Services/ServicePctl.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Ryujinx.OsHle.Objects.Am; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long PctlCreateService(ServiceCtx Context) - { - MakeObject(Context, new IParentalControlService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServicePl.cs b/Ryujinx/OsHle/Services/ServicePl.cs deleted file mode 100644 index 6981637f..00000000 --- a/Ryujinx/OsHle/Services/ServicePl.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Ryujinx.OsHle.Ipc; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long PlGetLoadState(ServiceCtx Context) - { - Context.ResponseData.Write(1); //Loaded - - return 0; - } - - public static long PlGetFontSize(ServiceCtx Context) - { - Context.ResponseData.Write(Horizon.FontSize); - - return 0; - } - - public static long PlGetSharedMemoryAddressOffset(ServiceCtx Context) - { - Context.ResponseData.Write(0); - - return 0; - } - - public static long PlGetSharedMemoryNativeHandle(ServiceCtx Context) - { - Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceSet.cs b/Ryujinx/OsHle/Services/ServiceSet.cs deleted file mode 100644 index f98e8f0d..00000000 --- a/Ryujinx/OsHle/Services/ServiceSet.cs +++ /dev/null @@ -1,32 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - private const int LangCodesCount = 13; - - public static long SetGetAvailableLanguageCodes(ServiceCtx Context) - { - int PtrBuffSize = Context.RequestData.ReadInt32(); - - if (Context.Request.RecvListBuff.Count > 0) - { - long Position = Context.Request.RecvListBuff[0].Position; - short Size = Context.Request.RecvListBuff[0].Size; - - //This should return an array of ints with values matching the LanguageCode enum. - byte[] Data = new byte[Size]; - - Data[0] = 0; - Data[1] = 1; - - AMemoryHelper.WriteBytes(Context.Memory, Position, Data); - } - - Context.ResponseData.Write(LangCodesCount); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceSm.cs b/Ryujinx/OsHle/Services/ServiceSm.cs deleted file mode 100644 index 8af3ed5e..00000000 --- a/Ryujinx/OsHle/Services/ServiceSm.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - private const int SmNotInitialized = 0x415; - - public static long SmInitialize(ServiceCtx Context) - { - Context.Session.Initialize(); - - return 0; - } - - public static long SmGetService(ServiceCtx Context) - { - //Only for kernel version > 3.0.0. - if (!Context.Session.IsInitialized) - { - //return SmNotInitialized; - } - - string Name = string.Empty; - - for (int Index = 0; Index < 8 && - Context.RequestData.BaseStream.Position < - Context.RequestData.BaseStream.Length; Index++) - { - byte Chr = Context.RequestData.ReadByte(); - - if (Chr >= 0x20 && Chr < 0x7f) - { - Name += (char)Chr; - } - } - - HSession Session = new HSession(Name); - - int Handle = Context.Ns.Os.Handles.GenerateId(Session); - - Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceTime.cs b/Ryujinx/OsHle/Services/ServiceTime.cs deleted file mode 100644 index 8a32aabc..00000000 --- a/Ryujinx/OsHle/Services/ServiceTime.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Ryujinx.OsHle.Objects.Time; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long TimeGetStandardUserSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.User)); - - return 0; - } - - public static long TimeGetStandardNetworkSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.Network)); - - return 0; - } - - public static long TimeGetStandardSteadyClock(ServiceCtx Context) - { - MakeObject(Context, new ISteadyClock()); - - return 0; - } - - public static long TimeGetTimeZoneService(ServiceCtx Context) - { - MakeObject(Context, new ITimeZoneService()); - - return 0; - } - - public static long TimeGetStandardLocalSystemClock(ServiceCtx Context) - { - MakeObject(Context, new ISystemClock(SystemClockType.Local)); - - return 0; - } - - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Services/ServiceVi.cs b/Ryujinx/OsHle/Services/ServiceVi.cs deleted file mode 100644 index 096bc18f..00000000 --- a/Ryujinx/OsHle/Services/ServiceVi.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Ryujinx.OsHle.Objects.Vi; - -using static Ryujinx.OsHle.Objects.ObjHelper; - -namespace Ryujinx.OsHle.Services -{ - static partial class Service - { - public static long ViGetDisplayService(ServiceCtx Context) - { - int Unknown = Context.RequestData.ReadInt32(); - - MakeObject(Context, new IApplicationDisplayService()); - - return 0; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcHandler.cs b/Ryujinx/OsHle/Svc/SvcHandler.cs deleted file mode 100644 index 3ab89d44..00000000 --- a/Ryujinx/OsHle/Svc/SvcHandler.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using System; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Svc -{ - partial class SvcHandler - { - private delegate void SvcFunc(AThreadState ThreadState); - - private Dictionary SvcFuncs; - - private Switch Ns; - private Process Process; - private AMemory Memory; - - private static Random Rng; - - public SvcHandler(Switch Ns, Process Process) - { - SvcFuncs = new Dictionary() - { - { 0x01, SvcSetHeapSize }, - { 0x03, SvcSetMemoryAttribute }, - { 0x04, SvcMapMemory }, - { 0x06, SvcQueryMemory }, - { 0x07, SvcExitProcess }, - { 0x08, SvcCreateThread }, - { 0x09, SvcStartThread }, - { 0x0b, SvcSleepThread }, - { 0x0c, SvcGetThreadPriority }, - { 0x13, SvcMapSharedMemory }, - { 0x14, SvcUnmapSharedMemory }, - { 0x15, SvcCreateTransferMemory }, - { 0x16, SvcCloseHandle }, - { 0x17, SvcResetSignal }, - { 0x18, SvcWaitSynchronization }, - { 0x1a, SvcArbitrateLock }, - { 0x1b, SvcArbitrateUnlock }, - { 0x1c, SvcWaitProcessWideKeyAtomic }, - { 0x1d, SvcSignalProcessWideKey }, - { 0x1e, SvcGetSystemTick }, - { 0x1f, SvcConnectToNamedPort }, - { 0x21, SvcSendSyncRequest }, - { 0x22, SvcSendSyncRequestWithUserBuffer }, - { 0x26, SvcBreak }, - { 0x27, SvcOutputDebugString }, - { 0x29, SvcGetInfo } - }; - - this.Ns = Ns; - this.Process = Process; - this.Memory = Process.Memory; - } - - static SvcHandler() - { - Rng = new Random(); - } - - public void SvcCall(object sender, AInstExceptEventArgs e) - { - AThreadState ThreadState = (AThreadState)sender; - - if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func)) - { - Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} called."); - - Func(ThreadState); - - Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} ended."); - } - else - { - throw new NotImplementedException(e.Id.ToString("x4")); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcMemory.cs b/Ryujinx/OsHle/Svc/SvcMemory.cs deleted file mode 100644 index fa91397c..00000000 --- a/Ryujinx/OsHle/Svc/SvcMemory.cs +++ /dev/null @@ -1,121 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.OsHle.Handles; - -namespace Ryujinx.OsHle.Svc -{ - partial class SvcHandler - { - private void SvcSetHeapSize(AThreadState ThreadState) - { - uint Size = (uint)ThreadState.X1; - - Memory.Manager.SetHeapSize(Size, (int)MemoryType.Heap); - - ThreadState.X0 = (int)SvcResult.Success; - ThreadState.X1 = (ulong)Memory.Manager.HeapAddr; - } - - private void SvcSetMemoryAttribute(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - int State0 = (int)ThreadState.X2; - int State1 = (int)ThreadState.X3; - - //TODO - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcMapMemory(AThreadState ThreadState) - { - long Dst = (long)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - Memory.Manager.MapMirror(Src, Dst, Size, (int)MemoryType.MappedMemory); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcQueryMemory(AThreadState ThreadState) - { - long InfoPtr = (long)ThreadState.X0; - long Position = (long)ThreadState.X2; - - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); - - MemoryInfo Info = new MemoryInfo(MapInfo); - - Memory.WriteInt64(InfoPtr + 0x00, Info.BaseAddress); - Memory.WriteInt64(InfoPtr + 0x08, Info.Size); - Memory.WriteInt32(InfoPtr + 0x10, Info.MemType); - Memory.WriteInt32(InfoPtr + 0x14, Info.MemAttr); - Memory.WriteInt32(InfoPtr + 0x18, Info.MemPerm); - Memory.WriteInt32(InfoPtr + 0x1c, Info.IpcRefCount); - Memory.WriteInt32(InfoPtr + 0x20, Info.DeviceRefCount); - Memory.WriteInt32(InfoPtr + 0x24, Info.Padding); - - //TODO: X1. - - ThreadState.X0 = (int)SvcResult.Success; - ThreadState.X1 = 0; - } - - private void SvcMapSharedMemory(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - long Src = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - int Perm = (int)ThreadState.X3; - - HSharedMem SharedMem = Ns.Os.Handles.GetData(Handle); - - if (SharedMem != null) - { - SharedMem.AddVirtualPosition(Src); - - Memory.Manager.MapPhys(Src, Size, (int)MemoryType.SharedMemory, (AMemoryPerm)Perm); - - ThreadState.X0 = (int)SvcResult.Success; - } - - //TODO: Error codes. - } - - private void SvcUnmapSharedMemory(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - long Position = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - - HSharedMem HndData = Ns.Os.Handles.GetData(Handle); - - if (HndData != null) - { - ThreadState.X0 = (int)SvcResult.Success; - } - - //TODO: Error codes. - } - - private void SvcCreateTransferMemory(AThreadState ThreadState) - { - long Position = (long)ThreadState.X1; - long Size = (long)ThreadState.X2; - int Perm = (int)ThreadState.X3; - - AMemoryMapInfo MapInfo = Memory.Manager.GetMapInfo(Position); - - Memory.Manager.Reprotect(Position, Size, (AMemoryPerm)Perm); - - HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Position, Size); - - int Handle = Ns.Os.Handles.GenerateId(HndData); - - ThreadState.X1 = (ulong)Handle; - ThreadState.X0 = (int)SvcResult.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcResult.cs b/Ryujinx/OsHle/Svc/SvcResult.cs deleted file mode 100644 index 4f0c4f1f..00000000 --- a/Ryujinx/OsHle/Svc/SvcResult.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.OsHle.Svc -{ - enum SvcResult - { - Success = 0, - ErrBadHandle = 0xe401, - ErrTimeout = 0xea01, - ErrBadInfo = 0xf001, - ErrBadIpcReq = 0xf601 - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcSystem.cs b/Ryujinx/OsHle/Svc/SvcSystem.cs deleted file mode 100644 index 0570ccb0..00000000 --- a/Ryujinx/OsHle/Svc/SvcSystem.cs +++ /dev/null @@ -1,227 +0,0 @@ -using ChocolArm64.Memory; -using ChocolArm64.State; -using Ryujinx.OsHle.Exceptions; -using Ryujinx.OsHle.Handles; -using Ryujinx.OsHle.Ipc; -using System; -using System.Threading; - -namespace Ryujinx.OsHle.Svc -{ - partial class SvcHandler - { - private void SvcExitProcess(AThreadState ThreadState) => Ns.Os.ExitProcess(ThreadState.ProcessId); - - private void SvcCloseHandle(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - Ns.Os.CloseHandle(Handle); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcResetSignal(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - //TODO: Implement events. - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcWaitSynchronization(AThreadState ThreadState) - { - long HandlesPtr = (long)ThreadState.X0; - int HandlesCount = (int)ThreadState.X2; - long Timeout = (long)ThreadState.X3; - - //TODO: Implement events. - - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - Process.Scheduler.Suspend(CurrThread.ProcessorId); - Process.Scheduler.Resume(CurrThread); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcGetSystemTick(AThreadState ThreadState) - { - ThreadState.X0 = (ulong)ThreadState.CntpctEl0; - } - - private void SvcConnectToNamedPort(AThreadState ThreadState) - { - long StackPtr = (long)ThreadState.X0; - long NamePtr = (long)ThreadState.X1; - - string Name = AMemoryHelper.ReadAsciiString(Memory, NamePtr, 8); - - //TODO: Validate that app has perms to access the service, and that the service - //actually exists, return error codes otherwise. - - HSession Session = new HSession(Name); - - ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session); - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcSendSyncRequest(AThreadState ThreadState) - { - SendSyncRequest(ThreadState, false); - } - - private void SvcSendSyncRequestWithUserBuffer(AThreadState ThreadState) - { - SendSyncRequest(ThreadState, true); - } - - private void SendSyncRequest(AThreadState ThreadState, bool UserBuffer) - { - long CmdPtr = ThreadState.Tpidr; - long Size = 0x100; - int Handle = 0; - - if (UserBuffer) - { - CmdPtr = (long)ThreadState.X0; - Size = (long)ThreadState.X1; - Handle = (int)ThreadState.X2; - } - else - { - Handle = (int)ThreadState.X0; - } - - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - Process.Scheduler.Suspend(CurrThread.ProcessorId); - - byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); - - HSession Session = Ns.Os.Handles.GetData(Handle); - - IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain); - - if (Session != null) - { - IpcHandler.IpcCall(Ns, Memory, Session, Cmd, CmdPtr, Handle); - - byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size); - - ThreadState.X0 = (int)SvcResult.Success; - } - else - { - ThreadState.X0 = (int)SvcResult.ErrBadIpcReq; - } - - Thread.Yield(); - - Process.Scheduler.Resume(CurrThread); - } - - private void SvcBreak(AThreadState ThreadState) - { - long Reason = (long)ThreadState.X0; - long Unknown = (long)ThreadState.X1; - long Info = (long)ThreadState.X2; - - throw new GuestBrokeExecutionException(); - } - - private void SvcOutputDebugString(AThreadState ThreadState) - { - long Position = (long)ThreadState.X0; - long Size = (long)ThreadState.X1; - - string Str = AMemoryHelper.ReadAsciiString(Memory, Position, (int)Size); - - Logging.Info($"SvcOutputDebugString: {Str}"); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcGetInfo(AThreadState ThreadState) - { - long StackPtr = (long)ThreadState.X0; - int InfoType = (int)ThreadState.X1; - long Handle = (long)ThreadState.X2; - int InfoId = (int)ThreadState.X3; - - //Fail for info not available on older Kernel versions. - if (InfoType == 18 || - InfoType == 19) - { - ThreadState.X0 = (int)SvcResult.ErrBadInfo; - - return; - } - - switch (InfoType) - { - case 2: ThreadState.X1 = GetMapRegionBaseAddr(); break; - case 3: ThreadState.X1 = GetMapRegionSize(); break; - case 4: ThreadState.X1 = GetHeapRegionBaseAddr(); break; - case 5: ThreadState.X1 = GetHeapRegionSize(); break; - case 6: ThreadState.X1 = GetTotalMem(); break; - case 7: ThreadState.X1 = GetUsedMem(); break; - case 11: ThreadState.X1 = GetRnd64(); break; - case 12: ThreadState.X1 = GetAddrSpaceBaseAddr(); break; - case 13: ThreadState.X1 = GetAddrSpaceSize(); break; - case 14: ThreadState.X1 = GetMapRegionBaseAddr(); break; - case 15: ThreadState.X1 = GetMapRegionSize(); break; - - default: throw new NotImplementedException($"SvcGetInfo: {InfoType} {Handle} {InfoId}"); - } - - ThreadState.X0 = (int)SvcResult.Success; - } - - private ulong GetTotalMem() - { - return (ulong)Memory.Manager.GetTotalMemorySize(); - } - - private ulong GetUsedMem() - { - return (ulong)Memory.Manager.GetUsedMemorySize(); - } - - private ulong GetRnd64() - { - return (ulong)Rng.Next() + ((ulong)Rng.Next() << 32); - } - - private ulong GetAddrSpaceBaseAddr() - { - return 0x08000000; - } - - private ulong GetAddrSpaceSize() - { - return AMemoryMgr.AddrSize - GetAddrSpaceBaseAddr(); - } - - private ulong GetMapRegionBaseAddr() - { - return 0x80000000; - } - - private ulong GetMapRegionSize() - { - return 0x40000000; - } - - private ulong GetHeapRegionBaseAddr() - { - return GetMapRegionBaseAddr() + GetMapRegionSize(); - } - - private ulong GetHeapRegionSize() - { - return 0x40000000; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcThread.cs b/Ryujinx/OsHle/Svc/SvcThread.cs deleted file mode 100644 index cc2bbb1e..00000000 --- a/Ryujinx/OsHle/Svc/SvcThread.cs +++ /dev/null @@ -1,85 +0,0 @@ -using ChocolArm64.State; -using Ryujinx.OsHle.Handles; - -namespace Ryujinx.OsHle.Svc -{ - partial class SvcHandler - { - private void SvcCreateThread(AThreadState ThreadState) - { - long EntryPoint = (long)ThreadState.X1; - long ArgsPtr = (long)ThreadState.X2; - long StackTop = (long)ThreadState.X3; - int Priority = (int)ThreadState.X4; - int ProcessorId = (int)ThreadState.X5; - - if (Ns.Os.TryGetProcess(ThreadState.ProcessId, out Process Process)) - { - if (ProcessorId == -2) - { - //TODO: Get this value from the NPDM file. - ProcessorId = 0; - } - - int Handle = Process.MakeThread( - EntryPoint, - StackTop, - ArgsPtr, - Priority, - ProcessorId); - - ThreadState.X0 = (int)SvcResult.Success; - ThreadState.X1 = (ulong)Handle; - } - - //TODO: Error codes. - } - - private void SvcStartThread(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X0; - - HThread Thread = Ns.Os.Handles.GetData(Handle); - - if (Thread != null) - { - Process.Scheduler.StartThread(Thread); - - ThreadState.X0 = (int)SvcResult.Success; - } - - //TODO: Error codes. - } - - private void SvcSleepThread(AThreadState ThreadState) - { - ulong NanoSecs = ThreadState.X0; - - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - if (NanoSecs == 0) - { - Process.Scheduler.Yield(CurrThread); - } - else - { - Process.Scheduler.WaitForSignal(CurrThread, (int)(NanoSecs / 1000000)); - } - } - - private void SvcGetThreadPriority(AThreadState ThreadState) - { - int Handle = (int)ThreadState.X1; - - HThread Thread = Ns.Os.Handles.GetData(Handle); - - if (Thread != null) - { - ThreadState.X1 = (ulong)Thread.Priority; - ThreadState.X0 = (int)SvcResult.Success; - } - - //TODO: Error codes. - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Svc/SvcThreadSync.cs b/Ryujinx/OsHle/Svc/SvcThreadSync.cs deleted file mode 100644 index f342f51d..00000000 --- a/Ryujinx/OsHle/Svc/SvcThreadSync.cs +++ /dev/null @@ -1,78 +0,0 @@ -using ChocolArm64.State; -using Ryujinx.OsHle.Handles; - -namespace Ryujinx.OsHle.Svc -{ - partial class SvcHandler - { - private void SvcArbitrateLock(AThreadState ThreadState) - { - int OwnerThreadHandle = (int)ThreadState.X0; - long MutexAddress = (long)ThreadState.X1; - int RequestingThreadHandle = (int)ThreadState.X2; - - HThread RequestingThread = Ns.Os.Handles.GetData(RequestingThreadHandle); - - Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle); - - M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); - - M.WaitForLock(RequestingThread, RequestingThreadHandle); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcArbitrateUnlock(AThreadState ThreadState) - { - long MutexAddress = (long)ThreadState.X0; - - if (Ns.Os.Mutexes.TryGetValue(MutexAddress, out Mutex M)) - { - M.Unlock(); - } - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcWaitProcessWideKeyAtomic(AThreadState ThreadState) - { - long MutexAddress = (long)ThreadState.X0; - long CondVarAddress = (long)ThreadState.X1; - int ThreadHandle = (int)ThreadState.X2; - long Timeout = (long)ThreadState.X3; - - HThread Thread = Ns.Os.Handles.GetData(ThreadHandle); - - Mutex M = new Mutex(Process, MutexAddress, ThreadHandle); - - M = Ns.Os.Mutexes.GetOrAdd(MutexAddress, M); - - M.GiveUpLock(ThreadHandle); - - CondVar Cv = new CondVar(Process, CondVarAddress, Timeout); - - Cv = Ns.Os.CondVars.GetOrAdd(CondVarAddress, Cv); - - Cv.WaitForSignal(Thread); - - M.WaitForLock(Thread, ThreadHandle); - - ThreadState.X0 = (int)SvcResult.Success; - } - - private void SvcSignalProcessWideKey(AThreadState ThreadState) - { - long CondVarAddress = (long)ThreadState.X0; - int Count = (int)ThreadState.X1; - - HThread CurrThread = Process.GetThread(ThreadState.Tpidr); - - if (Ns.Os.CondVars.TryGetValue(CondVarAddress, out CondVar Cv)) - { - Cv.SetSignal(CurrThread, Count); - } - - ThreadState.X0 = (int)SvcResult.Success; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Utilities/IdPool.cs b/Ryujinx/OsHle/Utilities/IdPool.cs deleted file mode 100644 index 836d6310..00000000 --- a/Ryujinx/OsHle/Utilities/IdPool.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Utilities -{ - class IdPool - { - private HashSet Ids; - - private int CurrId; - private int MinId; - private int MaxId; - - public IdPool(int Min, int Max) - { - Ids = new HashSet(); - - CurrId = Min; - MinId = Min; - MaxId = Max; - } - - public IdPool() : this(1, int.MaxValue) { } - - public int GenerateId() - { - lock (Ids) - { - for (int Cnt = MinId; Cnt < MaxId; Cnt++) - { - if (Ids.Add(CurrId)) - { - return CurrId; - } - - if (CurrId++ == MaxId) - { - CurrId = MinId; - } - } - - return -1; - } - } - - public bool DeleteId(int Id) - { - lock (Ids) - { - return Ids.Remove(Id); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Utilities/IdPoolWithObj.cs b/Ryujinx/OsHle/Utilities/IdPoolWithObj.cs deleted file mode 100644 index 621466a8..00000000 --- a/Ryujinx/OsHle/Utilities/IdPoolWithObj.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Ryujinx.OsHle.Utilities -{ - class IdPoolWithObj : IEnumerable> - { - private IdPool Ids; - - private ConcurrentDictionary Objs; - - public IdPoolWithObj() - { - Ids = new IdPool(); - - Objs = new ConcurrentDictionary(); - } - - public int GenerateId(object Data) - { - int Id = Ids.GenerateId(); - - if (Id == -1 || !Objs.TryAdd(Id, Data)) - { - throw new InvalidOperationException(); - } - - return Id; - } - - public bool ReplaceData(int Id, object Data) - { - if (Objs.ContainsKey(Id)) - { - Objs[Id] = Data; - - return true; - } - - return false; - } - - public T GetData(int Id) - { - if (Objs.TryGetValue(Id, out object Data) && Data is T) - { - return (T)Data; - } - - return default(T); - } - - public void Delete(int Id) - { - if (Objs.TryRemove(Id, out object Obj)) - { - if (Obj is IDisposable DisposableObj) - { - DisposableObj.Dispose(); - } - - Ids.DeleteId(Id); - } - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return Objs.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return Objs.GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Utilities/MemReader.cs b/Ryujinx/OsHle/Utilities/MemReader.cs deleted file mode 100644 index 9868293a..00000000 --- a/Ryujinx/OsHle/Utilities/MemReader.cs +++ /dev/null @@ -1,44 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.OsHle.Utilities -{ - class MemReader - { - private AMemory Memory; - - public long Position { get; private set; } - - public MemReader(AMemory Memory, long Position) - { - this.Memory = Memory; - this.Position = Position; - } - - public byte ReadByte() - { - byte Value = Memory.ReadByte(Position); - - Position++; - - return Value; - } - - public int ReadInt32() - { - int Value = Memory.ReadInt32(Position); - - Position += 4; - - return Value; - } - - public long ReadInt64() - { - long Value = Memory.ReadInt64(Position); - - Position += 8; - - return Value; - } - } -} \ No newline at end of file diff --git a/Ryujinx/OsHle/Utilities/MemWriter.cs b/Ryujinx/OsHle/Utilities/MemWriter.cs deleted file mode 100644 index 041b0a97..00000000 --- a/Ryujinx/OsHle/Utilities/MemWriter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using ChocolArm64.Memory; - -namespace Ryujinx.OsHle.Utilities -{ - class MemWriter - { - private AMemory Memory; - - public long Position { get; private set; } - - public MemWriter(AMemory Memory, long Position) - { - this.Memory = Memory; - this.Position = Position; - } - - public void WriteByte(byte Value) - { - Memory.WriteByte(Position, Value); - - Position++; - } - - public void WriteInt32(int Value) - { - Memory.WriteInt32(Position, Value); - - Position += 4; - } - - public void WriteInt64(long Value) - { - Memory.WriteInt64(Position, Value); - - Position += 8; - } - } -} \ No newline at end of file diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index 9b0e7396..bc5dbe04 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -9,6 +9,11 @@ + + + + + PreserveNewest diff --git a/Ryujinx/Switch.cs b/Ryujinx/Switch.cs deleted file mode 100644 index 4022061b..00000000 --- a/Ryujinx/Switch.cs +++ /dev/null @@ -1,51 +0,0 @@ -using ChocolArm64.Memory; -using Gal; -using Ryujinx.Gpu; -using Ryujinx.OsHle; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx -{ - public class Switch : IDisposable - { - public IntPtr Ram {get; private set; } - - internal NsGpu Gpu { get; private set; } - internal Horizon Os { get; private set; } - internal VirtualFs VFs { get; private set; } - internal Hid Hid { get; private set; } - - public event EventHandler Finish; - - public Switch(IGalRenderer Renderer) - { - Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); - - Gpu = new NsGpu(Renderer); - Os = new Horizon(this); - VFs = new VirtualFs(); - Hid = new Hid(this); - } - - internal virtual void OnFinish(EventArgs e) - { - Finish?.Invoke(this, e); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - VFs.Dispose(); - } - - Marshal.FreeHGlobal(Ram); - } - } -} \ No newline at end of file diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 8101648e..9c05953b 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -2,10 +2,11 @@ // to the Public Domain. // It is provided "as is" without express or implied warranty of any kind. -using Gal; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; +using Ryujinx.Core; +using Ryujinx.Graphics.Gal; using System; namespace Ryujinx @@ -346,7 +347,7 @@ void main(void) { }; //We just need one pair of JoyCon because it's emulate by the keyboard. - Ns.Hid.SendControllerButtons(HidControllerID.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, LeftJoystick, RightJoystick); + Ns.SendControllerButtons(HidControllerID.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, LeftJoystick, RightJoystick); } protected override void OnRenderFrame(FrameEventArgs e) diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index 2f29411a..7912147e 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -1,5 +1,6 @@ -using Gal; -using Gal.OpenGL; +using Ryujinx.Core; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Gal.OpenGL; using System; using System.IO; @@ -27,20 +28,20 @@ namespace Ryujinx { Logging.Info("Loading as cart with RomFS."); - Ns.Os.LoadCart(args[0], RomFsFiles[0]); + Ns.LoadCart(args[0], RomFsFiles[0]); } else { Logging.Info("Loading as cart WITHOUT RomFS."); - Ns.Os.LoadCart(args[0]); + Ns.LoadCart(args[0]); } } else if (File.Exists(args[0])) { Logging.Info("Loading as homebrew."); - Ns.Os.LoadProgram(args[0]); + Ns.LoadProgram(args[0]); } } else @@ -58,7 +59,7 @@ namespace Ryujinx Screen.Run(60.0); } - Ns.Os.FinalizeAllProcesses(); + Ns.FinalizeAllProcesses(); Ns.Dispose(); } diff --git a/Ryujinx/VirtualFs.cs b/Ryujinx/VirtualFs.cs deleted file mode 100644 index 98298053..00000000 --- a/Ryujinx/VirtualFs.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.IO; - -namespace Ryujinx -{ - class VirtualFs : IDisposable - { - private const string BasePath = "Fs"; - private const string SavesPath = "Saves"; - private const string SdCardPath = "SdCard"; - - public Stream RomFs { get; private set; } - - public void LoadRomFs(string FileName) - { - RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read); - } - - public string GetFullPath(string BasePath, string FileName) - { - if (FileName.StartsWith('/')) - { - FileName = FileName.Substring(1); - } - - string FullPath = Path.GetFullPath(Path.Combine(BasePath, FileName)); - - if (!FullPath.StartsWith(GetBasePath())) - { - return null; - } - - return FullPath; - } - - public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath); - - public string GetGameSavesPath() => MakeDirAndGetFullPath(SavesPath); - - private static string MakeDirAndGetFullPath(string Dir) - { - string FullPath = Path.Combine(GetBasePath(), Dir); - - if (!Directory.Exists(FullPath)) - { - Directory.CreateDirectory(FullPath); - } - - return FullPath; - } - - public static string GetBasePath() - { - return Path.Combine(Directory.GetCurrentDirectory(), BasePath); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - RomFs?.Dispose(); - } - } - } -} \ No newline at end of file -- cgit v1.2.3