summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2012-03-22 15:21:52 +0100
committerPierre Bourdon <delroth@gmail.com>2012-03-22 15:21:52 +0100
commit0ffc12bbfd6ac44b3030ec30f400a58e951087b7 (patch)
tree53a6fac9ec79bcd71fe2046d8fb579478da12fd2 /Source/Core
parent006923e871e496a7c6c0fe9ba76da4ee939ce14e (diff)
parentd95e31af3f779bfa3141047e8b6275e1fd2e4bbb (diff)
Merge branch 'master' into zcomploc-support
Conflicts: Source/Core/VideoCommon/Src/PixelShaderGen.cpp
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/AudioCommon/AudioCommon.vcxproj2
-rw-r--r--Source/Core/AudioCommon/CMakeLists.txt50
-rw-r--r--Source/Core/AudioCommon/Src/AOSoundStream.cpp2
-rw-r--r--Source/Core/AudioCommon/Src/AlsaSoundStream.cpp1
-rw-r--r--Source/Core/AudioCommon/Src/AudioCommonConfig.cpp5
-rw-r--r--Source/Core/AudioCommon/Src/AudioCommonConfig.h1
-rw-r--r--Source/Core/AudioCommon/Src/DSoundStream.cpp4
-rw-r--r--Source/Core/AudioCommon/Src/OpenALStream.cpp2
-rw-r--r--Source/Core/AudioCommon/Src/PulseAudioStream.cpp2
-rw-r--r--Source/Core/AudioCommon/Src/aldlist.cpp3
-rw-r--r--Source/Core/Common/Common.vcxproj2
-rw-r--r--Source/Core/Common/Src/ABI.cpp7
-rw-r--r--Source/Core/Common/Src/BreakPoints.cpp23
-rw-r--r--Source/Core/Common/Src/BreakPoints.h2
-rw-r--r--Source/Core/Common/Src/CPUDetect.cpp25
-rw-r--r--Source/Core/Common/Src/ChunkFile.h27
-rw-r--r--Source/Core/Common/Src/Common.h22
-rw-r--r--Source/Core/Common/Src/CommonFuncs.h13
-rw-r--r--Source/Core/Common/Src/CommonPaths.h2
-rw-r--r--Source/Core/Common/Src/Hash.cpp12
-rw-r--r--Source/Core/Common/Src/IniFile.cpp6
-rw-r--r--Source/Core/Common/Src/LinearDiskCache.h43
-rw-r--r--Source/Core/Common/Src/LogManager.cpp13
-rw-r--r--Source/Core/Common/Src/LogManager.h12
-rw-r--r--Source/Core/Common/Src/MemoryUtil.cpp49
-rw-r--r--Source/Core/Common/Src/MsgHandler.cpp2
-rw-r--r--Source/Core/Common/Src/StdThread.h2
-rw-r--r--Source/Core/Common/Src/StringUtil.cpp17
-rw-r--r--Source/Core/Common/Src/SysConf.cpp2
-rw-r--r--Source/Core/Common/Src/SysConf.h5
-rw-r--r--Source/Core/Common/Src/Thread.h7
-rw-r--r--Source/Core/Common/Src/Version.cpp5
-rw-r--r--Source/Core/Common/Src/VideoBackendBase.h6
-rw-r--r--Source/Core/Common/Src/x64Emitter.cpp96
-rw-r--r--Source/Core/Common/Src/x64Emitter.h11
-rw-r--r--Source/Core/Core/CMakeLists.txt1
-rw-r--r--Source/Core/Core/Core.vcxproj16
-rw-r--r--Source/Core/Core/Core.vcxproj.filters9
-rw-r--r--Source/Core/Core/SConscript1
-rw-r--r--Source/Core/Core/Src/Boot/Boot.cpp11
-rw-r--r--Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp7
-rw-r--r--Source/Core/Core/Src/ConfigManager.cpp6
-rw-r--r--Source/Core/Core/Src/ConfigManager.h6
-rw-r--r--Source/Core/Core/Src/Core.cpp27
-rw-r--r--Source/Core/Core/Src/Core.h1
-rw-r--r--Source/Core/Core/Src/CoreTiming.cpp3
-rw-r--r--Source/Core/Core/Src/DSP/DSPCore.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/DSPCore.h2
-rw-r--r--Source/Core/Core/Src/DSP/DSPHWInterface.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/DSPHWInterface.h2
-rw-r--r--Source/Core/Core/Src/DSP/DSPIntExtOps.h2
-rw-r--r--Source/Core/Core/Src/DSP/DSPIntUtil.h2
-rw-r--r--Source/Core/Core/Src/DSP/DSPInterpreter.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/DSPMemoryMap.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/DSPMemoryMap.h2
-rw-r--r--Source/Core/Core/Src/DSP/DSPStacks.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/DSPStacks.h2
-rw-r--r--Source/Core/Core/Src/DSP/disassemble.cpp2
-rw-r--r--Source/Core/Core/Src/DSP/disassemble.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp10
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoDataFile.cpp2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoDataFile.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoFileStruct.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoPlayer.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.cpp2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.h2
-rw-r--r--Source/Core/Core/Src/FifoPlayer/FifoRecorder.h2
-rw-r--r--Source/Core/Core/Src/GeckoCode.cpp123
-rw-r--r--Source/Core/Core/Src/GeckoCode.h14
-rw-r--r--Source/Core/Core/Src/GeckoCodeConfig.cpp13
-rw-r--r--Source/Core/Core/Src/GeckoCodeConfig.h13
-rw-r--r--Source/Core/Core/Src/HLE/HLE_OS.cpp7
-rw-r--r--Source/Core/Core/Src/HW/AudioInterface.cpp6
-rw-r--r--Source/Core/Core/Src/HW/CPU.cpp1
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp46
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp8
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h1
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp8
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.cpp4
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.h2
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.cpp4
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.h2
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp4
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.h2
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.cpp10
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.h4
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp7
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.h2
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp9
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp11
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.h14
-rw-r--r--Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp15
-rw-r--r--Source/Core/Core/Src/HW/DVDInterface.cpp2
-rw-r--r--Source/Core/Core/Src/HW/EXI.cpp26
-rw-r--r--Source/Core/Core/Src/HW/EXI.h3
-rw-r--r--Source/Core/Core/Src/HW/EXI_Channel.cpp81
-rw-r--r--Source/Core/Core/Src/HW/EXI_Channel.h7
-rw-r--r--Source/Core/Core/Src/HW/EXI_Device.cpp35
-rw-r--r--Source/Core/Core/Src/HW/EXI_Device.h35
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp7
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceAD16.h1
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp7
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h1
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp22
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceEthernet.h1
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp33
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp62
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h7
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceMic.cpp402
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceMic.h92
-rw-r--r--Source/Core/Core/Src/HW/GCMemcard.cpp (renamed from Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp)270
-rw-r--r--Source/Core/Core/Src/HW/GCMemcard.h (renamed from Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h)44
-rw-r--r--Source/Core/Core/Src/HW/GCPad.cpp13
-rw-r--r--Source/Core/Core/Src/HW/GCPad.h1
-rw-r--r--Source/Core/Core/Src/HW/GCPadEmu.cpp12
-rw-r--r--Source/Core/Core/Src/HW/GCPadEmu.h2
-rw-r--r--Source/Core/Core/Src/HW/GPFifo.cpp14
-rw-r--r--Source/Core/Core/Src/HW/HW.cpp18
-rw-r--r--Source/Core/Core/Src/HW/HW.h1
-rw-r--r--Source/Core/Core/Src/HW/Memmap.cpp124
-rw-r--r--Source/Core/Core/Src/HW/Memmap.h20
-rw-r--r--Source/Core/Core/Src/HW/SI.cpp14
-rw-r--r--Source/Core/Core/Src/HW/SI.h4
-rw-r--r--Source/Core/Core/Src/HW/SI_Device.cpp24
-rw-r--r--Source/Core/Core/Src/HW/SI_Device.h20
-rw-r--r--Source/Core/Core/Src/HW/SI_DeviceGCController.cpp83
-rw-r--r--Source/Core/Core/Src/HW/SI_DeviceGCController.h17
-rw-r--r--Source/Core/Core/Src/HW/SystemTimers.cpp15
-rw-r--r--Source/Core/Core/Src/HW/SystemTimers.h1
-rw-r--r--Source/Core/Core/Src/HW/VideoInterface.cpp34
-rw-r--r--Source/Core/Core/Src/HW/VideoInterface.h4
-rw-r--r--Source/Core/Core/Src/HW/Wiimote.cpp3
-rw-r--r--Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp55
-rw-r--r--Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h1
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp65
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm8
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp29
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h1
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp389
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h15
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h3
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp15
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp240
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h6
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp65
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h2
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp11
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.h8
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp2
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.h1
-rw-r--r--Source/Core/Core/Src/MemTools.cpp2
-rw-r--r--Source/Core/Core/Src/Movie.cpp573
-rw-r--r--Source/Core/Core/Src/Movie.h32
-rw-r--r--Source/Core/Core/Src/PatchEngine.cpp5
-rw-r--r--Source/Core/Core/Src/PowerPC/Gekko.h2
-rw-r--r--Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp4
-rw-r--r--Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp10
-rw-r--r--Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp18
-rw-r--r--Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp37
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp61
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit.h7
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp47
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp16
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp1210
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp100
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp9
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR.h10
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp41
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp20
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp16
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp3
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp47
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp2
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h5
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp59
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h3
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp35
-rw-r--r--Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h1
-rw-r--r--Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp2
-rw-r--r--Source/Core/Core/Src/PowerPC/PPCCache.cpp14
-rw-r--r--Source/Core/Core/Src/PowerPC/PPCCache.h3
-rw-r--r--Source/Core/Core/Src/PowerPC/PowerPC.cpp42
-rw-r--r--Source/Core/Core/Src/PowerPC/PowerPC.h1
-rw-r--r--Source/Core/Core/Src/PowerPC/Profiler.cpp27
-rw-r--r--Source/Core/Core/Src/State.cpp185
-rw-r--r--Source/Core/Core/Src/State.h7
-rw-r--r--Source/Core/DiscIO/DiscIO.vcxproj2
-rw-r--r--Source/Core/DiscIO/Src/BannerLoader.h3
-rw-r--r--Source/Core/DiscIO/Src/BannerLoaderWii.cpp73
-rw-r--r--Source/Core/DiscIO/Src/BannerLoaderWii.h28
-rw-r--r--Source/Core/DiscIO/Src/NANDContentLoader.cpp32
-rw-r--r--Source/Core/DiscIO/Src/NANDContentLoader.h2
-rw-r--r--Source/Core/DiscIO/Src/Volume.h1
-rw-r--r--Source/Core/DiscIO/Src/VolumeDirectory.cpp4
-rw-r--r--Source/Core/DiscIO/Src/VolumeWad.cpp45
-rw-r--r--Source/Core/DiscIO/Src/VolumeWad.h1
-rw-r--r--Source/Core/DolphinWX/CMakeLists.txt111
-rw-r--r--Source/Core/DolphinWX/Dolphin.vcxproj7
-rw-r--r--Source/Core/DolphinWX/Dolphin.vcxproj.filters12
-rw-r--r--Source/Core/DolphinWX/Info.plist.in63
-rw-r--r--Source/Core/DolphinWX/SConscript1
-rw-r--r--Source/Core/DolphinWX/Src/ConfigMain.cpp46
-rw-r--r--Source/Core/DolphinWX/Src/ConfigMain.h1
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp2
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp45
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/DSPRegisterView.cpp4
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/RegisterView.cpp6
-rw-r--r--Source/Core/DolphinWX/Src/Frame.cpp14
-rw-r--r--Source/Core/DolphinWX/Src/Frame.h2
-rw-r--r--Source/Core/DolphinWX/Src/FrameTools.cpp35
-rw-r--r--Source/Core/DolphinWX/Src/GCMicDlg.cpp290
-rw-r--r--Source/Core/DolphinWX/Src/GCMicDlg.h74
-rw-r--r--Source/Core/DolphinWX/Src/GameListCtrl.cpp261
-rw-r--r--Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp34
-rw-r--r--Source/Core/DolphinWX/Src/GeckoCodeDiag.h13
-rw-r--r--Source/Core/DolphinWX/Src/ISOFile.cpp98
-rw-r--r--Source/Core/DolphinWX/Src/ISOFile.h4
-rw-r--r--Source/Core/DolphinWX/Src/ISOProperties.cpp123
-rw-r--r--Source/Core/DolphinWX/Src/ISOProperties.h3
-rw-r--r--Source/Core/DolphinWX/Src/LogConfigWindow.cpp53
-rw-r--r--Source/Core/DolphinWX/Src/LogConfigWindow.h5
-rw-r--r--Source/Core/DolphinWX/Src/LogWindow.cpp97
-rw-r--r--Source/Core/DolphinWX/Src/LogWindow.h3
-rw-r--r--Source/Core/DolphinWX/Src/Main.cpp1
-rw-r--r--Source/Core/DolphinWX/Src/MemcardManager.cpp16
-rw-r--r--Source/Core/DolphinWX/Src/MemcardManager.h2
-rw-r--r--Source/Core/DolphinWX/Src/VideoConfigDiag.cpp16
-rw-r--r--Source/Core/DolphinWX/Src/VideoConfigDiag.h7
-rw-r--r--Source/Core/InputCommon/InputCommon.vcxproj2
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp5
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp4
-rw-r--r--Source/Core/InputCommon/Src/GCPadStatus.h1
-rw-r--r--Source/Core/VideoCommon/CMakeLists.txt4
-rw-r--r--Source/Core/VideoCommon/Src/AVIDump.cpp14
-rw-r--r--Source/Core/VideoCommon/Src/BPFunctions.cpp19
-rw-r--r--Source/Core/VideoCommon/Src/BPFunctions.h2
-rw-r--r--Source/Core/VideoCommon/Src/BPMemory.cpp2
-rw-r--r--Source/Core/VideoCommon/Src/BPMemory.h41
-rw-r--r--Source/Core/VideoCommon/Src/BPStructs.cpp77
-rw-r--r--Source/Core/VideoCommon/Src/CommandProcessor.cpp134
-rw-r--r--Source/Core/VideoCommon/Src/CommandProcessor.h7
-rw-r--r--Source/Core/VideoCommon/Src/EmuWindow.cpp30
-rw-r--r--Source/Core/VideoCommon/Src/EmuWindow.h1
-rw-r--r--Source/Core/VideoCommon/Src/Fifo.cpp4
-rw-r--r--Source/Core/VideoCommon/Src/ImageWrite.h1
-rw-r--r--Source/Core/VideoCommon/Src/LightingShaderGen.cpp15
-rw-r--r--Source/Core/VideoCommon/Src/LightingShaderGen.h3
-rw-r--r--Source/Core/VideoCommon/Src/MainBase.cpp17
-rw-r--r--Source/Core/VideoCommon/Src/PixelEngine.cpp86
-rw-r--r--Source/Core/VideoCommon/Src/PixelEngine.h3
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderGen.cpp557
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderGen.h74
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderManager.cpp42
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderManager.h6
-rw-r--r--Source/Core/VideoCommon/Src/RenderBase.cpp17
-rw-r--r--Source/Core/VideoCommon/Src/RenderBase.h29
-rw-r--r--Source/Core/VideoCommon/Src/TextureCacheBase.cpp335
-rw-r--r--Source/Core/VideoCommon/Src/TextureCacheBase.h97
-rw-r--r--Source/Core/VideoCommon/Src/TextureDecoder.h4
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader.cpp56
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader_Position.cpp4
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp4
-rw-r--r--Source/Core/VideoCommon/Src/VertexShaderGen.cpp80
-rw-r--r--Source/Core/VideoCommon/Src/VertexShaderGen.h26
-rw-r--r--Source/Core/VideoCommon/Src/VertexShaderManager.cpp6
-rw-r--r--Source/Core/VideoCommon/Src/VideoCommon.h9
-rw-r--r--Source/Core/VideoCommon/Src/VideoConfig.cpp17
-rw-r--r--Source/Core/VideoCommon/Src/VideoConfig.h5
-rw-r--r--Source/Core/VideoCommon/Src/VideoState.cpp11
-rw-r--r--Source/Core/VideoCommon/Src/VideoState.h1
-rw-r--r--Source/Core/VideoCommon/Src/XFStructs.cpp4
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcxproj3
275 files changed, 6538 insertions, 3052 deletions
diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj b/Source/Core/AudioCommon/AudioCommon.vcxproj
index b37cbf4ce7..a82ab9aecc 100644
--- a/Source/Core/AudioCommon/AudioCommon.vcxproj
+++ b/Source/Core/AudioCommon/AudioCommon.vcxproj
@@ -45,7 +45,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +55,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
diff --git a/Source/Core/AudioCommon/CMakeLists.txt b/Source/Core/AudioCommon/CMakeLists.txt
index 51476a6ea6..be8c58d14a 100644
--- a/Source/Core/AudioCommon/CMakeLists.txt
+++ b/Source/Core/AudioCommon/CMakeLists.txt
@@ -6,33 +6,33 @@ set(SRCS Src/AudioCommon.cpp
set(LIBS "")
+if(ALSA_FOUND)
+ set(SRCS ${SRCS} Src/AlsaSoundStream.cpp)
+ set(LIBS ${LIBS} ${ALSA_LIBRARIES})
+endif(ALSA_FOUND)
+
+if(AO_FOUND)
+ set(SRCS ${SRCS} Src/AOSoundStream.cpp)
+ set(LIBS ${LIBS} ${AO_LIBRARIES})
+endif(AO_FOUND)
+
+if(OPENAL_FOUND)
+ set(SRCS ${SRCS} Src/OpenALStream.cpp Src/aldlist.cpp)
+ set(LIBS ${LIBS} ${OPENAL_LIBRARY})
+endif(OPENAL_FOUND)
+
+if(PULSEAUDIO_FOUND)
+ set(SRCS ${SRCS} Src/PulseAudioStream.cpp)
+ set(LIBS ${LIBS} ${PULSEAUDIO_LIBRARIES})
+endif(PULSEAUDIO_FOUND)
+
+if(WIN32)
+ set(SRCS ${SRCS} Src/DSoundStream.cpp)
+ set(SRCS ${SRCS} Src/XAudio2Stream.cpp)
+endif(WIN32)
+
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(SRCS ${SRCS} Src/CoreAudioSoundStream.cpp)
-else()
- if(ALSA_FOUND)
- set(SRCS ${SRCS} Src/AlsaSoundStream.cpp)
- set(LIBS ${LIBS} ${ALSA_LIBRARIES})
- endif(ALSA_FOUND)
-
- if(AO_FOUND)
- set(SRCS ${SRCS} Src/AOSoundStream.cpp)
- set(LIBS ${LIBS} ${AO_LIBRARIES})
- endif(AO_FOUND)
-
- if(OPENAL_FOUND)
- set(SRCS ${SRCS} Src/OpenALStream.cpp Src/aldlist.cpp)
- set(LIBS ${LIBS} openal)
- endif(OPENAL_FOUND)
-
- if(PULSEAUDIO_FOUND)
- set(SRCS ${SRCS} Src/PulseAudioStream.cpp)
- set(LIBS ${LIBS} ${PULSEAUDIO_LIBRARIES})
- endif(PULSEAUDIO_FOUND)
-
- if(WIN32)
- set(SRCS ${SRCS} Src/DSoundStream.cpp)
- set(SRCS ${SRCS} Src/XAudio2Stream.cpp)
- endif(WIN32)
endif()
add_library(audiocommon STATIC ${SRCS})
diff --git a/Source/Core/AudioCommon/Src/AOSoundStream.cpp b/Source/Core/AudioCommon/Src/AOSoundStream.cpp
index e864ad1211..99ae2e661c 100644
--- a/Source/Core/AudioCommon/Src/AOSoundStream.cpp
+++ b/Source/Core/AudioCommon/Src/AOSoundStream.cpp
@@ -25,6 +25,8 @@
void AOSound::SoundLoop()
{
+ Common::SetCurrentThreadName("Audio thread - ao");
+
uint_32 numBytesToRender = 256;
ao_initialize();
default_driver = ao_default_driver_id();
diff --git a/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp b/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp
index 76f13b6cb1..710275d55a 100644
--- a/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp
+++ b/Source/Core/AudioCommon/Src/AlsaSoundStream.cpp
@@ -60,6 +60,7 @@ void AlsaSound::SoundLoop()
thread_data = 2;
return;
}
+ Common::SetCurrentThreadName("Audio thread - alsa");
while (!thread_data)
{
m_mixer->Mix(reinterpret_cast<short *>(mix_buffer), frames_to_deliver);
diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp
index 1ab4c261e2..533c6b4313 100644
--- a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp
+++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp
@@ -18,6 +18,7 @@
#include "AudioCommon.h"
#include "CommonPaths.h"
#include "FileUtil.h"
+#include "../../Core/Src/ConfigManager.h"
AudioCommonConfig ac_Config;
@@ -31,7 +32,6 @@ void AudioCommonConfig::Load()
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true);
- file.Get("Config", "EnableThrottle", &m_EnableThrottle, true);
file.Get("Config", "EnableJIT", &m_EnableJIT, true);
file.Get("Config", "DumpAudio", &m_DumpAudio, false);
#if defined __linux__ && HAVE_ALSA
@@ -54,7 +54,6 @@ void AudioCommonConfig::SaveSettings()
file.Load(File::GetUserPath(F_DSPCONFIG_IDX));
file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic);
- file.Set("Config", "EnableThrottle", m_EnableThrottle);
file.Set("Config", "EnableJIT", m_EnableJIT);
file.Set("Config", "DumpAudio", m_DumpAudio);
file.Set("Config", "Backend", sBackend);
@@ -67,7 +66,7 @@ void AudioCommonConfig::SaveSettings()
// Update according to the values (stream/mixer)
void AudioCommonConfig::Update() {
if (soundStream) {
- soundStream->GetMixer()->SetThrottle(m_EnableThrottle);
+ soundStream->GetMixer()->SetThrottle(SConfig::GetInstance().m_Framelimit == 2);
soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic);
soundStream->SetVolume(m_Volume);
}
diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h
index 49124344e0..076ef2d4e1 100644
--- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h
+++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h
@@ -34,7 +34,6 @@
struct AudioCommonConfig
{
bool m_EnableDTKMusic;
- bool m_EnableThrottle;
bool m_EnableJIT;
bool m_DumpAudio;
int m_Volume;
diff --git a/Source/Core/AudioCommon/Src/DSoundStream.cpp b/Source/Core/AudioCommon/Src/DSoundStream.cpp
index 38fbc2a851..b252dc90c5 100644
--- a/Source/Core/AudioCommon/Src/DSoundStream.cpp
+++ b/Source/Core/AudioCommon/Src/DSoundStream.cpp
@@ -96,6 +96,8 @@ bool DSound::WriteDataToBuffer(DWORD dwOffset, // Our own write
// The audio thread.
void DSound::SoundLoop()
{
+ Common::SetCurrentThreadName("Audio thread - dsound");
+
currentPos = 0;
lastPos = 0;
dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
@@ -130,7 +132,7 @@ bool DSound::Start()
DWORD num1;
short* p1;
- dsBuffer->Lock(0, bufferSize, (void* *)&p1, &num1, 0, 0, 0);
+ dsBuffer->Lock(0, bufferSize, (void* *)&p1, &num1, 0, 0, DSBLOCK_ENTIREBUFFER);
memset(p1, 0, num1);
dsBuffer->Unlock(p1, num1, 0, 0);
thread = std::thread(std::mem_fun(&DSound::SoundLoop), this);
diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp
index 91d2b3270c..99220f0ed2 100644
--- a/Source/Core/AudioCommon/Src/OpenALStream.cpp
+++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp
@@ -121,6 +121,8 @@ void OpenALStream::Clear(bool mute)
void OpenALStream::SoundLoop()
{
+ Common::SetCurrentThreadName("Audio thread - openal");
+
ALenum err;
u32 ulFrequency = m_mixer->GetSampleRate();
diff --git a/Source/Core/AudioCommon/Src/PulseAudioStream.cpp b/Source/Core/AudioCommon/Src/PulseAudioStream.cpp
index 6b3f9e7217..4851b4bd12 100644
--- a/Source/Core/AudioCommon/Src/PulseAudioStream.cpp
+++ b/Source/Core/AudioCommon/Src/PulseAudioStream.cpp
@@ -58,6 +58,8 @@ void PulseAudio::Update()
// Called on audio thread.
void PulseAudio::SoundLoop()
{
+ Common::SetCurrentThreadName("Audio thread - pulse");
+
thread_running = PulseInit();
while (thread_running)
diff --git a/Source/Core/AudioCommon/Src/aldlist.cpp b/Source/Core/AudioCommon/Src/aldlist.cpp
index 2008842486..69d42148ae 100644
--- a/Source/Core/AudioCommon/Src/aldlist.cpp
+++ b/Source/Core/AudioCommon/Src/aldlist.cpp
@@ -27,6 +27,9 @@
#ifdef _WIN32
#include "../../../../Externals/OpenAL/include/al.h"
#include "../../../../Externals/OpenAL/include/alc.h"
+#elif defined(__APPLE__)
+#include <al.h>
+#include <alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index d29043eb7d..732fc7258c 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -45,7 +45,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +55,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
diff --git a/Source/Core/Common/Src/ABI.cpp b/Source/Core/Common/Src/ABI.cpp
index 08e021f083..63a8e76934 100644
--- a/Source/Core/Common/Src/ABI.cpp
+++ b/Source/Core/Common/Src/ABI.cpp
@@ -189,7 +189,7 @@ unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
#ifdef __GNUC__
(frameSize + 15) & -16;
#else
- frameSize;
+ (frameSize + 3) & -4;
#endif
return alignedSize;
}
@@ -200,16 +200,15 @@ void XEmitter::ABI_AlignStack(unsigned int frameSize) {
// Linux requires the stack to be 16-byte aligned before calls that put SSE
// vectors on the stack, but since we do not keep track of which calls do that,
// it is effectively every call as well.
-// Windows binaries compiled with MSVC do not have such a restriction, but I
+// Windows binaries compiled with MSVC do not have such a restriction*, but I
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
// It would be nice if someone could verify this.
-#ifdef __GNUC__
+// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
unsigned int fillSize =
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
if (fillSize != 0) {
SUB(32, R(ESP), Imm8(fillSize));
}
-#endif
}
void XEmitter::ABI_RestoreStack(unsigned int frameSize) {
diff --git a/Source/Core/Common/Src/BreakPoints.cpp b/Source/Core/Common/Src/BreakPoints.cpp
index 45a0b52daf..1700276d85 100644
--- a/Source/Core/Common/Src/BreakPoints.cpp
+++ b/Source/Core/Common/Src/BreakPoints.cpp
@@ -18,6 +18,7 @@
#include "Common.h"
#include "DebugInterface.h"
#include "BreakPoints.h"
+#include "../../Core/Src/PowerPC/JitCommon/JitBase.h"
#include <sstream>
bool BreakPoints::IsAddressBreakPoint(u32 _iAddress)
@@ -70,7 +71,11 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
void BreakPoints::Add(const TBreakPoint& bp)
{
if (!IsAddressBreakPoint(bp.iAddress))
+ {
m_BreakPoints.push_back(bp);
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
+ }
}
void BreakPoints::Add(u32 em_address, bool temp)
@@ -83,21 +88,35 @@ void BreakPoints::Add(u32 em_address, bool temp)
pt.iAddress = em_address;
m_BreakPoints.push_back(pt);
+
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(em_address, 4);
}
}
-void BreakPoints::Remove(u32 _iAddress)
+void BreakPoints::Remove(u32 em_address)
{
for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
{
- if (i->iAddress == _iAddress)
+ if (i->iAddress == em_address)
{
m_BreakPoints.erase(i);
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(em_address, 4);
return;
}
}
}
+void BreakPoints::Clear()
+{
+ for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i)
+ {
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(i->iAddress, 4);
+ m_BreakPoints.erase(i);
+ }
+}
MemChecks::TMemChecksStr MemChecks::GetStrings() const
{
diff --git a/Source/Core/Common/Src/BreakPoints.h b/Source/Core/Common/Src/BreakPoints.h
index a97452cde6..c742f812a7 100644
--- a/Source/Core/Common/Src/BreakPoints.h
+++ b/Source/Core/Common/Src/BreakPoints.h
@@ -78,7 +78,7 @@ public:
// Remove Breakpoint
void Remove(u32 _iAddress);
- void Clear() { m_BreakPoints.clear(); };
+ void Clear();
void DeleteByAddress(u32 _Address);
diff --git a/Source/Core/Common/Src/CPUDetect.cpp b/Source/Core/Common/Src/CPUDetect.cpp
index 810c5d2a59..93e9d25087 100644
--- a/Source/Core/Common/Src/CPUDetect.cpp
+++ b/Source/Core/Common/Src/CPUDetect.cpp
@@ -32,6 +32,10 @@
//#include <config/i386/cpuid.h>
#include <xmmintrin.h>
+#if defined __FreeBSD__
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#else
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
@@ -39,41 +43,42 @@ static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to
// restored at the end of the asm block.
__asm__ (
- "mov %%rbx,%%rdi;"
"cpuid;"
"movl %%ebx,%1;"
- "mov %%rdi,%%rbx;"
: "=a" (*eax),
- "=g" (*ebx),
+ "=S" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
- : "rdi", "rbx"
+ : "rbx"
);
#else
- __asm__(
- "movl %%ebx,%%edi;"
+ __asm__ (
"cpuid;"
- "movl %%ebx,%1;"
- "movl %%edi,%%ebx;"
+ "movl %%ebx,%1;"
: "=a" (*eax),
- "=g" (*ebx),
+ "=S" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (*eax)
- : "edi", "ebx"
+ : "ebx"
);
#endif
}
+#endif /* defined __FreeBSD__ */
static void __cpuid(int info[4], int x)
{
+#if defined __FreeBSD__
+ do_cpuid((unsigned int)x, (unsigned int*)info);
+#else
unsigned int eax = x, ebx = 0, ecx = 0, edx = 0;
do_cpuid(&eax, &ebx, &ecx, &edx);
info[0] = eax;
info[1] = ebx;
info[2] = ecx;
info[3] = edx;
+#endif
}
#endif
diff --git a/Source/Core/Common/Src/ChunkFile.h b/Source/Core/Common/Src/ChunkFile.h
index 03216deaf1..4ed781dcbd 100644
--- a/Source/Core/Common/Src/ChunkFile.h
+++ b/Source/Core/Common/Src/ChunkFile.h
@@ -154,7 +154,21 @@ public:
}
(*ptr) += stringLen;
}
-
+
+ void Do(std::wstring &x)
+ {
+ int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
+ Do(stringLen);
+
+ switch (mode) {
+ case MODE_READ: x = (wchar_t*)*ptr; break;
+ case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
+ case MODE_MEASURE: break;
+ case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
+ }
+ (*ptr) += stringLen;
+ }
+
template<class T>
void DoArray(T *x, int count) {
DoVoid((void *)x, sizeof(T) * count);
@@ -170,6 +184,17 @@ public:
// TODO
PanicAlert("Do(linked list<>) does not yet work.");
}
+
+ void DoMarker(const char* prevName, u32 arbitraryNumber=0x42)
+ {
+ u32 cookie = arbitraryNumber;
+ Do(cookie);
+ if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
+ {
+ PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
+ mode = PointerWrap::MODE_MEASURE;
+ }
+ }
};
diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h
index bc9b4dc051..db889f7ddf 100644
--- a/Source/Core/Common/Src/Common.h
+++ b/Source/Core/Common/Src/Common.h
@@ -89,6 +89,8 @@ private:
// Since it is always around on windows
#define HAVE_WX 1
+ #define HAVE_PORTAUDIO 1
+
// Debug definitions
#if defined(_DEBUG)
#include <crtdbg.h>
@@ -137,14 +139,18 @@ private:
// wxWidgets does not have a true dummy macro for this.
#define _trans(a) a
-#if defined __APPLE__ && defined __i386__
-#define _M_SSE 0x300
-#elif defined __APPLE__ && defined __x86_64__
-#define _M_SSE 0x301
-#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
-#define _M_SSE 0x301
-#elif _MSC_VER >= 1500 // Visual Studio 2008
-#define _M_SSE 0x402
+#if defined __GNUC__
+# if defined __SSE4_2__
+# define _M_SSE 0x402
+# elif defined __SSE4_1__
+# define _M_SSE 0x401
+# elif defined __SSSE3__
+# define _M_SSE 0x301
+# elif defined __SSE3__
+# define _M_SSE 0x300
+# endif
+#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
+# define _M_SSE 0x402
#endif
// Host communication.
diff --git a/Source/Core/Common/Src/CommonFuncs.h b/Source/Core/Common/Src/CommonFuncs.h
index 7dd156f42e..74d317d95f 100644
--- a/Source/Core/Common/Src/CommonFuncs.h
+++ b/Source/Core/Common/Src/CommonFuncs.h
@@ -27,6 +27,13 @@
template <bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
+#define b2(x) ( (x) | ( (x) >> 1) )
+#define b4(x) ( b2(x) | ( b2(x) >> 2) )
+#define b8(x) ( b4(x) | ( b4(x) >> 4) )
+#define b16(x) ( b8(x) | ( b8(x) >> 8) )
+#define b32(x) (b16(x) | (b16(x) >>16) )
+#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
+
#if defined __GNUC__ && !defined __SSSE3__
#include <emmintrin.h>
static __inline __m128i __attribute__((__always_inline__))
@@ -45,6 +52,8 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
#include <errno.h>
#ifdef __linux__
#include <byteswap.h>
+#elif defined __FreeBSD__
+#include <sys/endian.h>
#endif
// go to debugger mode
@@ -137,6 +146,10 @@ inline __attribute__((always_inline)) u32 swap32(u32 _data)
{return __builtin_bswap32(_data);}
inline __attribute__((always_inline)) u64 swap64(u64 _data)
{return __builtin_bswap64(_data);}
+#elif __FreeBSD__
+inline u16 swap16(u16 _data) {return bswap16(_data);}
+inline u32 swap32(u32 _data) {return bswap32(_data);}
+inline u64 swap64(u64 _data) {return bswap64(_data);}
#else
// Slow generic implementation.
inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);}
diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h
index 8d37482ce1..d319fb541e 100644
--- a/Source/Core/Common/Src/CommonPaths.h
+++ b/Source/Core/Common/Src/CommonPaths.h
@@ -126,6 +126,8 @@
#define WII_USA_SETTING "setting-usa.txt"
#define WII_JAP_SETTING "setting-jpn.txt"
+#define GECKO_CODE_HANDLER "codehandler.bin"
+
// Subdirs in Sys
#define GC_SYS_DIR "GC"
#define WII_SYS_DIR "Wii"
diff --git a/Source/Core/Common/Src/Hash.cpp b/Source/Core/Common/Src/Hash.cpp
index 62ea25519e..8e8d6f85bd 100644
--- a/Source/Core/Common/Src/Hash.cpp
+++ b/Source/Core/Common/Src/Hash.cpp
@@ -167,7 +167,7 @@ u64 GetMurmurHash3(const u8 *src, int len, u32 samples)
const u8 * data = (const u8*)src;
const int nblocks = len / 16;
u32 Step = (len / 8);
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
@@ -245,7 +245,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
u32 Step = (len / 8);
const u64 *data = (const u64 *)src;
const u64 *end = data + Step;
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
while(data < end)
@@ -275,7 +275,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
u32 Step = (len / 8);
const u64 *data = (const u64 *)src;
const u64 *end = data + Step;
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
while(data < end)
@@ -318,7 +318,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
u32 Step = (len/4);
const u32 *data = (const u32 *)src;
const u32 *end = data + Step;
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
while(data < end)
@@ -390,7 +390,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
u32 out[2];
const int nblocks = len / 8;
u32 Step = (len / 4);
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
@@ -464,7 +464,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
u32 Step = (len / 8);
const u64 *data = (const u64 *)src;
const u64 *end = data + Step;
- if(samples == 0) samples = Step;
+ if(samples == 0) samples = max(Step, 1u);
Step = Step / samples;
if(Step < 1) Step = 1;
while(data < end)
diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp
index c81c060f1d..acad498106 100644
--- a/Source/Core/Common/Src/IniFile.cpp
+++ b/Source/Core/Common/Src/IniFile.cpp
@@ -459,7 +459,11 @@ bool IniFile::Save(const char* filename)
return false;
}
- for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
+ // Currently testing if dolphin community can handle the requirements of C++11 compilation
+ // If you get a compiler error on this line, your compiler is probably old.
+ // Update to g++ 4.4 or a recent version of clang (XCode 4.2 on OS X).
+ // If you don't want to update, complain in a google code issue, the dolphin forums or #dolphin-emu.
+ for (auto iter = sections.begin(); iter != sections.end(); ++iter)
{
const Section& section = *iter;
diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h
index 7a124aaa7b..f6e0d95f8c 100644
--- a/Source/Core/Common/Src/LinearDiskCache.h
+++ b/Source/Core/Common/Src/LinearDiskCache.h
@@ -21,12 +21,10 @@
#include "Common.h"
#include <fstream>
-// Update this to the current SVN revision every time you change shader generation code.
-// We don't automatically get this from SVN_REV because that would mean regenerating the
-// shader cache for every revision, graphics-related or not, which is simply annoying.
+// Increment this every time you change shader generation code.
enum
{
- LINEAR_DISKCACHE_VER = 6964
+ LINEAR_DISKCACHE_VER = 6972
};
// On disk format:
@@ -73,36 +71,58 @@ public:
// close any currently opened file
Close();
+ m_num_entries = 0;
// try opening for reading/writing
- m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary | ios_base::app);
+ m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary);
+
+ m_file.seekg(0, std::ios::end);
+ std::fstream::pos_type end_pos = m_file.tellg();
+ m_file.seekg(0, std::ios::beg);
+ std::fstream::pos_type start_pos = m_file.tellg();
+ std::streamoff file_size = end_pos - start_pos;
if (m_file.is_open() && ValidateHeader())
{
// good header, read some key/value pairs
- u32 num_entries = 0;
K key;
V *value = NULL;
u32 value_size;
+ u32 entry_number;
+
+ std::fstream::pos_type last_pos = m_file.tellg();
while (Read(&value_size))
{
+ std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
+ if (next_extent > file_size)
+ break;
+
delete[] value;
value = new V[value_size];
// read key/value and pass to reader
- if (Read(&key) && Read(value, value_size))
+ if (Read(&key) &&
+ Read(value, value_size) &&
+ Read(&entry_number) &&
+ entry_number == m_num_entries+1)
+ {
reader.Read(key, value, value_size);
+ }
else
+ {
break;
+ }
- ++num_entries;
+ m_num_entries++;
+ last_pos = m_file.tellg();
}
+ m_file.seekp(last_pos);
m_file.clear();
delete[] value;
- return num_entries;
+ return m_num_entries;
}
// failed to open file for reading or bad header
@@ -129,10 +149,12 @@ public:
// Appends a key-value pair to the store.
void Append(const K &key, const V *value, u32 value_size)
{
- // TODO: Should do a check that we don't already have "key"?
+ // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
Write(&value_size);
Write(&key);
Write(value, value_size);
+ m_num_entries++;
+ Write(&m_num_entries);
}
private:
@@ -176,6 +198,7 @@ private:
} m_header;
std::fstream m_file;
+ u32 m_num_entries;
};
#endif // _LINEAR_DISKCACHE
diff --git a/Source/Core/Common/Src/LogManager.cpp b/Source/Core/Common/Src/LogManager.cpp
index d95e76ac5b..a79c413cf8 100644
--- a/Source/Core/Common/Src/LogManager.cpp
+++ b/Source/Core/Common/Src/LogManager.cpp
@@ -85,12 +85,17 @@ LogManager::LogManager()
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
m_consoleLog = new ConsoleListener();
+ m_debuggerLog = new DebuggerLogListener();
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_Log[i]->SetEnable(true);
m_Log[i]->AddListener(m_fileLog);
m_Log[i]->AddListener(m_consoleLog);
+#ifdef _MSC_VER
+ if (IsDebuggerPresent())
+ m_Log[i]->AddListener(m_debuggerLog);
+#endif
}
}
@@ -100,6 +105,7 @@ LogManager::~LogManager()
{
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
+ m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
}
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
@@ -187,3 +193,10 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
std::lock_guard<std::mutex> lk(m_log_lock);
m_logfile << msg << std::flush;
}
+
+void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
+{
+#if _MSC_VER
+ ::OutputDebugStringA(msg);
+#endif
+}
diff --git a/Source/Core/Common/Src/LogManager.h b/Source/Core/Common/Src/LogManager.h
index 3f2b5cd168..1722c0b1bf 100644
--- a/Source/Core/Common/Src/LogManager.h
+++ b/Source/Core/Common/Src/LogManager.h
@@ -58,6 +58,12 @@ private:
bool m_enable;
};
+class DebuggerLogListener : public LogListener
+{
+public:
+ void Log(LogTypes::LOG_LEVELS, const char *msg);
+};
+
class LogContainer
{
public:
@@ -97,6 +103,7 @@ private:
LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
FileLogListener *m_fileLog;
ConsoleListener *m_consoleLog;
+ DebuggerLogListener *m_debuggerLog;
static LogManager *m_logManager; // Singleton. Ugh.
LogManager();
@@ -153,6 +160,11 @@ public:
return m_consoleLog;
}
+ DebuggerLogListener *GetDebuggerListener() const
+ {
+ return m_debuggerLog;
+ }
+
static LogManager* GetInstance()
{
return m_logManager;
diff --git a/Source/Core/Common/Src/MemoryUtil.cpp b/Source/Core/Common/Src/MemoryUtil.cpp
index bc65f856f4..3e3cafa335 100644
--- a/Source/Core/Common/Src/MemoryUtil.cpp
+++ b/Source/Core/Common/Src/MemoryUtil.cpp
@@ -27,28 +27,65 @@
#include <stdio.h>
#endif
+#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
+#include <unistd.h>
+#define PAGE_MASK (getpagesize() - 1)
+#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
+#endif
+
// This is purposely not a full wrapper for virtualalloc/mmap, but it
// provides exactly the primitive operations that Dolphin needs.
void* AllocateExecutableMemory(size_t size, bool low)
{
-#ifdef _WIN32
- void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+#if defined(_WIN32)
+ void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
- void* ptr = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ static char *map_hint = 0;
+#if defined(__x86_64__) && !defined(MAP_32BIT)
+ // This OS has no flag to enforce allocation below the 4 GB boundary,
+ // but if we hint that we want a low address it is very likely we will
+ // get one.
+ // An older version of this code used MAP_FIXED, but that has the side
+ // effect of discarding already mapped pages that happen to be in the
+ // requested virtual memory range (such as the emulated RAM, sometimes).
+ if (low && (!map_hint))
+ map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
+#endif
+ void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE
-#if defined __linux__ && defined __x86_64__
+#if defined(__x86_64__) && defined(MAP_32BIT)
| (low ? MAP_32BIT : 0)
#endif
, -1, 0);
-#endif
+#endif /* defined(_WIN32) */
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
// (unsigned long)size);
+#if defined(__FreeBSD__)
+ if (ptr == MAP_FAILED)
+ {
+ ptr = NULL;
+#else
if (ptr == NULL)
+ {
+#endif
PanicAlert("Failed to allocate executable memory");
-#ifdef _M_X64
+ }
+#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
+ else
+ {
+ if (low)
+ {
+ map_hint += size;
+ map_hint = (char*)round_page(map_hint); /* round up to the next page */
+ // printf("Next map will (hopefully) be at %p\n", map_hint);
+ }
+ }
+#endif
+
+#if defined(_M_X64)
if ((u64)ptr >= 0x80000000 && low == true)
PanicAlert("Executable memory ended up above 2GB!");
#endif
diff --git a/Source/Core/Common/Src/MsgHandler.cpp b/Source/Core/Common/Src/MsgHandler.cpp
index 3f68e1d29a..7c666227aa 100644
--- a/Source/Core/Common/Src/MsgHandler.cpp
+++ b/Source/Core/Common/Src/MsgHandler.cpp
@@ -86,7 +86,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
va_list args;
va_start(args, format);
- CharArrayFromFormatV(buffer, 2047, str_translator(format).c_str(), args);
+ CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
va_end(args);
ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer);
diff --git a/Source/Core/Common/Src/StdThread.h b/Source/Core/Common/Src/StdThread.h
index 6e9e903561..b64dbf2c4e 100644
--- a/Source/Core/Common/Src/StdThread.h
+++ b/Source/Core/Common/Src/StdThread.h
@@ -7,7 +7,9 @@
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
// GCC 4.4 provides <thread>
+#ifndef _GLIBCXX_USE_SCHED_YIELD
#define _GLIBCXX_USE_SCHED_YIELD
+#endif
#include <thread>
#else
diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp
index 18a3575086..664987d350 100644
--- a/Source/Core/Common/Src/StringUtil.cpp
+++ b/Source/Core/Common/Src/StringUtil.cpp
@@ -125,15 +125,26 @@ std::string StripQuotes(const std::string& s)
bool TryParse(const std::string &str, u32 *const output)
{
char *endptr = NULL;
- u32 value = strtoul(str.c_str(), &endptr, 0);
+
+ // Reset errno to a value other than ERANGE
+ errno = 0;
+
+ unsigned long value = strtoul(str.c_str(), &endptr, 0);
if (!endptr || *endptr)
return false;
- if (value == ULONG_MAX && errno == ERANGE)
+ if (errno == ERANGE)
return false;
- *output = value;
+ if (ULONG_MAX > UINT_MAX) {
+ // Note: The typecasts avoid GCC warnings when long is 32 bits wide.
+ if (value >= static_cast<unsigned long>(0x100000000ull)
+ && value <= static_cast<unsigned long>(0xFFFFFFFF00000000ull))
+ return false;
+ }
+
+ *output = static_cast<u32>(value);
return true;
}
diff --git a/Source/Core/Common/Src/SysConf.cpp b/Source/Core/Common/Src/SysConf.cpp
index ed8a4953e5..97170e5ff1 100644
--- a/Source/Core/Common/Src/SysConf.cpp
+++ b/Source/Core/Common/Src/SysConf.cpp
@@ -387,7 +387,7 @@ bool SysConf::SaveToFile(const char *filename)
}
else if (i->type == Type_SmallArray)
{
- const u8 len = i->dataLength;
+ const u8 len = (u8)(i->dataLength);
f.WriteArray(&len, 1);
}
diff --git a/Source/Core/Common/Src/SysConf.h b/Source/Core/Common/Src/SysConf.h
index 119cc3c45a..fb9c775828 100644
--- a/Source/Core/Common/Src/SysConf.h
+++ b/Source/Core/Common/Src/SysConf.h
@@ -66,10 +66,9 @@ struct SSysConfEntry
}
bool SetArrayData(u8* buffer, u16 bufferSize)
{
-
- if (buffer && bufferSize <= dataLength)
+ if (buffer)
{
- memcpy(data, buffer, bufferSize);
+ memcpy(data, buffer, min<u16>(bufferSize, dataLength));
return true;
}
return false;
diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h
index ba713ed64c..e711fcab5c 100644
--- a/Source/Core/Common/Src/Thread.h
+++ b/Source/Core/Common/Src/Thread.h
@@ -72,6 +72,13 @@ public:
is_set = false;
}
+ void Reset()
+ {
+ std::unique_lock<std::mutex> lk(m_mutex);
+ // no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
+ is_set = false;
+ }
+
private:
class IsSet
{
diff --git a/Source/Core/Common/Src/Version.cpp b/Source/Core/Common/Src/Version.cpp
index f3d30398c8..97e232785d 100644
--- a/Source/Core/Common/Src/Version.cpp
+++ b/Source/Core/Common/Src/Version.cpp
@@ -30,7 +30,12 @@ const char *scm_rev_str = "Dolphin "
#if !SCM_IS_MASTER
"[" SCM_BRANCH_STR "] "
#endif
+
+#ifdef __INTEL_COMPILER
+ BUILD_TYPE_STR SCM_DESC_STR "-ICC";
+#else
BUILD_TYPE_STR SCM_DESC_STR;
+#endif
#ifdef _M_X64
#define NP_ARCH "x64"
diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h
index 667a3d3a32..96f639832b 100644
--- a/Source/Core/Common/Src/VideoBackendBase.h
+++ b/Source/Core/Common/Src/VideoBackendBase.h
@@ -119,6 +119,7 @@ public:
virtual void Video_GatherPipeBursted() = 0;
virtual bool Video_IsPossibleWaitingSetDrawDone() = 0;
+ virtual bool Video_IsHiWatermarkActive() = 0;
virtual void Video_AbortFrame() = 0;
virtual readFn16 Video_CPRead16() = 0;
@@ -140,6 +141,7 @@ class VideoBackendHardware : public VideoBackend
{
void DoState(PointerWrap &p);
void RunLoop(bool enable);
+ bool Initialize(void *&) { InitializeShared(); return true; }
void EmuStateChange(EMUSTATE_CHANGE);
@@ -158,6 +160,7 @@ class VideoBackendHardware : public VideoBackend
void Video_GatherPipeBursted();
bool Video_IsPossibleWaitingSetDrawDone();
+ bool Video_IsHiWatermarkActive();
void Video_AbortFrame();
readFn16 Video_CPRead16();
@@ -165,6 +168,9 @@ class VideoBackendHardware : public VideoBackend
readFn16 Video_PERead16();
writeFn16 Video_PEWrite16();
writeFn32 Video_PEWrite32();
+
+protected:
+ void InitializeShared();
};
#endif
diff --git a/Source/Core/Common/Src/x64Emitter.cpp b/Source/Core/Common/Src/x64Emitter.cpp
index 9acfac5864..00c58a0fbc 100644
--- a/Source/Core/Common/Src/x64Emitter.cpp
+++ b/Source/Core/Common/Src/x64Emitter.cpp
@@ -834,6 +834,102 @@ void XEmitter::SHL(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, sh
void XEmitter::SHR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 5);}
void XEmitter::SAR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 7);}
+// index can be either imm8 or register, don't use memory destination because it's slow
+void XEmitter::WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext)
+{
+ if (dest.IsImm())
+ {
+ _assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms");
+ }
+ if ((index.IsImm() && index.GetImmBits() != 8))
+ {
+ _assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument");
+ }
+ if (bits == 16) Write8(0x66);
+ if (index.IsImm())
+ {
+ dest.WriteRex(this, bits, bits);
+ Write8(0x0F); Write8(0xBA);
+ dest.WriteRest(this, 1, (X64Reg)ext);
+ Write8((u8)index.offset);
+ }
+ else
+ {
+ X64Reg operand = index.GetSimpleReg();
+ dest.WriteRex(this, bits, bits, operand);
+ Write8(0x0F); Write8(0x83 + 8*ext);
+ dest.WriteRest(this, 1, operand);
+ }
+}
+
+void XEmitter::BT(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 4);}
+void XEmitter::BTS(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 5);}
+void XEmitter::BTR(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 6);}
+void XEmitter::BTC(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 7);}
+
+//shift can be either imm8 or cl
+void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift)
+{
+ bool writeImm = false;
+ if (dest.IsImm())
+ {
+ _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination");
+ }
+ if (!src.IsSimpleReg())
+ {
+ _assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source");
+ }
+ if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
+ {
+ _assert_msg_(DYNA_REC, 0, "SHRD - illegal shift");
+ }
+ if (bits == 16) Write8(0x66);
+ X64Reg operand = src.GetSimpleReg();
+ dest.WriteRex(this, bits, bits, operand);
+ if (shift.GetImmBits() == 8)
+ {
+ Write8(0x0F); Write8(0xAC);
+ dest.WriteRest(this, 1, operand);
+ Write8((u8)shift.offset);
+ }
+ else
+ {
+ Write8(0x0F); Write8(0xAD);
+ dest.WriteRest(this, 0, operand);
+ }
+}
+
+void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift)
+{
+ bool writeImm = false;
+ if (dest.IsImm())
+ {
+ _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination");
+ }
+ if (!src.IsSimpleReg())
+ {
+ _assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source");
+ }
+ if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
+ {
+ _assert_msg_(DYNA_REC, 0, "SHLD - illegal shift");
+ }
+ if (bits == 16) Write8(0x66);
+ X64Reg operand = src.GetSimpleReg();
+ dest.WriteRex(this, bits, bits, operand);
+ if (shift.GetImmBits() == 8)
+ {
+ Write8(0x0F); Write8(0xA4);
+ dest.WriteRest(this, 1, operand);
+ Write8((u8)shift.offset);
+ }
+ else
+ {
+ Write8(0x0F); Write8(0xA5);
+ dest.WriteRest(this, 0, operand);
+ }
+}
+
void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits)
{
if (bits == 16)
diff --git a/Source/Core/Common/Src/x64Emitter.h b/Source/Core/Common/Src/x64Emitter.h
index 9ffb890f54..3b699c81a0 100644
--- a/Source/Core/Common/Src/x64Emitter.h
+++ b/Source/Core/Common/Src/x64Emitter.h
@@ -249,6 +249,7 @@ private:
void WriteMulDivType(int bits, OpArg src, int ext);
void WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2);
void WriteShift(int bits, OpArg dest, OpArg &shift, int ext);
+ void WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext);
void WriteMXCSR(OpArg arg, int ext);
void WriteSSEOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes = 0);
void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg &a1, const OpArg &a2);
@@ -374,6 +375,16 @@ public:
void SHR(int bits, OpArg dest, OpArg shift);
void SAR(int bits, OpArg dest, OpArg shift);
+ // Bit Test
+ void BT(int bits, OpArg dest, OpArg index);
+ void BTS(int bits, OpArg dest, OpArg index);
+ void BTR(int bits, OpArg dest, OpArg index);
+ void BTC(int bits, OpArg dest, OpArg index);
+
+ // Double-Precision Shift
+ void SHRD(int bits, OpArg dest, OpArg src, OpArg shift);
+ void SHLD(int bits, OpArg dest, OpArg src, OpArg shift);
+
// Extend EAX into EDX in various ways
void CWD(int bits = 16);
inline void CDQ() {CWD(32);}
diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index b5e731ce15..734d966781 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -101,6 +101,7 @@ set(SRCS Src/ActionReplay.cpp
Src/HW/EXI_DeviceIPL.cpp
Src/HW/EXI_DeviceMemoryCard.cpp
Src/HW/EXI_DeviceMic.cpp
+ Src/HW/GCMemcard.cpp
Src/HW/GCPad.cpp
Src/HW/GCPadEmu.cpp
Src/HW/GPFifo.cpp
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index a9b0176a33..1e0561bc23 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -45,7 +45,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +55,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -117,7 +115,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -129,7 +127,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -141,7 +139,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -155,7 +153,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -169,7 +167,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -183,7 +181,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -289,6 +287,7 @@
<ClCompile Include="Src\HW\EXI_DeviceIPL.cpp" />
<ClCompile Include="Src\HW\EXI_DeviceMemoryCard.cpp" />
<ClCompile Include="Src\HW\EXI_DeviceMic.cpp" />
+ <ClCompile Include="Src\HW\GCMemcard.cpp" />
<ClCompile Include="Src\HW\GCPad.cpp" />
<ClCompile Include="Src\HW\GCPadEmu.cpp" />
<ClCompile Include="Src\HW\GPFifo.cpp" />
@@ -485,6 +484,7 @@
<ClInclude Include="Src\HW\EXI_DeviceIPL.h" />
<ClInclude Include="Src\HW\EXI_DeviceMemoryCard.h" />
<ClInclude Include="Src\HW\EXI_DeviceMic.h" />
+ <ClInclude Include="Src\HW\GCMemcard.h" />
<ClInclude Include="Src\HW\GCPad.h" />
<ClInclude Include="Src\HW\GCPadEmu.h" />
<ClInclude Include="Src\HW\GPFifo.h" />
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index e51098f2ec..66b25af176 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -553,6 +553,9 @@
<Filter>FifoPlayer</Filter>
</ClCompile>
<ClCompile Include="Src\Movie.cpp" />
+ <ClCompile Include="Src\HW\GCMemcard.cpp">
+ <Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ConfigManager.h" />
@@ -1027,6 +1030,9 @@
<Filter>FifoPlayer</Filter>
</ClInclude>
<ClInclude Include="Src\Movie.h" />
+ <ClInclude Include="Src\HW\GCMemcard.h">
+ <Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
@@ -1165,5 +1171,8 @@
<Filter Include="FifoPlayer">
<UniqueIdentifier>{ca7d56f7-4e84-4d15-9aea-7ae6fa7d6586}</UniqueIdentifier>
</Filter>
+ <Filter Include="HW %28Flipper/Hollywood%29\GCMemcard">
+ <UniqueIdentifier>{3e9e6e83-c1bf-45f9-aeff-231f98f60d29}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/Source/Core/Core/SConscript b/Source/Core/Core/SConscript
index 2f350557ec..3dafad8a62 100644
--- a/Source/Core/Core/SConscript
+++ b/Source/Core/Core/SConscript
@@ -97,6 +97,7 @@ files = [
'Src/HW/EXI_DeviceIPL.cpp',
'Src/HW/EXI_DeviceMemoryCard.cpp',
'Src/HW/EXI_DeviceMic.cpp',
+ 'Src/HW/GCMemcard.cpp',
'Src/HW/GCPad.cpp',
'Src/HW/GCPadEmu.cpp',
'Src/HW/GPFifo.cpp',
diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp
index 5a9880533e..3dcbf5730c 100644
--- a/Source/Core/Core/Src/Boot/Boot.cpp
+++ b/Source/Core/Core/Src/Boot/Boot.cpp
@@ -195,10 +195,13 @@ bool CBoot::BootUp()
NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str());
- // HLE jump to loader (homebrew)
- HLE::Patch(0x80001800, "HBReload");
- const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' };
- Memory::WriteBigEData(stubstr, 0x80001804, 8);
+ // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler
+ if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
+ {
+ HLE::Patch(0x80001800, "HBReload");
+ const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' };
+ Memory::WriteBigEData(stubstr, 0x80001804, 8);
+ }
g_symbolDB.Clear();
VideoInterface::Preset(_StartupPara.bNTSC);
diff --git a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
index c04938ca65..2555416a04 100644
--- a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
@@ -66,7 +66,7 @@ bool CBoot::EmulatedBS2_GC()
DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info
Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag
- Memory::Write_U32(0x01800000, 0x80000028); // Physical Memory Size (24MB on retail)
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
// TODO determine why some games fail when using a retail id. (Seem to take different EXI paths, see ikaruga for example)
Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2
@@ -172,7 +172,6 @@ bool CBoot::EmulatedBS2_GC()
return true;
}
-
bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
{
INFO_LOG(BOOT, "Setup Wii Memory...");
@@ -238,14 +237,14 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // Game Code
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
- Memory::Write_U32(0x01800000, 0x00000028); // MEM1 size 24MB
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
Memory::Write_U32(0x00000000, 0x00000030); // Init
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
// 38, 3C should get start, size of FST through apploader
Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
- Memory::Write_U32(0x01800000, 0x000000f0); // "Simulated memory size" (debug mode?)
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
Memory::Write_U32(0x8179b500, 0x000000f4); // __start
Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp
index 7b0716a3eb..da8337bd04 100644
--- a/Source/Core/Core/Src/ConfigManager.cpp
+++ b/Source/Core/Core/Src/ConfigManager.cpp
@@ -223,7 +223,6 @@ void SConfig::SaveSettings()
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
ini.Set("Core", "MemcardA", m_strMemoryCardA);
ini.Set("Core", "MemcardB", m_strMemoryCardB);
- ini.Set("Core", "ReloadMemcardOnState", b_reloadMCOnState);
ini.Set("Core", "SlotA", m_EXIDevice[0]);
ini.Set("Core", "SlotB", m_EXIDevice[1]);
ini.Set("Core", "SerialPort1", m_EXIDevice[2]);
@@ -354,8 +353,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
- ini.Get("Core", "ReloadMemcardOnState", &b_reloadMCOnState, true);
- ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD_A);
+ ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
ini.Get("Core", "BBA_MAC", &m_bba_mac);
@@ -366,7 +364,7 @@ void SConfig::LoadSettings()
for (int i = 0; i < 4; ++i)
{
sprintf(sidevicenum, "SIDevice%i", i);
- ini.Get("Core", sidevicenum, (u32*)&m_SIDevice[i], i==0 ? SI_GC_CONTROLLER:SI_NONE);
+ ini.Get("Core", sidevicenum, (u32*)&m_SIDevice[i], (i == 0) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE);
}
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
diff --git a/Source/Core/Core/Src/ConfigManager.h b/Source/Core/Core/Src/ConfigManager.h
index 585e3689d6..0c8f3f1af1 100644
--- a/Source/Core/Core/Src/ConfigManager.h
+++ b/Source/Core/Core/Src/ConfigManager.h
@@ -47,12 +47,8 @@ struct SConfig : NonCopyable
std::string m_strMemoryCardA;
std::string m_strMemoryCardB;
- // eject and reload the memory card on state
- // in ZTP and other games if the save file has been deleted from the memory card
- //this is necessary to save after loading a savestate
- bool b_reloadMCOnState;
TEXIDevices m_EXIDevice[3];
- TSIDevices m_SIDevice[4];
+ SIDevices m_SIDevice[4];
std::string m_bba_mac;
// interface language
diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp
index 06fe496eb6..bd4267c074 100644
--- a/Source/Core/Core/Src/Core.cpp
+++ b/Source/Core/Core/Src/Core.cpp
@@ -101,6 +101,7 @@ std::string g_stateFileName;
std::thread g_EmuThread;
static std::thread g_cpu_thread;
+static bool g_requestRefreshInfo;
SCoreStartupParameter g_CoreStartupParameter;
@@ -261,7 +262,7 @@ void Stop() // - Hammertime!
SConfig::GetInstance().m_SYSCONF->Reload();
INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----");
- Movie::g_InputCounter = 0;
+ Movie::g_currentInputCount = 0;
g_bStopping = false;
}
@@ -345,6 +346,8 @@ void EmuThread()
DisplayMessage(cpu_info.Summarize(), 8000);
DisplayMessage(_CoreParameter.m_strFilename, 3000);
+ Movie::Init();
+
HW::Init();
if (!g_video_backend->Initialize(g_pWindowHandle))
@@ -537,15 +540,20 @@ void SaveScreenShot()
SetState(CORE_RUN);
}
+void RequestRefreshInfo()
+{
+ g_requestRefreshInfo = true;
+}
+
// Apply Frame Limit and Display FPS info
// This should only be called from VI
void VideoThrottle()
{
- u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 1) ?
- SConfig::GetInstance().m_Framelimit * 5 : VideoInterface::TargetRefreshRate;
+ u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
+ (SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;
- // Disable the frame-limiter when the throttle (Tab) key is held down
- if (SConfig::GetInstance().m_Framelimit && !Host_GetKeyState('\t'))
+ // Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
+ if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
{
u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;
@@ -561,8 +569,9 @@ void VideoThrottle()
// Update info per second
u32 ElapseTime = (u32)Timer.GetTimeDifference();
- if ((ElapseTime >= 1000 && DrawnVideo > 0) || Movie::g_bFrameStep)
+ if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo)
{
+ g_requestRefreshInfo = false;
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
@@ -599,8 +608,10 @@ void VideoThrottle()
#else // Summary information
std::string SFPS;
- if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
- SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", Movie::g_frameCounter, Movie::g_InputCounter, FPS, VPS, Speed);
+ if (Movie::IsPlayingInput())
+ SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
+ else if (Movie::IsRecordingInput())
+ SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
else
SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
#endif
diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h
index 4b45d4bad2..8bfccc13b5 100644
--- a/Source/Core/Core/Src/Core.h
+++ b/Source/Core/Core/Src/Core.h
@@ -85,6 +85,7 @@ void StopTrace();
bool ShouldSkipFrame(int skipped);
void VideoThrottle();
+void RequestRefreshInfo();
#ifdef RERECORDING
diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp
index 9aacea5847..235593d679 100644
--- a/Source/Core/Core/Src/CoreTiming.cpp
+++ b/Source/Core/Core/Src/CoreTiming.cpp
@@ -133,6 +133,7 @@ void Init()
void Shutdown()
{
+ MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
@@ -163,6 +164,7 @@ void DoState(PointerWrap &p)
p.Do(fakeDecStartTicks);
p.Do(fakeTBStartValue);
p.Do(fakeTBStartTicks);
+ p.DoMarker("CoreTimingData");
// OK, here we're gonna need to specialize depending on the mode.
// Should do something generic to serialize linked lists.
switch (p.GetMode()) {
@@ -209,6 +211,7 @@ void DoState(PointerWrap &p)
break;
}
}
+ p.DoMarker("CoreTimingEvents");
}
u64 GetTicks()
diff --git a/Source/Core/Core/Src/DSP/DSPCore.cpp b/Source/Core/Core/Src/DSP/DSPCore.cpp
index bd2b3aa8e6..972eb53858 100644
--- a/Source/Core/Core/Src/DSP/DSPCore.cpp
+++ b/Source/Core/Core/Src/DSP/DSPCore.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPCore.h b/Source/Core/Core/Src/DSP/DSPCore.h
index f6a3b4e51f..34466ea4ad 100644
--- a/Source/Core/Core/Src/DSP/DSPCore.h
+++ b/Source/Core/Core/Src/DSP/DSPCore.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPHWInterface.cpp b/Source/Core/Core/Src/DSP/DSPHWInterface.cpp
index 63cff1651f..f2cbbc2b9f 100644
--- a/Source/Core/Core/Src/DSP/DSPHWInterface.cpp
+++ b/Source/Core/Core/Src/DSP/DSPHWInterface.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPHWInterface.h b/Source/Core/Core/Src/DSP/DSPHWInterface.h
index d44bc70ea7..13ea8cf7a1 100644
--- a/Source/Core/Core/Src/DSP/DSPHWInterface.h
+++ b/Source/Core/Core/Src/DSP/DSPHWInterface.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPIntExtOps.h b/Source/Core/Core/Src/DSP/DSPIntExtOps.h
index 33420a5b76..fa6d22edba 100644
--- a/Source/Core/Core/Src/DSP/DSPIntExtOps.h
+++ b/Source/Core/Core/Src/DSP/DSPIntExtOps.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPIntUtil.h b/Source/Core/Core/Src/DSP/DSPIntUtil.h
index 1da1c4eb21..49f8c209c2 100644
--- a/Source/Core/Core/Src/DSP/DSPIntUtil.h
+++ b/Source/Core/Core/Src/DSP/DSPIntUtil.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPInterpreter.cpp b/Source/Core/Core/Src/DSP/DSPInterpreter.cpp
index 8c3a59dbd9..4a841b41e5 100644
--- a/Source/Core/Core/Src/DSP/DSPInterpreter.cpp
+++ b/Source/Core/Core/Src/DSP/DSPInterpreter.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp b/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp
index 408cb48465..1cbced0713 100644
--- a/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp
+++ b/Source/Core/Core/Src/DSP/DSPMemoryMap.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPMemoryMap.h b/Source/Core/Core/Src/DSP/DSPMemoryMap.h
index 8aa0d77647..c271537130 100644
--- a/Source/Core/Core/Src/DSP/DSPMemoryMap.h
+++ b/Source/Core/Core/Src/DSP/DSPMemoryMap.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPStacks.cpp b/Source/Core/Core/Src/DSP/DSPStacks.cpp
index 511dd623ae..d1e70a616a 100644
--- a/Source/Core/Core/Src/DSP/DSPStacks.cpp
+++ b/Source/Core/Core/Src/DSP/DSPStacks.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/DSPStacks.h b/Source/Core/Core/Src/DSP/DSPStacks.h
index 1a5b9e872c..cb808ee8a7 100644
--- a/Source/Core/Core/Src/DSP/DSPStacks.h
+++ b/Source/Core/Core/Src/DSP/DSPStacks.h
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/disassemble.cpp b/Source/Core/Core/Src/DSP/disassemble.cpp
index 3547e7d766..99bd2811b3 100644
--- a/Source/Core/Core/Src/DSP/disassemble.cpp
+++ b/Source/Core/Core/Src/DSP/disassemble.cpp
@@ -19,7 +19,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/DSP/disassemble.h b/Source/Core/Core/Src/DSP/disassemble.h
index dba9f36287..c9c0a304c1 100644
--- a/Source/Core/Core/Src/DSP/disassemble.h
+++ b/Source/Core/Core/Src/DSP/disassemble.h
@@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
====================================================================*/
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp
index e18f26fe43..58ad9eded3 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp
+++ b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp
@@ -85,14 +85,14 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
{
- tlutAddr = (bpMem.tlutXferDest & 0x3FF) << 9;
- tlutXferCount = (bpMem.tlutXferDest & 0x1FFC00) >> 5;
+ tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
+ tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
// TODO - figure out a cleaner way.
if (Core::g_CoreStartupParameter.bWii)
- memAddr = bpmem.tlutXferSrc << 5;
+ memAddr = bpmem.tmem_config.tlut_src << 5;
else
- memAddr = (bpmem.tlutXferSrc & 0xFFFFF) << 5;
+ memAddr = (bpmem.tmem_config.tlut_src & 0xFFFFF) << 5;
}
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
@@ -232,4 +232,4 @@ void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMe
}
}
-} \ No newline at end of file
+}
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.h b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.h
index eb9a978aca..ba2051f848 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.h
@@ -51,4 +51,4 @@ namespace FifoAnalyzer
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMem);
}
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/Src/FifoPlayer/FifoDataFile.cpp
index 7933e67e64..cf252f5f82 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoDataFile.cpp
+++ b/Source/Core/Core/Src/FifoPlayer/FifoDataFile.cpp
@@ -282,4 +282,4 @@ void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector
file.Seek(srcUpdate.dataOffset, SEEK_SET);
file.ReadBytes(dstUpdate.data, srcUpdate.dataSize);
}
-} \ No newline at end of file
+}
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoDataFile.h b/Source/Core/Core/Src/FifoPlayer/FifoDataFile.h
index fc8ce516d6..a95a46c1fd 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoDataFile.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoDataFile.h
@@ -109,4 +109,4 @@ private:
std::vector<FifoFrameInfo> m_Frames;
};
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoFileStruct.h b/Source/Core/Core/Src/FifoPlayer/FifoFileStruct.h
index e35ebd31bf..97e84e7660 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoFileStruct.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoFileStruct.h
@@ -82,4 +82,4 @@ struct FileMemoryUpdate
}
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp
index 060ff4078b..4aea2acc98 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp
+++ b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp
@@ -343,4 +343,4 @@ void FifoPlaybackAnalyzer::StoreWrittenRegion(u32 address, u32 size)
m_WrittenMemory.push_back(range);
}
-} \ No newline at end of file
+}
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.h b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.h
index e8e582cf4c..7e345dd7f7 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.h
@@ -61,4 +61,4 @@ private:
FifoAnalyzer::CPMemory m_CpMem;
};
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h
index 2a02544a20..486c3c69e4 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h
@@ -118,4 +118,4 @@ private:
std::vector<AnalyzedFrameInfo> m_FrameInfo;
};
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.cpp
index bb7b8e3d04..1c0cd7abe1 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.cpp
+++ b/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.cpp
@@ -302,4 +302,4 @@ void FifoRecordAnalyzer::WriteTexMapMemory(int texMap, u32 &writtenTexMaps)
}
FifoRecorder::GetInstance().WriteMemory(imageBase, textureSize, MemoryUpdate::TEXTURE_MAP);
-} \ No newline at end of file
+}
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.h b/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.h
index ccec314272..0ffc279bf3 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoRecordAnalyzer.h
@@ -53,4 +53,4 @@ private:
FifoAnalyzer::CPMemory m_CpMem;
};
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/FifoPlayer/FifoRecorder.h b/Source/Core/Core/Src/FifoPlayer/FifoRecorder.h
index 44e7be5862..a07ba1fd15 100644
--- a/Source/Core/Core/Src/FifoPlayer/FifoRecorder.h
+++ b/Source/Core/Core/Src/FifoPlayer/FifoRecorder.h
@@ -77,4 +77,4 @@ private:
FifoRecordAnalyzer m_RecordAnalyzer;
};
-#endif \ No newline at end of file
+#endif
diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp
index 9ea30b9fb0..11b1ef2580 100644
--- a/Source/Core/Core/Src/GeckoCode.cpp
+++ b/Source/Core/Core/Src/GeckoCode.cpp
@@ -1,3 +1,17 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
#include "GeckoCode.h"
#include "Thread.h"
@@ -5,6 +19,8 @@
#include "ConfigManager.h"
#include "vector"
+#include "PowerPC/PowerPC.h"
+#include "CommonPaths.h"
namespace Gecko
{
@@ -40,6 +56,9 @@ static struct
// codes execute when counter is 0
static int code_execution_counter = 0;
+// Track whether the code handler has been installed
+static bool code_handler_installed = false;
+
// the currently active codes
std::vector<GeckoCode> active_codes;
@@ -93,6 +112,70 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
}
inserted_asm_codes.clear();
+
+ code_handler_installed = false;
+}
+
+bool InstallCodeHandler()
+{
+ u32 codelist_location = 0x800028B8; // Debugger on location (0x800022A8 = Debugger off, using codehandleronly.bin)
+ std::string data;
+ std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER;
+ if (!File::ReadFileToString(false, _rCodeHandlerFilename.c_str(), data))
+ return false;
+
+ // Install code handler
+ Memory::WriteBigEData((const u8*)data.data(), 0x80001800, data.length());
+
+ // Turn off Pause on start
+ Memory::Write_U32(0, 0x80002774);
+
+ // Write the Game ID into the location expected by WiiRD
+ Memory::WriteBigEData(Memory::GetPointer(0x80000000), 0x80001800, 6);
+
+ // Create GCT in memory
+ Memory::Write_U32(0x00d0c0de, codelist_location);
+ Memory::Write_U32(0x00d0c0de, codelist_location + 4);
+
+ std::lock_guard<std::mutex> lk(active_codes_lock);
+
+ int i = 0;
+ std::vector<GeckoCode>::iterator
+ gcodes_iter = active_codes.begin(),
+ gcodes_end = active_codes.end();
+ for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
+ {
+ if (gcodes_iter->enabled)
+ {
+ current_code = codes_start = &*gcodes_iter->codes.begin();
+ codes_end = &*gcodes_iter->codes.end();
+ for (; current_code < codes_end; ++current_code)
+ {
+ const GeckoCode::Code& code = *current_code;
+
+ // Make sure we have enough memory to hold the code list
+ if ((codelist_location + 24 + i) < 0x80003000)
+ {
+ Memory::Write_U32(code.address, codelist_location + 8 + i);
+ Memory::Write_U32(code.data, codelist_location + 12 + i);
+ i += 8;
+ }
+ }
+ }
+ }
+
+ Memory::Write_U32(0xff000000, codelist_location + 8 + i);
+ Memory::Write_U32(0x00000000, codelist_location + 12 + i);
+
+ // Turn on codes
+ Memory::Write_U8(1, 0x80001807);
+
+ // Invalidate the icache
+ for (int i = 0; i < data.length(); i += 32)
+ {
+ PowerPC::ppcState.iCache.Invalidate(0x80001800 + i);
+ }
+ return true;
}
bool RunGeckoCode(GeckoCode& gecko_code)
@@ -137,7 +220,7 @@ bool RunGeckoCode(GeckoCode& gecko_code)
gecko_code.enabled = false;
PanicAlertT("GeckoCode failed to run (CT%i CST%i) (%s)"
- "\n(either a bad code or the code type is not yet supported.)"
+ "\n(either a bad code or the code type is not yet supported. Try using the native code handler by placing the codehandler.bin file into the Sys directory and restarting Dolphin.)"
, code.type, code.subtype, gecko_code.name.c_str());
return false;
}
@@ -168,6 +251,44 @@ bool RunActiveCodes()
return true;
}
+void RunCodeHandler()
+{
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
+ {
+ u8 *gameId = Memory::GetPointer(0x80000000);
+ u8 *wiirdId = Memory::GetPointer(0x80001800);
+
+ if (!code_handler_installed || memcmp(gameId, wiirdId, 6))
+ code_handler_installed = InstallCodeHandler();
+
+ if (code_handler_installed)
+ {
+ if (PC == LR)
+ {
+ u32 oldLR = LR;
+ PowerPC::CoreMode oldMode = PowerPC::GetMode();
+
+ PC = 0x800018A8;
+ LR = 0;
+
+ // Execute the code handler in interpreter mode to track when it exits
+ PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
+
+ while (PC != 0)
+ PowerPC::SingleStep();
+
+ PowerPC::SetMode(oldMode);
+ PC = LR = oldLR;
+ }
+ }
+ else
+ {
+ // Use the emulated code handler
+ Gecko::RunActiveCodes();
+ }
+ }
+}
+
const std::map<u32, std::vector<u32> >& GetInsertedAsmCodes() {
return inserted_asm_codes;
}
diff --git a/Source/Core/Core/Src/GeckoCode.h b/Source/Core/Core/Src/GeckoCode.h
index 016e38f3d2..d9a53dcfc3 100644
--- a/Source/Core/Core/Src/GeckoCode.h
+++ b/Source/Core/Core/Src/GeckoCode.h
@@ -1,3 +1,16 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
#ifndef __GECKOCODE_h__
#define __GECKOCODE_h__
@@ -67,6 +80,7 @@ namespace Gecko
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
bool RunActiveCodes();
+ void RunCodeHandler();
const std::map<u32, std::vector<u32> >& GetInsertedAsmCodes();
} // namespace Gecko
diff --git a/Source/Core/Core/Src/GeckoCodeConfig.cpp b/Source/Core/Core/Src/GeckoCodeConfig.cpp
index f0e5a0585b..a23d531f7e 100644
--- a/Source/Core/Core/Src/GeckoCodeConfig.cpp
+++ b/Source/Core/Core/Src/GeckoCodeConfig.cpp
@@ -1,3 +1,16 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
#include "GeckoCodeConfig.h"
diff --git a/Source/Core/Core/Src/GeckoCodeConfig.h b/Source/Core/Core/Src/GeckoCodeConfig.h
index d7e28086c7..0ae630f784 100644
--- a/Source/Core/Core/Src/GeckoCodeConfig.h
+++ b/Source/Core/Core/Src/GeckoCodeConfig.h
@@ -1,3 +1,16 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
#ifndef __GECKOCODECONFIG_h__
#define __GECKOCODECONFIG_h__
diff --git a/Source/Core/Core/Src/HLE/HLE_OS.cpp b/Source/Core/Core/Src/HLE/HLE_OS.cpp
index eebff67ece..3ced001268 100644
--- a/Source/Core/Core/Src/HLE/HLE_OS.cpp
+++ b/Source/Core/Core/Src/HLE/HLE_OS.cpp
@@ -69,9 +69,10 @@ void GetStringVA(std::string& _rOutBuffer, u32 strReg)
char ArgumentBuffer[256];
u32 ParameterCounter = 4;
u32 FloatingParameterCounter = 1;
- char* pString = (char*)Memory::GetPointer(GPR(strReg));
- if (!pString) {
- //PanicAlert("Invalid GetStringVA call");
+ char *pString = (char*)Memory::GetPointer(GPR(strReg));
+ if (!pString)
+ {
+ ERROR_LOG(OSREPORT, "r%i invalid", strReg);
return;
}
diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp
index 4f1fbb920f..40b0c620b3 100644
--- a/Source/Core/Core/Src/HW/AudioInterface.cpp
+++ b/Source/Core/Core/Src/HW/AudioInterface.cpp
@@ -153,6 +153,12 @@ void Init()
m_Volume.hex = 0;
m_SampleCounter = 0;
m_InterruptTiming = 0;
+
+ g_LastCPUTime = 0;
+ g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
+
+ g_AISSampleRate = 48000;
+ g_AIDSampleRate = 32000;
}
void Shutdown()
diff --git a/Source/Core/Core/Src/HW/CPU.cpp b/Source/Core/Core/Src/HW/CPU.cpp
index 69b5055c9f..0f461b0fc5 100644
--- a/Source/Core/Core/Src/HW/CPU.cpp
+++ b/Source/Core/Core/Src/HW/CPU.cpp
@@ -115,6 +115,7 @@ void CCPU::EnableStepping(const bool _bStepping)
if (_bStepping)
{
PowerPC::Pause();
+ m_StepEvent.Reset();
g_video_backend->EmuStateChange(EMUSTATE_CHANGE_PAUSE);
DSP::GetDSPEmulator()->DSP_ClearAudioBuffer(true);
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp b/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp
index 069bbedc63..65362a19a0 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp
@@ -131,7 +131,51 @@ void DSPHLE::SwapUCode(u32 _crc)
void DSPHLE::DoState(PointerWrap &p)
{
p.Do(m_InitMixer);
- GetUCode()->DoState(p);
+ p.Do(m_DSPControl);
+ p.Do(m_dspState);
+
+ int ucode_crc = IUCode::GetCRC(m_pUCode);
+ int ucode_crc_beforeLoad = ucode_crc;
+ int lastucode_crc = IUCode::GetCRC(m_lastUCode);
+ int lastucode_crc_beforeLoad = lastucode_crc;
+
+ p.Do(ucode_crc);
+ p.Do(lastucode_crc);
+
+ // if a different type of ucode was being used when the savestate was created,
+ // we have to reconstruct the old type of ucode so that we have a valid thing to call DoState on.
+ IUCode* ucode = (ucode_crc == ucode_crc_beforeLoad) ? m_pUCode : UCodeFactory( ucode_crc, this, m_bWii);
+ IUCode* lastucode = (lastucode_crc != lastucode_crc_beforeLoad) ? m_lastUCode : UCodeFactory(lastucode_crc, this, m_bWii);
+
+ if (ucode)
+ ucode->DoState(p);
+ if (lastucode)
+ lastucode->DoState(p);
+
+ // if a different type of ucode was being used when the savestate was created,
+ // discard it if we're not loading, otherwise discard the old one and keep the new one.
+ if (ucode != m_pUCode)
+ {
+ if (p.GetMode() != PointerWrap::MODE_READ)
+ delete ucode;
+ else
+ {
+ delete m_pUCode;
+ m_pUCode = ucode;
+ }
+ }
+ if (lastucode != m_lastUCode)
+ {
+ if (p.GetMode() != PointerWrap::MODE_READ)
+ delete lastucode;
+ else
+ {
+ delete m_lastUCode;
+ m_lastUCode = lastucode;
+ }
+ }
+
+ m_MailHandler.DoState(p);
}
// Mailbox fuctions
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
index 8c88217494..33f0d2f1e6 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp
@@ -28,9 +28,8 @@
#include "UCode_AX_Voice.h"
CUCode_AX::CUCode_AX(DSPHLE *dsp_hle, u32 l_CRC)
- : IUCode(dsp_hle)
+ : IUCode(dsp_hle, l_CRC)
, m_addressPBs(0xFFFFFFFF)
- , _CRC(l_CRC)
{
// we got loaded
m_rMailHandler.PushMail(DSP_INIT);
@@ -175,7 +174,7 @@ void CUCode_AX::MixAdd(short* _pBuffer, int _iSize)
ProcessUpdates(PB);
- if (_CRC != 0x3389a79e)
+ if (m_CRC != 0x3389a79e)
VoiceHacks(PB);
MixAddVoice(PB, templbuffer, temprbuffer, _iSize);
@@ -463,11 +462,8 @@ void CUCode_AX::DoState(PointerWrap &p)
{
std::lock_guard<std::mutex> lk(m_csMix);
- p.Do(_CRC);
p.Do(numPBaddr);
p.Do(m_addressPBs);
p.Do(PBaddr);
p.Do(m_UploadSetupInProgress);
-
- m_rMailHandler.DoState(p);
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
index 6386e3ce6a..edb52a2801 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h
@@ -41,7 +41,6 @@ public:
u8 numPBaddr;
u32 PBaddr[8]; //2 needed for MP2
u32 m_addressPBs;
- u32 _CRC;
private:
enum
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
index 41f044f9be..6300b35b4a 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp
@@ -28,9 +28,8 @@
CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
- : IUCode(dsp_hle)
+ : IUCode(dsp_hle, l_CRC)
, m_addressPBs(0xFFFFFFFF)
- , _CRC(l_CRC)
{
// we got loaded
m_rMailHandler.PushMail(DSP_INIT);
@@ -38,7 +37,7 @@ CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC)
templbuffer = new int[1024 * 1024];
temprbuffer = new int[1024 * 1024];
- wiisportsHack = _CRC == 0xfa450138;
+ wiisportsHack = m_CRC == 0xfa450138;
}
CUCode_AXWii::~CUCode_AXWii()
@@ -260,10 +259,7 @@ void CUCode_AXWii::DoState(PointerWrap &p)
{
std::lock_guard<std::mutex> lk(m_csMix);
- p.Do(_CRC);
p.Do(m_addressPBs);
p.Do(wiisportsHack);
p.Do(m_UploadSetupInProgress);
-
- m_rMailHandler.DoState(p);
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
index 442d77ab85..dcd4e24e3f 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.cpp
@@ -21,8 +21,8 @@
#include "../../DSP.h"
-CUCode_CARD::CUCode_CARD(DSPHLE *dsp_hle)
- : IUCode(dsp_hle)
+CUCode_CARD::CUCode_CARD(DSPHLE *dsp_hle, u32 crc)
+ : IUCode(dsp_hle, crc)
{
DEBUG_LOG(DSPHLE, "CUCode_CARD - initialized");
m_rMailHandler.PushMail(DSP_INIT);
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.h
index 0246d4680a..a6f90124ad 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_CARD.h
@@ -23,7 +23,7 @@
class CUCode_CARD : public IUCode
{
public:
- CUCode_CARD(DSPHLE *dsp_hle);
+ CUCode_CARD(DSPHLE *dsp_hle, u32 crc);
virtual ~CUCode_CARD();
void HandleMail(u32 _uMail);
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.cpp
index b82c7ac0b2..42bc18ff49 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.cpp
@@ -20,8 +20,8 @@
#include "../../DSP.h"
-CUCode_GBA::CUCode_GBA(DSPHLE *dsp_hle)
-: IUCode(dsp_hle)
+CUCode_GBA::CUCode_GBA(DSPHLE *dsp_hle, u32 crc)
+: IUCode(dsp_hle, crc)
{
m_rMailHandler.PushMail(DSP_INIT);
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.h
index 412036835d..c61917339f 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_GBA.h
@@ -21,7 +21,7 @@
struct CUCode_GBA : public IUCode
{
- CUCode_GBA(DSPHLE *dsp_hle);
+ CUCode_GBA(DSPHLE *dsp_hle, u32 crc);
virtual ~CUCode_GBA();
void HandleMail(u32 _uMail);
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
index 663d4beadd..ae7716012a 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp
@@ -18,8 +18,8 @@
#include "UCodes.h"
#include "UCode_InitAudioSystem.h"
-CUCode_InitAudioSystem::CUCode_InitAudioSystem(DSPHLE *dsp_hle)
- : IUCode(dsp_hle)
+CUCode_InitAudioSystem::CUCode_InitAudioSystem(DSPHLE *dsp_hle, u32 crc)
+ : IUCode(dsp_hle, crc)
{
DEBUG_LOG(DSPHLE, "CUCode_InitAudioSystem - initialized");
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.h
index 09b54a4a4b..8dc237f1d0 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.h
@@ -23,7 +23,7 @@
class CUCode_InitAudioSystem : public IUCode
{
public:
- CUCode_InitAudioSystem(DSPHLE *dsp_hle);
+ CUCode_InitAudioSystem(DSPHLE *dsp_hle, u32 crc);
virtual ~CUCode_InitAudioSystem();
void HandleMail(u32 _uMail);
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
index 48dba7e28b..c1544792f5 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.cpp
@@ -20,8 +20,8 @@
#include "Hash.h"
#include "../../Memmap.h"
-CUCode_Rom::CUCode_Rom(DSPHLE *dsp_hle)
- : IUCode(dsp_hle)
+CUCode_Rom::CUCode_Rom(DSPHLE *dsp_hle, u32 crc)
+ : IUCode(dsp_hle, crc)
, m_CurrentUCode()
, m_BootTask_numSteps(0)
, m_NextParameter(0)
@@ -117,4 +117,10 @@ void CUCode_Rom::BootUCode()
m_DSPHLE->SetUCode(ector_crc);
}
+void CUCode_Rom::DoState(PointerWrap &p)
+{
+ p.Do(m_CurrentUCode);
+ p.Do(m_BootTask_numSteps);
+ p.Do(m_NextParameter);
+}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.h
index ecec9f87ea..f1e7b8ec7a 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_ROM.h
@@ -23,12 +23,14 @@
class CUCode_Rom : public IUCode
{
public:
- CUCode_Rom(DSPHLE *dsp_hle);
+ CUCode_Rom(DSPHLE *dsp_hle, u32 _crc);
virtual ~CUCode_Rom();
void HandleMail(u32 _uMail);
void Update(int cycles);
+ void DoState(PointerWrap &p);
+
private:
struct SUCode
{
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp
index 913de7107b..713236180d 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp
@@ -31,8 +31,7 @@
CUCode_Zelda::CUCode_Zelda(DSPHLE *dsp_hle, u32 _CRC)
:
- IUCode(dsp_hle),
- m_CRC(_CRC),
+ IUCode(dsp_hle, _CRC),
m_bSyncInProgress(false),
m_MaxVoice(0),
@@ -572,8 +571,6 @@ void CUCode_Zelda::DoState(PointerWrap &p)
// It's bad if we try to save during Mix()
std::lock_guard<std::mutex> lk(m_csMix);
- p.Do(m_CRC);
-
p.Do(m_AFCCoefTable);
p.Do(m_MiscTable);
@@ -616,6 +613,4 @@ void CUCode_Zelda::DoState(PointerWrap &p)
p.Do(m_PBAddress2);
p.Do(m_UploadSetupInProgress);
-
- m_rMailHandler.DoState(p);
}
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.h
index 3abe711c5b..f8a69536c2 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda.h
@@ -212,8 +212,6 @@ private:
}
}
- u32 m_CRC;
-
// These are the only dynamically allocated things allowed in the ucode.
s32* m_VoiceBuffer;
s16* m_ResampleBuffer;
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp
index a3e787cd8c..67f354007e 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp
@@ -426,18 +426,15 @@ void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s16 *_Buffer, int _Size)
PB.Unk36[0] = (u16)(ACC0 >> 16);
- // This subtract does really not make much sense at all.
ACC0 -= AX0 << 16;
if ((s64)ACC0 < 0)
{
- // There's something wrong with this looping code.
-
- ERROR_LOG(DSPHLE, "Raw loop: ReadAudio size = %04x 34:%04x %08x", PB.Unk36[0], PB.raw[0x34 ^ 1], (int)ACC0);
+ // ERROR_LOG(DSPHLE, "Raw loop: ReadAudio size = %04x 34:%04x %08x", PB.Unk36[0], PB.raw[0x34 ^ 1], (int)ACC0);
Decoder21_ReadAudio(PB, PB.Unk36[0], _Buffer);
- ACC0 = _Size << 16;
- ACC0 -= PB.Unk36[0] << 16;
+ ACC0 = -(s64)ACC0;
+ _Buffer += PB.Unk36[0];
PB.raw[0x34 ^ 1] = 0;
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp
index c982b97f51..62620253aa 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp
@@ -32,19 +32,19 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
{
case UCODE_ROM:
INFO_LOG(DSPHLE, "Switching to ROM ucode");
- return new CUCode_Rom(dsp_hle);
+ return new CUCode_Rom(dsp_hle, _CRC);
case UCODE_INIT_AUDIO_SYSTEM:
INFO_LOG(DSPHLE, "Switching to INIT ucode");
- return new CUCode_InitAudioSystem(dsp_hle);
+ return new CUCode_InitAudioSystem(dsp_hle, _CRC);
case 0x65d6cc6f: // CARD
INFO_LOG(DSPHLE, "Switching to CARD ucode");
- return new CUCode_CARD(dsp_hle);
+ return new CUCode_CARD(dsp_hle, _CRC);
case 0xdd7e72d5:
INFO_LOG(DSPHLE, "Switching to GBA ucode");
- return new CUCode_GBA(dsp_hle);
+ return new CUCode_GBA(dsp_hle, _CRC);
case 0x3ad3b7ac: // Naruto3, Paper Mario - The Thousand Year Door
case 0x3daf59b9: // Alien Hominid
@@ -103,6 +103,9 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii)
PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AX.\n\nTry LLE emulator if this is homebrew.", _CRC);
return new CUCode_AX(dsp_hle, _CRC);
}
+
+ case UCODE_NULL:
+ break;
}
return NULL;
diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.h
index cb3bc6a4f0..faea895609 100644
--- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.h
+++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.h
@@ -25,8 +25,9 @@
#include "../DSPHLE.h"
#include "../../Memmap.h"
-#define UCODE_ROM 0x0000000
-#define UCODE_INIT_AUDIO_SYSTEM 0x0000001
+#define UCODE_ROM 0x00000000
+#define UCODE_INIT_AUDIO_SYSTEM 0x00000001
+#define UCODE_NULL 0xFFFFFFFF
class CMailHandler;
@@ -73,10 +74,11 @@ inline void* HLEMemory_Get_Pointer(u32 _uAddress)
class IUCode
{
public:
- IUCode(DSPHLE *dsphle)
+ IUCode(DSPHLE *dsphle, u32 _crc)
: m_rMailHandler(dsphle->AccessMailHandler())
, m_UploadSetupInProgress(false)
, m_DSPHLE(dsphle)
+ , m_CRC(_crc)
, m_NextUCode()
, m_NextUCode_steps(0)
, m_NeedsResumeMail(false)
@@ -93,6 +95,8 @@ public:
virtual void DoState(PointerWrap &p) {}
+ static u32 GetCRC(IUCode* pUCode) { return pUCode ? pUCode->m_CRC : UCODE_NULL; }
+
protected:
void PrepareBootUCode(u32 mail);
@@ -121,6 +125,10 @@ protected:
// Need a pointer back to DSPHLE to switch ucodes.
DSPHLE *m_DSPHLE;
+ // used for reconstruction when loading saves,
+ // and for variations within certain ucodes.
+ u32 m_CRC;
+
private:
struct SUCode
{
diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp
index 7ee5f68001..a795b4966d 100644
--- a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp
+++ b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp
@@ -49,6 +49,9 @@ DSPLLE::DSPLLE() {
m_cycle_count = 0;
}
+Common::Event dspEvent;
+Common::Event ppcEvent;
+
void DSPLLE::DoState(PointerWrap &p)
{
p.Do(g_dsp.r);
@@ -96,7 +99,10 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
Common::AtomicStore(dsp_lle->m_cycle_count, 0);
}
else
- Common::YieldCPU();
+ {
+ ppcEvent.Set();
+ dspEvent.Wait();
+ }
}
}
@@ -138,6 +144,8 @@ void DSPLLE::DSP_StopSoundStream()
m_bIsRunning = false;
if (m_bDSPThread)
{
+ ppcEvent.Set();
+ dspEvent.Set();
m_hDSPThread.join();
}
}
@@ -274,9 +282,10 @@ void DSPLLE::DSP_Update(int cycles)
else
{
// Wait for dsp thread to complete its cycle. Note: this logic should be thought through.
- while (m_cycle_count != 0)
- ;
+ ppcEvent.Wait();
Common::AtomicStore(m_cycle_count, dsp_cycles);
+ dspEvent.Set();
+
}
}
diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp
index cea7486426..205cd00448 100644
--- a/Source/Core/Core/Src/HW/DVDInterface.cpp
+++ b/Source/Core/Core/Src/HW/DVDInterface.cpp
@@ -522,7 +522,7 @@ void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt)
void ExecuteCommand(UDICR& _DICR)
{
// _dbg_assert_(DVDINTERFACE, _DICR.RW == 0); // only DVD to Memory
- int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SI_AM_BASEBOARD)
+ int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD)
&& (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD))
? 1 : 0;
diff --git a/Source/Core/Core/Src/HW/EXI.cpp b/Source/Core/Core/Src/HW/EXI.cpp
index 7c93d5a567..bfc5c28819 100644
--- a/Source/Core/Core/Src/HW/EXI.cpp
+++ b/Source/Core/Core/Src/HW/EXI.cpp
@@ -64,29 +64,31 @@ void Shutdown()
void DoState(PointerWrap &p)
{
- // TODO: Complete DoState for each IEXIDevice
- g_Channels[0]->GetDevice(1)->DoState(p);
- g_Channels[0]->GetDevice(2)->DoState(p);
- g_Channels[0]->GetDevice(4)->DoState(p);
- g_Channels[1]->GetDevice(1)->DoState(p);
- g_Channels[2]->GetDevice(1)->DoState(p);
+ for (int c = 0; c < NUM_CHANNELS; ++c)
+ g_Channels[c]->DoState(p);
+}
+
+void OnAfterLoad()
+{
+ for (int c = 0; c < NUM_CHANNELS; ++c)
+ g_Channels[c]->OnAfterLoad();
}
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
{
u8 channel = (u8)(userdata >> 32);
- u8 device = (u8)(userdata >> 16);
- u8 slot = (u8)userdata;
+ u8 type = (u8)(userdata >> 16);
+ u8 num = (u8)userdata;
- g_Channels[channel]->AddDevice((TEXIDevices)device, slot);
+ g_Channels[channel]->AddDevice((TEXIDevices)type, num);
}
-void ChangeDevice(u8 channel, TEXIDevices device, u8 slot)
+void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num)
{
// Called from GUI, so we need to make it thread safe.
// Let the hardware see no device for .5b cycles
- CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | slot);
- CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device << 16) | slot);
+ CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | device_num);
+ CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device_type << 16) | device_num);
}
// Unused (?!)
diff --git a/Source/Core/Core/Src/HW/EXI.h b/Source/Core/Core/Src/HW/EXI.h
index 867700947a..1b913b7da1 100644
--- a/Source/Core/Core/Src/HW/EXI.h
+++ b/Source/Core/Core/Src/HW/EXI.h
@@ -28,12 +28,13 @@ namespace ExpansionInterface
void Init();
void Shutdown();
void DoState(PointerWrap &p);
+void OnAfterLoad();
void Update();
void UpdateInterrupts();
void ChangeDeviceCallback(u64 userdata, int cyclesLate);
-void ChangeDevice(u8 channel, TEXIDevices device, u8 slot);
+void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num);
void Read32(u32& _uReturnValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp
index 9ab0fd13d3..91cb691546 100644
--- a/Source/Core/Core/Src/HW/EXI_Channel.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Channel.cpp
@@ -18,6 +18,8 @@
#include "EXI_Channel.h"
#include "EXI_Device.h"
#include "EXI.h"
+#include "../ConfigManager.h"
+#include "../Movie.h"
#define EXI_READ 0
#define EXI_WRITE 1
@@ -42,7 +44,7 @@ CEXIChannel::CEXIChannel(u32 ChannelId) :
m_Status.CHIP_SELECT = 1;
for (int i = 0; i < NUM_DEVICES; i++)
- m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE);
+ m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId);
}
CEXIChannel::~CEXIChannel()
@@ -59,26 +61,35 @@ void CEXIChannel::RemoveDevices()
}
}
-void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot)
+void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
{
- _dbg_assert_(EXPANSIONINTERFACE, _iSlot < NUM_DEVICES);
+ IEXIDevice* pNewDevice = EXIDevice_Create(device_type, m_ChannelId);
+ AddDevice(pNewDevice, device_num);
+}
+
+void CEXIChannel::AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged)
+{
+ _dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES);
// delete the old device
- if (m_pDevices[_iSlot] != NULL)
+ if (m_pDevices[device_num] != NULL)
{
- delete m_pDevices[_iSlot];
- m_pDevices[_iSlot] = NULL;
+ delete m_pDevices[device_num];
+ m_pDevices[device_num] = NULL;
}
- // create the new one
- m_pDevices[_iSlot] = EXIDevice_Create(_device);
+ // replace it with the new one
+ m_pDevices[device_num] = pDevice;
- // This means "device presence changed", software has to check
- // m_Status.EXT to see if it is now present or not
- if (m_ChannelId != 2)
+ if(notifyPresenceChanged)
{
- m_Status.EXTINT = 1;
- UpdateInterrupts();
+ // This means "device presence changed", software has to check
+ // m_Status.EXT to see if it is now present or not
+ if (m_ChannelId != 2)
+ {
+ m_Status.EXTINT = 1;
+ UpdateInterrupts();
+ }
}
}
@@ -107,9 +118,9 @@ bool CEXIChannel::IsCausingInterrupt()
}
}
-IEXIDevice* CEXIChannel::GetDevice(u8 _CHIP_SELECT)
+IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select)
{
- switch(_CHIP_SELECT)
+ switch (chip_select)
{
case 1: return m_pDevices[0];
case 2: return m_pDevices[1];
@@ -264,3 +275,43 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
break;
}
}
+
+void CEXIChannel::DoState(PointerWrap &p)
+{
+ p.Do(m_Status);
+ p.Do(m_DMAMemoryAddress);
+ p.Do(m_DMALength);
+ p.Do(m_Control);
+ p.Do(m_ImmData);
+
+ for (int d = 0; d < NUM_DEVICES; ++d)
+ {
+ IEXIDevice* pDevice = m_pDevices[d];
+ TEXIDevices type = pDevice->m_deviceType;
+ p.Do(type);
+ IEXIDevice* pSaveDevice = (type == pDevice->m_deviceType) ? pDevice : EXIDevice_Create(type, m_ChannelId);
+ pSaveDevice->DoState(p);
+ if(pSaveDevice != pDevice)
+ {
+ // if we had to create a temporary device, discard it if we're not loading.
+ // also, if no movie is active, we'll assume the user wants to keep their current devices
+ // instead of the ones they had when the savestate was created,
+ // unless the device is NONE (since ChangeDevice sets that temporarily).
+ if(p.GetMode() != PointerWrap::MODE_READ)
+ {
+ delete pSaveDevice;
+ }
+ else
+ {
+ AddDevice(pSaveDevice, d, false);
+ }
+ }
+ }
+}
+
+void CEXIChannel::OnAfterLoad()
+{
+ for (int d = 0; d < NUM_DEVICES; ++d)
+ m_pDevices[d]->OnAfterLoad();
+}
+
diff --git a/Source/Core/Core/Src/HW/EXI_Channel.h b/Source/Core/Core/Src/HW/EXI_Channel.h
index df39939f38..21925f52e5 100644
--- a/Source/Core/Core/Src/HW/EXI_Channel.h
+++ b/Source/Core/Core/Src/HW/EXI_Channel.h
@@ -112,12 +112,13 @@ private:
public:
// get device
- IEXIDevice* GetDevice(u8 _CHIP_SELECT);
+ IEXIDevice* GetDevice(const u8 _CHIP_SELECT);
CEXIChannel(u32 ChannelId);
~CEXIChannel();
- void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
+ void AddDevice(const TEXIDevices device_type, const int device_num);
+ void AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged=true);
// Remove all devices
void RemoveDevices();
@@ -128,6 +129,8 @@ public:
void Update();
bool IsCausingInterrupt();
void UpdateInterrupts();
+ void DoState(PointerWrap &p);
+ void OnAfterLoad();
// This should only be used to transition interrupts from SP1 to Channel 2
void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp
index fc73f4e0d8..9c40a8f4d1 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.cpp
+++ b/Source/Core/Core/Src/HW/EXI_Device.cpp
@@ -102,49 +102,52 @@ public:
// F A C T O R Y
-IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
+IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num)
{
- switch(_EXIDevice)
+ IEXIDevice* result = NULL;
+
+ switch (device_type)
{
case EXIDEVICE_DUMMY:
- return new CEXIDummy("Dummy");
- break;
-
- case EXIDEVICE_MEMORYCARD_A:
- return new CEXIMemoryCard("MemoryCardA", SConfig::GetInstance().m_strMemoryCardA, 0);
+ result = new CEXIDummy("Dummy");
break;
- case EXIDEVICE_MEMORYCARD_B:
- return new CEXIMemoryCard("MemoryCardB", SConfig::GetInstance().m_strMemoryCardB, 1);
+ case EXIDEVICE_MEMORYCARD:
+ result = new CEXIMemoryCard(channel_num);
break;
case EXIDEVICE_MASKROM:
- return new CEXIIPL();
+ result = new CEXIIPL();
break;
case EXIDEVICE_AD16:
- return new CEXIAD16();
+ result = new CEXIAD16();
break;
case EXIDEVICE_MIC:
- return new CEXIMic(1);
+ result = new CEXIMic(channel_num);
break;
case EXIDEVICE_ETH:
- return new CEXIETHERNET(SConfig::GetInstance().m_bba_mac);
+ result = new CEXIETHERNET(SConfig::GetInstance().m_bba_mac);
break;
case EXIDEVICE_AM_BASEBOARD:
- return new CEXIAMBaseboard();
+ result = new CEXIAMBaseboard();
break;
case EXIDEVICE_GECKO:
- return new CEXIGecko();
+ result = new CEXIGecko();
break;
case EXIDEVICE_NONE:
default:
- return new IEXIDevice();
+ result = new IEXIDevice();
break;
}
+
+ if (result != NULL)
+ result->m_deviceType = device_type;
+
+ return result;
}
diff --git a/Source/Core/Core/Src/HW/EXI_Device.h b/Source/Core/Core/Src/HW/EXI_Device.h
index 4cc613950b..8cb2f99a64 100644
--- a/Source/Core/Core/Src/HW/EXI_Device.h
+++ b/Source/Core/Core/Src/HW/EXI_Device.h
@@ -21,6 +21,19 @@
#include "Common.h"
#include "ChunkFile.h"
+enum TEXIDevices
+{
+ EXIDEVICE_DUMMY,
+ EXIDEVICE_MEMORYCARD,
+ EXIDEVICE_MASKROM,
+ EXIDEVICE_AD16,
+ EXIDEVICE_MIC,
+ EXIDEVICE_ETH,
+ EXIDEVICE_AM_BASEBOARD,
+ EXIDEVICE_GECKO,
+ EXIDEVICE_NONE = (u8)-1
+};
+
class IEXIDevice
{
private:
@@ -40,30 +53,20 @@ public:
virtual bool IsPresent() {return false;}
virtual void SetCS(int) {}
virtual void DoState(PointerWrap&) {}
+ virtual void OnAfterLoad() {}
// Update
virtual void Update() {}
// Is generating interrupt ?
virtual bool IsInterruptSet() {return false;}
- virtual ~IEXIDevice() {};
+ virtual ~IEXIDevice() {}
+ // for savestates. storing it here seemed cleaner than requiring each implementation to report its type.
+ // I know this class is set up like an interface, but no code requires it to be strictly such.
+ TEXIDevices m_deviceType;
};
-enum TEXIDevices
-{
- EXIDEVICE_DUMMY,
- EXIDEVICE_MEMORYCARD_A,
- EXIDEVICE_MEMORYCARD_B,
- EXIDEVICE_MASKROM,
- EXIDEVICE_AD16,
- EXIDEVICE_MIC,
- EXIDEVICE_ETH,
- EXIDEVICE_AM_BASEBOARD,
- EXIDEVICE_GECKO,
- EXIDEVICE_NONE = (u8)-1
-};
-
-extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
+extern IEXIDevice* EXIDevice_Create(const TEXIDevices device_type, const int channel_num);
#endif
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp b/Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp
index 3b1b234d41..f65749865b 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAD16.cpp
@@ -90,3 +90,10 @@ void CEXIAD16::TransferByte(u8& _byte)
m_uPosition++;
}
+
+void CEXIAD16::DoState(PointerWrap &p)
+{
+ p.Do(m_uPosition);
+ p.Do(m_uCommand);
+ p.Do(m_uAD16Register);
+}
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAD16.h b/Source/Core/Core/Src/HW/EXI_DeviceAD16.h
index 094b26974a..62b7da0592 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceAD16.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAD16.h
@@ -24,6 +24,7 @@ public:
CEXIAD16();
virtual void SetCS(int _iCS);
virtual bool IsPresent();
+ virtual void DoState(PointerWrap &p);
private:
enum
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp
index a1b8be2eee..762c87a7d4 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp
@@ -128,3 +128,10 @@ bool CEXIAMBaseboard::IsInterruptSet()
ERROR_LOG(SP1, "AM-BB IRQ");
return m_have_irq;
}
+
+void CEXIAMBaseboard::DoState(PointerWrap &p)
+{
+ p.Do(m_position);
+ p.Do(m_have_irq);
+ p.Do(m_command);
+}
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h
index 091b478688..92a2ac4a8f 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h
@@ -26,6 +26,7 @@ public:
virtual void SetCS(int _iCS);
virtual bool IsPresent();
virtual bool IsInterruptSet();
+ virtual void DoState(PointerWrap &p);
private:
virtual void TransferByte(u8& _uByte);
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp
index 72a84d12b2..6572233b20 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp
@@ -415,4 +415,26 @@ void CEXIETHERNET::DMARead(u32 addr, u32 size)
ERROR_LOG(SP1, "Unhandled BBA DMA read: %i, %08x", size, addr);
}
+
+void CEXIETHERNET::DoState(PointerWrap &p)
+{
+ p.Do(m_uPosition);
+ p.Do(m_uCommand);
+ p.Do(m_bInterruptSet);
+ p.Do(mWriteP);
+ p.Do(mReadP);
+ p.Do(mExpectSpecialImmRead);
+ p.Do(mSpecialImmData);
+ p.Do(Activated);
+ p.Do(mRBRPP);
+ p.Do(mRBEmpty);
+ p.Do(mBbaMem);
+ p.Do(mExpectVariableLengthImmWrite);
+ p.Do(mReadyToSend);
+ p.Do(RegisterBlock);
+ // TODO?
+ //mWriteBuffer.DoState(p);
+ //mCbw.DoState(p);
+}
+
//#pragma optimize("",on)
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h
index ad70f9462b..3fa3a42d34 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h
@@ -246,6 +246,7 @@ public:
u32 ImmRead(u32 size);
void DMAWrite(u32 addr, u32 size);
void DMARead(u32 addr, u32 size);
+ void DoState(PointerWrap &p);
//private:
// STATE_TO_SAVE
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp
index 620b7e79b8..4aefb6dbdb 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp
@@ -25,6 +25,8 @@
#include "MemoryUtil.h"
#include "FileUtil.h"
#include "../Movie.h"
+#include "../CoreTiming.h"
+#include "SystemTimers.h"
// We should provide an option to choose from the above, or figure out the checksum (the algo in yagcd seems wrong)
// so that people can change default language.
@@ -107,7 +109,7 @@ CEXIIPL::CEXIIPL() :
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHLE_BS2)
{
// Copy header
- memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, sizeof(m_bNTSC ? iplverNTSC : iplverPAL));
+ memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, m_bNTSC ? sizeof(iplverNTSC) : sizeof(iplverPAL));
// Load fonts
LoadFileToIPL((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_SJIS), 0x1aff00);
@@ -152,7 +154,13 @@ CEXIIPL::~CEXIIPL()
}
void CEXIIPL::DoState(PointerWrap &p)
{
- p.DoArray(m_RTC, 4);
+ p.Do(m_RTC);
+ p.Do(m_uPosition);
+ p.Do(m_uAddress);
+ p.Do(m_uRWOffset);
+ p.Do(m_szBuffer);
+ p.Do(m_count);
+ p.Do(m_FontsLoaded);
}
void CEXIIPL::LoadFileToIPL(std::string filename, u32 offset)
@@ -336,14 +344,23 @@ void CEXIIPL::TransferByte(u8& _uByte)
u32 CEXIIPL::GetGCTime()
{
u64 ltime = 0;
- const u32 cJanuary2000 = 0x386D4380; // Seconds between 1.1.1970 and 1.1.2000
+ static const u32 cJanuary2000 = 0x386D4380; // Seconds between 1.1.1970 and 1.1.2000
- // hack in some netplay stuff
- ltime = NetPlay_GetGCTime();
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
- ltime = 1234567890; // TODO: Should you be able to set a custom time in movies?
- else if (0 == ltime)
- ltime = Common::Timer::GetLocalTimeSinceJan1970();
+ {
+ ltime = Movie::GetRecordingStartTime();
+
+ // let's keep time moving forward, regardless of what it starts at
+ ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond();
+ }
+ else
+ {
+ // hack in some netplay stuff
+ ltime = NetPlay_GetGCTime();
+
+ if (0 == ltime)
+ ltime = Common::Timer::GetLocalTimeSinceJan1970();
+ }
return ((u32)ltime - cJanuary2000);
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
index 341a14bec6..e7f052b864 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp
@@ -22,10 +22,12 @@
#include "../CoreTiming.h"
#include "../ConfigManager.h"
+#include "../Movie.h"
#include "EXI.h"
#include "EXI_Device.h"
#include "EXI_DeviceMemoryCard.h"
#include "Sram.h"
+#include "GCMemcard.h"
#define MC_STATUS_BUSY 0x80
#define MC_STATUS_UNLOCKED 0x40
@@ -34,23 +36,22 @@
#define MC_STATUS_PROGRAMEERROR 0x08
#define MC_STATUS_READY 0x01
#define SIZE_TO_Mb (1024 * 8 * 16)
-
-static CEXIMemoryCard *cards[2];
+#define MC_HDR_SIZE 0xA000
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
{
- CEXIMemoryCard *ptr = cards[userdata];
+ // casting userdata seems less error-prone than indexing a static (creation order issues, etc.)
+ CEXIMemoryCard *ptr = (CEXIMemoryCard*)userdata;
ptr->Flush();
}
-CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int _card_index) :
- m_strFilename(_rFilename),
- card_index(_card_index),
- m_bDirty(false)
+CEXIMemoryCard::CEXIMemoryCard(const int index)
+ : card_index(index)
+ , m_bDirty(false)
{
- cards[_card_index] = this;
- et_this_card = CoreTiming::RegisterEvent(_rName.c_str(), FlushCallback);
- reloadOnState = SConfig::GetInstance().b_reloadMCOnState;
+ m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
+ // we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
+ et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback);
interruptSwitch = 0;
m_bInterruptSet = 0;
@@ -84,7 +85,6 @@ CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rF
INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
pFile.ReadBytes(memory_card_content, memory_card_size);
- SetCardFlashID(memory_card_content, card_index);
}
else
@@ -94,11 +94,11 @@ CEXIMemoryCard::CEXIMemoryCard(const std::string& _rName, const std::string& _rF
memory_card_size = nintendo_card_id * SIZE_TO_Mb;
memory_card_content = new u8[memory_card_size];
- memset(memory_card_content, 0xFF, memory_card_size);
-
+ GCMemcard::Format(memory_card_content, m_strFilename.find(".JAP.raw") != std::string::npos, nintendo_card_id);
+ memset(memory_card_content+MC_HDR_SIZE, 0xFF, memory_card_size-MC_HDR_SIZE);
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create new.");
- Flush();
}
+ SetCardFlashID(memory_card_content, card_index);
}
void innerFlush(FlushData* data)
@@ -157,6 +157,7 @@ void CEXIMemoryCard::Flush(bool exiting)
CEXIMemoryCard::~CEXIMemoryCard()
{
+ CoreTiming::RemoveEvent(et_this_card);
Flush(true);
delete[] memory_card_content;
memory_card_content = NULL;
@@ -236,7 +237,7 @@ void CEXIMemoryCard::SetCS(int cs)
// Page written to memory card, not just to buffer - let's schedule a flush 0.5b cycles into the future (1 sec)
// But first we unschedule already scheduled flushes - no point in flushing once per page for a large write.
CoreTiming::RemoveEvent(et_this_card);
- CoreTiming::ScheduleEvent(500000000, et_this_card, card_index);
+ CoreTiming::ScheduleEvent(500000000, et_this_card, (u64)this);
break;
}
}
@@ -422,13 +423,34 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte);
}
+void CEXIMemoryCard::OnAfterLoad()
+{
+
+}
+
void CEXIMemoryCard::DoState(PointerWrap &p)
{
- if (reloadOnState)
+ // for movie sync, we need to save/load memory card contents (and other data) in savestates.
+ // otherwise, we'll assume the user wants to keep their memcards and saves separate,
+ // unless we're loading (in which case we let the savestate contents decide, in order to stay aligned with them).
+ bool storeContents = (Movie::IsRecordingInput() || Movie::IsPlayingInput());
+ p.Do(storeContents);
+
+ if (storeContents)
{
- int slot = 0;
- if (GetFileName() == SConfig::GetInstance().m_strMemoryCardA)
- slot = 1;
- ExpansionInterface::ChangeDevice(slot, slot ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A, 0);
+ p.Do(interruptSwitch);
+ p.Do(m_bInterruptSet);
+ p.Do(command);
+ p.Do(status);
+ p.Do(m_uPosition);
+ p.Do(programming_buffer);
+ p.Do(formatDelay);
+ p.Do(m_bDirty);
+ p.Do(address);
+
+ p.Do(nintendo_card_id);
+ p.Do(card_id);
+ p.Do(memory_card_size);
+ p.DoArray(memory_card_content, memory_card_size);
}
}
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
index 248fcd31cb..5da8c63183 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h
@@ -32,15 +32,14 @@ struct FlushData
class CEXIMemoryCard : public IEXIDevice
{
public:
- CEXIMemoryCard(const std::string& _rName, const std::string& _rFilename, int card_index);
+ CEXIMemoryCard(const int index);
virtual ~CEXIMemoryCard();
void SetCS(int cs);
void Update();
bool IsInterruptSet();
bool IsPresent();
void DoState(PointerWrap &p);
-
- inline const std::string &GetFileName() const { return m_strFilename; };
+ void OnAfterLoad();
private:
// This is scheduled whenever a page write is issued. The this pointer is passed
@@ -72,7 +71,6 @@ private:
std::string m_strFilename;
int card_index;
int et_this_card;
- bool reloadOnState;
//! memory card state
// STATE_TO_SAVE
@@ -84,7 +82,6 @@ private:
u8 programming_buffer[128];
u32 formatDelay;
bool m_bDirty;
-
//! memory card parameters
unsigned int nintendo_card_id, card_id;
unsigned int address;
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMic.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMic.cpp
index 5979463176..cba3940cdf 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMic.cpp
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMic.cpp
@@ -16,115 +16,165 @@
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
-#include "FileUtil.h"
-#include "StringUtil.h"
-#include "../Core.h"
+
+#if HAVE_PORTAUDIO
+
#include "../CoreTiming.h"
+#include "SystemTimers.h"
#include "EXI_Device.h"
#include "EXI_DeviceMic.h"
-// Unfortunately this must be enabled in Common.h for windows users. Scons should enable it otherwise
-#if !HAVE_PORTAUDIO
-
-void SetMic(bool Value){}
-
-CEXIMic::CEXIMic(int _Index){}
-CEXIMic::~CEXIMic(){}
-bool CEXIMic::IsPresent() {return false;}
-void CEXIMic::SetCS(int cs){}
-void CEXIMic::Update(){}
-void CEXIMic::TransferByte(u8 &byte){}
-bool CEXIMic::IsInterruptSet(){return false;}
-
-#else
-
-// We use PortAudio for cross-platform audio input.
-// It needs the headers and a lib file for the dll
#include <portaudio.h>
-#ifdef _WIN32
-#pragma comment(lib, "C:/Users/Shawn/Desktop/portaudio/portaudio-v19/portaudio_x64.lib")
-#endif
+#include "GCPad.h"
-static bool MicButton = false;
-static bool IsOpen;
+void CEXIMic::StreamLog(const char *msg)
+{
+ DEBUG_LOG(EXPANSIONINTERFACE, "%s: %s",
+ msg, Pa_GetErrorText(pa_error));
+}
-union InputData
+void CEXIMic::StreamInit()
{
- s16 word;
- u8 byte[2];
-};
+ // Setup the wonderful c-interfaced lib...
+ pa_stream = NULL;
-InputData inputData[64]; // 64 words = Max 128 bytes returned????
-PaStream *stream;
-PaError err;
-unsigned short SFreq;
-unsigned short SNum;
-bool m_bInterruptSet;
-bool Sampling;
+ if ((pa_error = Pa_Initialize()) != paNoError)
+ StreamLog("Pa_Initialize");
+ stream_buffer = NULL;
+ samples_avail = stream_wpos = stream_rpos = 0;
+}
-void SetMic(bool Value)
+void CEXIMic::StreamTerminate()
{
- MicButton = Value;
- if(Sampling)
- Pa_StartStream( stream );
- else
- Pa_StopStream( stream );
+ StreamStop();
+
+ if ((pa_error = Pa_Terminate()) != paNoError)
+ StreamLog("Pa_Terminate");
}
-int patestCallback( const void *inputBuffer, void *outputBuffer,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
+static int Pa_Callback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData)
{
- s16 *data = (s16*)inputBuffer;
- //s16 *out = (s16*)outputBuffer;
+ (void)outputBuffer;
+ (void)timeInfo;
+ (void)statusFlags;
+
+ CEXIMic *mic = (CEXIMic *)userData;
+
+ std::lock_guard<std::mutex> lk(mic->ring_lock);
+
+ if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size)
+ mic->stream_wpos = 0;
+
+ s16 *buff_in = (s16 *)inputBuffer;
+ s16 *buff_out = &mic->stream_buffer[mic->stream_wpos];
- if (!m_bInterruptSet && Sampling)
+ if (buff_in == NULL)
{
- for(unsigned int i = 0; i < SNum; ++i)
+ for (int i = 0; i < mic->buff_size_samples; i++)
{
- inputData[i].word = data[i];
- //out[i] = inputData[i].word;
+ buff_out[i] = 0;
}
- m_bInterruptSet = true;
}
+ else
+ {
+ for (int i = 0; i < mic->buff_size_samples; i++)
+ {
+ buff_out[i] = buff_in[i];
+ }
+ }
+
+ mic->samples_avail += mic->buff_size_samples;
+ if (mic->samples_avail > mic->stream_size)
+ {
+ mic->samples_avail = 0;
+ mic->status.buff_ovrflw = 1;
+ }
+
+ mic->stream_wpos += mic->buff_size_samples;
+ mic->stream_wpos %= mic->stream_size;
+
return paContinue;
}
+void CEXIMic::StreamStart()
+{
+ // Open stream with current parameters
+ stream_size = buff_size_samples * 500;
+ stream_buffer = new s16[stream_size];
+
+ pa_error = Pa_OpenDefaultStream(&pa_stream, 1, 0, paInt16,
+ sample_rate, buff_size_samples, Pa_Callback, this);
+ StreamLog("Pa_OpenDefaultStream");
+ pa_error = Pa_StartStream(pa_stream);
+ StreamLog("Pa_StartStream");
+}
+
+void CEXIMic::StreamStop()
+{
+ if (pa_stream != NULL && Pa_IsStreamActive(pa_stream) >= paNoError)
+ Pa_AbortStream(pa_stream);
-// EXI Mic Device
+ delete [] stream_buffer;
+ stream_buffer = NULL;
+}
-CEXIMic::CEXIMic(int _Index)
+void CEXIMic::StreamReadOne()
{
- Index = _Index;
+ std::lock_guard<std::mutex> lk(ring_lock);
+
+ if (samples_avail >= buff_size_samples)
+ {
+ s16 *last_buffer = &stream_buffer[stream_rpos];
+ memcpy(ring_buffer, last_buffer, buff_size);
+
+ samples_avail -= buff_size_samples;
+
+ stream_rpos += buff_size_samples;
+ stream_rpos %= stream_size;
+ }
+}
+
+// EXI Mic Device
+// This works by opening and starting a portaudio input stream when the is_active
+// bit is set. The interrupt is scheduled in the future based on sample rate and
+// buffer size settings. When the console handles the interrupt, it will send
+// cmdGetBuffer, which is when we actually read data from a buffer filled
+// in the background by Pa_Callback.
+
+u8 const CEXIMic::exi_id[] = { 0, 0x0a, 0, 0, 0 };
- memset(&inputData, 0 , sizeof(inputData));
- memset(&Status.U16, 0 , sizeof(u16));
+CEXIMic::CEXIMic(int index)
+ : slot(index)
+{
+ m_position = 0;
command = 0;
- m_uPosition = 0;
- m_bInterruptSet = false;
- MicButton = false;
- IsOpen = false;
- err = Pa_Initialize();
- if (err != paNoError)
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Initialize error %s", Pa_GetErrorText(err));
+ status.U16 = 0;
+
+ sample_rate = rate_base;
+ buff_size = ring_base;
+ buff_size_samples = buff_size / sample_size;
+
+ ring_pos = 0;
+ memset(ring_buffer, 0, sizeof(ring_buffer));
+
+ next_int_ticks = 0;
+
+ StreamInit();
}
CEXIMic::~CEXIMic()
{
- err = Pa_CloseStream( stream );
- if (err != paNoError)
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Close error %s", Pa_GetErrorText(err));
- err = Pa_Terminate();
- if (err != paNoError)
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio Terminate error %s", Pa_GetErrorText(err));
+ StreamTerminate();
}
-bool CEXIMic::IsPresent()
+bool CEXIMic::IsPresent()
{
return true;
}
@@ -132,38 +182,26 @@ bool CEXIMic::IsPresent()
void CEXIMic::SetCS(int cs)
{
if (cs) // not-selected to selected
- m_uPosition = 0;
- else
- {
- switch (command)
- {
- case cmdID:
- case cmdGetStatus:
- case cmdSetStatus:
- case cmdGetBuffer:
- break;
- case cmdWakeUp:
- // This is probably not a command, but anyway...
- // The command 0xff seems to be used to get in sync with the microphone or to wake it up.
- // Normally, it is issued before any other command, or to recover from errors.
- WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: WakeUp cmd");
- break;
- default:
- WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown CS command %02x\n", command);
- break;
- }
- }
+ m_position = 0;
+ // Doesn't appear to do anything we care about
+ //else if (command == cmdReset)
}
-void CEXIMic::Update()
+void CEXIMic::UpdateNextInterruptTicks()
{
+ next_int_ticks = CoreTiming::GetTicks() +
+ (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples;
}
bool CEXIMic::IsInterruptSet()
{
- if(m_bInterruptSet)
+ if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks)
{
- m_bInterruptSet = false;
+ if (status.is_active)
+ UpdateNextInterruptTicks();
+ else
+ next_int_ticks = 0;
+
return true;
}
else
@@ -174,124 +212,70 @@ bool CEXIMic::IsInterruptSet()
void CEXIMic::TransferByte(u8 &byte)
{
- if (m_uPosition == 0)
+ if (m_position == 0)
{
command = byte; // first byte is command
byte = 0xFF; // would be tristate, but we don't care.
- }
- else
+ m_position++;
+ return;
+ }
+
+ int pos = m_position - 1;
+
+ switch (command)
{
- switch (command)
+ case cmdID:
+ byte = exi_id[pos];
+ break;
+
+ case cmdGetStatus:
+ if (pos == 0)
+ status.button = Pad::GetMicButton(slot);
+
+ byte = status.U8[pos ^ 1];
+
+ if (pos == 1)
+ status.buff_ovrflw = 0;
+ break;
+
+ case cmdSetStatus:
+ {
+ bool wasactive = status.is_active;
+ status.U8[pos ^ 1] = byte;
+
+ // safe to do since these can only be entered if both bytes of status have been written
+ if (!wasactive && status.is_active)
+ {
+ sample_rate = rate_base << status.sample_rate;
+ buff_size = ring_base << status.buff_size;
+ buff_size_samples = buff_size / sample_size;
+
+ UpdateNextInterruptTicks();
+
+ StreamStart();
+ }
+ else if (wasactive && !status.is_active)
+ {
+ StreamStop();
+ }
+ }
+ break;
+
+ case cmdGetBuffer:
{
- case cmdID:
- if (m_uPosition == 1)
- ;//byte = 0x80; // dummy cycle - taken from memcard, it doesn't seem to need it here
- else
- byte = (u8)(EXI_DEVTYPE_MIC >> (24-(((m_uPosition-2) & 3) * 8)));
- break;
- case cmdGetStatus:
- {
- if (m_uPosition != 1 && m_uPosition != 2)
- WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: WARNING GetStatus @ pos: %d should never happen", m_uPosition);
- if((!Status.button && MicButton)||(Status.button && !MicButton))
- WARN_LOG(EXPANSIONINTERFACE, "EXI MIC: Mic button %s", MicButton ? "pressed" : "released");
-
- Status.button = MicButton ? 1 : 0;
- byte = Status.U8[ (m_uPosition - 1) ? 0 : 1];
- INFO_LOG(EXPANSIONINTERFACE, "EXI MIC: Status is 0x%04x", Status.U16);
- }
- break;
- case cmdSetStatus:
- {
- // 0x80 0xXX 0xYY
- // cmd pos1 pos2
-
- // Here we assign the byte to the proper place in Status and update portaudio settings
- Status.U8[ (m_uPosition - 1) ? 0 : 1] = byte;
-
- if(m_uPosition == 2)
- {
- Sampling = (Status.sampling == 1) ? true : false;
-
- switch (Status.sRate)
- {
- case 0:
- SFreq = 11025;
- break;
- case 1:
- SFreq = 22050;
- break;
- case 2:
- SFreq = 44100;
- break;
- default:
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: Trying to set unknown sampling rate");
- SFreq = 44100;
- break;
- }
-
- switch (Status.pLength)
- {
- case 0:
- SNum = 32;
- break;
- case 1:
- SNum = 64;
- break;
- case 2:
- SNum = 128;
- break;
- default:
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: Trying to set unknown period length");
- SNum = 128;
- break;
- }
-
- DEBUG_LOG(EXPANSIONINTERFACE, "//////////////////////////////////////////////////////////////////////////");
- DEBUG_LOG(EXPANSIONINTERFACE, "EXI MIC: Status is now 0x%04x", Status.U16);
- DEBUG_LOG(EXPANSIONINTERFACE, "\tbutton %i\tsRate %i\tpLength %i\tsampling %i\n",
- Status.button, SFreq, SNum, Status.sampling);
-
- if(!IsOpen)
- {
- // Open Our PortAudio Stream
- // (shuffle2) This (and the callback) could still be wrong
- err = Pa_OpenDefaultStream(
- &stream, // Our PaStream
- 1, // Input Channels
- 0, // Output Channels
- paInt16, // Output format - GC wants PCM samples in signed 16-bit format
- SFreq, // Sample Rate
- SNum, // Period Length (frames per buffer)
- patestCallback,// Our callback!
- NULL); // Pointer passed to our callback
- if (err != paNoError)
- {
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: PortAudio error %s", Pa_GetErrorText(err));
- }
- else
- IsOpen = true;
- }
- }
- }
- break;
- case cmdGetBuffer:
- {
- int pos = m_uPosition - 1;
- // (sonicadvance1)I think if we set the Interrupt to false, it reads another 64
- // Will Look in to it.
- // (shuffle2)Seems like games just continuously get the buffer as long as
- // they're sampling and the mic is generating interrupts
- byte = inputData[pos].byte[ (pos & 1) ? 0 : 1 ];
- INFO_LOG(EXPANSIONINTERFACE, "EXI MIC: GetBuffer%s%d/%d byte: 0x%02x",
- (pos > 9) ? " " : " ", pos, SNum, byte);
- }
- break;
- default:
- ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x\n", command);
- break;
+ if (ring_pos == 0)
+ StreamReadOne();
+
+ byte = ring_buffer[ring_pos ^ 1];
+ ring_pos = (ring_pos + 1) % buff_size;
}
+ break;
+
+ default:
+ ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x", command);
+ break;
}
- m_uPosition++;
+
+ m_position++;
}
#endif
diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMic.h b/Source/Core/Core/Src/HW/EXI_DeviceMic.h
index 3fa463e722..b9596ba85a 100644
--- a/Source/Core/Core/Src/HW/EXI_DeviceMic.h
+++ b/Source/Core/Core/Src/HW/EXI_DeviceMic.h
@@ -18,58 +18,106 @@
#ifndef _EXI_DEVICEMIC_H
#define _EXI_DEVICEMIC_H
+#if HAVE_PORTAUDIO
+
+#include "StdMutex.h"
+
class CEXIMic : public IEXIDevice
{
public:
- CEXIMic(int _Index);
+ CEXIMic(const int index);
virtual ~CEXIMic();
void SetCS(int cs);
- void Update();
bool IsInterruptSet();
bool IsPresent();
private:
+ static u8 const exi_id[];
+ static int const sample_size = sizeof(s16);
+ static int const rate_base = 11025;
+ static int const ring_base = 32;
enum
{
- EXI_DEVTYPE_MIC = 0x0A000000
- };
-
- enum
- {
cmdID = 0x00,
cmdGetStatus = 0x40,
cmdSetStatus = 0x80,
cmdGetBuffer = 0x20,
- cmdWakeUp = 0xFF,
+ cmdReset = 0xFF,
};
- // STATE_TO_SAVE
- int interruptSwitch;
+ int slot;
+
+ u32 m_position;
int command;
- union uStatus
+ union UStatus
{
u16 U16;
u8 U8[2];
struct
{
- u16 :8; // Unknown
- u16 button :1; // 1: Button Pressed
- u16 unk1 :1; // 1 ? Overflow?
- u16 unk2 :1; // Unknown related to 0 and 15 values It seems
- u16 sRate :2; // Sample Rate, 00-11025, 01-22050, 10-44100, 11-??
- u16 pLength :2; // Period Length, 00-32, 01-64, 10-128, 11-???
- u16 sampling :1; // If We Are Sampling or Not
+ u16 out :4; // MICSet/GetOut...???
+ u16 id :1; // Used for MICGetDeviceID (always 0)
+ u16 button_unk :3; // Button bits which appear unused
+ u16 button :1; // The actual button on the mic
+ u16 buff_ovrflw :1; // Ring buffer wrote over bytes which weren't read by console
+ u16 gain :1; // Gain: 0dB or 15dB
+ u16 sample_rate :2; // Sample rate, 00-11025, 01-22050, 10-44100, 11-??
+ u16 buff_size :2; // Ring buffer size in bytes, 00-32, 01-64, 10-128, 11-???
+ u16 is_active :1; // If we are sampling or not
};
};
- int Index;
- u32 m_uPosition;
- uStatus Status;
+
+ // 64 is the max size, can be 16 or 32 as well
+ int ring_pos;
+ u8 ring_buffer[64 * sample_size];
+
+ // 0 to disable interrupts, else it will be checked against current cpu ticks
+ // to determine if interrupt should be raised
+ u64 next_int_ticks;
+ void UpdateNextInterruptTicks();
+
+ // Streaming input interface
+ int pa_error; // PaError
+ void *pa_stream; // PaStream
+
+ void StreamLog(const char *msg);
+ void StreamInit();
+ void StreamTerminate();
+ void StreamStart();
+ void StreamStop();
+ void StreamReadOne();
+
+public:
+ UStatus status;
+
+ std::mutex ring_lock;
+
+ // status bits converted to nice numbers
+ int sample_rate;
+ int buff_size;
+ int buff_size_samples;
+
+ // Arbitrarily small ringbuffer used by audio input backend in order to
+ // keep delay tolerable
+ s16 *stream_buffer;
+ int stream_size;
+ int stream_wpos;
+ int stream_rpos;
+ int samples_avail;
protected:
virtual void TransferByte(u8 &byte);
};
-void SetMic(bool Value);
+#else // HAVE_PORTAUDIO
+
+class CEXIMic : public IEXIDevice
+{
+public:
+ CEXIMic(const int) {}
+};
#endif
+
+#endif // _EXI_DEVICEMIC_H
diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp
index df79e001f2..cab7d950a2 100644
--- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.cpp
+++ b/Source/Core/Core/Src/HW/GCMemcard.cpp
@@ -61,7 +61,10 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height)
}
}
-GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_valid(false), m_fileName(filename)
+GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
+ : m_valid(false)
+ , m_fileName(filename)
+ , mc_data(NULL)
{
File::IOFile mcdFile(m_fileName, "r+b");
if (!mcdFile.IsOpen())
@@ -71,10 +74,7 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_va
return;
}
Format(forceCreation ? sjis : !AskYesNoT("Format as ascii (NTSC\\PAL)?\nChoose no for sjis (NTSC-J)"));
- if (!mcdFile.Open(m_fileName, "r+b"))
- {
- return;
- }
+ return;
}
else
{
@@ -227,7 +227,7 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_va
bool GCMemcard::IsAsciiEncoding()
{
- return hdr.Encoding[1] == 0;
+ return hdr.Encoding == 0;
}
bool GCMemcard::Save()
@@ -245,51 +245,49 @@ bool GCMemcard::Save()
return mcdFile.Close();
}
-void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
+void GCMemcard::calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum)
{
- *c1 = 0;*c2 = 0;
- for (u32 i = 0; i < num; ++i)
+ *csum = *inv_csum = 0;
+
+ for (u32 i = 0; i < length; ++i)
{
//weird warnings here
- *c1 += Common::swap16(buf[i]);
- *c2 += Common::swap16((u16)(buf[i] ^ 0xffff));
+ *csum += BE16(buf[i]);
+ *inv_csum += BE16((u16)(buf[i] ^ 0xffff));
}
- if (*c1 == 0xffff)
+ *csum = BE16(*csum);
+ *inv_csum = BE16(*inv_csum);
+ if (*csum == 0xffff)
{
- *c1 = 0;
+ *csum = 0;
}
- if (*c2 == 0xffff)
+ if (*inv_csum == 0xffff)
{
- *c2 = 0;
+ *inv_csum = 0;
}
}
u32 GCMemcard::TestChecksums()
{
- u16 csum1=0,
- csum2=0;
+ u16 csum=0,
+ csum_inv=0;
u32 results = 0;
- calc_checksumsBE((u16*)&hdr, 0xFE , &csum1, &csum2);
- if (BE16(hdr.CheckSum1) != csum1) results |= 1;
- if (BE16(hdr.CheckSum2) != csum2) results |= 1;
+ calc_checksumsBE((u16*)&hdr, 0xFE , &csum, &csum_inv);
+ if ((hdr.Checksum != csum) || (hdr.Checksum_Inv != csum_inv)) results |= 1;
- calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
- if (BE16(dir.CheckSum1) != csum1) results |= 2;
- if (BE16(dir.CheckSum2) != csum2) results |= 2;
+ calc_checksumsBE((u16*)&dir, 0xFFE, &csum, &csum_inv);
+ if ((dir.Checksum != csum) || (dir.Checksum_Inv != csum_inv)) results |= 2;
- calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
- if (BE16(dir_backup.CheckSum1) != csum1) results |= 4;
- if (BE16(dir_backup.CheckSum2) != csum2) results |= 4;
+ calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum, &csum_inv);
+ if ((dir_backup.Checksum != csum) || (dir_backup.Checksum_Inv != csum_inv)) results |= 4;
- calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2);
- if (BE16(bat.CheckSum1) != csum1) results |= 8;
- if (BE16(bat.CheckSum2) != csum2) results |= 8;
+ calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum, &csum_inv);
+ if ((bat.Checksum != csum) || (bat.Checksum_Inv != csum_inv)) results |= 8;
- calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2);
- if (BE16(bat_backup.CheckSum1) != csum1) results |= 16;
- if (BE16(bat_backup.CheckSum2) != csum2) results |= 16;
+ calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum, &csum_inv);
+ if ((bat_backup.Checksum != csum) || (bat_backup.Checksum_Inv != csum_inv)) results |= 16;
return results;
}
@@ -298,39 +296,12 @@ bool GCMemcard::FixChecksums()
{
if (!m_valid)
return false;
-
- u16 csum1=0,
- csum2=0;
-
- calc_checksumsBE((u16*)&hdr, 0xFE, &csum1, &csum2);
- hdr.CheckSum1[0] = u8(csum1 >> 8);
- hdr.CheckSum1[1] = u8(csum1);
- hdr.CheckSum2[0] = u8(csum2 >> 8);
- hdr.CheckSum2[1] = u8(csum2);
-
- calc_checksumsBE((u16*)&dir, 0xFFE, &csum1, &csum2);
- dir.CheckSum1[0] = u8(csum1 >> 8);
- dir.CheckSum1[1] = u8(csum1);
- dir.CheckSum2[0] = u8(csum2 >> 8);
- dir.CheckSum2[1] = u8(csum2);
-
- calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum1, &csum2);
- dir_backup.CheckSum1[0] = u8(csum1 >> 8);
- dir_backup.CheckSum1[1] = u8(csum1);
- dir_backup.CheckSum2[0] = u8(csum2 >> 8);
- dir_backup.CheckSum2[1] = u8(csum2);
-
- calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum1, &csum2);
- bat.CheckSum1[0] = u8(csum1 >> 8);
- bat.CheckSum1[1] = u8(csum1);
- bat.CheckSum2[0] = u8(csum2 >> 8);
- bat.CheckSum2[1] = u8(csum2);
-
- calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum1, &csum2);
- bat_backup.CheckSum1[0] = u8(csum1 >> 8);
- bat_backup.CheckSum1[1] = u8(csum1);
- bat_backup.CheckSum2[0] = u8(csum2 >> 8);
- bat_backup.CheckSum2[1] = u8(csum2);
+
+ calc_checksumsBE((u16*)&hdr, 0xFE, &hdr.Checksum, &hdr.Checksum_Inv);
+ calc_checksumsBE((u16*)&dir, 0xFFE, &dir.Checksum, &dir.Checksum_Inv);
+ calc_checksumsBE((u16*)&dir_backup, 0xFFE, &dir_backup.Checksum, &dir_backup.Checksum_Inv);
+ calc_checksumsBE((u16*)&bat+2, 0xFFE, &bat.Checksum, &bat.Checksum_Inv);
+ calc_checksumsBE((u16*)&bat_backup+2, 0xFFE, &bat_backup.Checksum, &bat_backup.Checksum_Inv);
return true;
}
@@ -620,8 +591,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
{
index = i;
dir.Dir[i] = direntry;
- dir.Dir[i].FirstBlock[0] = u8(firstFree1 >> 8);
- dir.Dir[i].FirstBlock[1] = u8(firstFree1);
+ *(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1);
if (!remove)
{
dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1;
@@ -642,7 +612,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
int j = 2;
while(j < BE16(direntry.BlockCount) + 1)
{
- bat_backup.Map[i] = Common::swap16(last + (u16)j);
+ bat_backup.Map[i] = BE16(last + (u16)j);
i++;
j++;
}
@@ -654,25 +624,16 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
}
//update last allocated block
- int lastallocated = BE16(bat_backup.LastAllocated) + j - 1;
- bat_backup.LastAllocated[0] = u8(lastallocated >> 8);
- bat_backup.LastAllocated[1] = u8(lastallocated);
-
+ *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1);
//update freespace counter
- int freespace1 = totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS;
- bat_backup.FreeBlocks[0] = u8(freespace1 >> 8);
- bat_backup.FreeBlocks[1] = u8(freespace1);
+ *(u16*)&bat_backup.FreeBlocks = BE16(totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS);
if (!remove)
{ // ... and dir update counter
- int updateCtr = BE16(dir_backup.UpdateCounter) + 1;
- dir_backup.UpdateCounter[0] = u8(updateCtr >> 8);
- dir_backup.UpdateCounter[1] = u8(updateCtr);
+ *(u16*)&dir_backup.UpdateCounter = BE16(BE16(dir_backup.UpdateCounter) + 1);
// ... and bat update counter
- updateCtr = BE16(bat_backup.UpdateCounter) + 1;
- bat_backup.UpdateCounter[0] = u8(updateCtr >> 8);
- bat_backup.UpdateCounter[1] = u8(updateCtr);
+ *(u16*)&bat_backup.UpdateCounter = BE16(BE16(bat_backup.UpdateCounter) + 1);
}
bat = bat_backup;
return SUCCESS;
@@ -698,9 +659,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
//free the blocks
int blocks_left = BE16(dir.Dir[index].BlockCount);
- int block = BE16(dir.Dir[index].FirstBlock) - 1;
- bat.LastAllocated[0] = (u8)(block >> 8);
- bat.LastAllocated[1] = (u8)block;
+ *(u16*)&bat.LastAllocated = BE16(BE16(dir.Dir[index].FirstBlock) - 1);
u8 nextIndex = index + 1;
memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE);
@@ -713,9 +672,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
//Only get file data if it is a valid dir entry
if (BE16(tempDEntry->FirstBlock) != 0xFFFF)
{
- u16 freeBlock= BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount);
- bat.FreeBlocks[0] = u8(freeBlock >> 8);
- bat.FreeBlocks[1] = u8(freeBlock);
+ *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount));
u16 size = DEntry_BlockCount(nextIndex);
if (size != 0xFFFF)
@@ -754,9 +711,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
}
}
// increment update counter
- int updateCtr = BE16(dir.UpdateCounter) + 1;
- dir.UpdateCounter[0] = u8(updateCtr >> 8);
- dir.UpdateCounter[1] = u8(updateCtr);
+ *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1);
return SUCCESS;
}
@@ -989,9 +944,7 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length)
// It is stored only within the corresponding GSV file.
// If the GCS file is added without using the GameSaves software,
// the value stored is always "1"
- int blockCount = length / BLOCK_SIZE;
- tempDEntry->BlockCount[0] = u8(blockCount >> 8);
- tempDEntry->BlockCount[1] = u8(blockCount);
+ *(u16*)&tempDEntry->BlockCount = BE16(length / BLOCK_SIZE);
}
break;
case SAV:
@@ -1157,70 +1110,97 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
return frames;
}
-bool GCMemcard::Format(bool sjis, bool New, int slot, u16 SizeMb, bool hdrOnly)
+
+bool GCMemcard::Format(u8 * card_data, bool sjis, u16 SizeMb)
{
- // Currently only formats cards for slot A
- const u32 data_size = BLOCK_SIZE * (SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
+ if (!card_data)
+ return false;
+ memset(card_data, 0xFF, BLOCK_SIZE*3);
+ memset(card_data + BLOCK_SIZE*3, 0, BLOCK_SIZE*2);
- SRAM m_SRAM;
+ GCMC_Header gcp;
+ gcp.hdr = (Header*)card_data;
+ gcp.dir = (Directory *)(card_data + BLOCK_SIZE);
+ gcp.dir_backup = (Directory *)(card_data + BLOCK_SIZE*2);
+ gcp.bat = (BlockAlloc *)(card_data + BLOCK_SIZE*3);
+ gcp.bat_backup = (BlockAlloc *)(card_data + BLOCK_SIZE*4);
- if (New)
- {
- mc_data_size = data_size;
- mc_data = new u8[mc_data_size];
- }
- // Only Format 16MB memcards for now
- if ((SizeMb != MemCard2043Mb) || (data_size != mc_data_size)) return false;
+ *(u16*)gcp.hdr->SizeMb = BE16(SizeMb);
+ gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
- File::IOFile pStream(File::GetUserPath(F_GCSRAM_IDX), "rb");
- if (pStream)
- {
- pStream.ReadBytes(&m_SRAM, 64);
- pStream.Close();
- }
- else
+ FormatInternal(gcp);
+ return true;
+}
+
+bool GCMemcard::Format(bool sjis, u16 SizeMb)
+{
+ memset(&hdr, 0xFF, BLOCK_SIZE);
+ memset(&dir, 0xFF, BLOCK_SIZE);
+ memset(&dir_backup, 0xFF, BLOCK_SIZE);
+ memset(&bat, 0, BLOCK_SIZE);
+ memset(&bat_backup, 0, BLOCK_SIZE);
+
+ GCMC_Header gcp;
+ gcp.hdr = &hdr;
+ gcp.dir = &dir;
+ gcp.dir_backup = &dir_backup;
+ gcp.bat = &bat;
+ gcp.bat_backup = &bat_backup;
+
+ *(u16*)hdr.SizeMb = BE16(SizeMb);
+ hdr.Encoding = BE16(sjis ? 1 : 0);
+ FormatInternal(gcp);
+
+ m_sizeMb = SizeMb;
+ maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
+ if (mc_data)
{
- m_SRAM = sram_dump;
+ delete mc_data;
+ mc_data = NULL;
}
-
- const u64 time = CEXIIPL::GetGCTime();
- u64 rand = Common::swap64(time);
+ mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
+ mc_data = new u8[mc_data_size];
+ if (!mc_data)
+ return false;
+
+ memset(mc_data, 0xFF, mc_data_size);
+ m_valid = true;
+
+ return Save();
+}
+
+void GCMemcard::FormatInternal(GCMC_Header &GCP)
+{
+ Header *p_hdr = GCP.hdr;
+ u64 rand = CEXIIPL::GetGCTime();
+ p_hdr->formatTime = Common::swap64(rand);
- memset(&hdr, 0xFF, BLOCK_SIZE);
for(int i = 0; i < 12; i++)
{
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
- hdr.serial[i] = (u8)(m_SRAM.flash_id[slot][i] + (u32)rand);
+ p_hdr->serial[i] = (u8)(g_SRAM.flash_id[0][i] + (u32)rand);
rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16);
rand &= (u64)0x0000000000007fffULL;
}
-
- hdr.fmtTime.high = (time >> 32) & 0xFFFFFFFF;
- hdr.fmtTime.low = time & 0xFFFFFFFF;
- *(u32*)&(hdr.SramBias) = m_SRAM.counter_bias;
- *(u32*)&(hdr.SramLang) = m_SRAM.lang;
- *(u32*)&(hdr.Unk2) = Common::swap32(1); // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000;
- // TODO: find out why memcard cares if component cable used for now set to one like main app
- *(u16*)&(hdr.deviceID) = 0;
- *(u16*)&(hdr.SizeMb) = Common::swap16(SizeMb);
- *(u16*)&(hdr.Encoding) = Common::swap16(sjis ? 1 : 0);
-
- if (!hdrOnly)
- {
- memset(&dir, 0xFF, BLOCK_SIZE);
- memset(&dir_backup, 0xFF, BLOCK_SIZE);
- *(u16*)&dir.UpdateCounter = 0;
- *(u16*)&dir_backup.UpdateCounter = Common::swap16(1);
- memset(&bat, 0, BLOCK_SIZE);
- memset(&bat_backup, 0, BLOCK_SIZE);
- *(u16*)&bat.UpdateCounter = 0;
- *(u16*)&bat_backup.UpdateCounter = Common::swap16(1);
- *(u16*)&bat.FreeBlocks = *(u16*)&bat_backup.FreeBlocks = Common::swap16(SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
- *(u16*)&bat.LastAllocated = *(u16*)&bat_backup.LastAllocated = Common::swap16(4);
- memset(mc_data, 0xFF, mc_data_size);
- }
+ *(u32*)&p_hdr->SramBias = g_SRAM.counter_bias;
+ *(u32*)&p_hdr->SramLang = g_SRAM.lang;
+ // TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B
+ *(u32*)&p_hdr->Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000;
+ *(u16*)&p_hdr->deviceID = 0;
+ calc_checksumsBE((u16*)p_hdr, 0xFE, &p_hdr->Checksum, &p_hdr->Checksum_Inv);
+
+ Directory *p_dir = GCP.dir,
+ *p_dir_backup = GCP.dir_backup;
+ *(u16*)&p_dir->UpdateCounter = 0;
+ *(u16*)&p_dir_backup->UpdateCounter = BE16(1);
+ calc_checksumsBE((u16*)p_dir, 0xFFE, &p_dir->Checksum, &p_dir->Checksum_Inv);
+ calc_checksumsBE((u16*)p_dir_backup, 0xFFE, &p_dir_backup->Checksum, &p_dir_backup->Checksum_Inv);
- FixChecksums();
- Save();
- return true;
+ BlockAlloc *p_bat = GCP.bat,
+ *p_bat_backup = GCP.bat_backup;
+ *(u16*)&p_bat_backup->UpdateCounter = BE16(1);
+ *(u16*)&p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS);
+ *(u16*)&p_bat->LastAllocated = *(u16*)&p_bat_backup->LastAllocated = BE16(4);
+ calc_checksumsBE((u16*)p_bat+2, 0xFFE, &p_bat->Checksum, &p_bat->Checksum_Inv);
+ calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv);
}
diff --git a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h
index 07ce5656f8..8c7baa4774 100644
--- a/Source/Core/DolphinWX/Src/MemoryCards/GCMemcard.h
+++ b/Source/Core/Core/Src/HW/GCMemcard.h
@@ -19,12 +19,12 @@
#define __GCMEMCARD_h__
#include "Common.h"
-#include "../../../Core/Src/HW/Sram.h"
+#include "Sram.h"
#include "StringUtil.h"
-#include "../../../Core/Src/HW/EXI_DeviceIPL.h"
+#include "EXI_DeviceIPL.h"
-#define BE32(x) ((u32((x)[0])<<24) | (u32((x)[1])<<16) | (u32((x)[2])<<8) | u32((x)[3]))
-#define BE16(x) ((u16((x)[0])<<8) | u16((x)[1]))
+#define BE32(x) (Common::swap32(x))
+#define BE16(x) (Common::swap16(x))
#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8)));
enum
@@ -67,7 +67,7 @@ enum
CI8,
};
-class GCMemcard
+class GCMemcard : NonCopyable
{
private:
friend class CMemcardManagerDebug;
@@ -81,26 +81,21 @@ private:
u16 m_sizeMb;
#pragma pack(push,1)
- struct OSTime {
- u32 low;
- u32 high;
- };
-
struct Header { //Offset Size Description
// Serial in libogc
u8 serial[12]; //0x0000 12 ?
- OSTime fmtTime; //0x000c 8 time of format (OSTime value)
+ u64 formatTime; //0x000c 8 time of format (OSTime value)
u8 SramBias[4]; //0x0014 4 sram bias at time of format
u8 SramLang[4]; //0x0018 4 sram language
u8 Unk2[4]; //0x001c 4 ? almost always 0
// end Serial in libogc
u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B
u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits
- u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
+ u16 Encoding; //0x0024 2 encoding (ASCII or japanese)
u8 Unused1[468]; //0x0026 468 unused (0xff)
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
- u8 CheckSum1[2]; //0x01fc 2 Checksum 1 (?)
- u8 CheckSum2[2]; //0x01fe 2 Checksum 2 (?)
+ u16 Checksum; //0x01fc 2 Additive Checksum
+ u16 Checksum_Inv; //0x01fe 2 Inverse Checksum
u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff)
} hdr;
@@ -153,31 +148,38 @@ private:
DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127)
u8 Padding[0x3a];
u8 UpdateCounter[2];//0x1ffa 2 update Counter
- u8 CheckSum1[2]; //0x1ffc 2 Checksum 1
- u8 CheckSum2[2]; //0x1ffe 2 Checksum 2
+ u16 Checksum; //0x1ffc 2 Additive Checksum
+ u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum
} dir, dir_backup;
struct BlockAlloc {
- u8 CheckSum1[2]; //0x0000 2 Checksum 1
- u8 CheckSum2[2]; //0x0002 2 Checksum 2
+ u16 Checksum; //0x0000 2 Additive Checksum
+ u16 Checksum_Inv; //0x0002 2 Inverse Checksum
u8 UpdateCounter[2];//0x0004 2 update Counter
u8 FreeBlocks[2]; //0x0006 2 free Blocks
u8 LastAllocated[2];//0x0008 2 last allocated Block
u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks
} bat,bat_backup;
+ struct GCMC_Header
+ {
+ Header *hdr;
+ Directory *dir, *dir_backup;
+ BlockAlloc *bat, *bat_backup;
+ };
#pragma pack(pop)
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
-
+ static void FormatInternal(GCMC_Header &GCP);
public:
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
bool IsValid() { return m_valid; }
bool IsAsciiEncoding();
bool Save();
- bool Format(bool sjis = false, bool New = true, int slot = 0, u16 SizeMb = MemCard2043Mb, bool hdrOnly = false);
+ bool Format(bool sjis = false, u16 SizeMb = MemCard2043Mb);
+ static bool Format(u8 * card_data, bool sjis = false, u16 SizeMb = MemCard2043Mb);
- void calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2);
+ static void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum);
u32 TestChecksums();
bool FixChecksums();
diff --git a/Source/Core/Core/Src/HW/GCPad.cpp b/Source/Core/Core/Src/HW/GCPad.cpp
index 8027c82db5..4c1b4dabdd 100644
--- a/Source/Core/Core/Src/HW/GCPad.cpp
+++ b/Source/Core/Core/Src/HW/GCPad.cpp
@@ -62,8 +62,6 @@ void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
{
memset(_pPADStatus, 0, sizeof(*_pPADStatus));
_pPADStatus->err = PAD_ERR_NONE;
- // wtf is this?
- _pPADStatus->button = PAD_USE_ORIGIN;
std::unique_lock<std::recursive_mutex> lk(g_plugin.controls_lock, std::try_to_lock);
@@ -107,4 +105,15 @@ void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
}
}
+bool GetMicButton(u8 pad)
+{
+
+ std::unique_lock<std::recursive_mutex> lk(g_plugin.controls_lock, std::try_to_lock);
+
+ if (!lk.owns_lock())
+ return false;
+
+ return ((GCPad*)g_plugin.controllers[pad])->GetMicButton();
+}
+
}
diff --git a/Source/Core/Core/Src/HW/GCPad.h b/Source/Core/Core/Src/HW/GCPad.h
index c3e1ace61e..f7f6af2f20 100644
--- a/Source/Core/Core/Src/HW/GCPad.h
+++ b/Source/Core/Core/Src/HW/GCPad.h
@@ -33,6 +33,7 @@ InputPlugin *GetPlugin();
void GetStatus(u8 _numPAD, SPADStatus* _pPADStatus);
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
+bool GetMicButton(u8 pad);
}
#endif
diff --git a/Source/Core/Core/Src/HW/GCPadEmu.cpp b/Source/Core/Core/Src/HW/GCPadEmu.cpp
index 47e32b1efc..837c9104cc 100644
--- a/Source/Core/Core/Src/HW/GCPadEmu.cpp
+++ b/Source/Core/Core/Src/HW/GCPadEmu.cpp
@@ -25,7 +25,8 @@ const u16 button_bitmasks[] =
PAD_BUTTON_X,
PAD_BUTTON_Y,
PAD_TRIGGER_Z,
- PAD_BUTTON_START
+ PAD_BUTTON_START,
+ 0 // MIC HAX
};
const u16 trigger_bitmasks[] =
@@ -47,6 +48,7 @@ const char* const named_buttons[] =
"Y",
"Z",
_trans("Start"),
+ "Mic"
};
const char* const named_triggers[] =
@@ -63,10 +65,11 @@ const char* const named_triggers[] =
GCPad::GCPad(const unsigned int index) : m_index(index)
{
+ int const mic_hax = index > 1;
// buttons
groups.push_back(m_buttons = new Buttons(_trans("Buttons")));
- for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons); ++i)
+ for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons) - mic_hax; ++i)
m_buttons->controls.push_back(new ControlGroup::Input(named_buttons[i]));
// sticks
@@ -203,3 +206,8 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
set_control(m_triggers, 0, "Q"); // L
set_control(m_triggers, 1, "W"); // R
}
+
+bool GCPad::GetMicButton() const
+{
+ return m_buttons->controls.back()->control_ref->State();
+}
diff --git a/Source/Core/Core/Src/HW/GCPadEmu.h b/Source/Core/Core/Src/HW/GCPadEmu.h
index 5fa67e284f..5185ff221c 100644
--- a/Source/Core/Core/Src/HW/GCPadEmu.h
+++ b/Source/Core/Core/Src/HW/GCPadEmu.h
@@ -29,6 +29,8 @@ public:
GCPad(const unsigned int index);
void GetInput(SPADStatus* const pad);
void SetOutput(const bool on);
+
+ bool GetMicButton() const;
std::string GetName() const;
diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp
index 486c757587..3af387792f 100644
--- a/Source/Core/Core/Src/HW/GPFifo.cpp
+++ b/Source/Core/Core/Src/HW/GPFifo.cpp
@@ -19,9 +19,9 @@
#include "ChunkFile.h"
#include "ProcessorInterface.h"
#include "Memmap.h"
-#include "../PowerPC/PowerPC.h"
-
#include "VideoBackendBase.h"
+#include "../PowerPC/JitCommon/JitBase.h"
+#include "../PowerPC/PowerPC.h"
#include "GPFifo.h"
@@ -54,6 +54,7 @@ void DoState(PointerWrap &p)
void Init()
{
ResetGatherPipe();
+ memset(m_gatherPipe, 0, sizeof(m_gatherPipe));
}
bool IsEmpty()
@@ -95,6 +96,15 @@ void STACKALIGN CheckGatherPipe()
// move back the spill bytes
memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount);
+
+ // Profile where the FIFO writes are occurring.
+ if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end()))
+ {
+ jit->js.fifoWriteAddresses.insert(PC);
+
+ // Invalidate the JIT block so that it gets recompiled with the external exception check included.
+ jit->GetBlockCache()->InvalidateICache(PC, 4);
+ }
}
}
diff --git a/Source/Core/Core/Src/HW/HW.cpp b/Source/Core/Core/Src/HW/HW.cpp
index ec8aa7063f..0ec08b7d97 100644
--- a/Source/Core/Core/Src/HW/HW.cpp
+++ b/Source/Core/Core/Src/HW/HW.cpp
@@ -43,6 +43,7 @@ namespace HW
void Init()
{
CoreTiming::Init();
+ SystemTimers::PreInit();
State::Init();
@@ -89,18 +90,35 @@ namespace HW
void DoState(PointerWrap &p)
{
Memory::DoState(p);
+ p.DoMarker("Memory");
VideoInterface::DoState(p);
+ p.DoMarker("VideoInterface");
SerialInterface::DoState(p);
+ p.DoMarker("SerialInterface");
ProcessorInterface::DoState(p);
+ p.DoMarker("ProcessorInterface");
DSP::DoState(p);
+ p.DoMarker("DSP");
DVDInterface::DoState(p);
+ p.DoMarker("DVDInterface");
GPFifo::DoState(p);
+ p.DoMarker("GPFifo");
ExpansionInterface::DoState(p);
+ p.DoMarker("ExpansionInterface");
AudioInterface::DoState(p);
+ p.DoMarker("AudioInterface");
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{
WII_IPCInterface::DoState(p);
+ p.DoMarker("WII_IPCInterface");
WII_IPC_HLE_Interface::DoState(p);
+ p.DoMarker("WII_IPC_HLE_Interface");
}
+ p.DoMarker("WIIHW");
+ }
+
+ void OnAfterLoad()
+ {
+ ExpansionInterface::OnAfterLoad();
}
}
diff --git a/Source/Core/Core/Src/HW/HW.h b/Source/Core/Core/Src/HW/HW.h
index cd3375d3ac..3c4478ac2b 100644
--- a/Source/Core/Core/Src/HW/HW.h
+++ b/Source/Core/Core/Src/HW/HW.h
@@ -26,6 +26,7 @@ namespace HW
void Init();
void Shutdown();
void DoState(PointerWrap &p);
+ void OnAfterLoad();
}
#endif
diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp
index 1c185ccaf3..f26ac76a14 100644
--- a/Source/Core/Core/Src/HW/Memmap.cpp
+++ b/Source/Core/Core/Src/HW/Memmap.cpp
@@ -373,8 +373,13 @@ void DoState(PointerWrap &p)
p.DoArray(m_pPhysicalRAM, RAM_SIZE);
// p.DoArray(m_pVirtualEFB, EFB_SIZE);
p.DoArray(m_pVirtualL1Cache, L1_CACHE_SIZE);
+ p.DoMarker("Memory RAM");
+ if (bFakeVMEM)
+ p.DoArray(m_pVirtualFakeVMEM, FAKEVMEM_SIZE);
+ p.DoMarker("Memory FakeVMEM");
if (wii)
p.DoArray(m_pEXRAM, EXRAM_SIZE);
+ p.DoMarker("Memory EXRAM");
}
void Shutdown()
@@ -417,6 +422,44 @@ u32 Read_Instruction(const u32 em_address)
return inst.hex;
}
+u32 Read_Opcode_JIT_Uncached(const u32 _Address)
+{
+ u8* iCache;
+ u32 addr;
+ if (_Address & JIT_ICACHE_VMEM_BIT)
+ {
+ iCache = jit->GetBlockCache()->GetICacheVMEM();
+ addr = _Address & JIT_ICACHE_MASK;
+ }
+ else if (_Address & JIT_ICACHE_EXRAM_BIT)
+ {
+ iCache = jit->GetBlockCache()->GetICacheEx();
+ addr = _Address & JIT_ICACHEEX_MASK;
+ }
+ else
+ {
+ iCache = jit->GetBlockCache()->GetICache();
+ addr = _Address & JIT_ICACHE_MASK;
+ }
+ u32 inst = *(u32*)(iCache + addr);
+ if (inst == JIT_ICACHE_INVALID_WORD)
+ {
+ u32 cache_block_start = addr & ~0x1f;
+ u32 mem_block_start = _Address & ~0x1f;
+ u8 *pMem = Memory::GetPointer(mem_block_start);
+ memcpy(iCache + cache_block_start, pMem, 32);
+ inst = *(u32*)(iCache + addr);
+ }
+ inst = Common::swap32(inst);
+
+ if ((inst & 0xfc000000) == 0)
+ {
+ inst = jit->GetBlockCache()->GetOriginalFirstOp(inst);
+ }
+
+ return inst;
+}
+
u32 Read_Opcode_JIT(u32 _Address)
{
#ifdef FAST_ICACHE
@@ -428,8 +471,13 @@ u32 Read_Opcode_JIT(u32 _Address)
return 0;
}
}
+ u32 inst = 0;
- u32 inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
+ // Bypass the icache for the external interrupt exception handler
+ if ( (_Address & 0x0FFFFF00) == 0x00000500 )
+ inst = Read_Opcode_JIT_Uncached(_Address);
+ else
+ inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
@@ -580,69 +628,57 @@ void GetString(std::string& _string, const u32 em_address)
// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit
// programs don't have problems directly addressing any part of memory.
+// TODO re-think with respect to other BAT setups...
u8 *GetPointer(const u32 _Address)
{
- switch (_Address >> 24)
+ switch (_Address >> 28)
{
- case 0x00:
- case 0x01:
- case 0x80:
- case 0x81:
- case 0xC0:
- case 0xC1:
- return (u8*)(((char*)m_pPhysicalRAM) + (_Address & RAM_MASK));
+ case 0x0:
+ case 0x8:
+ return m_pPhysicalRAM + (_Address & RAM_MASK);
+ case 0xc:
+ switch (_Address >> 24)
+ {
+ case 0xcc:
+ case 0xcd:
+ _dbg_assert_msg_(MEMMAP, 0, "GetPointer from IO Bridge doesnt work");
+ case 0xc8:
+ // EFB. We don't want to return a pointer here since we have no memory mapped for it.
+ break;
+
+ default:
+ return m_pPhysicalRAM + (_Address & RAM_MASK);
+ }
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x90:
- case 0x91:
- case 0x92:
- case 0x93:
- case 0xD0:
- case 0xD1:
- case 0xD2:
- case 0xD3:
+ case 0x1:
+ case 0x9:
+ case 0xd:
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
- return (u8*)(((char*)m_pPhysicalEXRAM) + (_Address & EXRAM_MASK));
+ return m_pPhysicalEXRAM + (_Address & EXRAM_MASK);
else
- return 0;
+ break;
- case 0xE0:
+ case 0xe:
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
return GetCachePtr() + (_Address & L1_CACHE_MASK);
else
- return 0;
-
- case 0xC8:
- return 0; // EFB. We don't want to return a pointer here since we have no memory mapped for it.
+ break;
- case 0xCC:
- case 0xCD:
- _dbg_assert_msg_(MEMMAP, 0, "GetPointer from IO Bridge doesnt work");
- return NULL;
default:
if (bFakeVMEM)
- {
- return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK));
- }
- else
- {
- if (!Core::g_CoreStartupParameter.bMMU &&
- !PanicYesNoT("Unknown pointer %#08x\nContinue?", _Address))
- Crash();
- return 0;
- }
- break;
+ return m_pVirtualFakeVMEM + (_Address & FAKEVMEM_MASK);
}
+
+ ERROR_LOG(MEMMAP, "Unknown Pointer %#8x PC %#8x LR %#8x", _Address, PC, LR);
+
return NULL;
}
bool IsRAMAddress(const u32 addr, bool allow_locked_cache)
{
- switch ((addr >> 24) & 0xFC) {
+ switch ((addr >> 24) & 0xFC)
+ {
case 0x00:
case 0x80:
case 0xC0:
diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h
index 26a918fee8..6c808cbc00 100644
--- a/Source/Core/Core/Src/HW/Memmap.h
+++ b/Source/Core/Core/Src/HW/Memmap.h
@@ -58,20 +58,22 @@ extern u8 *m_pL1Cache;
enum
{
- // The size should be just 24MB instead of 32, but the RAM_MASK wouldn't
- // work.
- RAM_SIZE = 0x2000000,
- RAM_MASK = 0x1FFFFFF,
+ // RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is
+ // what will be reported in lowmem, and thus used by emulated software.
+ // Note: Writing to lowmem is done by IPL. If using retail IPL, it will
+ // always be set to 24MB.
+ REALRAM_SIZE = 0x1800000,
+ RAM_SIZE = ROUND_UP_POW2(REALRAM_SIZE),
+ RAM_MASK = RAM_SIZE - 1,
FAKEVMEM_SIZE = 0x2000000,
- FAKEVMEM_MASK = 0x1FFFFFF,
- REALRAM_SIZE = 0x1800000,
+ FAKEVMEM_MASK = FAKEVMEM_SIZE - 1,
L1_CACHE_SIZE = 0x40000,
- L1_CACHE_MASK = 0x3FFFF,
+ L1_CACHE_MASK = L1_CACHE_SIZE - 1,
EFB_SIZE = 0x200000,
- EFB_MASK = 0x1FFFFF,
+ EFB_MASK = EFB_SIZE - 1,
IO_SIZE = 0x10000,
EXRAM_SIZE = 0x4000000,
- EXRAM_MASK = 0x3FFFFFF,
+ EXRAM_MASK = EXRAM_SIZE - 1,
ADDR_MASK_HW_ACCESS = 0x0c000000,
ADDR_MASK_MEM1 = 0x20000000,
diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp
index 178550b445..09697f4965 100644
--- a/Source/Core/Core/Src/HW/SI.cpp
+++ b/Source/Core/Core/Src/HW/SI.cpp
@@ -246,10 +246,8 @@ void Init()
g_Channel[i].m_InHi.Hex = 0;
g_Channel[i].m_InLo.Hex = 0;
- if (Movie::IsUsingPad(i))
- AddDevice(SI_GC_CONTROLLER, i);
- else if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
- AddDevice(SI_NONE, i);
+ if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
+ AddDevice(Movie::IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
else
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
}
@@ -538,7 +536,7 @@ void RemoveDevice(int _iDeviceNumber)
g_Channel[_iDeviceNumber].m_pDevice = NULL;
}
-void AddDevice(const TSIDevices _device, int _iDeviceNumber)
+void AddDevice(const SIDevices _device, int _iDeviceNumber)
{
//_dbg_assert_(SERIALINTERFACE, _iDeviceNumber < NUMBER_OF_CHANNELS);
@@ -572,14 +570,14 @@ void ChangeDeviceCallback(u64 userdata, int cyclesLate)
SetNoResponse(channel);
- AddDevice((TSIDevices)(u32)userdata, channel);
+ AddDevice((SIDevices)(u32)userdata, channel);
}
-void ChangeDevice(TSIDevices device, int channel)
+void ChangeDevice(SIDevices device, int channel)
{
// Called from GUI, so we need to make it thread safe.
// Let the hardware see no device for .5b cycles
- CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SI_NONE);
+ CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE);
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device);
}
diff --git a/Source/Core/Core/Src/HW/SI.h b/Source/Core/Core/Src/HW/SI.h
index 59e38df9c8..c1eb336798 100644
--- a/Source/Core/Core/Src/HW/SI.h
+++ b/Source/Core/Core/Src/HW/SI.h
@@ -31,10 +31,10 @@ void DoState(PointerWrap &p);
void UpdateDevices();
void RemoveDevice(int _iDeviceNumber);
-void AddDevice(const TSIDevices _device, int _iDeviceNumber);
+void AddDevice(const SIDevices _device, int _iDeviceNumber);
void ChangeDeviceCallback(u64 userdata, int cyclesLate);
-void ChangeDevice(TSIDevices device, int channel);
+void ChangeDevice(SIDevices device, int channel);
void Read32(u32& _uReturnValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp
index c1a65ebcb8..6c0c40f40d 100644
--- a/Source/Core/Core/Src/HW/SI_Device.cpp
+++ b/Source/Core/Core/Src/HW/SI_Device.cpp
@@ -68,25 +68,29 @@ public:
// F A C T O R Y
-ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber)
+ISIDevice* SIDevice_Create(const SIDevices device, const int port_number)
{
- switch(_SIDevice)
+ switch (device)
{
- case SI_GC_CONTROLLER:
- return new CSIDevice_GCController(_iDeviceNumber);
+ case SIDEVICE_GC_CONTROLLER:
+ return new CSIDevice_GCController(port_number);
break;
- case SI_GBA:
- return new CSIDevice_GBA(_iDeviceNumber);
+ case SIDEVICE_GC_TARUKONGA:
+ return new CSIDevice_TaruKonga(port_number);
break;
- case SI_AM_BASEBOARD:
- return new CSIDevice_AMBaseboard(_iDeviceNumber);
+ case SIDEVICE_GC_GBA:
+ return new CSIDevice_GBA(port_number);
break;
- case SI_NONE:
+ case SIDEVICE_AM_BASEBOARD:
+ return new CSIDevice_AMBaseboard(port_number);
+ break;
+
+ case SIDEVICE_NONE:
default:
- return new CSIDevice_Null(_iDeviceNumber);
+ return new CSIDevice_Null(port_number);
break;
}
}
diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h
index 642a54d918..2ed982ad0a 100644
--- a/Source/Core/Core/Src/HW/SI_Device.h
+++ b/Source/Core/Core/Src/HW/SI_Device.h
@@ -57,7 +57,7 @@ public:
virtual void SendCommand(u32 _Cmd, u8 _Poll) = 0;
};
-// SI Device IDs
+// SI Device IDs for emulator use
enum TSIDevices
{
SI_NONE = SI_ERROR_NO_RESPONSE,
@@ -72,6 +72,22 @@ enum TSIDevices
SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state
};
-extern ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber);
+// For configuration use, since some devices can have the same SI Device ID
+enum SIDevices
+{
+ SIDEVICE_NONE,
+ SIDEVICE_N64_MIC,
+ SIDEVICE_N64_KEYBOARD,
+ SIDEVICE_N64_MOUSE,
+ SIDEVICE_N64_CONTROLLER,
+ SIDEVICE_GC_GBA,
+ SIDEVICE_GC_CONTROLLER,
+ SIDEVICE_GC_KEYBOARD,
+ SIDEVICE_GC_STEERING,
+ SIDEVICE_GC_TARUKONGA,
+ SIDEVICE_AM_BASEBOARD
+};
+
+extern ISIDevice* SIDevice_Create(const SIDevices device, const int port_number);
#endif
diff --git a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp
index f4ee12d9dc..abb4bf8dec 100644
--- a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp
+++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp
@@ -59,60 +59,49 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength)
// For debug logging only
ISIDevice::RunBuffer(_pBuffer, _iLength);
- int iPosition = 0;
- while (iPosition < _iLength)
+ // Read the command
+ EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
+
+ // Handle it
+ switch (command)
{
- // Read the command
- EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[iPosition ^ 3]);
- iPosition++;
+ case CMD_RESET:
+ *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER;
+ break;
- // Handle it
- switch (command)
+ case CMD_ORIGIN:
{
- case CMD_RESET:
- {
- *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER;
- iPosition = _iLength; // Break the while loop
- }
- break;
-
- case CMD_ORIGIN:
+ INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
+ u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
+ for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
- INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
- u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
- for (int i = 0; i < (int)sizeof(SOrigin); i++)
- {
- _pBuffer[i ^ 3] = *pCalibration++;
- }
+ _pBuffer[i ^ 3] = *pCalibration++;
}
- iPosition = _iLength;
- break;
-
- // Recalibrate (FiRES: i am not 100 percent sure about this)
- case CMD_RECALIBRATE:
- {
- INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
- u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
- for (int i = 0; i < (int)sizeof(SOrigin); i++)
- {
- _pBuffer[i ^ 3] = *pCalibration++;
- }
- }
- iPosition = _iLength;
- break;
+ }
+ break;
- // DEFAULT
- default:
+ // Recalibrate (FiRES: i am not 100 percent sure about this)
+ case CMD_RECALIBRATE:
+ {
+ INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
+ u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
+ for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
- ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
- PanicAlert("SI: Unknown command");
- iPosition = _iLength;
- }
- break;
+ _pBuffer[i ^ 3] = *pCalibration++;
+ }
}
+ break;
+
+ // DEFAULT
+ default:
+ {
+ ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
+ PanicAlert("SI: Unknown command");
+ }
+ break;
}
- return iPosition;
+ return _iLength;
}
@@ -156,9 +145,7 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
// Thankfully changing mode does not change the high bits ;)
_Hi = (u32)((u8)PadStatus.stickY);
_Hi |= (u32)((u8)PadStatus.stickX << 8);
- _Hi |= (u32)((u16)PadStatus.button << 16);
- _Hi |= 0x00800000; // F|RES: means that the pad must be "combined" with the origin to match the "final" OSPad-Struct
- //_Hi |= 0x20000000; // ?
+ _Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16);
// Low bits are packed differently per mode
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7)
@@ -239,8 +226,6 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
}
}
- SetMic(PadStatus.MicButton); // This is dumb and should not be here
-
return true;
}
diff --git a/Source/Core/Core/Src/HW/SI_DeviceGCController.h b/Source/Core/Core/Src/HW/SI_DeviceGCController.h
index 5493417793..81e0d9d03f 100644
--- a/Source/Core/Core/Src/HW/SI_DeviceGCController.h
+++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.h
@@ -30,7 +30,6 @@ private:
// Commands
enum EBufferCommands
{
- CMD_INVALID = 0xFFFFFFFF,
CMD_RESET = 0x00,
CMD_ORIGIN = 0x41,
CMD_RECALIBRATE = 0x42,
@@ -111,4 +110,20 @@ public:
// Send a command directly
virtual void SendCommand(u32 _Cmd, u8 _Poll);
};
+
+
+// "TaruKonga", the DK Bongo controller
+class CSIDevice_TaruKonga : public CSIDevice_GCController
+{
+public:
+ CSIDevice_TaruKonga(int _iDeviceNumber) : CSIDevice_GCController(_iDeviceNumber) { }
+
+ virtual bool GetData(u32& _Hi, u32& _Low)
+ {
+ CSIDevice_GCController::GetData(_Hi, _Low);
+ _Hi &= ~PAD_USE_ORIGIN << 16;
+ return true;
+ }
+};
+
#endif
diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp
index d7bbfc331b..b9f9fe0107 100644
--- a/Source/Core/Core/Src/HW/SystemTimers.cpp
+++ b/Source/Core/Core/Src/HW/SystemTimers.cpp
@@ -231,12 +231,19 @@ void PatchEngineCallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_PatchEngine);
}
-void Init()
+// split from Init to break a circular dependency between VideoInterface::Init and SystemTimers::Init
+void PreInit()
{
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
- {
CPU_CORE_CLOCK = 729000000u;
+ else
+ CPU_CORE_CLOCK = 486000000u;
+}
+void Init()
+{
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
+ {
if (!DSP::GetDSPEmulator()->IsLLE())
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.003f);
@@ -246,15 +253,13 @@ void Init()
// FIXME: does Wiimote Speaker support really require a different interval? (issue 4608)
const int interval = SConfig::GetInstance().m_LocalCoreStartupParameter.
- bDisableWiimoteSpeaker ? 1250 : 1500;
+ bDisableWiimoteSpeaker ? 15000 : 4000;
const int fields = SConfig::GetInstance().m_LocalCoreStartupParameter.
bVBeam ? 2 : 1;
IPC_HLE_PERIOD = GetTicksPerSecond() / (interval * fields);
}
else
{
- CPU_CORE_CLOCK = 486000000u;
-
if (!DSP::GetDSPEmulator()->IsLLE())
DSP_PERIOD = (int)(GetTicksPerSecond() * 0.005f);
}
diff --git a/Source/Core/Core/Src/HW/SystemTimers.h b/Source/Core/Core/Src/HW/SystemTimers.h
index ec8e425907..629593bc1d 100644
--- a/Source/Core/Core/Src/HW/SystemTimers.h
+++ b/Source/Core/Core/Src/HW/SystemTimers.h
@@ -24,6 +24,7 @@ namespace SystemTimers
{
u32 GetTicksPerSecond();
+void PreInit();
void Init();
void Shutdown();
diff --git a/Source/Core/Core/Src/HW/VideoInterface.cpp b/Source/Core/Core/Src/HW/VideoInterface.cpp
index d8d6d98570..677f30921f 100644
--- a/Source/Core/Core/Src/HW/VideoInterface.cpp
+++ b/Source/Core/Core/Src/HW/VideoInterface.cpp
@@ -28,6 +28,7 @@
#include "StringUtil.h"
#include "VideoBackendBase.h"
+#include "State.h"
namespace VideoInterface
{
@@ -157,6 +158,29 @@ void Preset(bool _bNTSC)
void Init()
{
+ m_VerticalTimingRegister.Hex = 0;
+ m_DisplayControlRegister.Hex = 0;
+ m_HTiming0.Hex = 0;
+ m_HTiming1.Hex = 0;
+ m_VBlankTimingOdd.Hex = 0;
+ m_VBlankTimingEven.Hex = 0;
+ m_BurstBlankingOdd.Hex = 0;
+ m_BurstBlankingEven.Hex = 0;
+ m_XFBInfoTop.Hex = 0;
+ m_XFBInfoBottom.Hex = 0;
+ m_3DFBInfoTop.Hex = 0;
+ m_3DFBInfoBottom.Hex = 0;
+ m_VBeamPos = 0;
+ m_HBeamPos = 0;
+ m_HorizontalStepping.Hex = 0;
+ m_HorizontalScaling.Hex = 0;
+ m_UnkAARegister = 0;
+ m_Clock = 0;
+ m_DTVStatus.Hex = 0;
+ m_FBWidth = 0;
+ m_BorderHBlank.Hex = 0;
+ memset(&m_FilterCoefTables, 0, sizeof(m_FilterCoefTables));
+
fields = Core::g_CoreStartupParameter.bVBeam ? 1 : 2;
m_DTVStatus.ntsc_j = Core::g_CoreStartupParameter.bForceNTSCJ;
@@ -164,6 +188,9 @@ void Init()
for (int i = 0; i < 4; i++)
m_InterruptRegister[i].Hex = 0;
+ for (int i = 0; i < 2; i++)
+ m_LatchRegister[i].Hex = 0;
+
m_DisplayControlRegister.Hex = 0;
UpdateParameters();
}
@@ -698,6 +725,9 @@ void UpdateInterrupts()
{
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false);
}
+
+ if (m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK)
+ State::ProcessRequestedStates(1);
}
u32 GetXFBAddressTop()
@@ -755,7 +785,7 @@ void UpdateParameters()
}
}
-int GetTicksPerLine()
+unsigned int GetTicksPerLine()
{
if (s_lineCount == 0)
{
@@ -767,7 +797,7 @@ int GetTicksPerLine()
}
}
-int GetTicksPerFrame()
+unsigned int GetTicksPerFrame()
{
return TicksPerFrame;
}
diff --git a/Source/Core/Core/Src/HW/VideoInterface.h b/Source/Core/Core/Src/HW/VideoInterface.h
index 021e48efdf..0eba189851 100644
--- a/Source/Core/Core/Src/HW/VideoInterface.h
+++ b/Source/Core/Core/Src/HW/VideoInterface.h
@@ -357,8 +357,8 @@ union UVIDTVStatus
// Change values pertaining to video mode
void UpdateParameters();
- int GetTicksPerLine();
- int GetTicksPerFrame();
+ unsigned int GetTicksPerLine();
+ unsigned int GetTicksPerFrame();
};
#endif // _VIDEOINTERFACE_H
diff --git a/Source/Core/Core/Src/HW/Wiimote.cpp b/Source/Core/Core/Src/HW/Wiimote.cpp
index 149c1db01e..30ab7af141 100644
--- a/Source/Core/Core/Src/HW/Wiimote.cpp
+++ b/Source/Core/Core/Src/HW/Wiimote.cpp
@@ -48,7 +48,8 @@ void Initialize(void* const hwnd)
WiimoteReal::Initialize();
- if (Movie::IsPlayingInput()) // reload Wiimotes with our settings
+ // reload Wiimotes with our settings
+ if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
Movie::ChangeWiiPads();
}
diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp
index 937f785feb..6f7f80ece7 100644
--- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp
+++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp
@@ -301,7 +301,7 @@ Wiimote::Wiimote( const unsigned int index )
m_options->settings.push_back(new ControlGroup::Setting(_trans("Upright Wiimote"), false));
// TODO: This value should probably be re-read if SYSCONF gets changed
- m_sensor_bar_on_top = (bool)SConfig::GetInstance().m_SYSCONF->GetData<u8>("BT.BAR");
+ m_sensor_bar_on_top = SConfig::GetInstance().m_SYSCONF->GetData<u8>("BT.BAR") != 0;
// --- reset eeprom/register/values to default ---
Reset();
@@ -318,7 +318,6 @@ std::string Wiimote::GetName() const
bool Wiimote::Step()
{
const bool has_focus = HAS_FOCUS;
- const bool is_sideways = m_options->settings[1]->value != 0;
// TODO: change this a bit
m_motion_plus_present = m_extension->settings[0]->value != 0;
@@ -329,13 +328,10 @@ bool Wiimote::Step()
m_rumble->controls[0]->control_ref->State(m_rumble_on);
- // update buttons in status struct
- m_status.buttons = 0;
- if (has_focus)
+ // when a movie is active, this button status update is disabled (moved), because movies only record data reports.
+ if(!(Movie::IsPlayingInput() || Movie::IsRecordingInput()))
{
- m_buttons->GetState(&m_status.buttons, button_bitmasks);
- m_dpad->GetState(&m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks);
- UDPTLayer::GetButtons(m_udp, &m_status.buttons);
+ UpdateButtonsStatus(has_focus);
}
// check if there is a read data request
@@ -375,8 +371,27 @@ bool Wiimote::Step()
return false;
}
+void Wiimote::UpdateButtonsStatus(bool has_focus)
+{
+ // update buttons in status struct
+ m_status.buttons = 0;
+ if (has_focus)
+ {
+ const bool is_sideways = m_options->settings[1]->value != 0;
+ m_buttons->GetState(&m_status.buttons, button_bitmasks);
+ m_dpad->GetState(&m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks);
+ UDPTLayer::GetButtons(m_udp, &m_status.buttons);
+ }
+}
+
void Wiimote::GetCoreData(u8* const data)
{
+ // when a movie is active, the button update happens here instead of Wiimote::Step, to avoid potential desync issues.
+ if(Movie::IsPlayingInput() || Movie::IsRecordingInput())
+ {
+ UpdateButtonsStatus(HAS_FOCUS);
+ }
+
*(wm_core*)data |= m_status.buttons;
}
@@ -637,11 +652,15 @@ void Wiimote::Update()
Movie::SetPolledDevice();
- if (!Movie::IsPlayingInput() || !Movie::PlayWiimote(m_index, data, rptf_size))
+ const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE];
+ rptf_size = rptf.size;
+ if (Movie::IsPlayingInput() && Movie::PlayWiimote(m_index, data, rptf, m_reg_ir.mode))
+ {
+ if (rptf.core)
+ m_status.buttons = *(wm_core*)(data + rptf.core);
+ }
+ else
{
- const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE];
- rptf_size = rptf.size;
-
data[0] = 0xA1;
data[1] = m_reporting_mode;
@@ -661,8 +680,8 @@ void Wiimote::Update()
if (rptf.ext)
GetExtData(data + rptf.ext);
- // hybrid wiimote stuff
- if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index])
+ // hybrid wiimote stuff (for now, it's not supported while recording)
+ if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && !Movie::IsRecordingInput())
{
using namespace WiimoteReal;
@@ -742,10 +761,10 @@ void Wiimote::Update()
}
}
}
- if (Movie::IsRecordingInput())
- {
- Movie::RecordWiimote(m_index, data, rptf_size);
- }
+ }
+ if (Movie::IsRecordingInput())
+ {
+ Movie::RecordWiimote(m_index, data, rptf, m_reg_ir.mode);
}
// don't send a data report if auto reporting is off
diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h
index ecc86ad5b3..17a3a2adfc 100644
--- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h
+++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h
@@ -113,6 +113,7 @@ protected:
bool Step();
void HidOutputReport(const wm_report* const sr, const bool send_ack = true);
void HandleExtensionSwap();
+ void UpdateButtonsStatus(bool has_focus);
void GetCoreData(u8* const data);
void GetAccelData(u8* const data, u8* const buttons);
diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp
index e7316a896d..c22e1972dc 100644
--- a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp
+++ b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp
@@ -124,11 +124,6 @@ inline void init_lib()
}
}
-// VID = Nintendo, PID = Wiimote
-static int VIDLength = 3;
-static int VID[3] = {0x057E, 0x0001, 0x0002};
-static int PID[3] = {0x0306, 0x0002, 0x00F7};
-
namespace WiimoteReal
{
@@ -210,39 +205,23 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes)
attr.Size = sizeof(attr);
HidD_GetAttributes(dev, &attr);
- bool foundWiimote = false;
- for (int i = 0; i < VIDLength; i++)
- {
- if (attr.VendorID == VID[i] && attr.ProductID == PID[i])
- {
- foundWiimote = true;
- break;
- }
- }
+ // Find an unused slot
+ unsigned int k = 0;
+ for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k);
+ wm[k] = new Wiimote(k);
+ wm[k]->dev_handle = dev;
+ memcpy(wm[k]->devicepath, detail_data->DevicePath, 197);
- if (foundWiimote)
+ if (!wm[k]->Connect())
{
- // This is a wiimote
- // Find an unused slot
- unsigned int k = 0;
- for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k);
- wm[k] = new Wiimote(k);
- wm[k]->dev_handle = dev;
- memcpy(wm[k]->devicepath, detail_data->DevicePath, 197);
-
- if (!wm[k]->Connect())
- {
- ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1);
- delete wm[k];
- wm[k] = NULL;
- }
- else
- ++found_wiimotes;
+ ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1);
+ delete wm[k];
+ wm[k] = NULL;
+ CloseHandle(dev);
}
else
{
- // Not a wiimote
- CloseHandle(dev);
+ ++found_wiimotes;
}
}
@@ -399,28 +378,16 @@ int Wiimote::IOWrite(unsigned char* buf, int len)
return i;
}
-#if 0
dw = GetLastError();
// Checking for 121 = timeout on semaphore/device off/disconnected to
// avoid trouble with other stacks toshiba/widcomm
- // 995 = The I/O operation has been aborted because of a thread exit or
- // an application request.
-
- if ( (dw == 121) || (dw == 995) )
+ if (dw == 121)
{
- NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]");
+ NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout");
RealDisconnect();
}
else ERROR_LOG(WIIMOTE,
"IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw);
-#endif
-
-
- // If the part below causes trouble on WIDCOMM/TOSHIBA stack uncomment
- // the lines above, and comment out the 3 lines below instead.
-
- NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]");
- RealDisconnect();
return 0;
}
@@ -456,8 +423,8 @@ int PairUp(bool unpair)
{
init_lib();
- // match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01"
- const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}");
+ // match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01", "Nintendo RVL-CNT-01-TR"
+ const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}(-\\w{2})?");
int nPaired = 0;
diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm
index 0c2f742987..a899dac201 100644
--- a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm
+++ b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm
@@ -129,7 +129,7 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
[bti setInquiryLength: 5];
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
- minorDeviceClass: kBluetoothDeviceClassMinorPeripheral2Joystick
+ minorDeviceClass: kBluetoothDeviceClassMinorAny
];
[bti setUpdateNewDeviceNames: NO];
@@ -177,6 +177,10 @@ bool Wiimote::Connect()
if (IsConnected())
return false;
+ if ([btd remoteNameRequest:nil] == kIOReturnSuccess)
+ m_motion_plus_inside =
+ static_cast<bool>([[btd getName] hasSuffix:@"-TR"]);
+
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
@@ -244,7 +248,7 @@ int Wiimote::IOWrite(unsigned char *buf, int len)
if (!IsConnected())
return 0;
- ret = [cchan writeAsync: buf length: len refcon: nil];
+ ret = [ichan writeAsync: buf length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;
diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp
index 0793900900..1ac0823ebb 100644
--- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp
+++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp
@@ -50,6 +50,7 @@ Wiimote::Wiimote(const unsigned int _index)
#endif
, leds(0), m_last_data_report(Report((u8 *)NULL, 0))
, m_channel(0), m_connected(false)
+ , m_motion_plus_inside(false)
{
#if defined(__linux__) && HAVE_BLUEZ
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
@@ -142,24 +143,16 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
- // some hax, since we just send the last data report to Dolphin on each Update() call
- // , make the wiimote only send updated data reports when data changes
- // == less bt traffic, eliminates some unneeded packets
- //if (WM_REPORT_MODE == ((u8*)data)[1])
- //{
- // // also delete the last data report
- // if (m_last_data_report.first)
- // {
- // delete[] m_last_data_report.first;
- // m_last_data_report.first = NULL;
- // }
-
- // // nice var names :p, this seems to be this one
- // ((wm_report_mode*)(rpt.first + 2))->all_the_time = false;
- // //((wm_report_mode*)(data + 2))->continuous = false;
- //}
-
- if (rpt.first[0] == 0xa2 && rpt.first[1] == 0x18 && rpt.second == 23)
+ // Convert output DATA packets to SET_REPORT packets for non-TR
+ // Wiimotes. Nintendo Wiimotes work without this translation, but 3rd
+ // party ones don't.
+ u8 head = m_motion_plus_inside ? 0xa2 : 0x52;
+ if (rpt.first[0] == 0xa2)
+ {
+ rpt.first[0] = head;
+ }
+
+ if (rpt.first[0] == head && rpt.first[1] == 0x18 && rpt.second == 23)
{
m_audio_reports.Push(rpt);
return;
diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h
index f3c5b884f8..8229abee52 100644
--- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h
+++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h
@@ -95,6 +95,7 @@ private:
void ThreadFunc();
bool m_connected;
+ bool m_motion_plus_inside;
std::thread m_wiimote_thread;
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp
index 2fa2587e60..cd4f679db9 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp
@@ -68,8 +68,13 @@ TDeviceMap g_DeviceMap;
// STATE_TO_SAVE
typedef std::map<u32, std::string> TFileNameMap;
-TFileNameMap g_FileNameMap;
-u32 g_LastDeviceID;
+
+#define IPC_MAX_FDS 0x18
+#define ES_MAX_COUNT 2
+IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
+bool es_inuse[ES_MAX_COUNT];
+IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];
+
typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm
@@ -78,14 +83,28 @@ static ipc_msg_queue reply_queue; // arm -> ppc
void Init()
{
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
+
+ u32 i;
+ for (i=0; i<IPC_MAX_FDS; i++)
+ {
+ g_FdMap[i] = NULL;
+ }
- u32 i = IPC_FIRST_HARDWARE_ID;
+ i = 0;
// Build hardware devices
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;
- g_DeviceMap[i] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
+
+ // IOS allows two ES devices at a time<
+ u32 j;
+ for (j=0; j<ES_MAX_COUNT; j++)
+ {
+ g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
+ es_inuse[j] = false;
+ }
+
g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
@@ -93,14 +112,27 @@ void Init()
g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, std::string("/dev/net/ip/top")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, std::string("/dev/usb/kbd")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, std::string("/dev/sdio/slot0")); i++;
+ g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
- g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_"));
-
- g_LastDeviceID = IPC_FIRST_FILEIO_ID;
+ g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
+ g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;
}
void Reset(bool _bHard)
{
+
+ u32 i;
+ for (i=0; i<IPC_MAX_FDS; i++)
+ {
+ if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
+ {
+ // close all files and delete their resources
+ g_FdMap[i]->Close(0, true);
+ delete g_FdMap[i];
+ }
+ g_FdMap[i] = NULL;
+ }
+
TDeviceMap::iterator itr = g_DeviceMap.begin();
while (itr != g_DeviceMap.end())
{
@@ -109,21 +141,17 @@ void Reset(bool _bHard)
// Force close
itr->second->Close(0, true);
// Hardware should not be deleted unless it is a hard reset
- if (_bHard || !itr->second->IsHardware())
+ if (_bHard)
delete itr->second;
}
++itr;
}
- // Skip hardware devices if not a hard reset
- itr = (_bHard) ? g_DeviceMap.begin() : g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
- // Erase devices
- g_DeviceMap.erase(itr, g_DeviceMap.end());
- g_FileNameMap.clear();
-
+ if (_bHard)
+ {
+ g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
+ }
request_queue.clear();
reply_queue.clear();
-
- g_LastDeviceID = IPC_FIRST_FILEIO_ID;
}
void Shutdown()
@@ -133,41 +161,53 @@ void Shutdown()
void SetDefaultContentFile(const std::string& _rFilename)
{
- CWII_IPC_HLE_Device_es* pDevice =
- (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
- if (pDevice)
- pDevice->LoadWAD(_rFilename);
+ TDeviceMap::const_iterator itr = g_DeviceMap.begin();
+ while (itr != g_DeviceMap.end())
+ {
+ if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
+ {
+ ((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
+ }
+ ++itr;
+ }
}
void ES_DIVerify(u8 *_pTMD, u32 _sz)
{
- CWII_IPC_HLE_Device_es* pDevice =
- (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
- if (pDevice)
- pDevice->ES_DIVerify(_pTMD, _sz);
- else
- ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available");
+ CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
}
void SDIO_EventNotify()
{
CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
- (CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0")));
+ (CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0"));
if (pDevice)
pDevice->EventNotify();
}
+int getFreeDeviceId()
+{
+ u32 i;
+ for (i=0; i<IPC_MAX_FDS; i++)
+ {
+ if (g_FdMap[i] == NULL)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
-int GetDeviceIDByName(const std::string& _rDeviceName)
+IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
{
TDeviceMap::const_iterator itr = g_DeviceMap.begin();
- while(itr != g_DeviceMap.end())
+ while (itr != g_DeviceMap.end())
{
- if (itr->second->GetDeviceName() == _rDeviceName)
- return itr->first;
+ if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
+ return itr->second;
++itr;
}
- return -1;
+ return NULL;
}
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
@@ -175,17 +215,7 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
return g_DeviceMap[_ID];
- return NULL;
-}
-
-void DeleteDeviceByID(u32 ID)
-{
- IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID);
- if (pDevice)
- delete pDevice;
-
- g_DeviceMap.erase(ID);
- g_FileNameMap.erase(ID);
+ return NULL;
}
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
@@ -203,60 +233,86 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName
void DoState(PointerWrap &p)
{
- p.Do(g_LastDeviceID);
+ p.Do(request_queue);
+ p.Do(reply_queue);
+
+ TDeviceMap::const_iterator itr;
+
+ itr = g_DeviceMap.begin();
+ while (itr != g_DeviceMap.end())
+ {
+ if (itr->second->IsHardware())
+ {
+ itr->second->DoState(p);
+ }
+ ++itr;
+ }
if (p.GetMode() == PointerWrap::MODE_READ)
- {
- TFileNameMap::const_iterator itr;
- // Delete file Handles
- itr = g_FileNameMap.begin();
- while (itr != g_FileNameMap.end())
+ {
+ u32 i;
+ for (i=0; i<IPC_MAX_FDS; i++)
{
- TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first);
- if (devitr != g_DeviceMap.end())
+ u32 exists;
+ p.Do(exists);
+ if (exists)
{
- if (devitr->second)
- delete devitr->second;
- g_DeviceMap.erase(itr->first);
+ u32 isHw;
+ p.Do(isHw);
+ if (isHw)
+ {
+ u32 hwId;
+ p.Do(hwId);
+ g_FdMap[i] = AccessDeviceByID(hwId);
+ }
+ else
+ {
+ g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
+ g_FdMap[i]->DoState(p);
+ }
+ }
+ else
+ {
+ g_FdMap[i] = NULL;
}
- ++itr;
}
- // Load file names
- p.Do(g_FileNameMap);
- // Rebuild file handles
- itr = g_FileNameMap.begin();
- while (itr != g_FileNameMap.end())
+ for (i=0; i<ES_MAX_COUNT; i++)
{
- g_DeviceMap[itr->first] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second);
- ++itr;
+ p.Do(es_inuse[i]);
+ u32 handleID = es_handles[i]->GetDeviceID();
+ p.Do(handleID);
+
+ es_handles[i] = AccessDeviceByID(handleID);
}
}
else
{
- p.Do(g_FileNameMap);
- }
-
- p.Do(request_queue);
- p.Do(reply_queue);
-
-
- TDeviceMap::const_iterator itr;
- //first, all the real devices
- //(because we need fs to be deserialized first)
- itr = g_DeviceMap.begin();
- while (itr != g_DeviceMap.end())
- {
- if (itr->second->IsHardware())
- itr->second->DoState(p);
- ++itr;
- }
- //then all the files
- itr = g_DeviceMap.begin();
- while (itr != g_DeviceMap.end())
- {
- if (!itr->second->IsHardware())
- itr->second->DoState(p);
- ++itr;
+ u32 i;
+ for (i=0; i<IPC_MAX_FDS; i++)
+ {
+ u32 exists = g_FdMap[i] ? 1 : 0;
+ p.Do(exists);
+ if (exists)
+ {
+ u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
+ p.Do(isHw);
+ if (isHw)
+ {
+ u32 hwId = g_FdMap[i]->GetDeviceID();
+ p.Do(hwId);
+ }
+ else
+ {
+ g_FdMap[i]->DoState(p);
+ }
+ }
+ }
+ for (i=0; i<ES_MAX_COUNT; i++)
+ {
+ p.Do(es_inuse[i]);
+ u32 handleID = es_handles[i]->GetDeviceID();
+ p.Do(handleID);
+ }
}
}
@@ -265,67 +321,110 @@ void ExecuteCommand(u32 _Address)
bool CmdSuccess = false;
ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
- int DeviceID = Memory::Read_U32(_Address + 8);
- IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID);
+ volatile int DeviceID = Memory::Read_U32(_Address + 8);
- INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) ", _Address, Command, DeviceID);
+ IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;
+
+ INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);
switch (Command)
{
case COMMAND_OPEN_DEVICE:
- {
- // Create a new HLE device. The Mode and DeviceName is given to us but we
- // generate a DeviceID to be used for access to this device until it is Closed.
- std::string DeviceName;
- Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
-
- u32 Mode = Memory::Read_U32(_Address + 0x10);
- DeviceID = GetDeviceIDByName(DeviceName);
-
- // check if a device with this name has been created already
- if (DeviceID == -1)
- {
- if (DeviceName.find("/dev/") != std::string::npos)
+ {
+ u32 Mode = Memory::Read_U32(_Address + 0x10);
+ DeviceID = getFreeDeviceId();
+
+ std::string DeviceName;
+ Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
+
+
+ WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID);
+ if (DeviceID >= 0)
+ {
+ if (DeviceName.find("/dev/es") == 0)
+ {
+ u32 j;
+ for (j=0; j<ES_MAX_COUNT; j++)
{
- WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
+ if (!es_inuse[j])
+ {
+ es_inuse[j] = true;
+ g_FdMap[DeviceID] = es_handles[j];
+ CmdSuccess = es_handles[j]->Open(_Address, Mode);
+ Memory::Write_U32(DeviceID, _Address+4);
+ break;
+ }
+ }
+ if (j == ES_MAX_COUNT)
+ {
+ Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
+ CmdSuccess = true;
+ }
- pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("_Unimplemented_Device_")));
+ }
+ else if (DeviceName.find("/dev/") == 0)
+ {
+ pDevice = GetDeviceByName(DeviceName);
+ if (pDevice)
+ {
+ g_FdMap[DeviceID] = pDevice;
CmdSuccess = pDevice->Open(_Address, Mode);
+ INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
+ pDevice->GetDeviceName().c_str(), DeviceID, Mode);
+ Memory::Write_U32(DeviceID, _Address+4);
}
else
{
- // create new file handle
- u32 CurrentDeviceID = g_LastDeviceID;
- pDevice = CreateFileIO(CurrentDeviceID, DeviceName);
- g_DeviceMap[CurrentDeviceID] = pDevice;
- g_FileNameMap[CurrentDeviceID] = DeviceName;
- g_LastDeviceID++;
-
- CmdSuccess = pDevice->Open(_Address, Mode);
-
- INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
- pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
+ WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
+ Memory::Write_U32(FS_ENOENT, _Address+4);
+ CmdSuccess = true;
}
- }
- else
- {
- // F|RES: prolly the re-open is just a mode change
- pDevice = AccessDeviceByID(DeviceID);
+ }
+ else
+ {
+ IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName);
CmdSuccess = pDevice->Open(_Address, Mode);
- INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
- pDevice->GetDeviceName().c_str(), DeviceID, Mode);
- }
- }
- break;
+ INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
+ pDevice->GetDeviceName().c_str(), DeviceID, Mode);
+ if (Memory::Read_U32(_Address + 4) == DeviceID)
+ {
+ g_FdMap[DeviceID] = pDevice;
+ }
+ else
+ {
+ delete pDevice;
+ }
+ }
+ }
+ else
+ {
+ Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
+ CmdSuccess = true;
+ }
+ break;
+ }
case COMMAND_CLOSE_DEVICE:
- if (pDevice)
+ {
+ if (pDevice)
{
CmdSuccess = pDevice->Close(_Address);
+
+ u32 j;
+ for (j=0; j<ES_MAX_COUNT; j++)
+ {
+ if (es_handles[j] == g_FdMap[DeviceID])
+ {
+ es_inuse[j] = false;
+ }
+ }
+
+ g_FdMap[DeviceID] = NULL;
+
// Don't delete hardware
if (!pDevice->IsHardware())
- DeleteDeviceByID(DeviceID);
+ delete pDevice;
}
else
{
@@ -333,50 +432,67 @@ void ExecuteCommand(u32 _Address)
CmdSuccess = true;
}
break;
-
+ }
case COMMAND_READ:
+ {
if (pDevice)
+ {
CmdSuccess = pDevice->Read(_Address);
+ }
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
}
break;
-
+ }
case COMMAND_WRITE:
+ {
if (pDevice)
+ {
CmdSuccess = pDevice->Write(_Address);
+ }
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
}
break;
-
+ }
case COMMAND_SEEK:
+ {
if (pDevice)
+ {
CmdSuccess = pDevice->Seek(_Address);
+ }
else
{
Memory::Write_U32(FS_EINVAL, _Address + 4);
CmdSuccess = true;
}
break;
-
+ }
case COMMAND_IOCTL:
+ {
if (pDevice)
+ {
CmdSuccess = pDevice->IOCtl(_Address);
+ }
break;
-
+ }
case COMMAND_IOCTLV:
+ {
if (pDevice)
+ {
CmdSuccess = pDevice->IOCtlV(_Address);
+ }
break;
-
+ }
default:
+ {
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
break;
+ }
}
// It seems that the original hardware overwrites the command after it has been
@@ -448,9 +564,10 @@ void Update()
void UpdateDevices()
{
// Check if a hardware device must be updated
- TDeviceMap::const_iterator itrEnd = g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID);
- for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != itrEnd; ++itr) {
- if (itr->second->IsOpened() && itr->second->Update()) {
+ for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
+ {
+ if (itr->second->IsOpened() && itr->second->Update())
+ {
break;
}
}
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h
index 11420d1cdd..2e056b5bec 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h
@@ -25,9 +25,9 @@ class IWII_IPC_HLE_Device;
namespace WII_IPC_HLE_Interface
{
-#define IPC_FIRST_HARDWARE_ID 0 // first IPC device ID
-#define IPC_FIRST_FILEIO_ID 33 // first IPC file ID
-
+#define IPC_FIRST_ID 0x00 // first IPC device ID
+#define IPC_MAX_FILES 0x10 // first IPC file ID
+
// Init
void Init();
@@ -46,14 +46,13 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz);
void SDIO_EventNotify();
-int GetDeviceIDByName(const std::string& _rDeviceName);
-
-IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
-
-void DeleteDeviceByID(u32 _ID);
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName);
+IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName);
+IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
+int getFreeDeviceId();
+
// Update
void Update();
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h
index 36709a084f..113b14cffb 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h
@@ -39,7 +39,7 @@ class PointerWrap;
#define FS_ENOENT2 (u32)-106 // File not found
#define FS_ENFILE (u32)-107 // Too many fds open
#define FS_EFBIG (u32)-108 // max block count reached?
-#define FS_ENFILE2 (u32)-109 // Too many fds open
+#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open
#define FS_ENAMELEN (u32)-110 // pathname is too long
#define FS_EFDOPEN (u32)-111 // FD is already open
#define FS_EIO2 (u32)-114 // returned on ECC error
@@ -47,6 +47,7 @@ class PointerWrap;
#define FS_EDIRDEPTH (u32)-116 // max directory depth exceeded
#define FS_EBUSY2 (u32)-118 // Resource busy
//#define FS_EFATAL (u32)-119 // fatal error not used by IOS as fatal ERROR
+#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time
class IWII_IPC_HLE_Device
{
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp
index c02ada362f..126f3daeb4 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp
@@ -211,7 +211,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
// Don't do anything if the log is unselected
if (LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
{
- const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
+ const char *pFilename = NULL;
+ if (m_pFileSystem)
+ pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)
{
INFO_LOG(WII_IPC_DVD, "DVDLowRead: %s (0x%llx) - (DVDAddr: 0x%llx, Size: 0x%x)",
@@ -233,7 +235,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
if (!VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
{
- PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
+ PanicAlertT("DVDLowRead - Fatal Error: failed to read from volume");
}
}
break;
@@ -325,10 +327,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
PanicAlertT("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
Size = _BufferOutSize;
}
-
- if (!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
+ if(!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
{
- PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
+ PanicAlertT("DVDLowUnencryptedRead - Fatal Error: failed to read from volume");
}
}
break;
@@ -348,7 +349,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
case DVDLowSeek:
{
u64 DVDAddress = Memory::Read_U32(_BufferIn + 0x4) << 2;
- const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
+ const char *pFilename = NULL;
+ if (m_pFileSystem)
+ pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)
{
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: %s (0x%llx) - (DVDAddr: 0x%llx)",
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
index 8a2cec7bea..1f0b0d72cd 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
@@ -28,7 +28,7 @@
static Common::replace_v replacements;
-// This is used by several of the FileIO and /dev/fs/ functions
+// This is used by several of the FileIO and /dev/fs functions
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
{
std::string path_full = File::GetUserPath(D_WIIROOT_IDX);
@@ -85,8 +85,8 @@ void HLE_IPC_CreateVirtualFATFilesystem()
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware
, m_pFileHandle(NULL)
- , m_FileLength(0)
, m_Mode(0)
+ , m_SeekPos(0)
{
Common::ReadReplacements(replacements);
}
@@ -98,10 +98,6 @@ CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO()
bool CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bForce)
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID);
-
- m_pFileHandle.Close();
-
- m_FileLength = 0;
m_Mode = 0;
// Close always return 0 for success
@@ -117,7 +113,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
u32 ReturnValue = 0;
// close the file handle if we get a reopen
- m_pFileHandle.Close();
+ //m_pFileHandle.Close();
static const char* const Modes[] =
{
@@ -128,31 +124,14 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
};
m_Filename = std::string(HLE_IPC_BuildFilename(m_Name.c_str(), 64));
-
+
+
// The file must exist before we can open it
// It should be created by ISFS_CreateFile, not here
- if(File::Exists(m_Filename))
+ if (File::Exists(m_Filename))
{
- INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s)", m_Name.c_str(), Modes[_Mode]);
- switch(_Mode)
- {
- case ISFS_OPEN_READ:
- m_pFileHandle.Open(m_Filename, "rb");
- break;
-
- // "r+b" is technically wrong, but OPEN_WRITE should not truncate the file as "wb" does.
- case ISFS_OPEN_WRITE:
- m_pFileHandle.Open(m_Filename, "r+b");
- break;
-
- case ISFS_OPEN_RW:
- m_pFileHandle.Open(m_Filename, "r+b");
- break;
-
- default:
- PanicAlertT("FileIO: Unknown open mode : 0x%02x", _Mode);
- break;
- }
+ INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
+ ReturnValue = m_DeviceID;
}
else
{
@@ -160,64 +139,103 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
ReturnValue = FS_FILE_NOT_EXIST;
}
- if (m_pFileHandle != NULL)
- {
- m_FileLength = (u32)m_pFileHandle.GetSize();
- ReturnValue = m_DeviceID;
- }
- else if (ReturnValue == 0)
- {
- ERROR_LOG(WII_IPC_FILEIO, " FileIO failed open: %s (%s) - I/O Error", m_Filename.c_str(), Modes[_Mode]);
- ReturnValue = FS_INVALID_ARGUMENT;
- }
-
if (_CommandAddress)
Memory::Write_U32(ReturnValue, _CommandAddress+4);
m_Active = true;
return true;
}
-bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
+
+
+bool CWII_IPC_HLE_Device_FileIO::OpenFile()
{
- u32 ReturnValue = FS_INVALID_ARGUMENT;
- const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
- const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
- const u64 fileSize = m_pFileHandle.GetSize();
+ switch (m_Mode)
+ {
+ case ISFS_OPEN_READ:
+ {
+ m_pFileHandle.Open(m_Filename, "rb");
+ break;
+ }
+ case ISFS_OPEN_WRITE:
+ {
+ m_pFileHandle.Open(m_Filename, "r+b");
+ break;
+ }
+ case ISFS_OPEN_RW:
+ {
+ m_pFileHandle.Open(m_Filename, "r+b");
+ break;
+ }
+ default:
+ {
+ PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
+ break;
+ }
+ }
+ return m_pFileHandle.IsOpen();
+}
- INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
+void CWII_IPC_HLE_Device_FileIO::CloseFile()
+{
+ m_pFileHandle.Close();
+}
- // Set seek mode
- int seek_mode[3] = {SEEK_SET, SEEK_CUR, SEEK_END};
+bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
+{
+ u32 ReturnValue = FS_RESULT_FATAL;
+ const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
+ const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
- if (Mode >= 0 && Mode <= 2)
+
+ if (OpenFile())
{
- // POSIX allows seek past EOF, the Wii does not.
- // TODO: Can we check this without tell'ing/seek'ing twice?
- const u64 curPos = m_pFileHandle.Tell();
- if (m_pFileHandle.Seek(SeekPosition, seek_mode[Mode]))
- {
- const u64 newPos = m_pFileHandle.Tell();
- if (newPos > fileSize)
+ ReturnValue = FS_RESULT_FATAL;
+
+ const u64 fileSize = m_pFileHandle.GetSize();
+ INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
+ switch (Mode){
+ case 0:
{
- ERROR_LOG(WII_IPC_FILEIO, "FILEIO: Seek past EOF - %s", m_Name.c_str());
- m_pFileHandle.Seek(curPos, SEEK_SET);
+ if (SeekPosition >=0 && SeekPosition <= fileSize)
+ {
+ m_SeekPos = SeekPosition;
+ ReturnValue = m_SeekPos;
+ }
+ break;
+ }
+ case 1:
+ {
+ s32 wantedPos = SeekPosition+m_SeekPos;
+ if (wantedPos >=0 && wantedPos <= fileSize)
+ {
+ m_SeekPos = wantedPos;
+ ReturnValue = m_SeekPos;
+ }
+ break;
+ }
+ case 2:
+ {
+ s32 wantedPos = fileSize+m_SeekPos;
+ if (wantedPos >=0 && wantedPos <= fileSize)
+ {
+ m_SeekPos = wantedPos;
+ ReturnValue = m_SeekPos;
+ }
+ break;
+ }
+ default:
+ {
+ PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode);
+ ReturnValue = FS_RESULT_FATAL;
+ break;
}
- else
- ReturnValue = (u32)newPos;
- }
- else
- {
- // Must clear the failbits, since subsequent seeks don't care about
- // past failure on Wii
- m_pFileHandle.Clear();
- ERROR_LOG(WII_IPC_FILEIO, "FILEIO: Seek failed - %s", m_Name.c_str());
}
+ CloseFile();
}
else
{
- PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode);
+ ReturnValue = FS_FILE_NOT_EXIST;
}
-
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
return true;
@@ -229,7 +247,8 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Read to this memory address
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
- if (m_pFileHandle != NULL)
+
+ if (OpenFile())
{
if (m_Mode == ISFS_OPEN_WRITE)
{
@@ -238,15 +257,24 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
else
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
-
+ m_pFileHandle.Seek(m_SeekPos, SEEK_SET);
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle.GetHandle());
if (ReturnValue != Size && ferror(m_pFileHandle.GetHandle()))
+ {
ReturnValue = FS_EACCESS;
+ }
+ else
+ {
+ m_SeekPos += Size;
+ }
+
}
+ CloseFile();
}
else
{
- ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file not open", m_Name.c_str(), Address, Size);
+ ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could not be opened or does not exist", m_Name.c_str(), Address, Size);
+ ReturnValue = FS_FILE_NOT_EXIST;
}
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
@@ -259,9 +287,8 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
- INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
- if (m_pFileHandle)
+ if (OpenFile())
{
if (m_Mode == ISFS_OPEN_READ)
{
@@ -269,9 +296,20 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
}
else
{
+ INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
+ m_pFileHandle.Seek(m_SeekPos, SEEK_SET);
if (m_pFileHandle.WriteBytes(Memory::GetPointer(Address), Size))
+ {
ReturnValue = Size;
+ m_SeekPos += Size;
+ }
}
+ CloseFile();
+ }
+ else
+ {
+ ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could not be opened or does not exist", m_Name.c_str(), Address, Size);
+ ReturnValue = FS_FILE_NOT_EXIST;
}
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
@@ -284,26 +322,29 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
#if defined(_DEBUG) || defined(DEBUGFAST)
DumpCommands(_CommandAddress);
#endif
- const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
-
- //u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
- //u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
- //u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
- //u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
+ const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC);
+ u32 ReturnValue = 0;
- switch(Parameter)
+ switch (Parameter)
{
case ISFS_IOCTL_GETFILESTATS:
{
- m_FileLength = (u32)m_pFileHandle.GetSize();
- const u32 Position = (u32)m_pFileHandle.Tell();
+ if (OpenFile())
+ {
+ u32 m_FileLength = (u32)m_pFileHandle.GetSize();
- const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
- INFO_LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
- INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, Position);
+ const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
+ INFO_LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
+ INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos);
- Memory::Write_U32(m_FileLength, BufferOut);
- Memory::Write_U32(Position, BufferOut+4);
+ Memory::Write_U32(m_FileLength, BufferOut);
+ Memory::Write_U32(m_SeekPos, BufferOut+4);
+ CloseFile();
+ }
+ else
+ {
+ ReturnValue = FS_FILE_NOT_EXIST;
+ }
}
break;
@@ -315,8 +356,6 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
}
- // Return Value
- const u32 ReturnValue = 0; // no error
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
return true;
@@ -324,24 +363,7 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
{
- bool have_file_handle = m_pFileHandle;
- s32 seek = (have_file_handle) ? (s32)m_pFileHandle.Tell() : 0;
-
- p.Do(have_file_handle);
p.Do(m_Mode);
- p.Do(seek);
-
- if (p.GetMode() == PointerWrap::MODE_READ)
- {
- if (have_file_handle)
- {
- Open(0, m_Mode);
- _dbg_assert_msg_(WII_IPC_HLE, m_pFileHandle, "bad filehandle");
- }
- else
- Close(0, true);
- }
-
- if (have_file_handle)
- m_pFileHandle.Seek(seek, SEEK_SET);
+ p.Do(m_SeekPos);
+ p.Do(m_Filename);
}
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h
index d1f51b7dfc..ff34a43a20 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h
@@ -39,6 +39,9 @@ public:
bool IOCtl(u32 _CommandAddress);
void DoState(PointerWrap &p);
+ bool OpenFile();
+ void CloseFile();
+
private:
enum
{
@@ -74,9 +77,10 @@ private:
};
File::IOFile m_pFileHandle;
- u32 m_FileLength;
u32 m_Mode;
+ u32 m_SeekPos;
+
std::string m_Filename;
};
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
index cba8274347..3bfeb847aa 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp
@@ -93,7 +93,7 @@ bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
{
// blindly grab the titleID from the disc - it's unencrypted at:
// offset 0x0F8001DC and 0x0F80044C
- VolumeHandler::RAWReadToPtr((u8*)&m_TitleID, (u64)0x0F8001DC, 8);
+ VolumeHandler::GetVolume()->GetTitleID((u8*)&m_TitleID);
m_TitleID = Common::swap64(m_TitleID);
}
else
@@ -177,11 +177,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
- const DiscIO::INANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
+ const DiscIO::INANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
u16 NumberOfPrivateContent = 0;
- if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
+ if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
{
- NumberOfPrivateContent = rNANDCOntent.GetNumEntries();
+ NumberOfPrivateContent = rNANDContent.GetNumEntries();
if ((u32)(TitleID>>32) == 0x00010000)
Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
@@ -191,10 +191,10 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
Memory::Write_U32(0, _CommandAddress + 0x4);
}
else
- Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
+ Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",
- (u32)(TitleID>>32), (u32)TitleID, rNANDCOntent.IsValid() ? NumberOfPrivateContent : (u32)rNANDCOntent.GetContentSize());
+ (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize());
return true;
}
@@ -254,24 +254,27 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
}
break;
- case IOCTL_ES_OPENCONTENT:
- {
- _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
- _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
+ case IOCTL_ES_OPENCONTENT:
+ {
+ _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
+ _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
- u32 CFD = AccessIdentID++;
- u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
+ u32 CFD = AccessIdentID++;
+ u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
- m_ContentAccessMap[CFD].m_Position = 0;
- m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
- _dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
+ m_ContentAccessMap[CFD].m_Position = 0;
+ m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
+ _dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
- Memory::Write_U32(CFD, _CommandAddress + 0x4);
+ if (m_ContentAccessMap[CFD].m_pContent == NULL)
+ CFD = 0xffffffff; //TODO: what is the correct error value here?
- INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
- return true;
- }
- break;
+ Memory::Write_U32(CFD, _CommandAddress + 0x4);
+
+ INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
+ return true;
+ }
+ break;
case IOCTL_ES_READCONTENT:
{
@@ -371,7 +374,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
- sprintf(Path, "/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
+ sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path);
}
@@ -509,11 +512,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
File::IOFile pFile(TicketFilename, "rb");
if (pFile)
{
- u8 Ticket[DiscIO::INANDContentLoader::TICKET_SIZE];
- for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(Ticket, DiscIO::INANDContentLoader::TICKET_SIZE); ++View)
+ u8 FileTicket[DiscIO::INANDContentLoader::TICKET_SIZE];
+ for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(FileTicket, DiscIO::INANDContentLoader::TICKET_SIZE); ++View)
{
Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8);
- Memory::WriteBigEData(Ticket+0x1D0, Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
+ Memory::WriteBigEData(FileTicket+0x1D0, Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, 212);
}
}
}
@@ -539,11 +542,6 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
- // Assert if title is not a disc title and the loader is not valid
- _dbg_assert_msg_(WII_IPC_ES, ((u32)(TitleID >> 32) == 0x00010000) ||
- ((u32)(TitleID >> 32) == 0x00010004) || Loader.IsValid(),
- "Loader not valid for TitleID %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID);
-
u32 TMDViewCnt = 0;
if (Loader.IsValid())
{
@@ -675,7 +673,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
// TODO: actually use this param in when writing to the outbuffer :/
MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
}
- const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(TitleID);
+ const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffersize: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
@@ -856,7 +854,7 @@ const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u6
m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
- _dbg_assert_msg_(WII_IPC_ES, m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
+ _dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
return *m_NANDContent[_TitleID];
}
@@ -878,11 +876,10 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
{
return -1;
}
- std::string tmdPath = Common::GetTMDFileName(tmdTitleID),
- dataPath = Common::GetTitleDataPath(tmdTitleID);
+ std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
File::CreateFullPath(tmdPath);
- File::CreateFullPath(dataPath);
+ File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
if(!File::Exists(tmdPath))
{
File::IOFile _pTMDFile(tmdPath, "wb");
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h
index 6c31e7be31..681baeebe6 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h
@@ -37,7 +37,7 @@ public:
virtual bool Close(u32 _CommandAddress, bool _bForce);
virtual bool IOCtlV(u32 _CommandAddress);
- u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
+ static u32 ES_DIVerify(u8 *_pTMD, u32 _sz);
private:
enum
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp
index c2ed0fac36..1b32410ef0 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp
@@ -109,17 +109,16 @@ bool CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
if (!File::Exists(DirName))
{
WARN_LOG(WII_IPC_FILEIO, "FS: Search not found: %s", DirName.c_str());
- ReturnValue = FS_DIRFILE_NOT_FOUND;
+ ReturnValue = FS_FILE_NOT_EXIST;
break;
}
-
- // AyuanX: what if we return "found one successfully" if it is a file?
else if (!File::IsDirectory(DirName))
{
// It's not a directory, so error.
- // Games don't usually seem to care WHICH error they get, as long as it's <0
- WARN_LOG(WII_IPC_FILEIO, "\tNot a directory - return FS_INVALID_ARGUMENT");
- ReturnValue = FS_INVALID_ARGUMENT;
+ // Games don't usually seem to care WHICH error they get, as long as it's <
+ // Well the system menu CARES!
+ WARN_LOG(WII_IPC_FILEIO, "\tNot a directory - return FS_RESULT_FATAL");
+ ReturnValue = FS_RESULT_FATAL;
break;
}
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.h
index be78de7e39..1afb01cf8d 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.h
@@ -31,12 +31,14 @@ struct NANDStat
};
enum {
- FS_RESULT_OK = 0,
+ FS_RESULT_OK = 0,
+ FS_INVALID = -4,
FS_DIRFILE_NOT_FOUND = -6,
- FS_INVALID_ARGUMENT = -101,
+ FS_RESULT_FATAL = -101,
+ FS_NO_ACCESS = -102,
FS_FILE_EXIST = -105,
FS_FILE_NOT_EXIST = -106,
- FS_RESULT_FATAL = -128,
+ FS_NO_HANDLE = -106,
};
class CWII_IPC_HLE_Device_fs : public IWII_IPC_HLE_Device
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp
index 24da87c257..dbd450785d 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp
@@ -129,7 +129,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
// Reset the connection of all connected wiimotes
for (unsigned int i = 0; i < 4; i++)
{
- if (m_WiiMotes[i].IsConnected())
+ if (!m_WiiMotes[i].IsInactive())
{
m_WiiMotes[i].Activate(false);
m_WiiMotes[i].Activate(true);
diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.h
index 21a7d7e1bd..f3180c7dc9 100644
--- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.h
+++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.h
@@ -59,6 +59,7 @@ public:
// we really have to clean all this code
bool IsConnected() const { return m_ConnectionState == CONN_COMPLETE; }
+ bool IsInactive() const { return m_ConnectionState == CONN_INACTIVE; }
bool LinkChannel();
void ResetChannels();
void Activate(bool ready);
diff --git a/Source/Core/Core/Src/MemTools.cpp b/Source/Core/Core/Src/MemTools.cpp
index 469ae32684..bb6fef6439 100644
--- a/Source/Core/Core/Src/MemTools.cpp
+++ b/Source/Core/Core/Src/MemTools.cpp
@@ -160,7 +160,7 @@ void InstallExceptionHandler()
#else // _WIN32
-#if defined __APPLE__ || defined __linux__ || defined _WIN32
+#if defined __APPLE__ || defined __linux__ || defined __FreeBSD__ || defined _WIN32
#ifndef _WIN32
#include <execinfo.h>
#endif
diff --git a/Source/Core/Core/Src/Movie.cpp b/Source/Core/Core/Src/Movie.cpp
index 5bfd5fbc24..9c2fb02d64 100644
--- a/Source/Core/Core/Src/Movie.cpp
+++ b/Source/Core/Core/Src/Movie.cpp
@@ -24,9 +24,12 @@
#include "PowerPC/PowerPC.h"
#include "HW/SI.h"
#include "HW/Wiimote.h"
+#include "HW/WiimoteEmu/WiimoteEmu.h"
+#include "HW/WiimoteEmu/WiimoteHid.h"
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "VideoBackendBase.h"
#include "State.h"
+#include "Timer.h"
// large enough for just over 24 hours of single-player recording
#define MAX_DTM_LENGTH (40 * 1024 * 1024)
@@ -46,38 +49,50 @@ u32 g_framesToSkip = 0, g_frameSkipCounter = 0;
u8 g_numPads = 0;
ControllerState g_padState;
DTMHeader tmpHeader;
-u8 *tmpInput = NULL;
-u64 inputOffset = 0, tmpLength = 0;
+u8* tmpInput = NULL;
+u64 g_currentByte = 0, g_totalBytes = 0;
+u64 g_currentFrame = 0, g_totalFrames = 0; // VI
+u64 g_currentLagCount = 0, g_totalLagCount = 0; // just stats
+u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats
+u64 g_recordingStartTime; // seconds since 1970 that recording started
-u64 g_frameCounter = 0, g_lagCounter = 0, g_totalFrameCount = 0, g_InputCounter = 0;
bool g_bRecordingFromSaveState = false;
bool g_bPolled = false;
+int g_currentSaveVersion = 0;
std::string tmpStateFilename = "dtm.sav";
-std::string g_InputDisplay[4];
+std::string g_InputDisplay[8];
ManipFunction mfunc = NULL;
+
std::string GetInputDisplay()
{
std::string inputDisplay = "";
- for (int i = 0; i < 4; ++i)
- inputDisplay.append(g_InputDisplay[i]);
+ for (int i = 0; i < 8; ++i)
+ if ((g_numPads & (1 << i)) != 0)
+ inputDisplay.append(g_InputDisplay[i]);
return inputDisplay;
}
void FrameUpdate()
{
- g_frameCounter++;
+ g_currentFrame++;
+ if(!g_bPolled)
+ g_currentLagCount++;
+
if (IsRecordingInput())
- g_totalFrameCount = g_frameCounter;
+ {
+ g_totalFrames = g_currentFrame;
+ g_totalLagCount = g_currentLagCount;
+ }
- if(!g_bPolled)
- g_lagCounter++;
-
if (g_bFrameStep)
+ {
Core::SetState(Core::CORE_PAUSE);
+ g_bFrameStep = false;
+ }
// ("framestop") the only purpose of this is to cause interpreter/jit Run() to return temporarily.
// after that we set it back to CPU_RUNNING and continue as normal.
@@ -90,9 +105,39 @@ void FrameUpdate()
g_bPolled = false;
}
+// called when game is booting up, even if no movie is active,
+// but potentially after BeginRecordingInput or PlayInput has been called.
+void Init()
+{
+ g_bPolled = false;
+ g_bFrameStep = false;
+ g_bFrameStop = false;
+ g_frameSkipCounter = g_framesToSkip;
+ memset(&g_padState, 0, sizeof(g_padState));
+ for (int i = 0; i < 8; ++i)
+ g_InputDisplay[i].clear();
+
+ if (!IsPlayingInput() && !IsRecordingInput())
+ {
+ g_bRecordingFromSaveState = false;
+ g_rerecords = 0;
+ g_numPads = 0;
+ g_currentByte = 0;
+ g_currentFrame = 0;
+ g_currentLagCount = 0;
+ g_currentInputCount = 0;
+ // we don't clear these things because otherwise we can't resume playback if we load a movie state later
+ //g_totalFrames = g_totalBytes = 0;
+ //delete tmpInput;
+ //tmpInput = NULL;
+ }
+}
+
void InputUpdate()
{
- g_InputCounter++;
+ g_currentInputCount++;
+ if (IsRecordingInput())
+ g_totalInputCount = g_currentInputCount;
}
void SetFrameSkipping(unsigned int framesToSkip)
@@ -113,9 +158,20 @@ void SetPolledDevice()
g_bPolled = true;
}
-void SetFrameStepping(bool bEnabled)
+void DoFrameStep()
{
- g_bFrameStep = bEnabled;
+ if(Core::GetState() == Core::CORE_PAUSE)
+ {
+ // if already paused, frame advance for 1 frame
+ Core::SetState(Core::CORE_RUN);
+ Core::RequestRefreshInfo();
+ g_bFrameStep = true;
+ }
+ else if(!g_bFrameStep)
+ {
+ // if not paused yet, pause immediately instead
+ Core::SetState(Core::CORE_PAUSE);
+ }
}
void SetFrameStopping(bool bEnabled)
@@ -125,6 +181,9 @@ void SetFrameStopping(bool bEnabled)
void SetReadOnly(bool bEnabled)
{
+ if (g_bReadOnly != bEnabled)
+ Core::DisplayMessage(bEnabled ? "Read-only mode." : "Read+Write mode.", 1000);
+
g_bReadOnly = bEnabled;
}
@@ -153,6 +212,11 @@ bool IsRecordingInputFromSaveState()
return g_bRecordingFromSaveState;
}
+bool IsJustStartingRecordingInputFromSaveState()
+{
+ return IsRecordingInputFromSaveState() && g_currentFrame == 0;
+}
+
bool IsPlayingInput()
{
return (g_playMode == MODE_PLAYING);
@@ -163,6 +227,11 @@ bool IsReadOnly()
return g_bReadOnly;
}
+u64 GetRecordingStartTime()
+{
+ return g_recordingStartTime;
+}
+
bool IsUsingPad(int controller)
{
return ((g_numPads & (1 << controller)) != 0);
@@ -181,7 +250,7 @@ void ChangePads(bool instantly)
int controllers = 0;
for (int i = 0; i < 4; i++)
- if (SConfig::GetInstance().m_SIDevice[i] == SI_GC_CONTROLLER)
+ if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER)
controllers |= (1 << i);
if (instantly && (g_numPads & 0x0F) == controllers)
@@ -189,9 +258,9 @@ void ChangePads(bool instantly)
for (int i = 0; i < 4; i++)
if (instantly) // Changes from savestates need to be instantaneous
- SerialInterface::AddDevice(IsUsingPad(i) ? SI_GC_CONTROLLER : SI_NONE, i);
+ SerialInterface::AddDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
else
- SerialInterface::ChangeDevice(IsUsingPad(i) ? SI_GC_CONTROLLER : SI_NONE, i);
+ SerialInterface::ChangeDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
}
void ChangeWiiPads(bool instantly)
@@ -228,89 +297,176 @@ bool BeginRecordingInput(int controllers)
}
g_numPads = controllers;
-
- g_frameCounter = g_lagCounter = g_InputCounter = 0;
+ g_currentFrame = g_totalFrames = 0;
+ g_currentLagCount = g_totalLagCount = 0;
+ g_currentInputCount = g_totalInputCount = 0;
+ g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
g_rerecords = 0;
g_playMode = MODE_RECORDING;
- inputOffset = 0;
+
delete tmpInput;
tmpInput = new u8[MAX_DTM_LENGTH];
-
-
+ g_currentByte = g_totalBytes = 0;
+
Core::DisplayMessage("Starting movie recording", 2000);
-
return true;
}
+static void Analog2DToString(u8 x, u8 y, const char* prefix, char* str)
+{
+ if((x <= 1 || x == 128 || x >= 255)
+ && (y <= 1 || y == 128 || y >= 255))
+ {
+ if(x != 128 || y != 128)
+ {
+ if(x != 128 && y != 128)
+ {
+ sprintf(str, "%s:%s,%s", prefix, x<128?"LEFT":"RIGHT", y<128?"DOWN":"UP");
+ }
+ else if(x != 128)
+ {
+ sprintf(str, "%s:%s", prefix, x<128?"LEFT":"RIGHT");
+ }
+ else
+ {
+ sprintf(str, "%s:%s", prefix, y<128?"DOWN":"UP");
+ }
+ }
+ else
+ {
+ str[0] = '\0';
+ }
+ }
+ else
+ {
+ sprintf(str, "%s:%d,%d", prefix, x, y);
+ }
+}
+
+static void Analog1DToString(u8 v, const char* prefix, char* str)
+{
+ if(v > 0)
+ {
+ if(v == 255)
+ {
+ strcpy(str, prefix);
+ }
+ else
+ {
+ sprintf(str, "%s:%d", prefix, v);
+ }
+ }
+ else
+ {
+ str[0] = '\0';
+ }
+}
+
void SetInputDisplayString(ControllerState padState, int controllerID)
{
char inp[70];
- sprintf(inp, "%dP:", controllerID + 1);
+ sprintf(inp, "P%d:", controllerID + 1);
g_InputDisplay[controllerID] = inp;
- sprintf(inp, " X: %d Y: %d rX: %d rY: %d L: %d R: %d",
- g_padState.AnalogStickX,
- g_padState.AnalogStickY,
- g_padState.CStickX,
- g_padState.CStickY,
- g_padState.TriggerL,
- g_padState.TriggerR);
- g_InputDisplay[controllerID].append(inp);
-
if(g_padState.A)
- {
g_InputDisplay[controllerID].append(" A");
- }
if(g_padState.B)
- {
g_InputDisplay[controllerID].append(" B");
- }
if(g_padState.X)
- {
g_InputDisplay[controllerID].append(" X");
- }
if(g_padState.Y)
- {
g_InputDisplay[controllerID].append(" Y");
- }
if(g_padState.Z)
- {
g_InputDisplay[controllerID].append(" Z");
- }
if(g_padState.Start)
- {
g_InputDisplay[controllerID].append(" START");
- }
if(g_padState.DPadUp)
- {
g_InputDisplay[controllerID].append(" UP");
- }
if(g_padState.DPadDown)
- {
g_InputDisplay[controllerID].append(" DOWN");
- }
if(g_padState.DPadLeft)
- {
g_InputDisplay[controllerID].append(" LEFT");
- }
if(g_padState.DPadRight)
- {
g_InputDisplay[controllerID].append(" RIGHT");
+
+ //if(g_padState.L)
+ //{
+ // g_InputDisplay[controllerID].append(" L");
+ //}
+ //if(g_padState.R)
+ //{
+ // g_InputDisplay[controllerID].append(" R");
+ //}
+
+ Analog1DToString(g_padState.TriggerL, " L", inp);
+ g_InputDisplay[controllerID].append(inp);
+
+ Analog1DToString(g_padState.TriggerR, " R", inp);
+ g_InputDisplay[controllerID].append(inp);
+
+ Analog2DToString(g_padState.AnalogStickX, g_padState.AnalogStickY, " ANA", inp);
+ g_InputDisplay[controllerID].append(inp);
+
+ Analog2DToString(g_padState.CStickX, g_padState.CStickY, " C", inp);
+ g_InputDisplay[controllerID].append(inp);
+
+ g_InputDisplay[controllerID].append("\n");
+}
+
+void SetWiiInputDisplayString(int remoteID, u8* const coreData, u8* const accelData, u8* const irData)
+{
+ int controllerID = remoteID + 4;
+
+ char inp[70];
+ sprintf(inp, "R%d:", remoteID + 1);
+ g_InputDisplay[controllerID] = inp;
+
+ if(coreData)
+ {
+ wm_core buttons = *(wm_core*)coreData;
+ if(buttons & WiimoteEmu::Wiimote::PAD_LEFT)
+ g_InputDisplay[controllerID].append(" LEFT");
+ if(buttons & WiimoteEmu::Wiimote::PAD_RIGHT)
+ g_InputDisplay[controllerID].append(" RIGHT");
+ if(buttons & WiimoteEmu::Wiimote::PAD_DOWN)
+ g_InputDisplay[controllerID].append(" DOWN");
+ if(buttons & WiimoteEmu::Wiimote::PAD_UP)
+ g_InputDisplay[controllerID].append(" UP");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_A)
+ g_InputDisplay[controllerID].append(" A");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_B)
+ g_InputDisplay[controllerID].append(" B");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_PLUS)
+ g_InputDisplay[controllerID].append(" +");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_MINUS)
+ g_InputDisplay[controllerID].append(" -");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_ONE)
+ g_InputDisplay[controllerID].append(" 1");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_TWO)
+ g_InputDisplay[controllerID].append(" 2");
+ if(buttons & WiimoteEmu::Wiimote::BUTTON_HOME)
+ g_InputDisplay[controllerID].append(" HOME");
}
- if(g_padState.L)
+ if(accelData)
{
- g_InputDisplay[controllerID].append(" L");
+ wm_accel* dt = (wm_accel*)accelData;
+ sprintf(inp, " ACC:%d,%d,%d", dt->x, dt->y, dt->z);
+ g_InputDisplay[controllerID].append(inp);
}
- if(g_padState.R)
+
+ if(irData) // incomplete
{
- g_InputDisplay[controllerID].append(" R");
+ sprintf(inp, " IR:%d,%d", ((u8*)irData)[0], ((u8*)irData)[1]);
+ g_InputDisplay[controllerID].append(inp);
}
g_InputDisplay[controllerID].append("\n");
}
+
+
void RecordInput(SPADStatus *PadStatus, int controllerID)
{
if(!IsRecordingInput() || !IsUsingPad(controllerID))
@@ -338,21 +494,31 @@ void RecordInput(SPADStatus *PadStatus, int controllerID)
g_padState.CStickX = PadStatus->substickX;
g_padState.CStickY = PadStatus->substickY;
-
- memcpy(&(tmpInput[inputOffset]), &g_padState, 8);
- inputOffset += 8;
+
+
+ memcpy(&(tmpInput[g_currentByte]), &g_padState, 8);
+ g_currentByte += 8;
+ g_totalBytes = g_currentByte;
SetInputDisplayString(g_padState, controllerID);
}
-void RecordWiimote(int wiimote, u8 *data, s8 size)
+void RecordWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
{
if(!IsRecordingInput() || !IsUsingWiimote(wiimote))
return;
- g_InputCounter++;
- tmpInput[inputOffset++] = (u8) size;
- memcpy(&(tmpInput[inputOffset]), data, size);
- inputOffset += size;
+
+ u8* const coreData = rptf.core?(data+rptf.core):NULL;
+ u8* const accelData = rptf.accel?(data+rptf.accel):NULL;
+ u8* const irData = rptf.ir?(data+rptf.ir):NULL;
+ u8 size = rptf.size;
+
+ InputUpdate();
+ tmpInput[g_currentByte++] = size;
+ memcpy(&(tmpInput[g_currentByte]), data, size);
+ g_currentByte += size;
+ g_totalBytes = g_currentByte;
+ SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
}
bool PlayInput(const char *filename)
@@ -399,15 +565,23 @@ bool PlayInput(const char *filename)
g_numPads = tmpHeader.numControllers;
g_rerecords = tmpHeader.numRerecords;
- g_totalFrameCount = tmpHeader.frameCount;
-
+
+ g_totalFrames = tmpHeader.frameCount;
+ g_totalLagCount = tmpHeader.lagCount;
+ g_totalInputCount = tmpHeader.inputCount;
+ g_recordingStartTime = tmpHeader.recordingStartTime;
+
+ g_currentFrame = 0;
+ g_currentLagCount = 0;
+ g_currentInputCount = 0;
+
g_playMode = MODE_PLAYING;
- tmpLength = g_recordfd.GetSize() - 256;
+ g_totalBytes = g_recordfd.GetSize() - 256;
delete tmpInput;
tmpInput = new u8[MAX_DTM_LENGTH];
- g_recordfd.ReadArray(tmpInput, tmpLength);
- inputOffset = 0;
+ g_recordfd.ReadArray(tmpInput, (size_t)g_totalBytes);
+ g_currentByte = 0;
g_recordfd.Close();
return true;
@@ -417,6 +591,27 @@ cleanup:
return false;
}
+void DoState(PointerWrap &p, bool doNot)
+{
+ if(doNot)
+ {
+ if(p.GetMode() == PointerWrap::MODE_READ)
+ g_currentSaveVersion = 0;
+ return;
+ }
+ static const int MOVIE_STATE_VERSION = 1;
+ g_currentSaveVersion = MOVIE_STATE_VERSION;
+ p.Do(g_currentSaveVersion);
+ // many of these could be useful to save even when no movie is active,
+ // and the data is tiny, so let's just save it regardless of movie state.
+ p.Do(g_currentFrame);
+ p.Do(g_currentByte);
+ p.Do(g_currentLagCount);
+ p.Do(g_currentInputCount);
+ p.Do(g_bPolled);
+ // other variables (such as g_totalBytes and g_totalFrames) are set in LoadInput
+}
+
void LoadInput(const char *filename)
{
File::IOFile t_record(filename, "r+b");
@@ -431,40 +626,124 @@ void LoadInput(const char *filename)
}
if (!g_bReadOnly)
+ {
tmpHeader.numRerecords++;
+ t_record.Seek(0, SEEK_SET);
+ t_record.WriteArray(&tmpHeader, 1);
+ }
- t_record.Seek(0, SEEK_SET);
- t_record.WriteArray(&tmpHeader, 1);
-
- g_frameCounter = tmpHeader.frameCount;
- g_totalFrameCount = (tmpHeader.totalFrameCount ? tmpHeader.totalFrameCount : tmpHeader.frameCount);
- g_InputCounter = tmpHeader.InputCount;
-
g_numPads = tmpHeader.numControllers;
-
ChangePads(true);
-
if (Core::g_CoreStartupParameter.bWii)
ChangeWiiPads(true);
- inputOffset = t_record.GetSize() - 256;
- delete tmpInput;
- tmpInput = new u8[MAX_DTM_LENGTH];
- t_record.ReadArray(tmpInput, inputOffset);
+ u64 totalSavedBytes = t_record.GetSize() - 256;
+
+ bool afterEnd = false;
+ if (g_currentByte > totalSavedBytes)
+ {
+ //PanicAlertT("Warning: You loaded a save whose movie ends before the current frame in the save (byte %u < %u) (frame %u < %u). You should load another save before continuing.", (u32)totalSavedBytes+256, (u32)g_currentByte+256, (u32)tmpHeader.frameCount, (u32)g_currentFrame);
+ afterEnd = true;
+ }
+
+ if (!g_bReadOnly || tmpInput == NULL)
+ {
+ g_totalFrames = tmpHeader.frameCount;
+ g_totalLagCount = tmpHeader.lagCount;
+ g_totalInputCount = tmpHeader.inputCount;
+
+ g_totalBytes = totalSavedBytes;
+ delete tmpInput;
+ tmpInput = new u8[MAX_DTM_LENGTH];
+ t_record.ReadArray(tmpInput, (size_t)g_totalBytes);
+ }
+ else if (g_currentByte > 0)
+ {
+ if (g_currentByte > totalSavedBytes)
+ {
+ }
+ else if (g_currentByte > g_totalBytes)
+ {
+ PanicAlertT("Warning: You loaded a save that's after the end of the current movie. (byte %u > %u) (frame %u > %u). You should load another save before continuing, or load this state with read-only mode off.", (u32)g_currentByte+256, (u32)g_totalBytes+256, (u32)g_currentFrame, (u32)g_totalFrames);
+ }
+ else if(g_currentByte > 0 && g_totalBytes > 0)
+ {
+ // verify identical from movie start to the save's current frame
+ u32 len = (u32)g_currentByte;
+ u8* movInput = new u8[len];
+ t_record.ReadArray(movInput, (size_t)len);
+ for (u32 i = 0; i < len; ++i)
+ {
+ if (movInput[i] != tmpInput[i])
+ {
+ // this is a "you did something wrong" alert for the user's benefit.
+ // we'll try to say what's going on in excruciating detail, otherwise the user might not believe us.
+ if(Core::g_CoreStartupParameter.bWii)
+ {
+ // TODO: more detail
+ PanicAlertT("Warning: You loaded a save whose movie mismatches on byte %d (0x%X). You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync.", i+256, i+256);
+ }
+ else
+ {
+ int frame = i/8;
+ ControllerState curPadState;
+ memcpy(&curPadState, &(tmpInput[frame*8]), 8);
+ ControllerState movPadState;
+ memcpy(&movPadState, &(movInput[frame*8]), 8);
+ PanicAlertT("Warning: You loaded a save whose movie mismatches on frame %d. You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync.\n\n"
+ "More information: The current movie is %d frames long and the savestate's movie is %d frames long.\n\n"
+ "On frame %d, the current movie presses:\n"
+ "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d"
+ "\n\n"
+ "On frame %d, the savestate's movie presses:\n"
+ "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d",
+ (int)frame,
+ (int)g_totalFrames, (int)tmpHeader.frameCount,
+ (int)frame,
+ (int)curPadState.Start, (int)curPadState.A, (int)curPadState.B, (int)curPadState.X, (int)curPadState.Y, (int)curPadState.Z, (int)curPadState.DPadUp, (int)curPadState.DPadDown, (int)curPadState.DPadLeft, (int)curPadState.DPadRight, (int)curPadState.L, (int)curPadState.R, (int)curPadState.TriggerL, (int)curPadState.TriggerR, (int)curPadState.AnalogStickX, (int)curPadState.AnalogStickY, (int)curPadState.CStickX, (int)curPadState.CStickY,
+ (int)frame,
+ (int)movPadState.Start, (int)movPadState.A, (int)movPadState.B, (int)movPadState.X, (int)movPadState.Y, (int)movPadState.Z, (int)movPadState.DPadUp, (int)movPadState.DPadDown, (int)movPadState.DPadLeft, (int)movPadState.DPadRight, (int)movPadState.L, (int)movPadState.R, (int)movPadState.TriggerL, (int)movPadState.TriggerR, (int)movPadState.AnalogStickX, (int)movPadState.AnalogStickY, (int)movPadState.CStickX, (int)movPadState.CStickY);
+ }
+ break;
+ }
+ }
+ delete movInput;
+ }
+ }
t_record.Close();
+
g_rerecords = tmpHeader.numRerecords;
- if (g_bReadOnly)
+ if (!afterEnd)
{
- tmpLength = inputOffset;
- inputOffset = tmpHeader.frameStart;
- Core::DisplayMessage("Resuming movie playback", 2000);
- g_playMode = MODE_PLAYING;
+ if (g_bReadOnly)
+ {
+ if(g_playMode != MODE_PLAYING)
+ {
+ g_playMode = MODE_PLAYING;
+ Core::DisplayMessage("Switched to playback", 2000);
+ }
+ }
+ else
+ {
+ if(g_playMode != MODE_RECORDING)
+ {
+ g_playMode = MODE_RECORDING;
+ Core::DisplayMessage("Switched to recording", 2000);
+ }
+ }
}
else
{
- Core::DisplayMessage("Resuming movie recording", 2000);
- g_playMode = MODE_RECORDING;
+ EndPlayInput(false);
+ }
+}
+
+static void CheckInputEnd()
+{
+ if (g_currentFrame > g_totalFrames || g_currentByte >= g_totalBytes)
+ {
+ EndPlayInput(!g_bReadOnly);
}
}
@@ -475,22 +754,22 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == NULL)
return;
- if (inputOffset + 8 > tmpLength)
+ if (g_currentByte + 8 > g_totalBytes)
{
+ PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)g_currentByte, (u32)g_totalBytes);
EndPlayInput(!g_bReadOnly);
return;
}
// dtm files don't save the mic button or error bit. not sure if they're actually
// used, but better safe than sorry
- bool m = PadStatus->MicButton;
signed char e = PadStatus->err;
memset(PadStatus, 0, sizeof(SPADStatus));
- PadStatus->MicButton = m;
PadStatus->err = e;
-
- memcpy(&g_padState, &(tmpInput[inputOffset]), 8);
- inputOffset += 8;
+
+
+ memcpy(&g_padState, &(tmpInput[g_currentByte]), 8);
+ g_currentByte += 8;
PadStatus->triggerLeft = g_padState.TriggerL;
PadStatus->triggerRight = g_padState.TriggerR;
@@ -514,88 +793,76 @@ void PlayController(SPADStatus *PadStatus, int controllerID)
PadStatus->analogB = 0xFF;
}
if(g_padState.X)
- {
PadStatus->button |= PAD_BUTTON_X;
- }
if(g_padState.Y)
- {
PadStatus->button |= PAD_BUTTON_Y;
- }
if(g_padState.Z)
- {
PadStatus->button |= PAD_TRIGGER_Z;
- }
if(g_padState.Start)
- {
PadStatus->button |= PAD_BUTTON_START;
- }
if(g_padState.DPadUp)
- {
PadStatus->button |= PAD_BUTTON_UP;
- }
if(g_padState.DPadDown)
- {
PadStatus->button |= PAD_BUTTON_DOWN;
- }
if(g_padState.DPadLeft)
- {
PadStatus->button |= PAD_BUTTON_LEFT;
- }
if(g_padState.DPadRight)
- {
PadStatus->button |= PAD_BUTTON_RIGHT;
- }
if(g_padState.L)
- {
PadStatus->button |= PAD_TRIGGER_L;
- }
if(g_padState.R)
- {
PadStatus->button |= PAD_TRIGGER_R;
- }
SetInputDisplayString(g_padState, controllerID);
- if (g_frameCounter >= g_totalFrameCount)
- {
- EndPlayInput(!g_bReadOnly);
- }
+ CheckInputEnd();
}
-bool PlayWiimote(int wiimote, u8 *data, s8 &size)
+bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
{
- s8 count = 0;
-
if(!IsPlayingInput() || !IsUsingWiimote(wiimote) || tmpInput == NULL)
return false;
-
- if (inputOffset > tmpLength)
+
+ if (g_currentByte > g_totalBytes)
{
+ PanicAlertT("Premature movie end in PlayWiimote. %u > %u", (u32)g_currentByte, (u32)g_totalBytes);
EndPlayInput(!g_bReadOnly);
return false;
}
-
- count = (s8) (tmpInput[inputOffset++]);
- if (inputOffset + count > tmpLength)
+ u8* const coreData = rptf.core?(data+rptf.core):NULL;
+ u8* const accelData = rptf.accel?(data+rptf.accel):NULL;
+ u8* const irData = rptf.ir?(data+rptf.ir):NULL;
+ u8 size = rptf.size;
+
+ u8 sizeInMovie = tmpInput[g_currentByte];
+
+ if (size != sizeInMovie)
{
+ PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", (u32)sizeInMovie, (u32)size, (u32)g_currentByte, (g_numPads & 0xF)?" Try re-creating the recording with all GameCube controllers disabled (in Configure > Gamecube > Device Settings).":"");
EndPlayInput(!g_bReadOnly);
return false;
}
-
- memcpy(data, &(tmpInput[inputOffset]), count);
- inputOffset += count;
- size = (count > size) ? size : count;
-
- g_InputCounter++;
-
- // TODO: merge this with the above so that there's no duplicate code
- if (g_frameCounter >= g_totalFrameCount)
+
+ g_currentByte++;
+
+ if (g_currentByte + size > g_totalBytes)
{
+ PanicAlertT("Premature movie end in PlayWiimote. %u + %d > %u", (u32)g_currentByte, size, (u32)g_totalBytes);
EndPlayInput(!g_bReadOnly);
+ return false;
}
+
+ memcpy(data, &(tmpInput[g_currentByte]), size);
+ g_currentByte += size;
+
+ SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
+
+ g_currentInputCount++;
+
+ CheckInputEnd();
return true;
}
@@ -604,16 +871,18 @@ void EndPlayInput(bool cont)
if (cont)
{
g_playMode = MODE_RECORDING;
- Core::DisplayMessage("Resuming movie recording", 2000);
+ Core::DisplayMessage("Reached movie end. Resuming recording.", 2000);
}
- else
+ else if(g_playMode != MODE_NONE)
{
g_numPads = g_rerecords = 0;
- g_totalFrameCount = g_frameCounter = g_lagCounter = 0;
+ g_currentByte = 0;
g_playMode = MODE_NONE;
- delete tmpInput;
- tmpInput = NULL;
- Core::DisplayMessage("Movie End", 2000);
+ Core::DisplayMessage("Movie End.", 2000);
+ // we don't clear these things because otherwise we can't resume playback if we load a movie state later
+ //g_totalFrames = g_totalBytes = 0;
+ //delete tmpInput;
+ //tmpInput = NULL;
}
}
@@ -631,10 +900,11 @@ void SaveRecording(const char *filename)
header.numControllers = g_numPads & (Core::g_CoreStartupParameter.bWii ? 0xFF : 0x0F);
header.bFromSaveState = g_bRecordingFromSaveState;
- header.frameCount = g_frameCounter;
- header.lagCount = g_lagCounter;
+ header.frameCount = g_totalFrames;
+ header.lagCount = g_totalLagCount;
+ header.inputCount = g_totalInputCount;
header.numRerecords = g_rerecords;
- header.InputCount = g_InputCounter;
+ header.recordingStartTime = g_recordingStartTime;
// TODO
header.uniqueID = 0;
@@ -642,20 +912,9 @@ void SaveRecording(const char *filename)
// header.videoBackend;
// header.audioEmulator;
- if (g_bReadOnly)
- {
- header.frameStart = inputOffset;
- header.totalFrameCount = g_totalFrameCount;
- }
-
save_record.WriteArray(&header, 1);
- bool success;
-
- if (g_bReadOnly)
- success = save_record.WriteArray(tmpInput, tmpLength);
- else
- success = save_record.WriteArray(tmpInput, inputOffset);
+ bool success = save_record.WriteArray(tmpInput, (size_t)g_totalBytes);
if (success && g_bRecordingFromSaveState)
{
diff --git a/Source/Core/Core/Src/Movie.h b/Source/Core/Core/Src/Movie.h
index 55ccf3a8da..16d0ba4997 100644
--- a/Source/Core/Core/Src/Movie.h
+++ b/Source/Core/Core/Src/Movie.h
@@ -24,6 +24,13 @@
#include <string>
+#include "ChunkFile.h"
+
+namespace WiimoteEmu
+{
+struct ReportFeatures;
+}
+
// Per-(video )Movie actions
namespace Movie {
@@ -62,7 +69,10 @@ extern ControllerState *g_padStates;
extern char g_playingFile[256];
extern std::string g_recordFile;
-extern u64 g_frameCounter, g_lagCounter, g_InputCounter;
+extern u64 g_currentByte, g_totalBytes;
+extern u64 g_currentFrame, g_totalFrames;
+extern u64 g_currentLagCount, g_totalLagCount;
+extern u64 g_currentInputCount, g_totalInputCount;
extern u32 g_rerecords;
@@ -77,9 +87,9 @@ struct DTMHeader {
bool bFromSaveState; // false indicates that the recording started from bootup, true for savestate
u64 frameCount; // Number of frames in the recording
- u64 InputCount; // Number of input frames in recording
+ u64 inputCount; // Number of input frames in recording
u64 lagCount; // Number of lag frames in the recording
- u64 uniqueID; // A Unique ID comprised of: md5(time + Game ID)
+ u64 uniqueID; // (not implemented) A Unique ID comprised of: md5(time + Game ID)
u32 numRerecords; // Number of rerecords/'cuts' of this TAS
u8 author[32]; // Author's name (encoded in UTF-8)
@@ -87,31 +97,32 @@ struct DTMHeader {
u8 audioEmulator[16]; // UTF-8 representation of the audio emulator
u8 padBackend[16]; // UTF-8 representation of the input backend
- // only used in read-only savestates
- u64 frameStart; // Offset to resume playback on
- u64 totalFrameCount; // Total frames, same as normal dtm's frameCount
+ u64 recordingStartTime; // seconds since 1970 that recording started (used for RTC)
- u8 reserved[111]; // Make heading 256 bytes, just because we can
+ u8 reserved[119]; // Make heading 256 bytes, just because we can
};
#pragma pack(pop)
void FrameUpdate();
void InputUpdate();
+void Init();
void SetPolledDevice();
bool IsAutoFiring();
bool IsRecordingInput();
bool IsRecordingInputFromSaveState();
+bool IsJustStartingRecordingInputFromSaveState();
bool IsPlayingInput();
bool IsReadOnly();
+u64 GetRecordingStartTime();
bool IsUsingPad(int controller);
bool IsUsingWiimote(int wiimote);
void ChangePads(bool instantly = false);
void ChangeWiiPads(bool instantly = false);
-void SetFrameStepping(bool bEnabled);
+void DoFrameStep();
void SetFrameStopping(bool bEnabled);
void SetReadOnly(bool bEnabled);
@@ -120,14 +131,15 @@ void FrameSkipping();
bool BeginRecordingInput(int controllers);
void RecordInput(SPADStatus *PadStatus, int controllerID);
-void RecordWiimote(int wiimote, u8* data, s8 size);
+void RecordWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode);
bool PlayInput(const char *filename);
void LoadInput(const char *filename);
void PlayController(SPADStatus *PadStatus, int controllerID);
-bool PlayWiimote(int wiimote, u8* data, s8 &size);
+bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode);
void EndPlayInput(bool cont);
void SaveRecording(const char *filename);
+void DoState(PointerWrap &p, bool doNot=false);
std::string GetInputDisplay();
diff --git a/Source/Core/Core/Src/PatchEngine.cpp b/Source/Core/Core/Src/PatchEngine.cpp
index 6528ad6752..74e778c916 100644
--- a/Source/Core/Core/Src/PatchEngine.cpp
+++ b/Source/Core/Core/Src/PatchEngine.cpp
@@ -210,13 +210,14 @@ void ApplyPatches(const std::vector<Patch> &patches)
void ApplyFramePatches()
{
ApplyPatches(onFrame);
+
+ // Run the Gecko code handler
+ Gecko::RunCodeHandler();
}
void ApplyARPatches()
{
ActionReplay::RunAllActive();
- // w/e this can be changed later
- Gecko::RunActiveCodes();
}
} // namespace
diff --git a/Source/Core/Core/Src/PowerPC/Gekko.h b/Source/Core/Core/Src/PowerPC/Gekko.h
index 76e34f7a8d..1ce6fae4cd 100644
--- a/Source/Core/Core/Src/PowerPC/Gekko.h
+++ b/Source/Core/Core/Src/PowerPC/Gekko.h
@@ -303,6 +303,8 @@ union UFPR
};
#define XER_CA_MASK 0x20000000
+#define XER_OV_MASK 0x40000000
+#define XER_SO_MASK 0x80000000
// XER
union UReg_XER
{
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp
index 1e368939cf..a8277d868a 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp
@@ -158,7 +158,7 @@ int Interpreter::SingleStepInner(void)
#if defined(_DEBUG) || defined(DEBUGFAST)
if (PowerPC::ppcState.gpr[1] == 0)
{
- printf("%i Corrupt stack", PowerPC::ppcState.DebugCount);
+ WARN_LOG(POWERPC, "%i Corrupt stack", PowerPC::ppcState.DebugCount);
}
PowerPC::ppcState.DebugCount++;
#endif
@@ -284,7 +284,7 @@ void Interpreter::unknown_instruction(UGeckoInstruction _inst)
{
char disasm[256];
DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
- printf("Last PC = %08x : %s\n", last_pc, disasm);
+ NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm);
Dolphin_Debugger::PrintCallstack();
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
}
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
index 3b0ae602cd..1d6ea2e70d 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
@@ -42,10 +42,6 @@ using namespace MathUtil;
void UpdateSSEState();
-#ifdef _MSC_VER
-#pragma float_control(precise, on, push)
-#endif
-
// Extremely rare - actually, never seen.
// Star Wars : Rogue Leader spams that at some point :|
void Interpreter::Helper_UpdateCR1(double _fValue)
@@ -518,8 +514,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst)
rPS0(_inst.FD) = sqrt(b);
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
-}
-
-#ifdef _MSC_VER
-#pragma float_control(pop)
-#endif
+} \ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
index 5d7cd28b20..cad4761e55 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
@@ -363,12 +363,23 @@ void Interpreter::dcbf(UGeckoInstruction _inst)
{
NPC = PC + 12;
}*/
+ // Invalidate the icache on dcbf
+ if (jit)
+ {
+ u32 address = Helper_Get_EA_X(_inst);
+ jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
+ }
}
void Interpreter::dcbi(UGeckoInstruction _inst)
{
- // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything.
- // Seen used during initialization.
+ // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache
+ // However, we invalidate the icache on dcbi
+ if (jit)
+ {
+ u32 address = Helper_Get_EA_X(_inst);
+ jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
+ }
}
void Interpreter::dcbst(UGeckoInstruction _inst)
@@ -390,7 +401,8 @@ void Interpreter::dcbtst(UGeckoInstruction _inst)
void Interpreter::dcbz(UGeckoInstruction _inst)
{
// HACK but works... we think
- Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
+ if (HID2.WPE || !HID0.DCFA)
+ Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
}
// eciwx/ecowx technically should access the specified device
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
index c6a0c352f8..13b1cf46c1 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
@@ -292,22 +292,27 @@ static GekkoOPTemplate table31[] =
static GekkoOPTemplate table31_2[] =
{
- {266, Interpreter::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
- {10, Interpreter::addcx, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {138, Interpreter::addex, {"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {234, Interpreter::addmex, {"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {202, Interpreter::addzex, {"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {491, Interpreter::divwx, {"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
- {459, Interpreter::divwux, {"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
- {75, Interpreter::mulhwx, {"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
- {11, Interpreter::mulhwux, {"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
- {235, Interpreter::mullwx, {"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
- {104, Interpreter::negx, {"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
- {40, Interpreter::subfx, {"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
- {8, Interpreter::subfcx, {"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {136, Interpreter::subfex, {"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {232, Interpreter::subfmex, {"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
- {200, Interpreter::subfzex, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {266, Interpreter::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
+ {778, Interpreter::addx, {"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
+ {10, Interpreter::addcx, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {138, Interpreter::addex, {"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {234, Interpreter::addmex, {"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {202, Interpreter::addzex, {"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {491, Interpreter::divwx, {"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
+ {1003, Interpreter::divwx, {"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
+ {459, Interpreter::divwux, {"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
+ {971, Interpreter::divwux, {"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39, 0, 0, 0}},
+ {75, Interpreter::mulhwx, {"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
+ {11, Interpreter::mulhwux, {"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
+ {235, Interpreter::mullwx, {"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
+ {747, Interpreter::mullwx, {"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4, 0, 0, 0}},
+ {104, Interpreter::negx, {"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
+ {40, Interpreter::subfx, {"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
+ {552, Interpreter::subfx, {"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}},
+ {8, Interpreter::subfcx, {"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {136, Interpreter::subfex, {"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {232, Interpreter::subfmex, {"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
+ {200, Interpreter::subfzex, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}},
};
static GekkoOPTemplate table59[] =
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp
index 3d5efd80ae..b43ed516dd 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp
@@ -41,6 +41,10 @@
#include "JitAsm.h"
#include "JitRegCache.h"
#include "Jit64_Tables.h"
+#include "HW/ProcessorInterface.h"
+#if defined(_DEBUG) || defined(DEBUGFAST)
+#include "PowerPCDisasm.h"
+#endif
using namespace Gen;
using namespace PowerPC;
@@ -393,6 +397,7 @@ void STACKALIGN Jit64::Jit(u32 em_address)
{
ClearCache();
}
+
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
@@ -411,13 +416,19 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
// Comment out the following to disable breakpoints (speed-up)
- blockSize = 1;
- broken_block = true;
- Trace();
+ if (!Profiler::g_ProfileBlocks)
+ {
+ if (GetState() == CPU_STEPPING)
+ blockSize = 1;
+ Trace();
+ }
}
if (em_address == 0)
- PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
+ {
+ Core::SetState(Core::CORE_PAUSE);
+ PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR);
+ }
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
{
@@ -565,6 +576,44 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
SetJumpTarget(b1);
}
+ // Add an external exception check if the instruction writes to the FIFO.
+ if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end())
+ {
+ gpr.Flush(FLUSH_ALL);
+ fpr.Flush(FLUSH_ALL);
+
+ TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER));
+ FixupBranch clearInt = J_CC(CC_NZ);
+ TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
+ FixupBranch noExtException = J_CC(CC_Z);
+ TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
+ FixupBranch noExtIntEnable = J_CC(CC_Z);
+ TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH));
+ FixupBranch noCPInt = J_CC(CC_Z);
+
+ MOV(32, M(&PC), Imm32(ops[i].address));
+ WriteExceptionExit();
+
+ SetJumpTarget(noCPInt);
+ SetJumpTarget(noExtIntEnable);
+ SetJumpTarget(noExtException);
+ SetJumpTarget(clearInt);
+ }
+
+ if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
+ {
+ MOV(32, M(&PC), Imm32(ops[i].address));
+ ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
+ TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
+ FixupBranch noBreakpoint = J_CC(CC_Z);
+
+ gpr.Flush(FLUSH_ALL);
+ fpr.Flush(FLUSH_ALL);
+
+ WriteExit(ops[i].address, 0);
+ SetJumpTarget(noBreakpoint);
+ }
+
Jit64Tables::CompileInstruction(ops[i]);
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
@@ -612,14 +661,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
#ifdef _M_IX86
if (js.compilerPC & JIT_ICACHE_VMEM_BIT)
MOV(32, M((jit->GetBlockCache()->GetICacheVMEM() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
- else if (js.blockStart & JIT_ICACHE_EXRAM_BIT)
+ else if (js.compilerPC & JIT_ICACHE_EXRAM_BIT)
MOV(32, M((jit->GetBlockCache()->GetICacheEx() + (js.compilerPC & JIT_ICACHEEX_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
else
MOV(32, M((jit->GetBlockCache()->GetICache() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
#else
if (js.compilerPC & JIT_ICACHE_VMEM_BIT)
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICacheVMEM() + (js.compilerPC & JIT_ICACHE_MASK)));
- else if (js.blockStart & JIT_ICACHE_EXRAM_BIT)
+ else if (js.compilerPC & JIT_ICACHE_EXRAM_BIT)
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICacheEx() + (js.compilerPC & JIT_ICACHEEX_MASK)));
else
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICache() + (js.compilerPC & JIT_ICACHE_MASK)));
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
index 38de5c8fa2..c01c1b017b 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
@@ -147,7 +147,13 @@ public:
void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup();
+ void GenerateConstantOverflow(bool overflow);
+ void GenerateOverflow();
+ void FinalizeCarryOverflow(bool oe, bool inv = false);
+ void GetCarryEAXAndClear();
+ void FinalizeCarryGenerateOverflowEAX(bool oe, bool inv = false);
void GenerateCarry();
+ void GenerateRC();
void ComputeRC(const Gen::OpArg & arg);
void tri_op(int d, int a, int b, bool reversible, void (XEmitter::*op)(Gen::X64Reg, Gen::OpArg));
@@ -173,6 +179,7 @@ public:
void mulhwux(UGeckoInstruction inst);
void mullwx(UGeckoInstruction inst);
void divwux(UGeckoInstruction inst);
+ void divwx(UGeckoInstruction inst);
void srawix(UGeckoInstruction inst);
void srawx(UGeckoInstruction inst);
void addex(UGeckoInstruction inst);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp
index 1632a76796..93963513ee 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp
@@ -210,12 +210,12 @@ static GekkoOPTemplate table31[] =
{824, &Jit64::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
{24, &Jit64::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
- {54, &Jit64::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
- {86, &Jit64::DoNothing}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
- {246, &Jit64::Default}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
- {278, &Jit64::Default}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
+ {54, &Jit64::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
+ {86, &Jit64::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
+ {246, &Jit64::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
+ {278, &Jit64::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
{470, &Jit64::Default}, //"dcbi", OPTYPE_DCACHE, 0, 4}},
- {758, &Jit64::Default}, //"dcba", OPTYPE_DCACHE, 0, 4}},
+ {758, &Jit64::DoNothing}, //"dcba", OPTYPE_DCACHE, 0, 4}},
{1014, &Jit64::dcbz}, //"dcbz", OPTYPE_DCACHE, 0, 4}},
//load word
@@ -305,22 +305,27 @@ static GekkoOPTemplate table31[] =
static GekkoOPTemplate table31_2[] =
{
- {266, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {10, &Jit64::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
- {138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {491, &Jit64::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
- {459, &Jit64::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
- {75, &Jit64::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {11, &Jit64::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {235, &Jit64::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {104, &Jit64::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {40, &Jit64::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {8, &Jit64::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
- {136, &Jit64::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {232, &Jit64::subfmex}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {200, &Jit64::subfzex}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {266, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {778, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {10, &Jit64::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
+ {138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {491, &Jit64::divwx}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {1003, &Jit64::divwx}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {459, &Jit64::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {971, &Jit64::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {75, &Jit64::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {11, &Jit64::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {235, &Jit64::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {747, &Jit64::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {104, &Jit64::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {40, &Jit64::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {552, &Jit64::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {8, &Jit64::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
+ {136, &Jit64::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {232, &Jit64::subfmex}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {200, &Jit64::subfzex}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
};
static GekkoOPTemplate table59[] =
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
index 4515cd5a79..04462872e6 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
@@ -81,12 +81,15 @@ void Jit64AsmRoutineManager::Generate()
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
+ TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
+ FixupBranch notStepping = J_CC(CC_Z);
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
FixupBranch noBreakpoint = J_CC(CC_Z);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
SetJumpTarget(noBreakpoint);
+ SetJumpTarget(notStepping);
}
SetJumpTarget(skipToRealDispatch);
@@ -206,14 +209,11 @@ void Jit64AsmRoutineManager::Generate()
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
testExceptions = GetCodePtr();
- TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
- FixupBranch skipExceptions = J_CC(CC_Z);
- MOV(32, R(EAX), M(&PC));
- MOV(32, M(&NPC), R(EAX));
- ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
- MOV(32, R(EAX), M(&NPC));
- MOV(32, M(&PC), R(EAX));
- SetJumpTarget(skipExceptions);
+ MOV(32, R(EAX), M(&PC));
+ MOV(32, M(&NPC), R(EAX));
+ ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
+ MOV(32, R(EAX), M(&NPC));
+ MOV(32, M(&PC), R(EAX));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp
index b41d8b1852..5aaf4b99f1 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp
@@ -24,6 +24,102 @@
#include "JitRegCache.h"
#include "JitAsm.h"
+void Jit64::GenerateConstantOverflow(bool overflow)
+{
+ if (overflow)
+ {
+ //XER[OV/SO] = 1
+ OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK));
+ }
+ else
+ {
+ //XER[OV] = 0
+ AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK));
+ }
+}
+
+void Jit64::GenerateOverflow()
+{
+ FixupBranch jno = J_CC(CC_NO);
+ //XER[OV/SO] = 1
+ OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK));
+ FixupBranch exit = J();
+ SetJumpTarget(jno);
+ //XER[OV] = 0
+ AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_OV_MASK));
+ SetJumpTarget(exit);
+}
+
+// Assumes CA,OV are clear
+void Jit64::FinalizeCarryOverflow(bool oe, bool inv)
+{
+ // USES_XER
+ if (oe)
+ {
+ FixupBranch jno = J_CC(CC_NO);
+ // Do carry
+ FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
+ JitSetCA();
+ SetJumpTarget(carry1);
+ //XER[OV/SO] = 1
+ OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_SO_MASK | XER_OV_MASK));
+ FixupBranch exit = J();
+ SetJumpTarget(jno);
+ // Do carry
+ FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC);
+ JitSetCA();
+ SetJumpTarget(carry2);
+ SetJumpTarget(exit);
+ }
+ else
+ {
+ // Do carry
+ FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
+ JitSetCA();
+ SetJumpTarget(carry1);
+ }
+}
+
+void Jit64::GetCarryEAXAndClear()
+{
+ MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
+ BTR(32, R(EAX), Imm8(29));
+}
+
+// Assumes that XER is in EAX and that the CA bit is clear.
+void Jit64::FinalizeCarryGenerateOverflowEAX(bool oe, bool inv)
+{
+ // USES_XER
+ if (oe)
+ {
+ FixupBranch jno = J_CC(CC_NO);
+ // Do carry
+ FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
+ OR(32, R(EAX), Imm32(XER_CA_MASK));
+ SetJumpTarget(carry1);
+ //XER[OV/SO] = 1
+ OR(32, R(EAX), Imm32(XER_SO_MASK | XER_OV_MASK));
+ FixupBranch exit = J();
+ SetJumpTarget(jno);
+ // Do carry
+ FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC);
+ OR(32, R(EAX), Imm32(XER_CA_MASK));
+ SetJumpTarget(carry2);
+ //XER[OV] = 0
+ AND(32, R(EAX), Imm32(~XER_OV_MASK));
+ SetJumpTarget(exit);
+ }
+ else
+ {
+ // Do carry
+ FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
+ OR(32, R(EAX), Imm32(XER_CA_MASK));
+ SetJumpTarget(carry1);
+ }
+ // Dump EAX back into XER
+ MOV(32, M(&PowerPC::ppcState.spr[SPR_XER]), R(EAX));
+}
+
// Assumes that the flags were just set through an addition.
void Jit64::GenerateCarry() {
// USES_XER
@@ -35,6 +131,24 @@ void Jit64::GenerateCarry() {
SetJumpTarget(pContinue);
}
+// Assumes that Sign and Zero flags were set by the last operation. Preserves all flags and registers.
+void Jit64::GenerateRC() {
+ FixupBranch pZero = J_CC(CC_Z);
+ FixupBranch pNegative = J_CC(CC_S);
+ MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x4)); // Result > 0
+ FixupBranch continue1 = J();
+
+ SetJumpTarget(pNegative);
+ MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x8)); // Result < 0
+ FixupBranch continue2 = J();
+
+ SetJumpTarget(pZero);
+ MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x2)); // Result == 0
+
+ SetJumpTarget(continue1);
+ SetJumpTarget(continue2);
+}
+
void Jit64::ComputeRC(const Gen::OpArg & arg) {
if( arg.IsImm() )
{
@@ -48,7 +162,10 @@ void Jit64::ComputeRC(const Gen::OpArg & arg) {
}
else
{
- CMP(32, arg, Imm8(0));
+ if (arg.IsSimpleReg())
+ TEST(32, arg, arg);
+ else
+ CMP(32, arg, Imm8(0));
FixupBranch pLesser = J_CC(CC_L);
FixupBranch pGreater = J_CC(CC_G);
MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x2)); // _x86Reg == 0
@@ -79,11 +196,20 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void
if (gpr.R(a).IsImm() && !carry)
{
gpr.SetImmediate32(d, doop((u32)gpr.R(a).offset, value));
+ if (Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
}
else if (a == d)
{
gpr.KillImmediate(d, true, true);
(this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16;
+ if (Rc)
+ {
+ // All of the possible passed operators affect Sign/Zero flags
+ GenerateRC();
+ }
if (carry)
GenerateCarry();
}
@@ -92,6 +218,11 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void
gpr.BindToRegister(d, false);
MOV(32, gpr.R(d), gpr.R(a));
(this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16;
+ if (Rc)
+ {
+ // All of the possible passed operators affect Sign/Zero flags
+ GenerateRC();
+ }
if (carry)
GenerateCarry();
}
@@ -100,15 +231,15 @@ void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void
{
// a == 0, which for these instructions imply value = 0
gpr.SetImmediate32(d, value);
+ if (Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
}
else
{
_assert_msg_(DYNA_REC, 0, "WTF regimmop");
}
- if (Rc)
- {
- ComputeRC(gpr.R(d));
- }
gpr.UnlockAll();
}
@@ -135,7 +266,7 @@ void Jit64::reg_imm(UGeckoInstruction inst)
case 15:
if (a == 0) { // lis
// Merge with next instruction if loading a 32-bits immediate value (lis + addi, lis + ori)
- if (!js.isLastInstruction) {
+ if (!js.isLastInstruction && !Core::g_CoreStartupParameter.bEnableDebugging) {
if ((js.next_inst.OPCD == 14) && (js.next_inst.RD == d) && (js.next_inst.RA == d)) { // addi
gpr.SetImmediate32(d, ((u32)inst.SIMM_16 << 16) + (u32)(s32)js.next_inst.SIMM_16);
js.downcountAmount++;
@@ -435,6 +566,10 @@ void Jit64::boolX(UGeckoInstruction inst)
gpr.SetImmediate32(a, (u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset);
else if (inst.SUBOP10 == 284) /* eqvx */
gpr.SetImmediate32(a, ~((u32)gpr.R(s).offset ^ (u32)gpr.R(b).offset));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if (s == b)
{
@@ -475,6 +610,10 @@ void Jit64::boolX(UGeckoInstruction inst)
{
PanicAlert("WTF!");
}
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if ((a == s) || (a == b))
{
@@ -485,11 +624,19 @@ void Jit64::boolX(UGeckoInstruction inst)
if (inst.SUBOP10 == 28) /* andx */
{
AND(32, gpr.R(a), operand);
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 476) /* nandx */
{
AND(32, gpr.R(a), operand);
NOT(32, gpr.R(a));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if (inst.SUBOP10 == 60) /* andcx */
{
@@ -504,15 +651,27 @@ void Jit64::boolX(UGeckoInstruction inst)
NOT(32, R(EAX));
AND(32, gpr.R(a), R(EAX));
}
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 444) /* orx */
{
OR(32, gpr.R(a), operand);
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 124) /* norx */
{
OR(32, gpr.R(a), operand);
NOT(32, gpr.R(a));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if (inst.SUBOP10 == 412) /* orcx */
{
@@ -527,15 +686,27 @@ void Jit64::boolX(UGeckoInstruction inst)
NOT(32, R(EAX));
OR(32, gpr.R(a), R(EAX));
}
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 316) /* xorx */
{
XOR(32, gpr.R(a), operand);
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 284) /* eqvx */
{
- XOR(32, gpr.R(a), operand);
NOT(32, gpr.R(a));
+ XOR(32, gpr.R(a), operand);
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else
{
@@ -552,46 +723,78 @@ void Jit64::boolX(UGeckoInstruction inst)
{
MOV(32, gpr.R(a), gpr.R(s));
AND(32, gpr.R(a), gpr.R(b));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 476) /* nandx */
{
MOV(32, gpr.R(a), gpr.R(s));
AND(32, gpr.R(a), gpr.R(b));
NOT(32, gpr.R(a));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if (inst.SUBOP10 == 60) /* andcx */
{
MOV(32, gpr.R(a), gpr.R(b));
NOT(32, gpr.R(a));
AND(32, gpr.R(a), gpr.R(s));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 444) /* orx */
{
MOV(32, gpr.R(a), gpr.R(s));
OR(32, gpr.R(a), gpr.R(b));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 124) /* norx */
{
MOV(32, gpr.R(a), gpr.R(s));
OR(32, gpr.R(a), gpr.R(b));
NOT(32, gpr.R(a));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else if (inst.SUBOP10 == 412) /* orcx */
{
MOV(32, gpr.R(a), gpr.R(b));
NOT(32, gpr.R(a));
OR(32, gpr.R(a), gpr.R(s));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 316) /* xorx */
{
MOV(32, gpr.R(a), gpr.R(s));
XOR(32, gpr.R(a), gpr.R(b));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else if (inst.SUBOP10 == 284) /* eqvx */
{
MOV(32, gpr.R(a), gpr.R(s));
- XOR(32, gpr.R(a), gpr.R(b));
NOT(32, gpr.R(a));
+ XOR(32, gpr.R(a), gpr.R(b));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else
{
@@ -599,11 +802,6 @@ void Jit64::boolX(UGeckoInstruction inst)
}
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(a));
- }
}
void Jit64::extsbx(UGeckoInstruction inst)
@@ -670,11 +868,45 @@ void Jit64::subfic(UGeckoInstruction inst)
gpr.Lock(a, d);
gpr.BindToRegister(d, a == d, true);
int imm = inst.SIMM_16;
- MOV(32, R(EAX), gpr.R(a));
- NOT(32, R(EAX));
- ADD(32, R(EAX), Imm32(imm + 1));
- MOV(32, gpr.R(d), R(EAX));
- GenerateCarry();
+ if (d == a)
+ {
+ if (imm == 0)
+ {
+ JitClearCA();
+ // Flags act exactly like subtracting from 0
+ NEG(32, gpr.R(d));
+ // Output carry is inverted
+ FixupBranch carry1 = J_CC(CC_C);
+ JitSetCA();
+ SetJumpTarget(carry1);
+ }
+ else if (imm == -1)
+ {
+ // CA is always set in this case
+ JitSetCA();
+ NOT(32, gpr.R(d));
+ }
+ else
+ {
+ JitClearCA();
+ NOT(32, gpr.R(d));
+ ADD(32, gpr.R(d), Imm32(imm+1));
+ // Output carry is normal
+ FixupBranch carry1 = J_CC(CC_NC);
+ JitSetCA();
+ SetJumpTarget(carry1);
+ }
+ }
+ else
+ {
+ JitClearCA();
+ MOV(32, gpr.R(d), Imm32(imm));
+ SUB(32, gpr.R(d), gpr.R(a));
+ // Output carry is inverted
+ FixupBranch carry1 = J_CC(CC_C);
+ JitSetCA();
+ SetJumpTarget(carry1);
+ }
gpr.UnlockAll();
// This instruction has no RC flag
}
@@ -687,26 +919,28 @@ void Jit64::subfcx(UGeckoInstruction inst)
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
- // For some reason, I could not get the jit versions of sub*
- // working with x86 sub...so we use the ~a + b + 1 method
- JitClearCA();
- MOV(32, R(EAX), gpr.R(a));
- NOT(32, R(EAX));
- ADD(32, R(EAX), gpr.R(b));
- FixupBranch carry1 = J_CC(CC_NC);
- JitSetCA();
- SetJumpTarget(carry1);
- ADD(32, R(EAX), Imm32(1));
- FixupBranch carry2 = J_CC(CC_NC);
- JitSetCA();
- SetJumpTarget(carry2);
- MOV(32, gpr.R(d), R(EAX));
-
- gpr.UnlockAll();
- if (inst.OE) PanicAlert("OE: subfcx");
+ JitClearCAOV(inst.OE);
+ if (d == b)
+ {
+ SUB(32, gpr.R(d), gpr.R(a));
+ }
+ else if (d == a)
+ {
+ MOV(32, R(EAX), gpr.R(a));
+ MOV(32, gpr.R(d), gpr.R(b));
+ SUB(32, gpr.R(d), R(EAX));
+ }
+ else
+ {
+ MOV(32, gpr.R(d), gpr.R(b));
+ SUB(32, gpr.R(d), gpr.R(a));
+ }
if (inst.Rc) {
- ComputeRC(R(EAX));
+ GenerateRC();
}
+ FinalizeCarryOverflow(inst.OE, true);
+
+ gpr.UnlockAll();
}
void Jit64::subfex(UGeckoInstruction inst)
@@ -714,39 +948,36 @@ void Jit64::subfex(UGeckoInstruction inst)
INSTRUCTION_START;
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
- gpr.FlushLockX(ECX);
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
- // Get CA
- MOV(32, R(ECX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(ECX), Imm8(29));
- AND(32, R(ECX), Imm32(1));
- // Don't need it anymore
- JitClearCA();
-
- // ~a + b
- MOV(32, R(EAX), gpr.R(a));
- NOT(32, R(EAX));
- ADD(32, R(EAX), gpr.R(b));
- FixupBranch carry1 = J_CC(CC_NC);
- JitSetCA();
- SetJumpTarget(carry1);
-
- // + CA
- ADD(32, R(EAX), R(ECX));
- FixupBranch carry2 = J_CC(CC_NC);
- JitSetCA();
- SetJumpTarget(carry2);
-
- MOV(32, gpr.R(d), R(EAX));
-
- gpr.UnlockAll();
- gpr.UnlockAllX();
- if (inst.OE) PanicAlert("OE: subfex");
+ GetCarryEAXAndClear();
+
+ bool invertedCarry = false;
+ if (d == b)
+ {
+ // Convert carry to borrow
+ CMC();
+ SBB(32, gpr.R(d), gpr.R(a));
+ invertedCarry = true;
+ }
+ else if (d == a)
+ {
+ NOT(32, gpr.R(d));
+ ADC(32, gpr.R(d), gpr.R(b));
+ }
+ else
+ {
+ MOV(32, gpr.R(d), gpr.R(a));
+ NOT(32, gpr.R(d));
+ ADC(32, gpr.R(d), gpr.R(b));
+ }
if (inst.Rc) {
- ComputeRC(R(EAX));
+ GenerateRC();
}
+ FinalizeCarryGenerateOverflowEAX(inst.OE, invertedCarry);
+
+ gpr.UnlockAll();
}
void Jit64::subfmex(UGeckoInstruction inst)
@@ -755,35 +986,22 @@ void Jit64::subfmex(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, d = inst.RD;
-
- if (d == a)
+ gpr.Lock(a, d);
+ gpr.BindToRegister(d, d == a);
+
+ GetCarryEAXAndClear();
+ if (d != a)
{
- gpr.Lock(d);
- gpr.BindToRegister(d, true);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
- NOT(32, gpr.R(d));
- ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
- GenerateCarry();
- gpr.UnlockAll();
+ MOV(32, gpr.R(d), gpr.R(a));
}
- else
+ NOT(32, gpr.R(d));
+ ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
+ if (inst.Rc)
{
- gpr.Lock(a, d);
- gpr.BindToRegister(d, false);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
- MOV(32, gpr.R(d), gpr.R(a));
- NOT(32, gpr.R(d));
- ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
- GenerateCarry();
- gpr.UnlockAll();
+ GenerateRC();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
+ gpr.UnlockAll();
}
void Jit64::subfzex(UGeckoInstruction inst)
@@ -793,34 +1011,23 @@ void Jit64::subfzex(UGeckoInstruction inst)
JITDISABLE(Integer)
int a = inst.RA, d = inst.RD;
- if (d == a)
+ gpr.Lock(a, d);
+ gpr.BindToRegister(d, d == a);
+
+ GetCarryEAXAndClear();
+ if (d != a)
{
- gpr.Lock(d);
- gpr.BindToRegister(d, true);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
- NOT(32, gpr.R(d));
- ADC(32, gpr.R(d), Imm8(0));
- GenerateCarry();
- gpr.UnlockAll();
+ MOV(32, gpr.R(d), gpr.R(a));
}
- else
+ NOT(32, gpr.R(d));
+ ADC(32, gpr.R(d), Imm8(0));
+ if (inst.Rc)
{
- gpr.Lock(a, d);
- gpr.BindToRegister(d, false);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
- MOV(32, gpr.R(d), gpr.R(a));
- NOT(32, gpr.R(d));
- ADC(32, gpr.R(d), Imm8(0));
- GenerateCarry();
- gpr.UnlockAll();
+ GenerateRC();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
+
+ gpr.UnlockAll();
}
void Jit64::subfx(UGeckoInstruction inst)
@@ -831,23 +1038,46 @@ void Jit64::subfx(UGeckoInstruction inst)
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
{
- gpr.SetImmediate32(d, (u32)gpr.R(b).offset - (u32)gpr.R(a).offset);
+ s32 i = (s32)gpr.R(b).offset, j = (s32)gpr.R(a).offset;
+ gpr.SetImmediate32(d, i - j);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
+ if (inst.OE)
+ {
+ GenerateConstantOverflow((s64)(i - j) != (s64)i - (s64)j);
+ }
}
else
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
- MOV(32, R(EAX), gpr.R(b));
- SUB(32, R(EAX), gpr.R(a));
- MOV(32, gpr.R(d), R(EAX));
+ if (d == b)
+ {
+ SUB(32, gpr.R(d), gpr.R(a));
+ }
+ else if (d == a)
+ {
+ MOV(32, R(EAX), gpr.R(a));
+ MOV(32, gpr.R(d), gpr.R(b));
+ SUB(32, gpr.R(d), R(EAX));
+ }
+ else
+ {
+ MOV(32, gpr.R(d), gpr.R(b));
+ SUB(32, gpr.R(d), gpr.R(a));
+ }
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ if (inst.OE)
+ {
+ GenerateOverflow();
+ }
gpr.UnlockAll();
}
-
- if (inst.OE) PanicAlert("OE: subfx");
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::mulli(UGeckoInstruction inst)
@@ -855,17 +1085,39 @@ void Jit64::mulli(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, d = inst.RD;
+ u32 imm = inst.SIMM_16;
if (gpr.R(a).IsImm())
{
- gpr.SetImmediate32(d, (s32)gpr.R(a).offset * (s32)inst.SIMM_16);
+ gpr.SetImmediate32(d, (u32)gpr.R(a).offset * imm);
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, (d == a), true);
- gpr.KillImmediate(a, true, false);
- IMUL(32, gpr.RX(d), gpr.R(a), Imm32((u32)(s32)inst.SIMM_16));
+ if (imm == 0)
+ XOR(32, gpr.R(d), gpr.R(d));
+ else if(imm == -1)
+ {
+ if (d != a)
+ MOV(32, gpr.R(d), gpr.R(a));
+ NEG(32, gpr.R(d));
+ }
+ else if((imm & (imm - 1)) == 0)
+ {
+ u32 shift = 0;
+ if (imm & 0xFFFF0000) shift |= 16;
+ if (imm & 0xFF00FF00) shift |= 8;
+ if (imm & 0xF0F0F0F0) shift |= 4;
+ if (imm & 0xCCCCCCCC) shift |= 2;
+ if (imm & 0xAAAAAAAA) shift |= 1;
+ if (d != a)
+ MOV(32, gpr.R(d), gpr.R(a));
+ if (shift)
+ SHL(32, gpr.R(d), Imm8(shift));
+ }
+ else
+ IMUL(32, gpr.RX(d), gpr.R(a), Imm32(imm));
gpr.UnlockAll();
}
}
@@ -878,23 +1130,60 @@ void Jit64::mullwx(UGeckoInstruction inst)
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
{
- gpr.SetImmediate32(d, (s32)gpr.R(a).offset * (s32)gpr.R(b).offset);
+ s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
+ gpr.SetImmediate32(d, i * j);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow((s64)(i*j) != (s64)i * (s64)j);
+ }
}
else
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, (d == a || d == b), true);
- if (d == a) {
+ if (gpr.R(a).IsImm() || gpr.R(b).IsImm())
+ {
+ u32 imm = gpr.R(a).IsImm() ? (u32)gpr.R(a).offset : (u32)gpr.R(b).offset;
+ int src = gpr.R(a).IsImm() ? b : a;
+ if (imm == 0)
+ XOR(32, gpr.R(d), gpr.R(d));
+ else if(imm == -1)
+ {
+ if (d != src)
+ MOV(32, gpr.R(d), gpr.R(src));
+ NEG(32, gpr.R(d));
+ }
+ else if((imm & (imm - 1)) == 0 && !inst.OE)
+ {
+ u32 shift = 0;
+ if (imm & 0xFFFF0000) shift |= 16;
+ if (imm & 0xFF00FF00) shift |= 8;
+ if (imm & 0xF0F0F0F0) shift |= 4;
+ if (imm & 0xCCCCCCCC) shift |= 2;
+ if (imm & 0xAAAAAAAA) shift |= 1;
+ if (d != src)
+ MOV(32, gpr.R(d), gpr.R(src));
+ if (shift)
+ SHL(32, gpr.R(d), Imm8(shift));
+ }
+ else
+ IMUL(32, gpr.RX(d), gpr.R(src), Imm32(imm));
+ }
+ else if (d == a)
IMUL(32, gpr.RX(d), gpr.R(b));
- } else if (d == b) {
- IMUL(32, gpr.RX(d), gpr.R(a));
- } else {
- MOV(32, gpr.R(d), gpr.R(b));
+ else if (d == b)
IMUL(32, gpr.RX(d), gpr.R(a));
+ else
+ {
+ MOV(32, gpr.R(d), gpr.R(b));
+ IMUL(32, gpr.RX(d), gpr.R(a));
+ }
+ if (inst.OE)
+ {
+ GenerateOverflow();
}
gpr.UnlockAll();
}
-
if (inst.Rc)
{
ComputeRC(gpr.R(d));
@@ -927,7 +1216,9 @@ void Jit64::mulhwux(UGeckoInstruction inst)
}
if (inst.Rc)
+ {
ComputeRC(gpr.R(d));
+ }
}
void Jit64::divwux(UGeckoInstruction inst)
@@ -939,9 +1230,118 @@ void Jit64::divwux(UGeckoInstruction inst)
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
{
if( gpr.R(b).offset == 0 )
+ {
gpr.SetImmediate32(d, 0);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ }
else
+ {
gpr.SetImmediate32(d, (u32)gpr.R(a).offset / (u32)gpr.R(b).offset);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(false);
+ }
+ }
+ }
+ else if (gpr.R(b).IsImm())
+ {
+ u32 divisor = (u32)gpr.R(b).offset;
+ if (divisor == 0)
+ {
+ gpr.SetImmediate32(d, 0);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ }
+ else
+ {
+ u32 shift = 31;
+ while(!(divisor & (1 << shift)))
+ shift--;
+
+ if (divisor == (1 << shift))
+ {
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(d, d == a, true);
+ if (d != a)
+ MOV(32, gpr.R(d), gpr.R(a));
+ if (shift)
+ SHR(32, gpr.R(d), Imm8(shift));
+ }
+ else
+ {
+ u64 magic_dividend = 0x100000000ULL << shift;
+ u32 magic = (u32)(magic_dividend / divisor);
+ u32 max_quotient = magic >> shift;
+
+ // Test for failure in round-up method
+ if (((u64)(magic+1) * (max_quotient*divisor-1)) >> (shift + 32) != max_quotient-1)
+ {
+ // If failed, use slower round-down method
+#ifdef _M_X64
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(d, d == a, true);
+ MOV(32, R(EAX), Imm32(magic));
+ if (d != a)
+ MOV(32, gpr.R(d), gpr.R(a));
+ IMUL(64, gpr.RX(d), R(RAX));
+ ADD(64, gpr.R(d), R(RAX));
+ SHR(64, gpr.R(d), Imm8(shift+32));
+#else
+ gpr.FlushLockX(EDX);
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(d, d == a, true);
+ MOV(32, R(EAX), Imm32(magic));
+ MUL(32, gpr.R(a));
+ XOR(32, gpr.R(d), gpr.R(d));
+ ADD(32, R(EAX), Imm32(magic));
+ ADC(32, gpr.R(d), R(EDX));
+ if (shift)
+ SHR(32, gpr.R(d), Imm8(shift));
+ gpr.UnlockAllX();
+#endif
+ }
+ else
+ {
+ // If success, use faster round-up method
+#ifdef _M_X64
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(a, true, false);
+ gpr.BindToRegister(d, false, true);
+ if (d == a)
+ {
+ MOV(32, R(EAX), Imm32(magic+1));
+ IMUL(64, gpr.RX(d), R(RAX));
+ }
+ else
+ {
+ MOV(32, gpr.R(d), Imm32(magic+1));
+ IMUL(64, gpr.RX(d), gpr.R(a));
+ }
+ SHR(64, gpr.R(d), Imm8(shift+32));
+#else
+ gpr.FlushLockX(EDX);
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(d, d == a, true);
+ MOV(32, R(EAX), Imm32(magic+1));
+ MUL(32, gpr.R(a));
+ MOV(32, gpr.R(d), R(EDX));
+ if (shift)
+ SHR(32, gpr.R(d), Imm8(shift));
+ gpr.UnlockAllX();
+#endif
+ }
+ }
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(false);
+ }
+ gpr.UnlockAll();
+ }
}
else
{
@@ -952,14 +1352,21 @@ void Jit64::divwux(UGeckoInstruction inst)
XOR(32, R(EDX), R(EDX));
gpr.KillImmediate(b, true, false);
CMP(32, gpr.R(b), Imm32(0));
- // doesn't handle if OE is set, but int doesn't either...
FixupBranch not_div_by_zero = J_CC(CC_NZ);
MOV(32, gpr.R(d), R(EDX));
- MOV(32, R(EAX), gpr.R(d));
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ //MOV(32, R(EAX), gpr.R(d));
FixupBranch end = J();
SetJumpTarget(not_div_by_zero);
DIV(32, gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(false);
+ }
SetJumpTarget(end);
gpr.UnlockAll();
gpr.UnlockAllX();
@@ -971,18 +1378,100 @@ void Jit64::divwux(UGeckoInstruction inst)
}
}
+void Jit64::divwx(UGeckoInstruction inst)
+{
+ INSTRUCTION_START
+ JITDISABLE(Integer)
+ int a = inst.RA, b = inst.RB, d = inst.RD;
+
+ if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
+ {
+ s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
+ if( j == 0 || i == 0x80000000 && j == -1)
+ {
+ gpr.SetImmediate32(d, (i >> 31) ^ j);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ }
+ else
+ {
+ gpr.SetImmediate32(d, i / j);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(false);
+ }
+ }
+ }
+ else
+ {
+ gpr.FlushLockX(EDX);
+ gpr.Lock(a, b, d);
+ gpr.BindToRegister(d, (d == a || d == b), true);
+ MOV(32, R(EAX), gpr.R(a));
+ CDQ();
+ gpr.BindToRegister(b, true, false);
+ TEST(32, gpr.R(b), gpr.R(b));
+ FixupBranch not_div_by_zero = J_CC(CC_NZ);
+ MOV(32, gpr.R(d), R(EDX));
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ FixupBranch end1 = J();
+ SetJumpTarget(not_div_by_zero);
+ CMP(32, gpr.R(b), R(EDX));
+ FixupBranch not_div_by_neg_one = J_CC(CC_NZ);
+ MOV(32, gpr.R(d), R(EAX));
+ NEG(32, gpr.R(d));
+ FixupBranch no_overflow = J_CC(CC_NO);
+ XOR(32, gpr.R(d), gpr.R(d));
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(true);
+ }
+ FixupBranch end2 = J();
+ SetJumpTarget(not_div_by_neg_one);
+ IDIV(32, gpr.R(b));
+ MOV(32, gpr.R(d), R(EAX));
+ SetJumpTarget(no_overflow);
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(false);
+ }
+ SetJumpTarget(end1);
+ SetJumpTarget(end2);
+ gpr.UnlockAll();
+ gpr.UnlockAllX();
+ }
+
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
+}
+
void Jit64::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
- _assert_msg_(DYNA_REC, !inst.OE, "Add - OE enabled :(");
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
{
- gpr.SetImmediate32(d, (u32)gpr.R(a).offset + (u32)gpr.R(b).offset);
+ s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
+ gpr.SetImmediate32(d, i + j);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
+ if (inst.OE)
+ {
+ GenerateConstantOverflow((s64)(i + j) != (s64)i + (s64)j);
+ }
}
- else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg())
+ else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && !inst.Rc && !inst.OE)
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, false);
@@ -995,6 +1484,14 @@ void Jit64::addx(UGeckoInstruction inst)
gpr.Lock(a, b, d);
gpr.BindToRegister(d, true);
ADD(32, gpr.R(d), gpr.R(operand));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ if (inst.OE)
+ {
+ GenerateOverflow();
+ }
gpr.UnlockAll();
}
else
@@ -1003,13 +1500,16 @@ void Jit64::addx(UGeckoInstruction inst)
gpr.BindToRegister(d, false);
MOV(32, gpr.R(d), gpr.R(a));
ADD(32, gpr.R(d), gpr.R(b));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ if (inst.OE)
+ {
+ GenerateOverflow();
+ }
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::addex(UGeckoInstruction inst)
@@ -1023,28 +1523,31 @@ void Jit64::addex(UGeckoInstruction inst)
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, true);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
ADC(32, gpr.R(d), gpr.R((d == a) ? b : a));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, false);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), gpr.R(b));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::addcx(UGeckoInstruction inst)
@@ -1052,31 +1555,35 @@ void Jit64::addcx(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, d = inst.RD;
- _assert_msg_(DYNA_REC, !inst.OE, "Add - OE enabled :(");
if ((d == a) || (d == b))
{
int operand = ((d == a) ? b : a);
gpr.Lock(a, b, d);
gpr.BindToRegister(d, true);
+ JitClearCAOV(inst.OE);
ADD(32, gpr.R(d), gpr.R(operand));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryOverflow(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, b, d);
gpr.BindToRegister(d, false);
+ JitClearCAOV(inst.OE);
MOV(32, gpr.R(d), gpr.R(a));
ADD(32, gpr.R(d), gpr.R(b));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryOverflow(inst.OE);
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::addmex(UGeckoInstruction inst)
@@ -1090,28 +1597,31 @@ void Jit64::addmex(UGeckoInstruction inst)
{
gpr.Lock(d);
gpr.BindToRegister(d, true);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, false);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::addzex(UGeckoInstruction inst)
@@ -1125,28 +1635,31 @@ void Jit64::addzex(UGeckoInstruction inst)
{
gpr.Lock(d);
gpr.BindToRegister(d, true);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
ADC(32, gpr.R(d), Imm8(0));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
else
{
gpr.Lock(a, d);
gpr.BindToRegister(d, false);
- MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
- SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
+
+ GetCarryEAXAndClear();
MOV(32, gpr.R(d), gpr.R(a));
ADC(32, gpr.R(d), Imm8(0));
- GenerateCarry();
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ FinalizeCarryGenerateOverflowEAX(inst.OE);
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::rlwinmx(UGeckoInstruction inst)
@@ -1162,6 +1675,10 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
result = _rotl(result, inst.SH);
result &= Helper_Mask(inst.MB, inst.ME);
gpr.SetImmediate32(a, result);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else
{
@@ -1172,36 +1689,43 @@ void Jit64::rlwinmx(UGeckoInstruction inst)
MOV(32, gpr.R(a), gpr.R(s));
}
- if (inst.MB == 0 && inst.ME==31-inst.SH)
+ if (inst.SH && inst.MB == 0 && inst.ME==31-inst.SH)
{
SHL(32, gpr.R(a), Imm8(inst.SH));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
- else if (inst.ME == 31 && inst.MB == 32 - inst.SH)
+ else if (inst.SH && inst.ME == 31 && inst.MB == 32 - inst.SH)
{
SHR(32, gpr.R(a), Imm8(inst.MB));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
}
else
{
- bool written = false;
if (inst.SH != 0)
{
ROL(32, gpr.R(a), Imm8(inst.SH));
- written = true;
}
if (!(inst.MB==0 && inst.ME==31))
{
- written = true;
AND(32, gpr.R(a), Imm32(Helper_Mask(inst.MB, inst.ME)));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ }
+ else if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
}
- _assert_msg_(DYNA_REC, written, "W T F!!!");
}
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(a));
- }
}
@@ -1216,25 +1740,79 @@ void Jit64::rlwimix(UGeckoInstruction inst)
{
u32 mask = Helper_Mask(inst.MB,inst.ME);
gpr.SetImmediate32(a, ((u32)gpr.R(a).offset & ~mask) | (_rotl((u32)gpr.R(s).offset,inst.SH) & mask));
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else
{
gpr.Lock(a, s);
- gpr.KillImmediate(a, true, true);
+ gpr.BindToRegister(a, true, true);
u32 mask = Helper_Mask(inst.MB, inst.ME);
- MOV(32, R(EAX), gpr.R(s));
- AND(32, gpr.R(a), Imm32(~mask));
- if (inst.SH)
- ROL(32, R(EAX), Imm8(inst.SH));
- AND(32, R(EAX), Imm32(mask));
- OR(32, gpr.R(a), R(EAX));
+ if (mask == 0 || (a == s && inst.SH == 0))
+ {
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
+ }
+ else if (mask == 0xFFFFFFFF)
+ {
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ if (inst.SH)
+ {
+ ROL(32, gpr.R(a), Imm8(inst.SH));
+ }
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
+ }
+ else if (inst.SH)
+ {
+ if (mask == -(1U << inst.SH))
+ {
+ MOV(32, R(EAX), gpr.R(s));
+ SHL(32, R(EAX), Imm8(inst.SH));
+ AND(32, gpr.R(a), Imm32(~mask));
+ OR(32, gpr.R(a), R(EAX));
+ }
+ else if (mask == (1U << inst.SH) - 1)
+ {
+ MOV(32, R(EAX), gpr.R(s));
+ SHR(32, R(EAX), Imm8(32-inst.SH));
+ AND(32, gpr.R(a), Imm32(~mask));
+ OR(32, gpr.R(a), R(EAX));
+ }
+ else
+ {
+ MOV(32, R(EAX), gpr.R(s));
+ ROL(32, R(EAX), Imm8(inst.SH));
+ XOR(32, R(EAX), gpr.R(a));
+ AND(32, R(EAX), Imm32(mask));
+ XOR(32, gpr.R(a), R(EAX));
+ }
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ }
+ else
+ {
+ XOR(32, gpr.R(a), gpr.R(s));
+ AND(32, gpr.R(a), Imm32(~mask));
+ XOR(32, gpr.R(a), gpr.R(s));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ }
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(a));
- }
}
void Jit64::rlwnmx(UGeckoInstruction inst)
@@ -1242,31 +1820,35 @@ void Jit64::rlwnmx(UGeckoInstruction inst)
INSTRUCTION_START
JITDISABLE(Integer)
int a = inst.RA, b = inst.RB, s = inst.RS;
-
+
u32 mask = Helper_Mask(inst.MB, inst.ME);
if (gpr.R(b).IsImm() && gpr.R(s).IsImm())
{
gpr.SetImmediate32(a, _rotl((u32)gpr.R(s).offset, (u32)gpr.R(b).offset & 0x1F) & mask);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else
{
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
- gpr.KillImmediate(a, (a == s || a == b), true);
- MOV(32, R(EAX), gpr.R(s));
+ gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
- AND(32, R(ECX), Imm32(0x1f));
- ROL(32, R(EAX), R(ECX));
- AND(32, R(EAX), Imm32(mask));
- MOV(32, gpr.R(a), R(EAX));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ ROL(32, gpr.R(a), R(ECX));
+ AND(32, gpr.R(a), Imm32(mask));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
gpr.UnlockAll();
gpr.UnlockAllX();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(a));
- }
}
void Jit64::negx(UGeckoInstruction inst)
@@ -1279,6 +1861,14 @@ void Jit64::negx(UGeckoInstruction inst)
if (gpr.R(a).IsImm())
{
gpr.SetImmediate32(d, ~((u32)gpr.R(a).offset) + 1);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(d));
+ }
+ if (inst.OE)
+ {
+ GenerateConstantOverflow(gpr.R(d).offset == 0x80000000);
+ }
}
else
{
@@ -1287,13 +1877,16 @@ void Jit64::negx(UGeckoInstruction inst)
if (a != d)
MOV(32, gpr.R(d), gpr.R(a));
NEG(32, gpr.R(d));
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ if (inst.OE)
+ {
+ GenerateOverflow();
+ }
gpr.UnlockAll();
}
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(d));
- }
}
void Jit64::srwx(UGeckoInstruction inst)
@@ -1311,22 +1904,38 @@ void Jit64::srwx(UGeckoInstruction inst)
}
else
{
+#ifdef _M_X64
+ gpr.FlushLockX(ECX);
+ gpr.Lock(a, b, s);
+ gpr.BindToRegister(a, (a == b || a == s), true);
+ MOV(32, R(ECX), gpr.R(b));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ SHR(64, gpr.R(a), R(ECX));
+ gpr.UnlockAll();
+ gpr.UnlockAllX();
+#else
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
- gpr.BindToRegister(a, a == s || a == b || s == b, true);
+ gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
- XOR(32, R(EAX), R(EAX));
TEST(32, R(ECX), Imm32(32));
- FixupBranch branch = J_CC(CC_NZ);
- MOV(32, R(EAX), gpr.R(s));
- SHR(32, R(EAX), R(ECX));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ FixupBranch branch = J_CC(CC_Z);
+ XOR(32, gpr.R(a), gpr.R(a));
SetJumpTarget(branch);
- MOV(32, gpr.R(a), R(EAX));
+ SHR(32, gpr.R(a), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();
+#endif
}
-
- if (inst.Rc)
+ // Shift of 0 doesn't update flags, so compare manually just in case
+ if (inst.Rc)
{
ComputeRC(gpr.R(a));
}
@@ -1344,27 +1953,56 @@ void Jit64::slwx(UGeckoInstruction inst)
{
u32 amount = (u32)gpr.R(b).offset;
gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (u32)gpr.R(s).offset << amount);
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
}
else
{
+#ifdef _M_X64
gpr.FlushLockX(ECX);
gpr.Lock(a, b, s);
- gpr.BindToRegister(a, a == s || a == b || s == b, true);
+ gpr.BindToRegister(a, (a == b || a == s), true);
+ MOV(32, R(ECX), gpr.R(b));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ SHL(64, gpr.R(a), R(ECX));
+ if (inst.Rc)
+ {
+ AND(32, gpr.R(a), gpr.R(a));
+ GenerateRC();
+ }
+ else
+ {
+ MOV(32, gpr.R(a), gpr.R(a));
+ }
+ gpr.UnlockAll();
+ gpr.UnlockAllX();
+#else
+ gpr.FlushLockX(ECX);
+ gpr.Lock(a, b, s);
+ gpr.BindToRegister(a, (a == b || a == s), true);
MOV(32, R(ECX), gpr.R(b));
- XOR(32, R(EAX), R(EAX));
TEST(32, R(ECX), Imm32(32));
- FixupBranch branch = J_CC(CC_NZ);
- MOV(32, R(EAX), gpr.R(s));
- SHL(32, R(EAX), R(ECX));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), gpr.R(s));
+ }
+ FixupBranch branch = J_CC(CC_Z);
+ XOR(32, gpr.R(a), gpr.R(a));
SetJumpTarget(branch);
- MOV(32, gpr.R(a), R(EAX));
+ SHL(32, gpr.R(a), R(ECX));
gpr.UnlockAll();
gpr.UnlockAllX();
- }
-
- if (inst.Rc)
- {
- ComputeRC(gpr.R(a));
+ // Shift of 0 doesn't update flags, so compare manually just in case
+ if (inst.Rc)
+ {
+ ComputeRC(gpr.R(a));
+ }
+#endif
}
}
@@ -1376,37 +2014,51 @@ void Jit64::srawx(UGeckoInstruction inst)
int a = inst.RA;
int b = inst.RB;
int s = inst.RS;
+#ifdef _M_X64
gpr.Lock(a, s, b);
gpr.FlushLockX(ECX);
- gpr.BindToRegister(a, a == s || a == b, true);
+ gpr.BindToRegister(a, (a == s || a == b), true);
+ JitClearCA();
MOV(32, R(ECX), gpr.R(b));
- TEST(32, R(ECX), Imm32(32));
- FixupBranch topBitSet = J_CC(CC_NZ);
if (a != s)
MOV(32, gpr.R(a), gpr.R(s));
- MOV(32, R(EAX), Imm32(1));
- SHL(32, R(EAX), R(ECX));
- ADD(32, R(EAX), Imm32(0x7FFFFFFF));
- AND(32, R(EAX), gpr.R(a));
- ADD(32, R(EAX), Imm32(-1));
- CMP(32, R(EAX), Imm32(-1));
- SETcc(CC_L, R(EAX));
+ SHL(64, gpr.R(a), Imm8(32));
+ SAR(64, gpr.R(a), R(ECX));
+ MOV(32, R(EAX), gpr.R(a));
+ SHR(64, gpr.R(a), Imm8(32));
+ TEST(32, gpr.R(a), R(EAX));
+ FixupBranch nocarry = J_CC(CC_Z);
+ JitSetCA();
+ SetJumpTarget(nocarry);
+ gpr.UnlockAll();
+ gpr.UnlockAllX();
+#else
+ gpr.Lock(a, s, b);
+ gpr.FlushLockX(ECX);
+ gpr.BindToRegister(a, (a == s || a == b), true);
+ JitClearCA();
+ MOV(32, R(ECX), gpr.R(b));
+ if (a != s)
+ MOV(32, gpr.R(a), gpr.R(s));
+ TEST(32, R(ECX), Imm32(32));
+ FixupBranch topBitSet = J_CC(CC_NZ);
+ XOR(32, R(EAX), R(EAX));
+ SHRD(32, R(EAX), gpr.R(a), R(ECX));
SAR(32, gpr.R(a), R(ECX));
- AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~(1 << 29)));
- SHL(32, R(EAX), Imm8(29));
- OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), R(EAX));
+ TEST(32, R(EAX), gpr.R(a));
+ FixupBranch nocarry1 = J_CC(CC_Z);
+ JitSetCA();
FixupBranch end = J();
SetJumpTarget(topBitSet);
- MOV(32, R(EAX), gpr.R(s));
- SAR(32, R(EAX), Imm8(31));
- MOV(32, gpr.R(a), R(EAX));
- AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~(1 << 29)));
- AND(32, R(EAX), Imm32(1<<29));
- OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), R(EAX));
+ SAR(32, gpr.R(a), Imm8(31));
+ FixupBranch nocarry2 = J_CC(CC_Z);
+ JitSetCA();
SetJumpTarget(end);
+ SetJumpTarget(nocarry1);
+ SetJumpTarget(nocarry2);
gpr.UnlockAll();
gpr.UnlockAllX();
-
+#endif
if (inst.Rc) {
ComputeRC(gpr.R(a));
}
@@ -1423,19 +2075,22 @@ void Jit64::srawix(UGeckoInstruction inst)
{
gpr.Lock(a, s);
gpr.BindToRegister(a, a == s, true);
+ JitClearCA();
MOV(32, R(EAX), gpr.R(s));
- MOV(32, gpr.R(a), R(EAX));
+ if (a != s)
+ {
+ MOV(32, gpr.R(a), R(EAX));
+ }
SAR(32, gpr.R(a), Imm8(amount));
- CMP(32, R(EAX), Imm8(0));
- FixupBranch nocarry1 = J_CC(CC_GE);
- TEST(32, R(EAX), Imm32((u32)0xFFFFFFFF >> (32 - amount))); // were any 1s shifted out?
- FixupBranch nocarry2 = J_CC(CC_Z);
+ if (inst.Rc)
+ {
+ GenerateRC();
+ }
+ SHL(32, R(EAX), Imm8(32-amount));
+ TEST(32, R(EAX), gpr.R(a));
+ FixupBranch nocarry = J_CC(CC_Z);
JitSetCA();
- FixupBranch carry = J(false);
- SetJumpTarget(nocarry1);
- SetJumpTarget(nocarry2);
- JitClearCA();
- SetJumpTarget(carry);
+ SetJumpTarget(nocarry);
gpr.UnlockAll();
}
else
@@ -1445,13 +2100,14 @@ void Jit64::srawix(UGeckoInstruction inst)
JitClearCA();
gpr.BindToRegister(a, a == s, true);
if (a != s)
+ {
MOV(32, gpr.R(a), gpr.R(s));
+ }
+ if (inst.Rc) {
+ ComputeRC(gpr.R(a));
+ }
gpr.UnlockAll();
}
-
- if (inst.Rc) {
- ComputeRC(gpr.R(a));
- }
}
// count leading zeroes
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
index 55990d6abf..25ad18acf5 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
@@ -177,81 +177,77 @@ void Jit64::stfd(UGeckoInstruction inst)
Default(inst);
return;
}
- s32 offset = (s32)(s16)inst.SIMM_16;
+
+ u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS;
+ if (Core::g_CoreStartupParameter.bMMU ||
+ Core::g_CoreStartupParameter.iTLBHack) {
+ mem_mask |= Memory::ADDR_MASK_MEM1;
+ }
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bEnableDebugging)
+ {
+ mem_mask |= Memory::EXRAM_MASK;
+ }
+#endif
+
gpr.FlushLockX(ABI_PARAM1);
gpr.Lock(a);
fpr.Lock(s);
gpr.BindToRegister(a, true, false);
+
+ s32 offset = (s32)(s16)inst.SIMM_16;
LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset));
- TEST(32, R(ABI_PARAM1), Imm32(0x0c000000));
- FixupBranch not_ram = J_CC(CC_Z);
- // Assume that any hardware writes using this instruction will go to the FIFO.
- // Star Wars - The Force Unleashed uses this trick.
- if (cpu_info.bSSSE3) {
- MOVAPD(XMM0, fpr.R(s));
- PSHUFB(XMM0, M((void *)bswapShuffle1x8));
- CALL(asm_routines.fifoDirectWriteXmm64);
- } else {
- // This ain't working yet
- MOVAPD(XMM0, fpr.R(s));
- MOVQ_xmm(M(&temp64), XMM0);
- MOV(32, R(EAX), M(&temp64));
- MOV(32, R(ABI_PARAM1), M((void*)((u8 *)&temp64 + 4)));
- BSWAP(32, EAX);
- BSWAP(32, ABI_PARAM1);
- MOV(32, M(((u8 *)&temp64) + 4), R(EAX));
- MOV(32, M((u8 *)&temp64), R(ABI_PARAM1));
- MOVQ_xmm(XMM0, M(&temp64));
- CALL(asm_routines.fifoDirectWriteXmm64);
- }
- FixupBranch quit = J(false);
- SetJumpTarget(not_ram);
-#ifdef _M_IX86
- AND(32, R(ABI_PARAM1), Imm32(Memory::MEMVIEW32_MASK));
-#endif
+ TEST(32, R(ABI_PARAM1), Imm32(mem_mask));
+ FixupBranch safe = J_CC(CC_NZ);
+
+ // Fast routine
if (cpu_info.bSSSE3) {
MOVAPD(XMM0, fpr.R(s));
- PSHUFB(XMM0, M((void *)bswapShuffle1x8));
+ PSHUFB(XMM0, M((void*)bswapShuffle1x8));
#ifdef _M_X64
MOVQ_xmm(MComplex(RBX, ABI_PARAM1, SCALE_1, 0), XMM0);
#else
+ AND(32, R(ECX), Imm32(Memory::MEMVIEW32_MASK));
MOVQ_xmm(MDisp(ABI_PARAM1, (u32)Memory::base), XMM0);
#endif
} else {
-#ifdef _M_X64
- fpr.BindToRegister(s, true, false);
- MOVSD(M(&temp64), fpr.RX(s));
-
- MEMCHECK_START
+ MOVAPD(XMM0, fpr.R(s));
+ MOVD_xmm(R(EAX), XMM0);
+ UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4);
- MOV(64, R(EAX), M(&temp64));
- BSWAP(64, EAX);
- MOV(64, MComplex(RBX, ABI_PARAM1, SCALE_1, 0), R(EAX));
+ PSRLQ(XMM0, 32);
+ MOVD_xmm(R(EAX), XMM0);
+ UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0);
+ }
+ FixupBranch exit = J();
+ SetJumpTarget(safe);
- MEMCHECK_END
-#else
- fpr.BindToRegister(s, true, false);
- MOVSD(M(&temp64), fpr.RX(s));
+ // Safe but slow routine
+ MOVAPD(XMM0, fpr.R(s));
+ PSRLQ(XMM0, 32);
+ MOVD_xmm(R(EAX), XMM0);
+ SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0);
- MEMCHECK_START
+ MOVAPD(XMM0, fpr.R(s));
+ MOVD_xmm(R(EAX), XMM0);
+ LEA(32, ABI_PARAM1, MDisp(gpr.R(a).GetSimpleReg(), offset));
+ SafeWriteRegToReg(EAX, ABI_PARAM1, 32, 4);
- MOV(32, R(EAX), M(&temp64));
- BSWAP(32, EAX);
- MOV(32, MDisp(ABI_PARAM1, (u32)Memory::base + 4), R(EAX));
- MOV(32, R(EAX), M((void*)((u8 *)&temp64 + 4)));
- BSWAP(32, EAX);
- MOV(32, MDisp(ABI_PARAM1, (u32)Memory::base), R(EAX));
+ SetJumpTarget(exit);
- MEMCHECK_END
-#endif
- }
- SetJumpTarget(quit);
gpr.UnlockAll();
gpr.UnlockAllX();
fpr.UnlockAll();
}
-
+// In Release on 32bit build,
+// this seemed to cause a problem with PokePark2
+// at start after talking to first pokemon,
+// you run and smash a box, then he goes on about
+// following him and then you cant do anything.
+// I have enabled interpreter for this function
+// in the mean time.
+// Parlane
void Jit64::stfs(UGeckoInstruction inst)
{
INSTRUCTION_START
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp
index 3a60a0ae11..13c4b02f4d 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp
@@ -1212,7 +1212,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
}
bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const {
- return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op1)) == 0;
+ return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op2)) == 0;
}
// Returns I' if I == (0 - I')
@@ -1260,8 +1260,8 @@ static const std::string opcodeNames[] = {
"FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg",
"FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit",
"InterpreterBranch", "IdleBranch", "ShortIdleLoop",
- "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp",
- "BlockStart", "BlockEnd", "Int3",
+ "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck",
+ "Tramp", "BlockStart", "BlockEnd", "Int3",
};
static const unsigned alwaysUsedList[] = {
InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR,
@@ -1269,7 +1269,8 @@ static const unsigned alwaysUsedList[] = {
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart,
- FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop
+ FPExceptionCheckEnd, ISIException, ExtExceptionCheck, BreakPointCheck,
+ Int3, Tramp, Nop
};
static const unsigned extra8RegList[] = {
LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero,
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
index aca3dd0e37..f41742b01c 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
@@ -165,10 +165,10 @@ enum Opcode {
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
// just a branch
- // used for MMU, at least until someone
+ // used for exception checking, at least until someone
// has a better idea of integrating it
FPExceptionCheckStart, FPExceptionCheckEnd,
- ISIException,
+ ISIException, ExtExceptionCheck, BreakPointCheck,
// "Opcode" representing a register too far away to
// reference directly; this is a size optimization
Tramp,
@@ -411,6 +411,12 @@ public:
InstLoc EmitISIException(InstLoc dest) {
return EmitUOp(ISIException, dest);
}
+ InstLoc EmitExtExceptionCheck(InstLoc pc) {
+ return EmitUOp(ExtExceptionCheck, pc);
+ }
+ InstLoc EmitBreakPointCheck(InstLoc pc) {
+ return EmitUOp(BreakPointCheck, pc);
+ }
InstLoc EmitRFIExit() {
return FoldZeroOp(RFIExit, 0);
}
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
index d8bb2bfc55..7579c69a03 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
@@ -50,6 +50,7 @@ The register allocation is linear scan allocation.
#include "../../../../Common/Src/CPUDetect.h"
#include "MathUtil.h"
#include "../../Core.h"
+#include "HW/ProcessorInterface.h"
static ThunkManager thunks;
@@ -761,6 +762,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
case FPExceptionCheckStart:
case FPExceptionCheckEnd:
case ISIException:
+ case ExtExceptionCheck:
+ case BreakPointCheck:
case Int3:
case Tramp:
// No liveness effects
@@ -1347,6 +1350,12 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Core::g_CoreStartupParameter.iTLBHack) {
mem_mask |= Memory::ADDR_MASK_MEM1;
}
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bEnableDebugging)
+ {
+ mem_mask |= Memory::EXRAM_MASK;
+ }
+#endif
Jit->TEST(32, regLocForInst(RI, getOp2(I)), Imm32(mem_mask));
FixupBranch safe = Jit->J_CC(CC_NZ);
// Fast routine
@@ -1914,6 +1923,38 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->WriteExceptionExit();
break;
}
+ case ExtExceptionCheck: {
+ unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
+
+ Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER));
+ FixupBranch clearInt = Jit->J_CC(CC_NZ);
+ Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
+ FixupBranch noExtException = Jit->J_CC(CC_Z);
+ Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
+ FixupBranch noExtIntEnable = Jit->J_CC(CC_Z);
+ Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP || ProcessorInterface::INT_CAUSE_PE_TOKEN || ProcessorInterface::INT_CAUSE_PE_FINISH));
+ FixupBranch noCPInt = Jit->J_CC(CC_Z);
+
+ Jit->MOV(32, M(&PC), Imm32(InstLoc));
+ Jit->WriteExceptionExit();
+
+ Jit->SetJumpTarget(noCPInt);
+ Jit->SetJumpTarget(noExtIntEnable);
+ Jit->SetJumpTarget(noExtException);
+ Jit->SetJumpTarget(clearInt);
+ break;
+ }
+ case BreakPointCheck: {
+ unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
+
+ Jit->MOV(32, M(&PC), Imm32(InstLoc));
+ Jit->ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
+ Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
+ FixupBranch noBreakpoint = Jit->J_CC(CC_Z);
+ Jit->WriteExit(InstLoc, 0);
+ Jit->SetJumpTarget(noBreakpoint);
+ break;
+ }
case Int3: {
Jit->INT3();
break;
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
index 4110c37f96..e079fb7896 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
@@ -494,7 +494,7 @@ void JitIL::Trace()
}
#endif
- NOTICE_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
+ DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs);
@@ -524,8 +524,12 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
// Comment out the following to disable breakpoints (speed-up)
- blockSize = 1;
- Trace();
+ if (!Profiler::g_ProfileBlocks)
+ {
+ if (GetState() == CPU_STEPPING)
+ blockSize = 1;
+ Trace();
+ }
}
if (em_address == 0)
@@ -648,6 +652,16 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{
ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address));
}
+
+ if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end())
+ {
+ ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address));
+ }
+
+ if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
+ {
+ ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address));
+ }
JitILTables::CompileInstruction(ops[i]);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp
index adf215135d..ac533dd473 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp
@@ -83,12 +83,15 @@ void JitILAsmRoutineManager::Generate()
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
+ TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING));
+ FixupBranch notStepping = J_CC(CC_Z);
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
FixupBranch noBreakpoint = J_CC(CC_Z);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
SetJumpTarget(noBreakpoint);
+ SetJumpTarget(notStepping);
}
SetJumpTarget(skipToRealDispatch);
@@ -210,14 +213,11 @@ void JitILAsmRoutineManager::Generate()
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
testExceptions = GetCodePtr();
- TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
- FixupBranch skipExceptions = J_CC(CC_Z);
- MOV(32, R(EAX), M(&PC));
- MOV(32, M(&NPC), R(EAX));
- ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
- MOV(32, R(EAX), M(&NPC));
- MOV(32, M(&PC), R(EAX));
- SetJumpTarget(skipExceptions);
+ MOV(32, R(EAX), M(&PC));
+ MOV(32, M(&NPC), R(EAX));
+ ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
+ MOV(32, R(EAX), M(&NPC));
+ MOV(32, M(&PC), R(EAX));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
index 572cb63861..379aaca48a 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
@@ -493,6 +493,9 @@ void JitIL::srawx(UGeckoInstruction inst)
test = ibuild.EmitOr(val, mask2);
test = ibuild.EmitICmpUgt(test, mask);
ibuild.EmitStoreCarry(test);
+
+ if (inst.Rc)
+ ComputeRC(ibuild, val);
}
void JitIL::srawix(UGeckoInstruction inst)
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp
index f34f100657..68e3e7493c 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp
@@ -212,12 +212,12 @@ static GekkoOPTemplate table31[] =
{824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
{24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
- {54, &JitIL::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
- {86, &JitIL::DoNothing}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
- {246, &JitIL::Default}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
- {278, &JitIL::Default}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
+ {54, &JitIL::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}},
+ {86, &JitIL::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}},
+ {246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}},
+ {278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}},
{470, &JitIL::Default}, //"dcbi", OPTYPE_DCACHE, 0, 4}},
- {758, &JitIL::Default}, //"dcba", OPTYPE_DCACHE, 0, 4}},
+ {758, &JitIL::DoNothing}, //"dcba", OPTYPE_DCACHE, 0, 4}},
{1014, &JitIL::dcbz}, //"dcbz", OPTYPE_DCACHE, 0, 4}},
//load word
{23, &JitIL::lXzx}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
@@ -306,22 +306,27 @@ static GekkoOPTemplate table31[] =
static GekkoOPTemplate table31_2[] =
{
- {266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {10, &JitIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
- {138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {234, &JitIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {491, &JitIL::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
- {459, &JitIL::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
- {75, &JitIL::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {11, &JitIL::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {235, &JitIL::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
- {104, &JitIL::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
- {8, &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
- {136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {232, &JitIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
- {200, &JitIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {778, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {10, &JitIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
+ {138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {234, &JitIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {491, &JitIL::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {1003, &JitIL::Default}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {459, &JitIL::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {971, &JitIL::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
+ {75, &JitIL::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {11, &JitIL::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {235, &JitIL::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {747, &JitIL::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
+ {104, &JitIL::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {552, &JitIL::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}},
+ {8, &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},
+ {136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {232, &JitIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
+ {200, &JitIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
};
static GekkoOPTemplate table59[] =
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp
index 7f6cac8dd3..6203a81e15 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp
@@ -13,6 +13,8 @@
// If not, see http://www.gnu.org/licenses/
#include "JitBase.h"
+#include "PowerPCDisasm.h"
+#include "disasm.h"
JitBase *jit;
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h
index b832e96e1f..c2febde722 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h
@@ -28,8 +28,7 @@
#include "JitBackpatch.h" // for EmuCodeBlock
#include "JitAsmCommon.h"
-#include "PowerPCDisasm.h"
-#include "disasm.h"
+#include <set>
#define JIT_OPCODE 0
@@ -75,6 +74,8 @@ protected:
u8* rewriteStart;
JitBlock *curBlock;
+
+ std::set<u32> fifoWriteAddresses;
};
public:
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
index 1ed997ce4c..8cc85e3284 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
@@ -126,7 +126,7 @@ bool JitBlock::ContainsAddress(u32 em_address)
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
// is full and when saving and loading states.
void JitBlockCache::Clear()
- {
+ {
Core::DisplayMessage("Clearing code cache.", 3000);
for (int i = 0; i < num_blocks; i++)
{
@@ -353,6 +353,24 @@ bool JitBlock::ContainsAddress(u32 em_address)
}
}
+ void JitBlockCache::UnlinkBlock(int i)
+ {
+ JitBlock &b = blocks[i];
+ std::map<u32, int>::iterator iter;
+ pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
+ ppp = links_to.equal_range(b.originalAddress);
+ if (ppp.first == ppp.second)
+ return;
+ for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) {
+ JitBlock &sourceBlock = blocks[iter2->second];
+ for (int e = 0; e < 2; e++)
+ {
+ if (sourceBlock.exitAddress[e] == b.originalAddress)
+ sourceBlock.linkStatus[e] = false;
+ }
+ }
+ }
+
void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
{
if (block_num < 0 || block_num >= num_blocks)
@@ -375,8 +393,10 @@ bool JitBlock::ContainsAddress(u32 em_address)
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
#endif
- // We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
- // Not entirely ideal, but .. pretty good.
+ UnlinkBlock(block_num);
+
+ // Send anyone who tries to run this block back to the dispatcher.
+ // Not entirely ideal, but .. pretty good.
// Spurious entrances from previously linked blocks can only come through checkedEntry
XEmitter emit((u8 *)b.checkedEntry);
emit.MOV(32, M(&PC), Imm32(b.originalAddress));
@@ -390,14 +410,31 @@ bool JitBlock::ContainsAddress(u32 em_address)
}
- void JitBlockCache::InvalidateICache(u32 address)
- {
- address &= ~0x1f;
+ void JitBlockCache::InvalidateICache(u32 address, const u32 length)
+ {
// destroy JIT blocks
// !! this works correctly under assumption that any two overlapping blocks end at the same address
- std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it;
- while (it2 != block_map.end() && it2->first.second < address + 0x20)
+ std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it;
+ while (it2 != block_map.end() && it2->first.second < address + length)
{
+#ifdef JIT_UNLIMITED_ICACHE
+ JitBlock &b = blocks[it2->second];
+ if (b.originalAddress & JIT_ICACHE_VMEM_BIT)
+ {
+ u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
+ memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
+ }
+ else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT)
+ {
+ u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK;
+ memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
+ }
+ else
+ {
+ u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK;
+ memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4);
+ }
+#endif
DestroyBlock(it2->second, true);
it2++;
}
@@ -418,17 +455,17 @@ bool JitBlock::ContainsAddress(u32 em_address)
if (address & JIT_ICACHE_VMEM_BIT)
{
u32 cacheaddr = address & JIT_ICACHE_MASK;
- memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
+ memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
}
else if (address & JIT_ICACHE_EXRAM_BIT)
{
u32 cacheaddr = address & JIT_ICACHEEX_MASK;
- memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
+ memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
}
else
{
u32 cacheaddr = address & JIT_ICACHE_MASK;
- memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
+ memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length);
}
#endif
}
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h
index 91d47a3d0e..16f16d6d14 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h
@@ -87,6 +87,7 @@ class JitBlockCache
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
void LinkBlockExits(int i);
void LinkBlock(int i);
+ void UnlinkBlock(int i);
public:
JitBlockCache() :
@@ -129,7 +130,7 @@ public:
CompiledCode GetCompiledCodeFromBlock(int block_num);
// DOES NOT WORK CORRECTLY WITH INLINING
- void InvalidateICache(u32 em_address);
+ void InvalidateICache(u32 address, const u32 length);
void DestroyBlock(int block_num, bool invalidate);
// Not currently used
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp
index 1b3155bf63..26abb5a890 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp
@@ -118,7 +118,11 @@ void EmuCodeBlock::UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize,
void EmuCodeBlock::SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend)
{
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging)
+#else
if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU)
+#endif
{
// BackPatch only supports 32-bits accesses
UnsafeLoadToEAX(opAddress, accessSize, offset, signExtend);
@@ -130,7 +134,14 @@ void EmuCodeBlock::SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s
{
mem_mask |= Memory::ADDR_MASK_MEM1;
}
-
+
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bEnableDebugging)
+ {
+ mem_mask |= Memory::EXRAM_MASK;
+ }
+#endif
+
if (opAddress.IsImm())
{
u32 address = (u32)opAddress.offset + offset;
@@ -232,6 +243,13 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce
mem_mask |= Memory::ADDR_MASK_MEM1;
}
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bEnableDebugging)
+ {
+ mem_mask |= Memory::EXRAM_MASK;
+ }
+#endif
+
TEST(32, R(reg_addr), Imm32(mem_mask));
FixupBranch fast = J_CC(CC_Z);
@@ -256,6 +274,13 @@ void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr)
mem_mask |= Memory::ADDR_MASK_MEM1;
}
+#ifdef ENABLE_MEM_CHECK
+ if (Core::g_CoreStartupParameter.bEnableDebugging)
+ {
+ mem_mask |= Memory::EXRAM_MASK;
+ }
+#endif
+
TEST(32, R(reg_addr), Imm32(mem_mask));
if (false && cpu_info.bSSSE3) {
// This path should be faster but for some reason it causes errors so I've disabled it.
@@ -327,3 +352,11 @@ void EmuCodeBlock::JitSetCA()
{
OR(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(XER_CA_MASK)); //XER.CA = 1
}
+
+void EmuCodeBlock::JitClearCAOV(bool oe)
+{
+ if (oe)
+ AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_CA_MASK & ~XER_OV_MASK)); //XER.CA, XER.OV = 0
+ else
+ AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_CA_MASK)); //XER.CA = 0
+}
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h
index 70d4e294e4..e151c5e914 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.h
@@ -38,6 +38,7 @@ public:
void WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address);
void JitClearCA();
void JitSetCA();
+ void JitClearCAOV(bool oe);
void ForceSinglePrecisionS(Gen::X64Reg xmm);
void ForceSinglePrecisionP(Gen::X64Reg xmm);
diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
index f354ea4291..c3aa56acd0 100644
--- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
+++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
@@ -299,7 +299,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa,
merged_addresses[0] = address;
size_of_merged_addresses = 1;
- memset(st, 0, sizeof(st));
+ memset(st, 0, sizeof(*st));
// Disabled the following optimization in preference of FAST_ICACHE
//UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4);
diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp
index 33ecc0ee88..6956e9db1c 100644
--- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp
+++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp
@@ -80,10 +80,18 @@ namespace PowerPC
jit->GetBlockCache()->ClearSafe();
}
+ void InstructionCache::Init()
+ {
+ memset(data, 0, sizeof(data));
+ memset(tags, 0, sizeof(tags));
+ memset(way_from_valid, 0, sizeof(way_from_valid));
+ memset(way_from_plru, 0, sizeof(way_from_plru));
+
+ Reset();
+ }
+
void InstructionCache::Invalidate(u32 addr)
{
- if (jit)
- jit->GetBlockCache()->InvalidateICache(addr);
if (!HID0.ICE)
return;
// invalidates the whole set
@@ -101,6 +109,8 @@ namespace PowerPC
}
#endif
valid[set] = 0;
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(addr & ~0x1f, 32);
}
u32 InstructionCache::ReadInstruction(u32 addr)
diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.h b/Source/Core/Core/Src/PowerPC/PPCCache.h
index c2e428946c..6d62720d43 100644
--- a/Source/Core/Core/Src/PowerPC/PPCCache.h
+++ b/Source/Core/Core/Src/PowerPC/PPCCache.h
@@ -50,9 +50,10 @@ namespace PowerPC
#endif
InstructionCache();
- void Reset();
u32 ReadInstruction(u32 addr);
void Invalidate(u32 addr);
+ void Init();
+ void Reset();
};
}
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
index 567f3ff98e..2ae520faab 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
@@ -37,6 +37,7 @@
#include "CPUCoreBase.h"
#include "../Host.h"
+#include "HW/EXI.h"
CPUCoreBase *cpu_core_base;
@@ -74,13 +75,20 @@ void ExpandCR()
void DoState(PointerWrap &p)
{
- rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
- *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :)
+ // some of this code has been disabled, because
+ // it changes registers even in MODE_MEASURE (which is suspicious and seems like it could cause desyncs)
+ // and because the values it's changing have been added to CoreTiming::DoState, so it might conflict to mess with them here.
+
+// rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer();
+// *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :)
p.Do(ppcState);
- SystemTimers::DecrementerSet();
- SystemTimers::TimeBaseSet();
+// SystemTimers::DecrementerSet();
+// SystemTimers::TimeBaseSet();
+
+ if (jit && p.GetMode() == PointerWrap::MODE_READ)
+ jit->GetBlockCache()->ClearSafe();
}
void ResetRegisters()
@@ -146,6 +154,17 @@ void Init(int cpu_core)
//but still - set any useful sse options here
#endif
+ memset(ppcState.mojs, 0, sizeof(ppcState.mojs));
+ memset(ppcState.sr, 0, sizeof(ppcState.sr));
+ ppcState.DebugCount = 0;
+ ppcState.dtlb_last = 0;
+ ppcState.dtlb_last = 0;
+ memset(ppcState.dtlb_va, 0, sizeof(ppcState.dtlb_va));
+ memset(ppcState.dtlb_pa, 0, sizeof(ppcState.dtlb_pa));
+ ppcState.itlb_last = 0;
+ memset(ppcState.itlb_va, 0, sizeof(ppcState.itlb_va));
+ memset(ppcState.itlb_pa, 0, sizeof(ppcState.itlb_pa));
+
ResetRegisters();
PPCTables::InitTables(cpu_core);
@@ -189,7 +208,7 @@ void Init(int cpu_core)
}
state = CPU_STEPPING;
- ppcState.iCache.Reset();
+ ppcState.iCache.Init();
}
void Shutdown()
@@ -205,6 +224,11 @@ void Shutdown()
state = CPU_POWERDOWN;
}
+CoreMode GetMode()
+{
+ return mode;
+}
+
void SetMode(CoreMode new_mode)
{
if (new_mode == mode)
@@ -215,7 +239,6 @@ void SetMode(CoreMode new_mode)
switch (mode)
{
case MODE_INTERPRETER: // Switching from JIT to interpreter
- jit->ClearCache(); // Remove all those nasty JIT patches.
cpu_core_base = interpreter;
break;
@@ -268,10 +291,13 @@ void Stop()
void CheckExceptions()
{
+ // Make sure we are checking against the latest EXI status. This is required
+ // for devices which interrupt frequently, such as the gc mic
+ ExpansionInterface::UpdateInterrupts();
+
// Read volatile data once
u32 exceptions = ppcState.Exceptions;
- // This check is unnecessary in JIT mode. However, it probably doesn't really hurt.
if (!exceptions)
return;
@@ -303,7 +329,7 @@ void CheckExceptions()
{
SRR0 = PC;
// say that it's a trap exception
- SRR1 = (MSR & 0x87C0FFFF) | 0x40000;
+ SRR1 = (MSR & 0x87C0FFFF) | 0x20000;
MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36;
NPC = 0x80000700;
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h
index 9ac979bcfb..54690ac6b5 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.h
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.h
@@ -97,6 +97,7 @@ void Init(int cpu_core);
void Shutdown();
void DoState(PointerWrap &p);
+CoreMode GetMode();
void SetMode(CoreMode _coreType);
void SingleStep();
diff --git a/Source/Core/Core/Src/PowerPC/Profiler.cpp b/Source/Core/Core/Src/PowerPC/Profiler.cpp
index 2874705d4b..3636b00717 100644
--- a/Source/Core/Core/Src/PowerPC/Profiler.cpp
+++ b/Source/Core/Core/Src/PowerPC/Profiler.cpp
@@ -56,18 +56,21 @@ void WriteProfileResults(const char *filename)
for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++)
{
const JitBlock *block = jit->GetBlockCache()->GetBlock(i);
- // Rough heuristic. Mem instructions should cost more.
- u64 cost = block->originalSize * (block->runCount / 4);
+ if (block && !block->invalid)
+ {
+ // Rough heuristic. Mem instructions should cost more.
+ u64 cost = block->originalSize * (block->runCount / 4);
#ifdef _WIN32
- u64 timecost = block->ticCounter;
+ u64 timecost = block->ticCounter;
#endif
- // Todo: tweak.
- if (block->runCount >= 1)
- stats.push_back(BlockStat(i, cost));
- cost_sum += cost;
+ // Todo: tweak.
+ if (block->runCount >= 1)
+ stats.push_back(BlockStat(i, cost));
+ cost_sum += cost;
#ifdef _WIN32
- timecost_sum += timecost;
+ timecost_sum += timecost;
#endif
+ }
}
sort(stats.begin(), stats.end());
@@ -77,18 +80,18 @@ void WriteProfileResults(const char *filename)
PanicAlert("failed to open %s", filename);
return;
}
- fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
+ fprintf(f.GetHandle(), "origAddr\tblkName\tcost\trunCount\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
for (unsigned int i = 0; i < stats.size(); i++)
{
const JitBlock *block = jit->GetBlockCache()->GetBlock(stats[i].blockNum);
- if (block)
+ if (block && !block->invalid)
{
std::string name = g_symbolDB.GetDescription(block->originalAddress);
double percent = 100.0 * (double)stats[i].cost / (double)cost_sum;
#ifdef _WIN32
double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum;
- fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n",
- block->originalAddress, name.c_str(), stats[i].cost,
+ fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n",
+ block->originalAddress, name.c_str(), stats[i].cost, block->runCount,
block->ticCounter, percent, timePercent,
(double)block->ticCounter*1000.0/(double)countsPerSec, block->codeSize);
#else
diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp
index d942255d2a..8ba238f2d7 100644
--- a/Source/Core/Core/Src/State.cpp
+++ b/Source/Core/Core/Src/State.cpp
@@ -31,6 +31,9 @@
#include "VideoBackendBase.h"
#include <lzo/lzo1x.h>
+#include "HW/Memmap.h"
+#include "HW/VideoInterface.h"
+#include "HW/SystemTimers.h"
namespace State
{
@@ -58,14 +61,23 @@ static int ev_FileSave, ev_BufferSave, ev_FileLoad, ev_BufferLoad, ev_FileVerify
static std::string g_current_filename, g_last_filename;
+static CallbackFunc g_onAfterLoadCb = NULL;
+
// Temporary undo state buffer
static std::vector<u8> g_undo_load_buffer;
static std::vector<u8> g_current_buffer;
+static int g_loadDepth = 0;
static std::thread g_save_thread;
+static const u8 NUM_HOOKS = 2;
+static u8 waiting;
+static u8 waitingslot;
+static u64 lastCheckedStates[NUM_HOOKS];
+static u8 hook;
+
// Don't forget to increase this after doing changes on the savestate system
-static const int STATE_VERSION = 5;
+static const int STATE_VERSION = 7;
struct StateHeader
{
@@ -73,6 +85,13 @@ struct StateHeader
size_t size;
};
+enum
+{
+ STATE_NONE = 0,
+ STATE_SAVE = 1,
+ STATE_LOAD = 2,
+};
+
static bool g_use_compression = true;
void EnableCompression(bool compression)
@@ -82,29 +101,60 @@ void EnableCompression(bool compression)
void DoState(PointerWrap &p)
{
- u32 cookie = 0xBAADBABE + STATE_VERSION;
- p.Do(cookie);
- if (cookie != 0xBAADBABE + STATE_VERSION)
+ u32 version = STATE_VERSION;
{
- p.SetMode(PointerWrap::MODE_MEASURE);
- return;
+ u32 cookie = version + 0xBAADBABE;
+ p.Do(cookie);
+ version = cookie - 0xBAADBABE;
}
+
+ if (version != STATE_VERSION)
+ {
+ if (version == 5 && STATE_VERSION == 6)
+ {
+ // from version 5 to 6, the only difference was the addition of calling Movie::DoState,
+ // so (because it's easy) let's not break compatibility in this case
+ }
+ else
+ {
+ // if the version doesn't match, fail.
+ // this will trigger a message like "Can't load state from other revisions"
+ p.SetMode(PointerWrap::MODE_MEASURE);
+ return;
+ }
+ }
+
+ p.DoMarker("Version");
+
// Begin with video backend, so that it gets a chance to clear it's caches and writeback modified things to RAM
// Pause the video thread in multi-threaded mode
g_video_backend->RunLoop(false);
g_video_backend->DoState(p);
+ p.DoMarker("video_backend");
if (Core::g_CoreStartupParameter.bWii)
Wiimote::DoState(p.GetPPtr(), p.GetMode());
+ p.DoMarker("Wiimote");
PowerPC::DoState(p);
+ p.DoMarker("PowerPC");
HW::DoState(p);
+ p.DoMarker("HW");
CoreTiming::DoState(p);
+ p.DoMarker("CoreTiming");
+ Movie::DoState(p, version<6);
+ p.DoMarker("Movie");
// Resume the video thread
g_video_backend->RunLoop(true);
}
+void ResetCounters()
+{
+ for (int i = 0; i < NUM_HOOKS; ++i)
+ lastCheckedStates[i] = CoreTiming::GetTicks();
+}
+
void LoadBufferStateCallback(u64 userdata, int cyclesLate)
{
u8* ptr = &g_current_buffer[0];
@@ -217,10 +267,6 @@ void SaveFileStateCallback(u64 userdata, int cyclesLate)
// Pause the core while we save the state
CCPU::EnableStepping(true);
- // Wait for the other threaded sub-systems to stop too
- // TODO: this is ugly
- SLEEP(100);
-
Flush();
// Measure the size of the buffer.
@@ -235,7 +281,7 @@ void SaveFileStateCallback(u64 userdata, int cyclesLate)
p.SetMode(PointerWrap::MODE_WRITE);
DoState(p);
- if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsRecordingInputFromSaveState())
+ if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsJustStartingRecordingInputFromSaveState())
Movie::SaveRecording((g_current_filename + ".dtm").c_str());
else if (!Movie::IsRecordingInput() && !Movie::IsPlayingInput())
File::Delete(g_current_filename + ".dtm");
@@ -318,9 +364,7 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
// Stop the core while we load the state
CCPU::EnableStepping(true);
- // Wait for the other threaded sub-systems to stop too
- // TODO: uglyyy
- SLEEP(100);
+ g_loadDepth++;
Flush();
@@ -340,22 +384,44 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
DoState(p);
if (p.GetMode() == PointerWrap::MODE_READ)
+ {
Core::DisplayMessage(StringFromFormat("Loaded state from %s", g_current_filename.c_str()).c_str(), 2000);
+ if (File::Exists(g_current_filename + ".dtm"))
+ Movie::LoadInput((g_current_filename + ".dtm").c_str());
+ else if (!Movie::IsJustStartingRecordingInputFromSaveState())
+ Movie::EndPlayInput(false);
+ }
else
+ {
+ // failed to load
Core::DisplayMessage("Unable to Load : Can't load state from other revisions !", 4000);
-
- if (File::Exists(g_current_filename + ".dtm"))
- Movie::LoadInput((g_current_filename + ".dtm").c_str());
- else if (!Movie::IsRecordingInputFromSaveState())
- Movie::EndPlayInput(false);
+
+ // since we're probably in an inconsistent state now (and might crash or whatever), undo.
+ if(g_loadDepth < 2)
+ UndoLoadState();
+ }
}
+ ResetCounters();
+
+ HW::OnAfterLoad();
+
g_op_in_progress = false;
+ if (g_onAfterLoadCb)
+ g_onAfterLoadCb();
+
+ g_loadDepth--;
+
// resume dat core
CCPU::EnableStepping(false);
}
+void SetOnAfterLoadCallback(CallbackFunc callback)
+{
+ g_onAfterLoadCb = callback;
+}
+
void VerifyFileStateCallback(u64 userdata, int cyclesLate)
{
Flush();
@@ -386,6 +452,11 @@ void Init()
ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback);
ev_BufferVerify = CoreTiming::RegisterEvent("VerifyBufferState", &VerifyBufferStateCallback);
+ waiting = STATE_NONE;
+ waitingslot = 0;
+ hook = 0;
+ ResetCounters();
+
if (lzo_init() != LZO_E_OK)
PanicAlertT("Internal LZO Error - lzo_init() failed");
}
@@ -413,40 +484,100 @@ static std::string MakeStateFilename(int number)
SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), number);
}
-void ScheduleFileEvent(const std::string &filename, int ev)
+void ScheduleFileEvent(const std::string &filename, int ev, bool immediate)
{
if (g_op_in_progress)
return;
g_op_in_progress = true;
g_current_filename = filename;
- CoreTiming::ScheduleEvent_Threadsafe_Immediate(ev);
+
+ if (immediate)
+ CoreTiming::ScheduleEvent_Threadsafe_Immediate(ev);
+ else
+ CoreTiming::ScheduleEvent_Threadsafe(0, ev);
}
-void SaveAs(const std::string &filename)
+void SaveAs(const std::string &filename, bool immediate)
{
g_last_filename = filename;
- ScheduleFileEvent(filename, ev_FileSave);
+ ScheduleFileEvent(filename, ev_FileSave, immediate);
+}
+
+void SaveAs(const std::string &filename)
+{
+ SaveAs(filename, true);
+}
+
+void LoadAs(const std::string &filename, bool immediate)
+{
+ ScheduleFileEvent(filename, ev_FileLoad, immediate);
}
void LoadAs(const std::string &filename)
{
- ScheduleFileEvent(filename, ev_FileLoad);
+ LoadAs(filename, true);
}
void VerifyAt(const std::string &filename)
{
- ScheduleFileEvent(filename, ev_FileVerify);
+ ScheduleFileEvent(filename, ev_FileVerify, true);
+}
+
+bool ProcessRequestedStates(int priority)
+{
+ bool save = true;
+
+ if (hook == priority)
+ {
+ if (waiting == STATE_SAVE)
+ {
+ SaveAs(MakeStateFilename(waitingslot), false);
+ waitingslot = 0;
+ waiting = STATE_NONE;
+ }
+ else if (waiting == STATE_LOAD)
+ {
+ LoadAs(MakeStateFilename(waitingslot), false);
+ waitingslot = 0;
+ waiting = STATE_NONE;
+ save = false;
+ }
+ }
+
+ // Change hooks if the new hook gets called frequently (at least once a frame) and if the old
+ // hook has not been called for the last 5 seconds
+ if ((CoreTiming::GetTicks() - lastCheckedStates[priority]) < (VideoInterface::GetTicksPerFrame()))
+ {
+ lastCheckedStates[priority] = CoreTiming::GetTicks();
+ if (hook < NUM_HOOKS && priority >= (hook + 1) &&
+ (lastCheckedStates[priority] - lastCheckedStates[hook]) > (SystemTimers::GetTicksPerSecond() * 5))
+ {
+ hook++;
+ }
+ }
+ else
+ lastCheckedStates[priority] = CoreTiming::GetTicks();
+
+ return save;
}
void Save(int slot)
{
- SaveAs(MakeStateFilename(slot));
+ if (waiting == STATE_NONE)
+ {
+ waiting = STATE_SAVE;
+ waitingslot = slot;
+ }
}
void Load(int slot)
{
- LoadAs(MakeStateFilename(slot));
+ if (waiting == STATE_NONE)
+ {
+ waiting = STATE_LOAD;
+ waitingslot = slot;
+ }
}
void Verify(int slot)
diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h
index 791468f154..2c3a38cd8c 100644
--- a/Source/Core/Core/Src/State.h
+++ b/Source/Core/Core/Src/State.h
@@ -26,6 +26,7 @@ namespace State
{
void Init();
+
void Shutdown();
void EnableCompression(bool compression);
@@ -39,6 +40,8 @@ void Save(int slot);
void Load(int slot);
void Verify(int slot);
+bool ProcessRequestedStates(int priority);
+
void SaveAs(const std::string &filename);
void LoadAs(const std::string &filename);
void VerifyAt(const std::string &filename);
@@ -53,6 +56,10 @@ void UndoLoadState();
void Flush(); // wait until previously scheduled savestate event (if any) is done
+// for calling back into UI code without introducing a dependency on it in core
+typedef void(*CallbackFunc)(void);
+void SetOnAfterLoadCallback(CallbackFunc callback);
+
}
#endif
diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj
index 8c1f684213..d94ac13212 100644
--- a/Source/Core/DiscIO/DiscIO.vcxproj
+++ b/Source/Core/DiscIO/DiscIO.vcxproj
@@ -45,7 +45,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +55,6 @@
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
diff --git a/Source/Core/DiscIO/Src/BannerLoader.h b/Source/Core/DiscIO/Src/BannerLoader.h
index 02d60858e4..1fe48dd364 100644
--- a/Source/Core/DiscIO/Src/BannerLoader.h
+++ b/Source/Core/DiscIO/Src/BannerLoader.h
@@ -39,10 +39,11 @@ class IBannerLoader
virtual bool GetBanner(u32* _pBannerImage) = 0;
virtual bool GetName(std::string* _rName) = 0;
-
+ virtual bool GetName(std::vector<std::wstring>& _rNames) {return false;};
virtual bool GetCompany(std::string& _rCompany) = 0;
virtual bool GetDescription(std::string* _rDescription) = 0;
+ virtual bool GetDescription(std::wstring& _rDescription) {return false;};
protected:
diff --git a/Source/Core/DiscIO/Src/BannerLoaderWii.cpp b/Source/Core/DiscIO/Src/BannerLoaderWii.cpp
index 9c02ef8d08..b23dc4d91a 100644
--- a/Source/Core/DiscIO/Src/BannerLoaderWii.cpp
+++ b/Source/Core/DiscIO/Src/BannerLoaderWii.cpp
@@ -144,26 +144,59 @@ bool CBannerLoaderWii::GetBanner(u32* _pBannerImage)
return true;
}
-bool CBannerLoaderWii::GetName(std::string* _rName)
+bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::string& s)
+{
+ bool ret = false;
+
+ if (IsValid())
+ {
+ // find Banner type
+ SWiiBanner *pBanner = (SWiiBanner*)m_pBannerFile;
+
+ // Ensure the string is null-terminating, since the banner format
+ // doesn't require it
+ u16 *src = new u16[COMMENT_SIZE + 1];
+ memcpy(src, &pBanner->m_Comment[index], COMMENT_SIZE * sizeof(u16));
+ src[COMMENT_SIZE] = 0;
+
+ ret = CopyBeUnicodeToString(s, src, COMMENT_SIZE + 1);
+
+ delete [] src;
+ }
+
+ return ret;
+}
+
+bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::wstring& s)
{
if (IsValid())
{
// find Banner type
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
- std::string name;
- if (CopyBeUnicodeToString(name, pBanner->m_Comment[0], WII_BANNER_COMMENT_SIZE))
- {
- for (int i = 0; i < 6; i++)
- {
- _rName[i] = name;
- }
- return true;
- }
+ std::wstring description;
+ for (int i = 0; i < COMMENT_SIZE; ++i)
+ description.push_back(Common::swap16(pBanner->m_Comment[index][i]));
+
+ s = description;
+ return true;
}
return false;
}
+bool CBannerLoaderWii::GetName(std::string* _rName)
+{
+ return GetStringFromComments(NAME_IDX, *_rName);
+}
+
+bool CBannerLoaderWii::GetName(std::vector<std::wstring>& _rNames)
+{
+ std::wstring temp;
+ bool ret = GetStringFromComments(NAME_IDX, temp);
+ _rNames.push_back(temp);
+ return ret;
+}
+
bool CBannerLoaderWii::GetCompany(std::string& _rCompany)
{
_rCompany = "N/A";
@@ -172,22 +205,12 @@ bool CBannerLoaderWii::GetCompany(std::string& _rCompany)
bool CBannerLoaderWii::GetDescription(std::string* _rDescription)
{
- if (IsValid())
- {
- // find Banner type
- SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
+ return GetStringFromComments(DESC_IDX, *_rDescription);
+}
- std::string description;
- if (CopyBeUnicodeToString(description, pBanner->m_Comment[1], WII_BANNER_COMMENT_SIZE))
- {
- for (int i = 0; i< 6; i++)
- {
- _rDescription[i] = description;
- }
- return true;
- }
- }
- return false;
+bool CBannerLoaderWii::GetDescription(std::wstring& _rDescription)
+{
+ return GetStringFromComments(DESC_IDX, _rDescription);
}
void CBannerLoaderWii::decode5A3image(u32* dst, u16* src, int width, int height)
diff --git a/Source/Core/DiscIO/Src/BannerLoaderWii.h b/Source/Core/DiscIO/Src/BannerLoaderWii.h
index fb28f5a2e0..83733cf5ed 100644
--- a/Source/Core/DiscIO/Src/BannerLoaderWii.h
+++ b/Source/Core/DiscIO/Src/BannerLoaderWii.h
@@ -37,16 +37,28 @@ class CBannerLoaderWii
virtual bool GetName(std::string* _rName);
+ bool GetName(std::vector<std::wstring>& _rNames);
+
virtual bool GetCompany(std::string& _rCompany);
virtual bool GetDescription(std::string* _rDescription);
+ bool GetDescription(std::wstring& _rDescription);
private:
- #define WII_BANNER_TEXTURE_SIZE (192 * 64 * 2)
- #define WII_BANNER_ICON_SIZE ( 48 * 48 * 2)
- #define WII_BANNER_COMMENT_SIZE 32
+ enum
+ {
+ TEXTURE_SIZE = 192 * 64 * 2,
+ ICON_SIZE = 48 * 48 * 2,
+ COMMENT_SIZE = 32
+ };
+
+ enum CommentIndex
+ {
+ NAME_IDX,
+ DESC_IDX
+ };
struct SWiiBanner
{
@@ -56,9 +68,10 @@ class CBannerLoaderWii
u16 m_Speed;
u8 m_Unknown[22];
- u16 m_Comment[2][WII_BANNER_COMMENT_SIZE];
- u8 m_BannerTexture[WII_BANNER_TEXTURE_SIZE];
- u8 m_IconTexture[8][WII_BANNER_ICON_SIZE];
+ // Not null terminated!
+ u16 m_Comment[2][COMMENT_SIZE];
+ u8 m_BannerTexture[TEXTURE_SIZE];
+ u8 m_IconTexture[8][ICON_SIZE];
} ;
u8* m_pBannerFile;
@@ -66,6 +79,9 @@ class CBannerLoaderWii
bool m_IsValid;
void decode5A3image(u32* dst, u16* src, int width, int height);
+
+ bool GetStringFromComments(const CommentIndex index, std::string& s);
+ bool GetStringFromComments(const CommentIndex index, std::wstring& s);
};
} // namespace
diff --git a/Source/Core/DiscIO/Src/NANDContentLoader.cpp b/Source/Core/DiscIO/Src/NANDContentLoader.cpp
index c8e409636b..f010b7ed98 100644
--- a/Source/Core/DiscIO/Src/NANDContentLoader.cpp
+++ b/Source/Core/DiscIO/Src/NANDContentLoader.cpp
@@ -191,6 +191,8 @@ const SNANDContent* CNANDContentLoader::GetContentByIndex(int _Index) const
bool CNANDContentLoader::Initialize(const std::string& _rName)
{
+ if (_rName.empty())
+ return false;
m_Path = _rName;
WiiWAD Wad(_rName);
u8* pDataApp = NULL;
@@ -221,7 +223,7 @@ bool CNANDContentLoader::Initialize(const std::string& _rName)
File::IOFile pTMDFile(TMDFileName, "rb");
if (!pTMDFile)
{
- ERROR_LOG(DISCIO, "CreateFromDirectory: error opening %s",
+ DEBUG_LOG(DISCIO, "CreateFromDirectory: error opening %s",
TMDFileName.c_str());
return false;
}
@@ -536,20 +538,14 @@ u64 CNANDContentManager::Install_WiiWAD(std::string &fileName)
pTMDFile.Close();
- //Extract and copy WAD's ticket to ticket directory
- std::string TicketFileName = Common::GetTicketFileName(TitleID);
- File::CreateFullPath(TicketFileName);
- File::IOFile pTicketFile(TicketFileName, "wb");
- if (!pTicketFile)
- {
- PanicAlertT("WAD installation failed: error creating %s", TicketFileName.c_str());
- return 0;
- }
- if (ContentLoader.GetTIK())
+
+ //Extract and copy WAD's ticket to ticket directory
+ if (!Add_Ticket(TitleID, ContentLoader.GetTIK(), ContentLoader.GetTIKSize()))
{
- pTicketFile.WriteBytes(ContentLoader.GetTIK(), ContentLoader.GetTIKSize());
+ PanicAlertT("WAD installation failed: error creating ticket");
+ return 0;
}
cUIDsys::AccessInstance().AddTitle(TitleID);
@@ -558,6 +554,18 @@ u64 CNANDContentManager::Install_WiiWAD(std::string &fileName)
return TitleID;
}
+bool Add_Ticket(u64 TitleID, const u8 *p_tik, u32 tikSize)
+{
+ std::string TicketFileName = Common::GetTicketFileName(TitleID);
+ File::CreateFullPath(TicketFileName);
+ File::IOFile pTicketFile(TicketFileName, "wb");
+ if (!pTicketFile || !p_tik)
+ {
+ //PanicAlertT("WAD installation failed: error creating %s", TicketFileName.c_str());
+ return false;
+ }
+ return pTicketFile.WriteBytes(p_tik, tikSize);
+}
} // namespace end
diff --git a/Source/Core/DiscIO/Src/NANDContentLoader.h b/Source/Core/DiscIO/Src/NANDContentLoader.h
index 14a2062641..63135df693 100644
--- a/Source/Core/DiscIO/Src/NANDContentLoader.h
+++ b/Source/Core/DiscIO/Src/NANDContentLoader.h
@@ -29,7 +29,7 @@
namespace DiscIO
{
-
+ bool Add_Ticket(u64 TitleID, const u8 *p_tik, u32 tikSize);
struct SNANDContent
{
u32 m_ContentID;
diff --git a/Source/Core/DiscIO/Src/Volume.h b/Source/Core/DiscIO/Src/Volume.h
index f1bb5d3773..ec20e47b6c 100644
--- a/Source/Core/DiscIO/Src/Volume.h
+++ b/Source/Core/DiscIO/Src/Volume.h
@@ -38,6 +38,7 @@ public:
virtual std::string GetUniqueID() const = 0;
virtual std::string GetMakerID() const = 0;
virtual std::string GetName() const = 0;
+ virtual bool GetWName(std::vector<std::wstring>& _rwNames) const {return false;};
virtual u32 GetFSTSize() const = 0;
virtual std::string GetApploaderDate() const = 0;
diff --git a/Source/Core/DiscIO/Src/VolumeDirectory.cpp b/Source/Core/DiscIO/Src/VolumeDirectory.cpp
index 08188bac71..52e9f4389a 100644
--- a/Source/Core/DiscIO/Src/VolumeDirectory.cpp
+++ b/Source/Core/DiscIO/Src/VolumeDirectory.cpp
@@ -389,8 +389,8 @@ void CVolumeDirectory::BuildFST()
// write FST size and location
_dbg_assert_(DVDINTERFACE, m_diskHeader);
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader);
- Write32((u32)m_fstSize, 0x0428, m_diskHeader);
- Write32((u32)m_fstSize, 0x042c, m_diskHeader);
+ Write32((u32)(m_fstSize >> m_addressShift), 0x0428, m_diskHeader);
+ Write32((u32)(m_fstSize >> m_addressShift), 0x042c, m_diskHeader);
}
void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src,
diff --git a/Source/Core/DiscIO/Src/VolumeWad.cpp b/Source/Core/DiscIO/Src/VolumeWad.cpp
index 5fd81cca8b..0cdfc85925 100644
--- a/Source/Core/DiscIO/Src/VolumeWad.cpp
+++ b/Source/Core/DiscIO/Src/VolumeWad.cpp
@@ -107,6 +107,45 @@ bool CVolumeWAD::GetTitleID(u8* _pBuffer) const
return true;
}
+bool CVolumeWAD::GetWName(std::vector<std::wstring>& _rwNames) const
+{
+ u32 footer_size;
+
+ if (!Read(0x1C, 4, (u8*)&footer_size))
+ {
+ return false;
+ }
+ //Japanese, English, German, French, Spanish, Italian, Dutch, unknown, unknown, Korean
+
+ // Offset to the english title
+ for (int i = 0; i < 10; i++)
+ {
+ u16 temp[42];
+ std::wstring out_temp;
+
+ if (!Read(0x9C + (i*84) + OpeningBnrOffset, 84, (u8*)&temp) || Common::swap32(footer_size) < 0xF1
+ || !temp[0])
+ {
+ _rwNames.push_back(L"");
+ continue;
+ }
+ for (int i = 0; i < 42; ++i)
+ {
+ u16 t = Common::swap16(temp[i]);
+ if (t == 0 && i > 0)
+ {
+ if (out_temp.at(out_temp.size()-1) != ' ')
+ out_temp.push_back(' ');
+ }
+ else
+ out_temp.push_back(t);
+ }
+
+ _rwNames.push_back(out_temp);
+ }
+ return true;
+}
+
std::string CVolumeWAD::GetName() const
{
u32 footer_size;
@@ -114,9 +153,13 @@ std::string CVolumeWAD::GetName() const
if (!Read(0x1C, 4, (u8*)&footer_size))
return "";
+
+ //Japanese, English, German, French, Spanish, Italian, Dutch, unknown, unknown, Korean
+
// Offset to the english title
char temp[84];
- if (!Read(0xF1 + OpeningBnrOffset, 84, (u8*)&temp) || Common::swap32(footer_size) < 0xF1)
+ if (!Read(0xF1 + OpeningBnrOffset, 84, (u8*)&temp) || Common::swap32(footer_size) < 0xF1 ||
+ !Common::swap16(temp[0]))
return "";
// Remove the null bytes due to 16bit char length
diff --git a/Source/Core/DiscIO/Src/VolumeWad.h b/Source/Core/DiscIO/Src/VolumeWad.h
index 06bd772699..956844acd1 100644
--- a/Source/Core/DiscIO/Src/VolumeWad.h
+++ b/Source/Core/DiscIO/Src/VolumeWad.h
@@ -39,6 +39,7 @@ public:
std::string GetUniqueID() const;
std::string GetMakerID() const;
std::string GetName() const;
+ bool GetWName(std::vector<std::wstring>& _rwNames) const;
u32 GetFSTSize() const { return 0; }
std::string GetApploaderDate() const { return "0"; }
ECountry GetCountry() const;
diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt
index 7890c9fe96..2d7ed7e0ce 100644
--- a/Source/Core/DolphinWX/CMakeLists.txt
+++ b/Source/Core/DolphinWX/CMakeLists.txt
@@ -1,5 +1,5 @@
set(LIBS core
- lzo2
+ ${LZO}
discio
bdisasm
inputcommon
@@ -8,10 +8,14 @@ set(LIBS core
z
sfml-network
SDL
- GL
+ ${OPENGL_LIBRARIES}
${XRANDR_LIBRARIES}
${X11_LIBRARIES})
+if(LIBAV_FOUND)
+ set(LIBS ${LIBS} ${LIBAV_LIBRARIES})
+endif()
+
if(wxWidgets_FOUND)
set(SRCS Src/ARCodeAddEdit.cpp
Src/AboutDolphin.cpp
@@ -48,7 +52,6 @@ if(wxWidgets_FOUND)
Src/LogWindow.cpp
Src/Main.cpp
Src/MemcardManager.cpp
- Src/MemoryCards/GCMemcard.cpp
Src/MemoryCards/WiiSaveCrypted.cpp
Src/NetWindow.cpp
Src/PHackSettings.cpp
@@ -68,10 +71,28 @@ endif()
if(WIN32)
set(SRCS ${SRCS} Src/stdafx.cpp)
-elseif((${CMAKE_SYSTEM_NAME} MATCHES "Darwin") AND NOT wxWidgets_FOUND)
- # TODO
-elseif((${CMAKE_SYSTEM_NAME} MATCHES "Darwin") AND wxWidgets_FOUND)
- # TODO
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ # Link against OS X system frameworks.
+ list(APPEND LIBS
+ ${APPKIT_LIBRARY}
+ ${AU_LIBRARY}
+ ${COREAUDIO_LIBRARY}
+ ${COREFUND_LIBRARY}
+ ${CORESERV_LIBRARY}
+ ${IOB_LIBRARY}
+ ${IOK_LIBRARY}
+ )
+ if(wxWidgets_FOUND)
+ list(APPEND LIBS
+ ${APPSERV_LIBRARY}
+ ${COCOA_LIBRARY}
+ )
+ endif()
+ # Add resource files to application bundle.
+ set(RESOURCES resources/Dolphin.icns)
+ list(APPEND SRCS ${RESOURCES})
+ set_source_files_properties(${RESOURCES} PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
else()
set(SRCS ${SRCS} Src/X11Utils.cpp)
endif()
@@ -81,13 +102,83 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR
set(LIBS ${LIBS} usbhid)
endif()
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(DOLPHIN_EXE_BASE Dolphin)
+else()
+ set(DOLPHIN_EXE_BASE dolphin-emu)
+endif()
if(wxWidgets_FOUND)
- set(DOLPHIN_EXE dolphin-emu)
+ set(DOLPHIN_EXE ${DOLPHIN_EXE_BASE})
else()
- set(DOLPHIN_EXE dolphin-emu-nogui)
+ set(DOLPHIN_EXE ${DOLPHIN_EXE_BASE}-nogui)
endif()
add_executable(${DOLPHIN_EXE} ${SRCS})
target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS})
-install(TARGETS ${DOLPHIN_EXE} RUNTIME DESTINATION ${bindir})
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ include(BundleUtilities)
+ set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DOLPHIN_EXE}.app)
+
+ # Ask for an application bundle.
+ set_target_properties(${DOLPHIN_EXE} PROPERTIES
+ MACOSX_BUNDLE true
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
+ )
+
+ # Install Cg framework into application bundle.
+ copy_resolved_framework_into_bundle(
+ # Our framework in "Externals" does not have "Versions/Current/" in
+ # its path; work around the missing directory levels using "././".
+ "${CMAKE_SOURCE_DIR}/Externals/Cg/Cg.framework/././Cg"
+ "${BUNDLE_PATH}/Contents/Frameworks/Cg.framework/././Cg"
+ )
+
+ # Fix up the bundle after it is finished.
+ # There does not seem to be an easy way to run CMake commands post-build,
+ # so we invoke CMake again on a generated script.
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/postprocess_bundle.cmake "
+ include(BundleUtilities)
+ message(\"Fixing up application bundle: ${BUNDLE_PATH}\")
+ fixup_bundle(\"${BUNDLE_PATH}\" \"\" \"\")
+ ")
+ add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -P postprocess_bundle.cmake
+ )
+
+ # Copy data files into application bundle.
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/copy_data_into_bundle.cmake "
+ file(INSTALL ${CMAKE_SOURCE_DIR}/Data/Sys ${CMAKE_SOURCE_DIR}/Data/User
+ DESTINATION ${BUNDLE_PATH}/Contents/Resources
+ )
+ file(GLOB TRANSLATION_FILES RELATIVE ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}/*.gmo
+ )
+ foreach(TRANSLATION_FILE \${TRANSLATION_FILES})
+ string(REPLACE \".gmo\" \".lproj\" TRANSLATION_DIR
+ \${TRANSLATION_FILE}
+ )
+ # It would be better to copy to the new name as a single action,
+ # but I can't figure out a way to let CMake do that.
+ file(COPY ${CMAKE_BINARY_DIR}/\${TRANSLATION_FILE}
+ DESTINATION ${BUNDLE_PATH}/Contents/Resources/\${TRANSLATION_DIR}
+ NO_SOURCE_PERMISSIONS
+ )
+ file(RENAME
+ ${BUNDLE_PATH}/Contents/Resources/\${TRANSLATION_DIR}/\${TRANSLATION_FILE}
+ ${BUNDLE_PATH}/Contents/Resources/\${TRANSLATION_DIR}/dolphin-emu.mo
+ )
+ endforeach(TRANSLATION_FILE)
+ ")
+ add_custom_target(CopyDataIntoBundle ALL
+ COMMAND ${CMAKE_COMMAND} -P copy_data_into_bundle.cmake
+ VERBATIM
+ )
+
+ # Install bundle into systemwide /Applications directory.
+ install(DIRECTORY ${BUNDLE_PATH} DESTINATION /Applications
+ USE_SOURCE_PERMISSIONS
+ )
+else()
+ install(TARGETS ${DOLPHIN_EXE} RUNTIME DESTINATION ${bindir})
+endif()
diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj b/Source/Core/DolphinWX/Dolphin.vcxproj
index 534f61b70e..942bd41f4e 100644
--- a/Source/Core/DolphinWX/Dolphin.vcxproj
+++ b/Source/Core/DolphinWX/Dolphin.vcxproj
@@ -45,7 +45,7 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -56,7 +56,6 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -237,6 +236,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<ClCompile Include="Src\FrameAui.cpp" />
<ClCompile Include="Src\FrameTools.cpp" />
<ClCompile Include="Src\GameListCtrl.cpp" />
+ <ClCompile Include="Src\GCMicDlg.cpp" />
<ClCompile Include="Src\GeckoCodeDiag.cpp" />
<ClCompile Include="Src\HotkeyDlg.cpp" />
<ClCompile Include="Src\InputConfigDiag.cpp" />
@@ -256,7 +256,6 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Src\MemcardManager.cpp" />
- <ClCompile Include="Src\MemoryCards\GCMemcard.cpp" />
<ClCompile Include="Src\MemoryCards\WiiSaveCrypted.cpp" />
<ClCompile Include="Src\Debugger\MemoryCheckDlg.cpp" />
<ClCompile Include="Src\Debugger\MemoryView.cpp" />
@@ -299,6 +298,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<ClInclude Include="Src\FifoPlayerDlg.h" />
<ClInclude Include="Src\Frame.h" />
<ClInclude Include="Src\GameListCtrl.h" />
+ <ClInclude Include="Src\GCMicDlg.h" />
<ClInclude Include="Src\GeckoCodeDiag.h" />
<ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\HotkeyDlg.h" />
@@ -310,7 +310,6 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<ClInclude Include="Src\LogWindow.h" />
<ClInclude Include="Src\Main.h" />
<ClInclude Include="Src\MemcardManager.h" />
- <ClInclude Include="Src\MemoryCards\GCMemcard.h" />
<ClInclude Include="Src\MemoryCards\WiiSaveCrypted.h" />
<ClInclude Include="Src\Debugger\MemoryCheckDlg.h" />
<ClInclude Include="Src\Debugger\MemoryView.h" />
diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj.filters b/Source/Core/DolphinWX/Dolphin.vcxproj.filters
index 3c14226fc0..ec7d68798b 100644
--- a/Source/Core/DolphinWX/Dolphin.vcxproj.filters
+++ b/Source/Core/DolphinWX/Dolphin.vcxproj.filters
@@ -6,9 +6,6 @@
<ClCompile Include="Src\stdafx.cpp" />
<ClCompile Include="Src\WXInputBase.cpp" />
<ClCompile Include="Src\WxUtils.cpp" />
- <ClCompile Include="Src\MemoryCards\GCMemcard.cpp">
- <Filter>GUI\Saves</Filter>
- </ClCompile>
<ClCompile Include="Src\MemoryCards\WiiSaveCrypted.cpp">
<Filter>GUI\Saves</Filter>
</ClCompile>
@@ -135,15 +132,15 @@
<ClCompile Include="Src\TASInputDlg.cpp">
<Filter>GUI</Filter>
</ClCompile>
+ <ClCompile Include="Src\GCMicDlg.cpp">
+ <Filter>GUI</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\Main.h" />
<ClInclude Include="Src\stdafx.h" />
<ClInclude Include="Src\WXInputBase.h" />
<ClInclude Include="Src\WxUtils.h" />
- <ClInclude Include="Src\MemoryCards\GCMemcard.h">
- <Filter>GUI\Saves</Filter>
- </ClInclude>
<ClInclude Include="Src\MemoryCards\WiiSaveCrypted.h">
<Filter>GUI\Saves</Filter>
</ClInclude>
@@ -264,6 +261,9 @@
<ClInclude Include="Src\TASInputDlg.h">
<Filter>GUI</Filter>
</ClInclude>
+ <ClInclude Include="Src\GCMicDlg.h">
+ <Filter>GUI</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Src\SConscript" />
diff --git a/Source/Core/DolphinWX/Info.plist.in b/Source/Core/DolphinWX/Info.plist.in
new file mode 100644
index 0000000000..9a05a972c8
--- /dev/null
+++ b/Source/Core/DolphinWX/Info.plist.in
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>ciso</string>
+ <string>dol</string>
+ <string>elf</string>
+ <string>gcm</string>
+ <string>gcz</string>
+ <string>iso</string>
+ <string>wad</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>Dolphin.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Nintendo GC/Wii file</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>Dolphin</string>
+ <key>CFBundleIconFile</key>
+ <string>Dolphin.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.dolphin-emulator.dolphin</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleLocalizations</key>
+ <array>
+ <string>ar</string>
+ <string>el</string>
+ <string>en</string>
+ <string>es</string>
+ <string>fr</string>
+ <string>hu</string>
+ <string>pt</string>
+ <string>pt_BR</string>
+ <string>tr</string>
+ </array>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${DOLPHIN_WC_DESCRIBE}</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${DOLPHIN_WC_REVISION}</string>
+ <key>CFBundleVersion</key>
+ <string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Licensed under GPL version 2</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${OSX_MIN_VERSION}</string>
+ <key>LSRequiresCarbon</key>
+ <true/>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Source/Core/DolphinWX/SConscript b/Source/Core/DolphinWX/SConscript
index 3d3d1e56c2..92ca4f9f62 100644
--- a/Source/Core/DolphinWX/SConscript
+++ b/Source/Core/DolphinWX/SConscript
@@ -43,7 +43,6 @@ else:
'Src/LogWindow.cpp',
'Src/Main.cpp',
'Src/MemcardManager.cpp',
- 'Src/MemoryCards/GCMemcard.cpp',
'Src/MemoryCards/WiiSaveCrypted.cpp',
'Src/NetWindow.cpp',
'Src/PHackSettings.cpp',
diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp
index 8b2dcb07f6..fdca309aee 100644
--- a/Source/Core/DolphinWX/Src/ConfigMain.cpp
+++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp
@@ -27,6 +27,7 @@
#include "HW/SI.h"
#include "HW/DSPHLE/DSPHLE.h"
#include "HW/DSPLLE/DSPLLE.h"
+#include "HW/GCMemcard.h"
#include "IPC_HLE/WII_IPC_HLE.h"
#include "NANDContentLoader.h"
@@ -37,7 +38,6 @@
#include "Frame.h"
#include "HotkeyDlg.h"
#include "Main.h"
-#include "MemoryCards/GCMemcard.h"
#include "VideoBackendBase.h"
#define TEXT_BOX(page, text) new wxStaticText(page, wxID_ANY, text, wxDefaultPosition, wxDefaultSize)
@@ -55,6 +55,7 @@ static const wxLanguage langIds[] =
wxLANGUAGE_CZECH,
wxLANGUAGE_DUTCH,
wxLANGUAGE_ENGLISH,
+ wxLANGUAGE_FARSI,
wxLANGUAGE_FRENCH,
wxLANGUAGE_GERMAN,
wxLANGUAGE_GREEK,
@@ -78,6 +79,7 @@ static const wxLanguage langIds[] =
#define DEV_DUMMY_STR _trans("Dummy")
#define SIDEV_STDCONT_STR _trans("Standard Controller")
+#define SIDEV_BONGO_STR _trans("TaruKonga (Bongos)")
#define SIDEV_GBA_STR "GBA"
#define SIDEV_AM_BB_STR _trans("AM-Baseboard")
@@ -236,6 +238,7 @@ void CConfigMain::InitializeGUILists()
// Framelimit
arrayStringFor_Framelimit.Add(_("Off"));
arrayStringFor_Framelimit.Add(_("Auto"));
+ arrayStringFor_Framelimit.Add(_("Audio"));
for (int i = 10; i <= 120; i += 5) // from 10 to 120
arrayStringFor_Framelimit.Add(wxString::Format(wxT("%i"), i));
@@ -293,6 +296,7 @@ void CConfigMain::InitializeGUILists()
arrayStringFor_InterfaceLang.Add(_("Czech"));
arrayStringFor_InterfaceLang.Add(_("Dutch"));
arrayStringFor_InterfaceLang.Add(_("English"));
+ arrayStringFor_InterfaceLang.Add(_("Farsi"));
arrayStringFor_InterfaceLang.Add(_("French"));
arrayStringFor_InterfaceLang.Add(_("German"));
arrayStringFor_InterfaceLang.Add(_("Greek"));
@@ -357,7 +361,6 @@ void CConfigMain::InitializeGUIValues()
VolumeText->SetLabel(wxString::Format(wxT("%d %%"), ac_Config.m_Volume));
EnableDTKMusic->SetValue(ac_Config.m_EnableDTKMusic ? true : false);
DSPThread->SetValue(startup_params.bDSPThread);
- EnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
DumpAudio->SetValue(ac_Config.m_DumpAudio ? true : false);
FrequencySelection->SetSelection(
FrequencySelection->FindString(wxString::Format(_("%d Hz"), ac_Config.iFrequency)));
@@ -388,6 +391,7 @@ void CConfigMain::InitializeGUIValues()
wxArrayString SIDevices;
SIDevices.Add(_(DEV_NONE_STR));
SIDevices.Add(_(SIDEV_STDCONT_STR));
+ SIDevices.Add(_(SIDEV_BONGO_STR));
SIDevices.Add(_(SIDEV_GBA_STR));
SIDevices.Add(_(SIDEV_AM_BB_STR));
@@ -406,8 +410,7 @@ void CConfigMain::InitializeGUIValues()
case EXIDEVICE_NONE:
GCEXIDevice[i]->SetStringSelection(SlotDevices[0]);
break;
- case EXIDEVICE_MEMORYCARD_A:
- case EXIDEVICE_MEMORYCARD_B:
+ case EXIDEVICE_MEMORYCARD:
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
break;
case EXIDEVICE_MIC:
@@ -437,15 +440,18 @@ void CConfigMain::InitializeGUIValues()
switch (SConfig::GetInstance().m_SIDevice[i])
{
- case SI_GC_CONTROLLER:
+ case SIDEVICE_GC_CONTROLLER:
GCSIDevice[i]->SetStringSelection(SIDevices[1]);
break;
- case SI_GBA:
+ case SIDEVICE_GC_TARUKONGA:
GCSIDevice[i]->SetStringSelection(SIDevices[2]);
break;
- case SI_AM_BASEBOARD:
+ case SIDEVICE_GC_GBA:
GCSIDevice[i]->SetStringSelection(SIDevices[3]);
break;
+ case SIDEVICE_AM_BASEBOARD:
+ GCSIDevice[i]->SetStringSelection(SIDevices[4]);
+ break;
default:
GCSIDevice[i]->SetStringSelection(SIDevices[0]);
break;
@@ -478,7 +484,7 @@ void CConfigMain::InitializeGUITooltips()
{
// General - Basic
CPUThread->SetToolTip(_("This splits the Video and CPU threads, so they can be run on separate cores.\nCauses major speed improvements on PCs with more than one core, but can also cause occasional crashes/glitches."));
- Framelimit->SetToolTip(_("If you set Framelimit higher than game full speed (NTSC:60, PAL:50), you also have to disable Audio Throttle in DSP to make it effective."));
+ Framelimit->SetToolTip(_("If you set Framelimit higher than game full speed (NTSC:60, PAL:50). Use Audio to throttle using the DSP (might fix audio clicks but can also cause constant noise depending on the game)."));
// General - Advanced
_NTSCJ->SetToolTip(_("Forces NTSC-J mode for using the Japanese ROM font.\nLeft unchecked, dolphin defaults to NTSC-U and automatically enables this setting when playing Japanese games."));
@@ -498,7 +504,6 @@ void CConfigMain::InitializeGUITooltips()
// Audio tooltips
EnableDTKMusic->SetToolTip(_("This is used to play music tracks, like BGM."));
DSPThread->SetToolTip(_("Run DSP LLE on a dedicated thread (not recommended)."));
- EnableThrottle->SetToolTip(_("This is used to control game speed by sound throttle.\nDisabling this could cause abnormal game speed, such as too fast.\nBut sometimes enabling this could cause constant noise.\n\nKeyboard Shortcut <TAB>: Hold down to instantly disable Throttle."));
FrequencySelection->SetToolTip(_("Changing this will have no effect while the emulator is running!"));
BackendSelection->SetToolTip(_("Changing this will have no effect while the emulator is running!"));
@@ -600,8 +605,6 @@ void CConfigMain::CreateGUIControls()
EnableDTKMusic = new wxCheckBox(AudioPage, ID_ENABLE_DTK_MUSIC, _("Enable DTK Music"),
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
DSPThread = new wxCheckBox(AudioPage, ID_DSPTHREAD, _("DSP LLE on Thread"));
- EnableThrottle = new wxCheckBox(AudioPage, ID_ENABLE_THROTTLE, _("Enable Audio Throttle"),
- wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
DumpAudio = new wxCheckBox(AudioPage, ID_DUMP_AUDIO, _("Dump Audio"),
wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
VolumeSlider = new wxSlider(AudioPage, ID_VOLUME, 0, 1, 100,
@@ -619,7 +622,6 @@ void CConfigMain::CreateGUIControls()
sbAudioSettings->Add(DSPEngine, 0, wxALL | wxEXPAND, 5);
sbAudioSettings->Add(EnableDTKMusic, 0, wxALL, 5);
sbAudioSettings->Add(DSPThread, 0, wxALL, 5);
- sbAudioSettings->Add(EnableThrottle, 0, wxALL, 5);
sbAudioSettings->Add(DumpAudio, 0, wxALL, 5);
wxStaticBoxSizer *sbVolume = new wxStaticBoxSizer(wxVERTICAL, AudioPage, _("Volume"));
@@ -835,6 +837,7 @@ void CConfigMain::CoreSettingsChanged(wxCommandEvent& event)
break;
case ID_FRAMELIMIT:
SConfig::GetInstance().m_Framelimit = Framelimit->GetSelection();
+ ac_Config.Update();
break;
case ID_FRAMELIMIT_USEFPSFORLIMITING:
SConfig::GetInstance().b_UseFPS = UseFPSForLimiting->IsChecked();
@@ -916,7 +919,6 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event)
default:
ac_Config.m_EnableDTKMusic = EnableDTKMusic->GetValue();
- ac_Config.m_EnableThrottle = EnableThrottle->GetValue();
ac_Config.m_DumpAudio = DumpAudio->GetValue();
long int frequency;
@@ -1030,7 +1032,7 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
// Change memcard to the new file
ExpansionInterface::ChangeDevice(
isSlotA ? 0 : 1, // SlotA: channel 0, SlotB channel 1
- isSlotA ? EXIDEVICE_MEMORYCARD_A : EXIDEVICE_MEMORYCARD_B,
+ EXIDEVICE_MEMORYCARD,
0); // SP1 is device 2, slots are device 0
}
}
@@ -1044,15 +1046,17 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum)
{
- TSIDevices tempType;
+ SIDevices tempType;
if (!deviceName.compare(CSTR_TRANS(SIDEV_STDCONT_STR)))
- tempType = SI_GC_CONTROLLER;
+ tempType = SIDEVICE_GC_CONTROLLER;
+ else if (!deviceName.compare(CSTR_TRANS(SIDEV_BONGO_STR)))
+ tempType = SIDEVICE_GC_TARUKONGA;
else if (!deviceName.compare(SIDEV_GBA_STR))
- tempType = SI_GBA;
+ tempType = SIDEVICE_GC_GBA;
else if (!deviceName.compare(CSTR_TRANS(SIDEV_AM_BB_STR)))
- tempType = SI_AM_BASEBOARD;
+ tempType = SIDEVICE_AM_BASEBOARD;
else
- tempType = SI_NONE;
+ tempType = SIDEVICE_NONE;
SConfig::GetInstance().m_SIDevice[deviceNum] = tempType;
@@ -1068,7 +1072,7 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
TEXIDevices tempType;
if (!deviceName.compare(CSTR_TRANS(EXIDEV_MEMCARD_STR)))
- tempType = deviceNum ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A;
+ tempType = EXIDEVICE_MEMORYCARD;
else if (!deviceName.compare(CSTR_TRANS(EXIDEV_MIC_STR)))
tempType = EXIDEVICE_MIC;
else if (!deviceName.compare(EXIDEV_BBA_STR))
@@ -1083,7 +1087,7 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
tempType = EXIDEVICE_DUMMY;
// Gray out the memcard path button if we're not on a memcard
- if (tempType == EXIDEVICE_MEMORYCARD_A || tempType == EXIDEVICE_MEMORYCARD_B)
+ if (tempType == EXIDEVICE_MEMORYCARD)
GCMemcardPath[deviceNum]->Enable();
else if (deviceNum == 0 || deviceNum == 1)
GCMemcardPath[deviceNum]->Disable();
diff --git a/Source/Core/DolphinWX/Src/ConfigMain.h b/Source/Core/DolphinWX/Src/ConfigMain.h
index e89a3c148a..3ec798fb8e 100644
--- a/Source/Core/DolphinWX/Src/ConfigMain.h
+++ b/Source/Core/DolphinWX/Src/ConfigMain.h
@@ -157,7 +157,6 @@ private:
wxSlider* VolumeSlider;
wxStaticText* VolumeText;
wxCheckBox* EnableDTKMusic;
- wxCheckBox* EnableThrottle;
wxCheckBox* DumpAudio;
wxArrayString wxArrayBackends;
wxChoice* BackendSelection;
diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp
index 37ff81772a..0b6b366c88 100644
--- a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp
+++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp
@@ -263,6 +263,8 @@ void CCodeWindow::SingleStep()
{
if (CCPU::IsStepping())
{
+ if (jit)
+ jit->GetBlockCache()->InvalidateICache(PC, 4);
CCPU::StepOpcode(&sync_event);
wxThread::Sleep(20);
// need a short wait here
diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp
index a3dd9a9ab8..05915ecd20 100644
--- a/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp
+++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp
@@ -187,35 +187,40 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar)
void CCodeWindow::OnProfilerMenu(wxCommandEvent& event)
{
- if (Core::GetState() == Core::CORE_RUN) {
- event.Skip();
- return;
- }
switch (event.GetId())
{
case IDM_PROFILEBLOCKS:
- if (jit != NULL) jit->ClearCache();
+ Core::SetState(Core::CORE_PAUSE);
+ if (jit != NULL)
+ jit->ClearCache();
Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILEBLOCKS);
+ Core::SetState(Core::CORE_RUN);
break;
case IDM_WRITEPROFILE:
- if (jit != NULL)
- {
- std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
- File::CreateFullPath(filename);
- Profiler::WriteProfileResults(filename.c_str());
+ if (Core::GetState() == Core::CORE_RUN)
+ Core::SetState(Core::CORE_PAUSE);
- wxFileType* filetype = NULL;
- if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("txt"))))
+ if (Core::GetState() == Core::CORE_PAUSE && PowerPC::GetMode() == PowerPC::MODE_JIT)
+ {
+ if (jit != NULL)
{
- // From extension failed, trying with MIME type now
- if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain"))))
- // MIME type failed, aborting mission
- break;
+ std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
+ File::CreateFullPath(filename);
+ Profiler::WriteProfileResults(filename.c_str());
+
+ wxFileType* filetype = NULL;
+ if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("txt"))))
+ {
+ // From extension failed, trying with MIME type now
+ if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain"))))
+ // MIME type failed, aborting mission
+ break;
+ }
+ wxString OpenCommand;
+ OpenCommand = filetype->GetOpenCommand(wxString::From8BitData(filename.c_str()));
+ if(!OpenCommand.IsEmpty())
+ wxExecute(OpenCommand, wxEXEC_SYNC);
}
- wxString OpenCommand;
- OpenCommand = filetype->GetOpenCommand(wxString::From8BitData(filename.c_str()));
- if(!OpenCommand.IsEmpty())
- wxExecute(OpenCommand, wxEXEC_SYNC);
}
break;
}
diff --git a/Source/Core/DolphinWX/Src/Debugger/DSPRegisterView.cpp b/Source/Core/DolphinWX/Src/Debugger/DSPRegisterView.cpp
index 863d09436c..ca275ba66a 100644
--- a/Source/Core/DolphinWX/Src/Debugger/DSPRegisterView.cpp
+++ b/Source/Core/DolphinWX/Src/Debugger/DSPRegisterView.cpp
@@ -27,10 +27,10 @@ wxString CDSPRegTable::GetValue(int row, int col)
{
case 0: return wxString::FromAscii(pdregname(row));
case 1: return wxString::Format(wxT("0x%04x"), DSPCore_ReadRegister(row));
- default: return wxString::FromAscii("");
+ default: return wxEmptyString;
}
}
- return wxString::FromAscii("");
+ return wxEmptyString;
}
void CDSPRegTable::SetValue(int, int, const wxString &)
diff --git a/Source/Core/DolphinWX/Src/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Src/Debugger/RegisterView.cpp
index ecd706cf9a..c4a30fd522 100644
--- a/Source/Core/DolphinWX/Src/Debugger/RegisterView.cpp
+++ b/Source/Core/DolphinWX/Src/Debugger/RegisterView.cpp
@@ -56,18 +56,18 @@ wxString CRegTable::GetValue(int row, int col)
case 2: return wxString::FromAscii(GetFPRName(row));
case 3: return wxString::Format(wxT("%016llx"), riPS0(row));
case 4: return wxString::Format(wxT("%016llx"), riPS1(row));
- default: return wxString::FromAscii("");
+ default: return wxEmptyString;
}
} else {
if (row - 32 < NUM_SPECIALS) {
switch (col) {
case 0: return wxString::FromAscii(special_reg_names[row - 32]);
case 1: return wxString::Format(wxT("%08x"), GetSpecialRegValue(row - 32));
- default: return wxString::FromAscii("");
+ default: return wxEmptyString;
}
}
}
- return wxString::FromAscii("");
+ return wxEmptyString;
}
static void SetSpecialRegValue(int reg, u32 value) {
diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp
index 261d3d6d6d..e7c4fca067 100644
--- a/Source/Core/DolphinWX/Src/Frame.cpp
+++ b/Source/Core/DolphinWX/Src/Frame.cpp
@@ -116,7 +116,7 @@ CPanel::CPanel(
wxWindow *parent,
wxWindowID id
)
- : wxPanel(parent, id)
+ : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, 0) // disables wxTAB_TRAVERSAL because it was breaking hotkeys
{
}
@@ -410,6 +410,8 @@ CFrame::CFrame(wxFrame* parent,
g_TASInputDlg = new TASInputDlg(this);
Movie::SetInputManip(TASManipFunction);
+ State::SetOnAfterLoadCallback(OnAfterLoadCallback);
+
// Setup perspectives
if (g_pCodeWindow)
{
@@ -859,6 +861,16 @@ int GetCmdForHotkey(unsigned int key)
return -1;
}
+void OnAfterLoadCallback()
+{
+ // warning: this gets called from the CPU thread, so we should only queue things to do on the proper thread
+ if(main_frame)
+ {
+ wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATEGUI);
+ main_frame->GetEventHandler()->AddPendingEvent(event);
+ }
+}
+
void TASManipFunction(SPADStatus *PadStatus, int controllerID)
{
if (main_frame)
diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h
index 526e52f3c9..770d459220 100644
--- a/Source/Core/DolphinWX/Src/Frame.h
+++ b/Source/Core/DolphinWX/Src/Frame.h
@@ -361,6 +361,8 @@ private:
int GetCmdForHotkey(unsigned int key);
+void OnAfterLoadCallback();
+
// For TASInputDlg
void TASManipFunction(SPADStatus *PadStatus, int controllerID);
diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp
index be24228c98..607c920906 100644
--- a/Source/Core/DolphinWX/Src/FrameTools.cpp
+++ b/Source/Core/DolphinWX/Src/FrameTools.cpp
@@ -145,7 +145,7 @@ void CFrame::CreateMenu()
emulationMenu->Check(IDM_RECORDREADONLY, true);
emulationMenu->AppendSeparator();
- emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString, wxITEM_CHECK);
+ emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString);
wxMenu *skippingMenu = new wxMenu;
emulationMenu->AppendSubMenu(skippingMenu, _("Frame S&kipping"));
@@ -678,11 +678,8 @@ void CFrame::DoOpen(bool Boot)
File::SetCurrentDir(currentDir);
}
- if (path.IsEmpty())
- return;
-
// Should we boot a new game or just change the disc?
- if (Boot)
+ if (Boot && !path.IsEmpty())
BootGame(std::string(path.mb_str()));
else
{
@@ -704,7 +701,13 @@ void CFrame::OnTASInput(wxCommandEvent& event)
void CFrame::OnFrameStep(wxCommandEvent& event)
{
- Movie::SetFrameStepping(event.IsChecked());
+ bool wasPaused = (Core::GetState() == Core::CORE_PAUSE);
+
+ Movie::DoFrameStep();
+
+ bool isPaused = (Core::GetState() == Core::CORE_PAUSE);
+ if(isPaused && !wasPaused) // don't update on unpause, otherwise the status would be wrong when pausing next frame
+ UpdateGUI();
}
void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED (event))
@@ -718,12 +721,15 @@ void CFrame::OnRecord(wxCommandEvent& WXUNUSED (event))
if (Movie::IsReadOnly())
{
- PanicAlertT("Cannot record movies in read-only mode.");
- return;
+ //PanicAlertT("Cannot record movies in read-only mode.");
+ //return;
+ // the user just chose to record a movie, so that should take precedence
+ Movie::SetReadOnly(false);
+ GetMenuBar()->FindItem(IDM_RECORDREADONLY)->Check(false);
}
for (int i = 0; i < 4; i++) {
- if (SConfig::GetInstance().m_SIDevice[i] == SI_GC_CONTROLLER)
+ if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER)
controllers |= (1 << i);
if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE)
@@ -747,6 +753,13 @@ void CFrame::OnPlayRecording(wxCommandEvent& WXUNUSED (event))
if(path.IsEmpty())
return;
+ if (!Movie::IsReadOnly())
+ {
+ // let's make the read-only flag consistent at the start of a movie.
+ Movie::SetReadOnly(true);
+ GetMenuBar()->FindItem(IDM_RECORDREADONLY)->Check(true);
+ }
+
if(Movie::PlayInput(path.mb_str()))
BootGame(std::string(""));
}
@@ -1561,7 +1574,7 @@ void CFrame::UpdateGUI()
GetMenuBar()->FindItem(IDM_RESET)->Enable(Running || Paused);
GetMenuBar()->FindItem(IDM_RECORD)->Enable(!Movie::IsRecordingInput());
GetMenuBar()->FindItem(IDM_PLAYRECORD)->Enable(!Initialized);
- GetMenuBar()->FindItem(IDM_RECORDEXPORT)->Enable(Movie::IsRecordingInput());
+ GetMenuBar()->FindItem(IDM_RECORDEXPORT)->Enable(Movie::IsPlayingInput() || Movie::IsRecordingInput());
GetMenuBar()->FindItem(IDM_FRAMESTEP)->Enable(Running || Paused);
GetMenuBar()->FindItem(IDM_SCREENSHOT)->Enable(Running || Paused);
GetMenuBar()->FindItem(IDM_TOGGLE_FULLSCREEN)->Enable(Running || Paused);
@@ -1615,6 +1628,8 @@ void CFrame::UpdateGUI()
m_ToolBar->SetToolLabel(IDM_PLAY, _("Play"));
}
}
+
+ GetMenuBar()->FindItem(IDM_RECORDREADONLY)->Enable(Running || Paused);
if (!Initialized && !m_bGameLoading)
{
diff --git a/Source/Core/DolphinWX/Src/GCMicDlg.cpp b/Source/Core/DolphinWX/Src/GCMicDlg.cpp
new file mode 100644
index 0000000000..1cdd166cf5
--- /dev/null
+++ b/Source/Core/DolphinWX/Src/GCMicDlg.cpp
@@ -0,0 +1,290 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include <wx/notebook.h>
+
+#include "GCMicDlg.h"
+#include "ConfigManager.h"
+
+BEGIN_EVENT_TABLE(GCMicDialog,wxDialog)
+ EVT_COMMAND_RANGE(0, NUM_HOTKEYS - 1,
+ wxEVT_COMMAND_BUTTON_CLICKED, GCMicDialog::OnButtonClick)
+ EVT_TIMER(wxID_ANY, GCMicDialog::OnButtonTimer)
+END_EVENT_TABLE()
+
+GCMicDialog::GCMicDialog(wxWindow *parent, wxWindowID id, const wxString &title,
+ const wxPoint &position, const wxSize& size, long style)
+: wxDialog(parent, id, title, position, size, style)
+{
+ CreateHotkeyGUIControls();
+
+#if wxUSE_TIMER
+ m_ButtonMappingTimer = new wxTimer(this, wxID_ANY);
+ g_Pressed = 0;
+ g_Modkey = 0;
+ ClickedButton = NULL;
+ GetButtonWaitingID = 0;
+ GetButtonWaitingTimer = 0;
+#endif
+}
+
+GCMicDialog::~GCMicDialog()
+{
+ delete m_ButtonMappingTimer;
+}
+
+// Save keyboard key mapping
+void GCMicDialog::SaveButtonMapping(int Id, int Key, int Modkey)
+{
+ SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[Id] = Key;
+ SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[Id] = Modkey;
+}
+
+void GCMicDialog::EndGetButtons(void)
+{
+ wxTheApp->Disconnect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
+ wxKeyEventHandler(GCMicDialog::OnKeyDown),
+ (wxObject*)0, this);
+ m_ButtonMappingTimer->Stop();
+ GetButtonWaitingTimer = 0;
+ GetButtonWaitingID = 0;
+ ClickedButton = NULL;
+ SetEscapeId(wxID_ANY);
+}
+
+void GCMicDialog::OnKeyDown(wxKeyEvent& event)
+{
+ if(ClickedButton != NULL)
+ {
+ // Save the key
+ g_Pressed = event.GetKeyCode();
+ g_Modkey = event.GetModifiers();
+
+ // Don't allow modifier keys
+ if (g_Pressed == WXK_CONTROL || g_Pressed == WXK_ALT ||
+ g_Pressed == WXK_SHIFT || g_Pressed == WXK_COMMAND)
+ return;
+
+ // Use the space key to set a blank key
+ if (g_Pressed == WXK_SPACE)
+ {
+ SaveButtonMapping(ClickedButton->GetId(), -1, 0);
+ SetButtonText(ClickedButton->GetId(), wxString());
+ }
+ else
+ {
+ SetButtonText(ClickedButton->GetId(),
+ InputCommon::WXKeyToString(g_Pressed),
+ InputCommon::WXKeymodToString(g_Modkey));
+ SaveButtonMapping(ClickedButton->GetId(), g_Pressed, g_Modkey);
+ }
+ EndGetButtons();
+ }
+}
+
+// Update the textbox for the buttons
+void GCMicDialog::SetButtonText(int id, const wxString &keystr, const wxString &modkeystr)
+{
+ m_Button_Hotkeys[id]->SetLabel(modkeystr + keystr);
+}
+
+void GCMicDialog::DoGetButtons(int _GetId)
+{
+ // Values used in this function
+ const int Seconds = 4; // Seconds to wait for
+ const int TimesPerSecond = 40; // How often to run the check
+
+ // If the Id has changed or the timer is not running we should start one
+ if( GetButtonWaitingID != _GetId || !m_ButtonMappingTimer->IsRunning() )
+ {
+ if(m_ButtonMappingTimer->IsRunning())
+ m_ButtonMappingTimer->Stop();
+
+ // Save the button Id
+ GetButtonWaitingID = _GetId;
+ GetButtonWaitingTimer = 0;
+
+ // Start the timer
+ #if wxUSE_TIMER
+ m_ButtonMappingTimer->Start(1000 / TimesPerSecond);
+ #endif
+ }
+
+ // Process results
+ // Count each time
+ GetButtonWaitingTimer++;
+
+ // This is run every second
+ if (GetButtonWaitingTimer % TimesPerSecond == 0)
+ {
+ // Current time
+ int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond);
+ // Update text
+ SetButtonText(_GetId, wxString::Format(wxT("[ %d ]"), TmpTime));
+ }
+
+ // Time's up
+ if (GetButtonWaitingTimer / TimesPerSecond >= Seconds)
+ {
+ // Revert back to old label
+ SetButtonText(_GetId, OldLabel);
+ EndGetButtons();
+ }
+}
+
+// Input button clicked
+void GCMicDialog::OnButtonClick(wxCommandEvent& event)
+{
+ event.Skip();
+
+ if (m_ButtonMappingTimer->IsRunning()) return;
+
+ wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard
+ wxKeyEventHandler(GCMicDialog::OnKeyDown),
+ (wxObject*)0, this);
+
+ // Get the button
+ ClickedButton = (wxButton *)event.GetEventObject();
+ SetEscapeId(wxID_CANCEL);
+ // Save old label so we can revert back
+ OldLabel = ClickedButton->GetLabel();
+ ClickedButton->SetWindowStyle(wxWANTS_CHARS);
+ ClickedButton->SetLabel(_("<Press Key>"));
+ DoGetButtons(ClickedButton->GetId());
+}
+
+#define HOTKEY_NUM_COLUMNS 2
+
+void GCMicDialog::CreateHotkeyGUIControls(void)
+{
+ const wxString pageNames[] =
+ {
+ _("General"),
+ _("State Saves")
+ };
+
+ const wxString hkText[] =
+ {
+ _("Open"),
+ _("Change Disc"),
+ _("Refresh List"),
+
+ _("Play/Pause"),
+ _("Stop"),
+ _("Reset"),
+ _("Frame Advance"),
+
+ _("Start Recording"),
+ _("Play Recording"),
+ _("Export Recording"),
+ _("Read-only mode"),
+
+ _("Toggle Fullscreen"),
+ _("Take Screenshot"),
+
+ _("Connect Wiimote 1"),
+ _("Connect Wiimote 2"),
+ _("Connect Wiimote 3"),
+ _("Connect Wiimote 4"),
+
+ _("Load State Slot 1"),
+ _("Load State Slot 2"),
+ _("Load State Slot 3"),
+ _("Load State Slot 4"),
+ _("Load State Slot 5"),
+ _("Load State Slot 6"),
+ _("Load State Slot 7"),
+ _("Load State Slot 8"),
+
+ _("Save State Slot 1"),
+ _("Save State Slot 2"),
+ _("Save State Slot 3"),
+ _("Save State Slot 4"),
+ _("Save State Slot 5"),
+ _("Save State Slot 6"),
+ _("Save State Slot 7"),
+ _("Save State Slot 8")
+ };
+
+ const int page_breaks[3] = {HK_OPEN, HK_LOAD_STATE_SLOT_1, NUM_HOTKEYS};
+
+ // Configuration controls sizes
+ wxSize size(100,20);
+ // A small type font
+ wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+
+ wxNotebook *Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
+
+ for (int j = 0; j < 2; j++)
+ {
+ wxPanel *Page = new wxPanel(Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
+ Notebook->AddPage(Page, pageNames[j]);
+
+ wxGridBagSizer *sHotkeys = new wxGridBagSizer();
+
+ // Header line
+ for (int i = 0; i < HOTKEY_NUM_COLUMNS; i++)
+ {
+ wxBoxSizer *HeaderSizer = new wxBoxSizer(wxHORIZONTAL);
+ wxStaticText *StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Action"));
+ HeaderSizer->Add(StaticTextHeader, 1, wxALL, 2);
+ StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Key"), wxDefaultPosition, size);
+ HeaderSizer->Add(StaticTextHeader, 0, wxALL, 2);
+ sHotkeys->Add(HeaderSizer, wxGBPosition(0, i), wxDefaultSpan, wxEXPAND | wxLEFT, (i > 0) ? 30 : 1);
+ }
+
+ int column_break = (page_breaks[j+1] + page_breaks[j] + 1) / 2;
+
+ for (int i = page_breaks[j]; i < page_breaks[j+1]; i++)
+ {
+ // Text for the action
+ wxStaticText *stHotkeys = new wxStaticText(Page, wxID_ANY, hkText[i]);
+
+ // Key selection button
+ m_Button_Hotkeys[i] = new wxButton(Page, i, wxEmptyString,
+ wxDefaultPosition, size);
+ m_Button_Hotkeys[i]->SetFont(m_SmallFont);
+ m_Button_Hotkeys[i]->SetToolTip(_("Left click to detect hotkeys.\nEnter space to clear."));
+ SetButtonText(i,
+ InputCommon::WXKeyToString(SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[i]),
+ InputCommon::WXKeymodToString(
+ SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[i]));
+
+ wxBoxSizer *sHotkey = new wxBoxSizer(wxHORIZONTAL);
+ sHotkey->Add(stHotkeys, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 2);
+ sHotkey->Add(m_Button_Hotkeys[i], 0, wxALL, 2);
+ sHotkeys->Add(sHotkey,
+ wxGBPosition((i < column_break) ? i - page_breaks[j] + 1 : i - column_break + 1,
+ (i < column_break) ? 0 : 1),
+ wxDefaultSpan, wxEXPAND | wxLEFT, (i < column_break) ? 1 : 30);
+ }
+
+ wxStaticBoxSizer *sHotkeyBox = new wxStaticBoxSizer(wxVERTICAL, Page, _("Hotkeys"));
+ sHotkeyBox->Add(sHotkeys);
+
+ wxBoxSizer* const sPage = new wxBoxSizer(wxVERTICAL);
+ sPage->Add(sHotkeyBox, 0, wxEXPAND | wxALL, 5);
+ Page->SetSizer(sPage);
+ }
+
+ wxBoxSizer *sMainSizer = new wxBoxSizer(wxVERTICAL);
+ sMainSizer->Add(Notebook, 0, wxEXPAND | wxALL, 5);
+ sMainSizer->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxDOWN, 5);
+ SetSizerAndFit(sMainSizer);
+ SetFocus();
+}
+
diff --git a/Source/Core/DolphinWX/Src/GCMicDlg.h b/Source/Core/DolphinWX/Src/GCMicDlg.h
new file mode 100644
index 0000000000..c817a67254
--- /dev/null
+++ b/Source/Core/DolphinWX/Src/GCMicDlg.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef __HOTKEYDIALOG_h__
+#define __HOTKEYDIALOG_h__
+
+#include <wx/wx.h>
+#include <wx/textctrl.h>
+#include <wx/button.h>
+#include <wx/stattext.h>
+#include <wx/combobox.h>
+#include <wx/checkbox.h>
+#include <wx/gbsizer.h>
+
+#include "Common.h"
+#include "CoreParameter.h"
+#include "WXInputBase.h"
+
+#if defined(HAVE_X11) && HAVE_X11
+#include "X11InputBase.h"
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#endif
+
+class GCMicDialog : public wxDialog
+{
+ public:
+ GCMicDialog(wxWindow *parent,
+ wxWindowID id = 1,
+ const wxString &title = _("GCMic Configuration"),
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxDEFAULT_DIALOG_STYLE);
+ virtual ~GCMicDialog();
+
+ private:
+ DECLARE_EVENT_TABLE();
+
+ wxString OldLabel;
+
+ wxButton *ClickedButton,
+ *m_Button_Hotkeys[NUM_HOTKEYS];
+
+ wxTimer *m_ButtonMappingTimer;
+
+ void OnButtonTimer(wxTimerEvent& WXUNUSED(event)) { DoGetButtons(GetButtonWaitingID); }
+ void OnButtonClick(wxCommandEvent& event);
+ void OnKeyDown(wxKeyEvent& event);
+ void SaveButtonMapping(int Id, int Key, int Modkey);
+ void CreateHotkeyGUIControls(void);
+
+ void SetButtonText(int id, const wxString &keystr, const wxString &modkeystr = wxString());
+
+ void DoGetButtons(int id);
+ void EndGetButtons(void);
+
+ int GetButtonWaitingID, GetButtonWaitingTimer, g_Pressed, g_Modkey;
+};
+#endif
+
diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.cpp b/Source/Core/DolphinWX/Src/GameListCtrl.cpp
index de7bd83581..8e0a498915 100644
--- a/Source/Core/DolphinWX/Src/GameListCtrl.cpp
+++ b/Source/Core/DolphinWX/Src/GameListCtrl.cpp
@@ -52,13 +52,21 @@ size_t CGameListCtrl::m_currentItem = 0;
size_t CGameListCtrl::m_numberItem = 0;
std::string CGameListCtrl::m_currentFilename;
-static int currentColumn = 0;
-bool operator < (const GameListItem &one, const GameListItem &other)
+static int CompareGameListItems(const GameListItem* iso1, const GameListItem* iso2,
+ long sortData = CGameListCtrl::COLUMN_TITLE)
{
+ int t = 1;
+
+ if (sortData < 0)
+ {
+ t = -1;
+ sortData = -sortData;
+ }
+
int indexOne = 0;
int indexOther = 0;
- switch (one.GetCountry())
+ switch (iso1->GetCountry())
{
case DiscIO::IVolume::COUNTRY_JAPAN:
case DiscIO::IVolume::COUNTRY_USA:
@@ -68,7 +76,7 @@ bool operator < (const GameListItem &one, const GameListItem &other)
indexOne = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
}
- switch (other.GetCountry())
+ switch (iso2->GetCountry())
{
case DiscIO::IVolume::COUNTRY_JAPAN:
case DiscIO::IVolume::COUNTRY_USA:
@@ -78,35 +86,63 @@ bool operator < (const GameListItem &one, const GameListItem &other)
indexOther = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
}
- switch (currentColumn)
+ switch(sortData)
{
case CGameListCtrl::COLUMN_TITLE:
- return strcasecmp(one.GetName(indexOne).c_str(),
- other.GetName(indexOther).c_str()) < 0;
+ return strcasecmp(iso1->GetName(indexOne).c_str(),
+ iso2->GetName(indexOther).c_str()) * t;
case CGameListCtrl::COLUMN_NOTES:
{
- // On Gamecube we show the company string, while it's empty on
- // other platforms, so we show the description instead
std::string cmp1 =
- (one.GetPlatform() == GameListItem::GAMECUBE_DISC) ?
- one.GetCompany() : one.GetDescription(indexOne);
+ (iso1->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
+ iso1->GetCompany() : iso1->GetDescription(indexOne);
std::string cmp2 =
- (other.GetPlatform() == GameListItem::GAMECUBE_DISC) ?
- other.GetCompany() : other.GetDescription(indexOther);
- return strcasecmp(cmp1.c_str(), cmp2.c_str()) < 0;
+ (iso2->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
+ iso2->GetCompany() : iso2->GetDescription(indexOther);
+ return strcasecmp(cmp1.c_str(), cmp2.c_str()) * t;
}
case CGameListCtrl::COLUMN_COUNTRY:
- return (one.GetCountry() < other.GetCountry());
+ if(iso1->GetCountry() > iso2->GetCountry())
+ return 1 * t;
+ if(iso1->GetCountry() < iso2->GetCountry())
+ return -1 * t;
+ return 0;
case CGameListCtrl::COLUMN_SIZE:
- return (one.GetFileSize() < other.GetFileSize());
+ if (iso1->GetFileSize() > iso2->GetFileSize())
+ return 1 * t;
+ if (iso1->GetFileSize() < iso2->GetFileSize())
+ return -1 * t;
+ return 0;
case CGameListCtrl::COLUMN_PLATFORM:
- return (one.GetPlatform() < other.GetPlatform());
- default:
- return strcasecmp(one.GetName(indexOne).c_str(),
- other.GetName(indexOther).c_str()) < 0;
+ if(iso1->GetPlatform() > iso2->GetPlatform())
+ return 1 * t;
+ if(iso1->GetPlatform() < iso2->GetPlatform())
+ return -1 * t;
+ return 0;
+
+ case CGameListCtrl::COLUMN_EMULATION_STATE:
+ {
+ const int
+ nState1 = iso1->GetEmuState(),
+ nState2 = iso2->GetEmuState();
+
+ if (nState1 > nState2)
+ return 1 * t;
+ if (nState1 < nState2)
+ return -1 * t;
+ else
+ return 0;
+ }
+ break;
}
+
+ return 0;
}
+bool operator < (const GameListItem &one, const GameListItem &other)
+{
+ return CompareGameListItems(&one, &other) < 0;
+}
BEGIN_EVENT_TABLE(wxEmuStateTip, wxTipWindow)
EVT_KEY_DOWN(wxEmuStateTip::OnKeyDown)
@@ -410,7 +446,9 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932");
}
#else
- wxCSConv SJISConv(wxFontMapper::GetEncodingName(wxFONTENCODING_EUC_JP));
+ // on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
+ // it returns CP-932, in order to use iconv we need to use CP932
+ wxCSConv SJISConv(wxT("CP932"));
#endif
GameListItem& rISOFile = *m_ISOFiles[_Index];
@@ -429,60 +467,54 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
// Set the game's banner in the second column
SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex);
-
- if (rISOFile.GetPlatform() != GameListItem::WII_WAD)
+
+ std::wstring wstring_name;
+ const std::wstring& wstring_description = rISOFile.GetDescription();
+ std::string company;
+
+ wxString name;
+ wxString description;
+
+ // We show the company string on Gamecube only
+ // On Wii we show the description instead as the company string is empty
+ if (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC)
+ company = rISOFile.GetCompany().c_str();
+ int SelectedLanguage = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
+ switch (rISOFile.GetCountry())
{
- std::string company;
-
- // We show the company string on Gamecube only
- // On Wii we show the description instead as the company string is empty
- if (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC)
- company = rISOFile.GetCompany().c_str();
-
- switch (rISOFile.GetCountry())
+ case DiscIO::IVolume::COUNTRY_TAIWAN:
+ case DiscIO::IVolume::COUNTRY_JAPAN:
{
- case DiscIO::IVolume::COUNTRY_TAIWAN:
- case DiscIO::IVolume::COUNTRY_JAPAN:
- {
- wxString name = wxString(rISOFile.GetName(0).c_str(), SJISConv);
- m_gameList.append(StringFromFormat("%s (J)\n", (const char *)name.c_str()));
- SetItem(_Index, COLUMN_TITLE, name, -1);
- SetItem(_Index, COLUMN_NOTES, wxString(company.size() ?
- company.c_str() : rISOFile.GetDescription(0).c_str(),
- SJISConv), -1);
- }
- break;
- case DiscIO::IVolume::COUNTRY_USA:
- m_gameList.append(StringFromFormat("%s (U)\n", rISOFile.GetName(0).c_str()));
- SetItem(_Index, COLUMN_TITLE,
- wxString::From8BitData(rISOFile.GetName(0).c_str()), -1);
- SetItem(_Index, COLUMN_NOTES,
- wxString::From8BitData(company.size() ?
- company.c_str() : rISOFile.GetDescription(0).c_str()), -1);
- break;
- default:
- m_gameList.append(StringFromFormat("%s (E)\n",
- rISOFile.GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage).c_str()));
- SetItem(_Index, COLUMN_TITLE,
- wxString::From8BitData(
- rISOFile.GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage).c_str()),
- -1);
- SetItem(_Index, COLUMN_NOTES,
- wxString::From8BitData(company.size() ?
- company.c_str() :
- rISOFile.GetDescription(SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage).c_str()),
- -1);
- break;
+ rISOFile.GetName(wstring_name, -1);
+ name = wxString(rISOFile.GetName(0).c_str(), SJISConv);
+ m_gameList.append(StringFromFormat("%s (J)\n", (const char *)name.c_str()));
+ description = wxString(company.size() ? company.c_str() :
+ rISOFile.GetDescription(0).c_str(), SJISConv);
}
+ break;
+ case DiscIO::IVolume::COUNTRY_USA:
+ SelectedLanguage = 0;
+ default:
+ {
+ wxCSConv WindowsCP1252(wxFontMapper::GetEncodingName(wxFONTENCODING_CP1252));
+ rISOFile.GetName(wstring_name, SelectedLanguage);
+
+ name = wxString(rISOFile.GetName(SelectedLanguage).c_str(), WindowsCP1252);
+ m_gameList.append(StringFromFormat("%s (%c)\n",
+ rISOFile.GetName(SelectedLanguage).c_str(), (rISOFile.GetCountry() == DiscIO::IVolume::COUNTRY_USA)?'U':'E'));
+ description = wxString(company.size() ? company.c_str() :
+ rISOFile.GetDescription(SelectedLanguage).c_str(), WindowsCP1252);
+ }
+ break;
}
- else // It's a Wad file
- {
- m_gameList.append(StringFromFormat("%s (WAD)\n", rISOFile.GetName(0).c_str()));
- SetItem(_Index, COLUMN_TITLE,
- wxString(rISOFile.GetName(0).c_str(), SJISConv), -1);
- SetItem(_Index, COLUMN_NOTES,
- wxString(rISOFile.GetDescription(0).c_str(), SJISConv), -1);
- }
+
+ if (wstring_name.length())
+ name = wstring_name.c_str();
+ if (wstring_description.length())
+ description = wstring_description.c_str();
+
+ SetItem(_Index, COLUMN_TITLE, name, -1);
+ SetItem(_Index, COLUMN_NOTES, description, -1);
#ifndef _WIN32
// Emulation state
@@ -702,88 +734,7 @@ int wxCALLBACK wxListCompare(long item1, long item2, long sortData)
const GameListItem *iso1 = caller->GetISO(item1);
const GameListItem *iso2 = caller->GetISO(item2);
- int t = 1;
-
- if (sortData < 0)
- {
- t = -1;
- sortData = -sortData;
- }
-
- int indexOne = 0;
- int indexOther = 0;
-
- switch (iso1->GetCountry())
- {
- case DiscIO::IVolume::COUNTRY_JAPAN:
- case DiscIO::IVolume::COUNTRY_USA:
- indexOne = 0;
- break;
- default:
- indexOne = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
- }
-
- switch (iso2->GetCountry())
- {
- case DiscIO::IVolume::COUNTRY_JAPAN:
- case DiscIO::IVolume::COUNTRY_USA:
- indexOther = 0;
- break;
- default:
- indexOther = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage;
- }
-
- switch(sortData)
- {
- case CGameListCtrl::COLUMN_TITLE:
- return strcasecmp(iso1->GetName(indexOne).c_str(),
- iso2->GetName(indexOther).c_str()) * t;
- case CGameListCtrl::COLUMN_NOTES:
- {
- std::string cmp1 =
- (iso1->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
- iso1->GetCompany() : iso1->GetDescription(indexOne);
- std::string cmp2 =
- (iso2->GetPlatform() == GameListItem::GAMECUBE_DISC) ?
- iso2->GetCompany() : iso2->GetDescription(indexOther);
- return strcasecmp(cmp1.c_str(), cmp2.c_str()) * t;
- }
- case CGameListCtrl::COLUMN_COUNTRY:
- if(iso1->GetCountry() > iso2->GetCountry())
- return 1 * t;
- if(iso1->GetCountry() < iso2->GetCountry())
- return -1 * t;
- return 0;
- case CGameListCtrl::COLUMN_SIZE:
- if (iso1->GetFileSize() > iso2->GetFileSize())
- return 1 * t;
- if (iso1->GetFileSize() < iso2->GetFileSize())
- return -1 * t;
- return 0;
- case CGameListCtrl::COLUMN_PLATFORM:
- if(iso1->GetPlatform() > iso2->GetPlatform())
- return 1 * t;
- if(iso1->GetPlatform() < iso2->GetPlatform())
- return -1 * t;
- return 0;
-
- case CGameListCtrl::COLUMN_EMULATION_STATE:
- {
- const int
- nState1 = iso1->GetEmuState(),
- nState2 = iso2->GetEmuState();
-
- if (nState1 > nState2)
- return 1 * t;
- if (nState1 < nState2)
- return -1 * t;
- else
- return 0;
- }
- break;
- }
-
- return 0;
+ return CompareGameListItems(iso1, iso2, sortData);
}
void CGameListCtrl::OnColumnClick(wxListEvent& event)
@@ -1225,7 +1176,7 @@ void CGameListCtrl::CompressSelection(bool _compress)
if (wxFileExists(wxString::FromAscii(OutputFileName.c_str())) &&
wxMessageBox(
wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"),
- OutputFileName.c_str()),
+ wxString(OutputFileName.c_str(), *wxConvCurrent).c_str()),
_("Confirm File Overwrite"),
wxYES_NO) == wxNO)
continue;
@@ -1253,7 +1204,7 @@ void CGameListCtrl::CompressSelection(bool _compress)
if (wxFileExists(wxString::FromAscii(OutputFileName.c_str())) &&
wxMessageBox(
wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"),
- OutputFileName.c_str()),
+ wxString(OutputFileName.c_str(), *wxConvCurrent).c_str()),
_("Confirm File Overwrite"),
wxYES_NO) == wxNO)
continue;
diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
index c491424376..cffeb25e7f 100644
--- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
+++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.cpp
@@ -1,3 +1,16 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
#include "GeckoCodeDiag.h"
@@ -65,7 +78,7 @@ void CodeConfigPanel::UpdateCodeList()
gcodes_end = m_gcodes.end();
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
{
- m_listbox_gcodes->Append(wxString::FromAscii(gcodes_iter->name.c_str()));
+ m_listbox_gcodes->Append(wxString(gcodes_iter->name.c_str(), *wxConvCurrent));
if (gcodes_iter->enabled)
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true);
}
@@ -98,7 +111,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
if (sel > -1)
{
- m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + wxString::FromAscii(m_gcodes[sel].name.c_str()));
+ m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + wxString(m_gcodes[sel].name.c_str(), *wxConvCurrent));
// notes textctrl
m_infobox.textctrl_notes->Clear();
@@ -106,10 +119,10 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
notes_iter = m_gcodes[sel].notes.begin(),
notes_end = m_gcodes[sel].notes.end();
for (; notes_iter!=notes_end; ++notes_iter)
- m_infobox.textctrl_notes->AppendText(wxString::FromAscii(notes_iter->c_str()));
+ m_infobox.textctrl_notes->AppendText(wxString(notes_iter->c_str(), *wxConvCurrent));
m_infobox.textctrl_notes->ScrollLines(-99); // silly
- m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
+ m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + wxString(m_gcodes[sel].creator.c_str(), *wxConvCurrent));
// add codes to info listbox
std::vector<GeckoCode::Code>::const_iterator
@@ -138,9 +151,18 @@ void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
std::string gameid = m_gameid;
- // WiiWare are identified by their first four characters
- if (m_gameid[0] == 'W')
+
+ switch (m_gameid[0])
+ {
+ case 'R':
+ case 'S':
+ case 'G':
+ break;
+ default:
+ // All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters
gameid = m_gameid.substr(0, 4);
+ break;
+ }
sf::Http::Request req;
req.SetURI("/txt.php?txt=" + gameid);
diff --git a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
index 92328d5f43..338c57c6e9 100644
--- a/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
+++ b/Source/Core/DolphinWX/Src/GeckoCodeDiag.h
@@ -1,3 +1,16 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
#ifndef __GECKOCODEDIAG_h__
#define __GECKOCODEDIAG_h__
diff --git a/Source/Core/DolphinWX/Src/ISOFile.cpp b/Source/Core/DolphinWX/Src/ISOFile.cpp
index 8505203322..9734e97131 100644
--- a/Source/Core/DolphinWX/Src/ISOFile.cpp
+++ b/Source/Core/DolphinWX/Src/ISOFile.cpp
@@ -36,7 +36,7 @@
#include "ChunkFile.h"
#include "../resources/no_banner.cpp"
-#define CACHE_REVISION 0x10B
+#define CACHE_REVISION 0x10D
#define DVD_BANNER_WIDTH 96
#define DVD_BANNER_HEIGHT 32
@@ -63,18 +63,26 @@ GameListItem::GameListItem(const std::string& _rFileName)
if (!DiscIO::IsVolumeWadFile(pVolume))
m_Platform = DiscIO::IsVolumeWiiDisc(pVolume) ? WII_DISC : GAMECUBE_DISC;
else
+ {
m_Platform = WII_WAD;
+ pVolume->GetWName(m_wNames);
+ }
m_Company = "N/A";
+
+
+ m_Name[0] = pVolume->GetName();
+
+ if(m_Name[0] == "") // Couldn't find the name in the WAD...
+ {
+ std::string FileName;
+ SplitPath(m_FileName, NULL, &FileName, NULL);
+ m_Name[0] = FileName; // Then just display the filename... Better than something like "No Name"
+ }
+
for (int i = 0; i < 6; i++)
{
- m_Name[i] = pVolume->GetName();
- if(m_Name[i] == "") // Couldn't find the name in the WAD...
- {
- std::string FileName;
- SplitPath(_rFileName, NULL, &FileName, NULL);
- m_Name[i] = FileName; // Then just display the filename... Better than something like "No Name"
- }
+ m_Name[i] = m_Name[0];
m_Description[i] = "No Description";
}
m_Country = pVolume->GetCountry();
@@ -95,9 +103,13 @@ GameListItem::GameListItem(const std::string& _rFileName)
{
if (pBannerLoader->IsValid())
{
- pBannerLoader->GetName(m_Name); //m_Country == DiscIO::IVolume::COUNTRY_JAP ? 1 : 0);
+ m_wNames.clear();
+ pBannerLoader->GetName(m_wNames);
+ pBannerLoader->GetName(m_Name);
pBannerLoader->GetCompany(m_Company);
+ pBannerLoader->GetDescription(m_wDescription);
pBannerLoader->GetDescription(m_Description);
+
if (pBannerLoader->GetBanner(g_ImageTemp))
{
// resize vector to image size
@@ -116,6 +128,25 @@ GameListItem::GameListItem(const std::string& _rFileName)
delete pFileSystem;
}
+ std::vector<std::wstring>::iterator i, end = m_wNames.end();
+ std::wstring wFileName;
+ for (i = m_wNames.begin(); i != end; ++i)
+ {
+ if (*i == L"")
+ {
+ if (!wFileName.length())
+ {
+ std::string FileName;
+ SplitPath(m_FileName, NULL, &FileName, NULL);
+ int length = FileName.length();
+ wFileName.reserve(length+1);
+ for (int i = 0; i < length; ++i)
+ wFileName.push_back(FileName[i]);
+ wFileName.push_back(0);
+ }
+ *i = wFileName;
+ }
+ }
delete pVolume;
@@ -172,9 +203,31 @@ void GameListItem::DoState(PointerWrap &p)
{
p.Do(m_Name[0]); p.Do(m_Name[1]); p.Do(m_Name[2]);
p.Do(m_Name[3]); p.Do(m_Name[4]); p.Do(m_Name[5]);
+
+ int wNamesSize = m_wNames.size();
+ p.Do(wNamesSize);
+
+ if (p.mode == p.MODE_READ)
+ {
+ for (int i = 0; i < wNamesSize; ++i)
+ {
+ std::wstring temp;
+ p.Do(temp);
+ m_wNames.push_back(temp);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < wNamesSize; ++i)
+ {
+ p.Do(m_wNames[i]);
+ }
+ }
+
p.Do(m_Company);
p.Do(m_Description[0]); p.Do(m_Description[1]); p.Do(m_Description[2]);
p.Do(m_Description[3]); p.Do(m_Description[4]); p.Do(m_Description[5]);
+ p.Do(m_wDescription);
p.Do(m_UniqueID);
p.Do(m_FileSize);
p.Do(m_VolumeSize);
@@ -211,6 +264,11 @@ const std::string& GameListItem::GetDescription(int index) const
return m_Description[0];
}
+const std::wstring& GameListItem::GetDescription() const
+{
+ return m_wDescription;
+}
+
const std::string& GameListItem::GetName(int index) const
{
if ((index >=0) && (index < 6))
@@ -220,6 +278,28 @@ const std::string& GameListItem::GetName(int index) const
return m_Name[0];
}
+bool GameListItem::GetName(std::wstring& wName, int index) const
+{
+ // This function will only succeed for wii discs with banners or WADs
+ // utilize the same array as for gc discs (-1= Japanese, 0 = English etc
+ index++;
+ if ((index >=0) && (index < 10))
+ {
+ if (m_wNames.size() > index)
+ {
+ wName = m_wNames[index];
+ return true;
+ }
+ }
+ if (m_wNames.size() > 0)
+ {
+ wName = m_wNames[0];
+ return true;
+ }
+ return false;
+
+}
+
const std::string GameListItem::GetWiiFSPath() const
{
DiscIO::IVolume *Iso = DiscIO::CreateVolumeFromFilename(m_FileName);
diff --git a/Source/Core/DolphinWX/Src/ISOFile.h b/Source/Core/DolphinWX/Src/ISOFile.h
index 35cec18772..fe7d3d6c6c 100644
--- a/Source/Core/DolphinWX/Src/ISOFile.h
+++ b/Source/Core/DolphinWX/Src/ISOFile.h
@@ -35,8 +35,10 @@ public:
bool IsValid() const {return m_Valid;}
const std::string& GetFileName() const {return m_FileName;}
const std::string& GetName(int index) const;
+ bool GetName(std::wstring& wName, int index=0) const;
const std::string& GetCompany() const {return m_Company;}
const std::string& GetDescription(int index) const;
+ const std::wstring& GetDescription() const;
const std::string& GetUniqueID() const {return m_UniqueID;}
const std::string GetWiiFSPath() const;
DiscIO::IVolume::ECountry GetCountry() const {return m_Country;}
@@ -63,8 +65,10 @@ public:
private:
std::string m_FileName;
std::string m_Name[6];
+ std::vector<std::wstring> m_wNames;
std::string m_Company;
std::string m_Description[6];
+ std::wstring m_wDescription;
std::string m_UniqueID;
std::string m_issues;
diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp
index a6977727dc..b5e5c82d1d 100644
--- a/Source/Core/DolphinWX/Src/ISOProperties.cpp
+++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp
@@ -154,7 +154,15 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW
}
// Disk header and apploader
- m_Name->SetValue(wxString(OpenISO->GetName().c_str(), wxConvUTF8));
+
+ std::wstring wname;
+ wxString name;
+ if (OpenGameListItem->GetName(wname))
+ name = wname.c_str();
+ else
+ name = wxString(OpenISO->GetName().c_str(), wxConvUTF8);
+ m_Name->SetValue(name);
+
m_GameID->SetValue(wxString(OpenISO->GetUniqueID().c_str(), wxConvUTF8));
switch (OpenISO->GetCountry())
{
@@ -321,10 +329,13 @@ void CISOProperties::CreateGUIControls(bool IsWad)
// Wii Console
EnableProgressiveScan = new wxCheckBox(m_GameConfig, ID_ENABLEPROGRESSIVESCAN, _("Enable Progressive Scan"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
- DisableWiimoteSpeaker = new wxCheckBox(m_GameConfig, ID_DISABLEWIIMOTESPEAKER, _("Disable Wiimote Speaker"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
+ DisableWiimoteSpeaker = new wxCheckBox(m_GameConfig, ID_DISABLEWIIMOTESPEAKER, _("Alternate Wiimote Timing"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DisableWiimoteSpeaker->SetToolTip(_("Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes."));
// Video
+ UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
+ UseBBox->SetToolTip(_("If checked, the bounding box registers will be updated. Used by the Paper Mario games."));
+
UseZTPSpeedupHack = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("ZTP hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
UseZTPSpeedupHack->SetToolTip(_("Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for ANY other game."));
@@ -383,6 +394,7 @@ void CISOProperties::CreateGUIControls(bool IsWad)
wxStaticBoxSizer * const sbVideoOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video"));
+ sbVideoOverrides->Add(UseBBox, 0, wxLEFT, 5);
sbVideoOverrides->Add(UseZTPSpeedupHack, 0, wxLEFT, 5);
szrPHackSettings->Add(PHackEnable, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5);
szrPHackSettings->Add(PHSettings, 0, wxLEFT, 5);
@@ -898,7 +910,13 @@ void CISOProperties::LoadGameConfig()
DisableWiimoteSpeaker->Set3StateValue((wxCheckBoxState)bTemp);
else
DisableWiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED);
-
+
+ if (GameIni.Get("Video", "UseBBox", &bTemp))
+ UseBBox->Set3StateValue((wxCheckBoxState)bTemp);
+ else
+ UseBBox->Set3StateValue(wxCHK_UNDETERMINED);
+
+
if (GameIni.Get("Video", "ZTPSpeedupHack", &bTemp))
UseZTPSpeedupHack->Set3StateValue((wxCheckBoxState)bTemp);
else
@@ -992,6 +1010,11 @@ bool CISOProperties::SaveGameConfig()
else
GameIni.Set("Wii", "DisableWiimoteSpeaker", DisableWiimoteSpeaker->Get3StateValue());
+ if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED)
+ GameIni.DeleteKey("Video", "UseBBox");
+ else
+ GameIni.Set("Video", "UseBBox", UseBBox->Get3StateValue());
+
if (UseZTPSpeedupHack->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "ZTPSpeedupHack");
else
@@ -1238,53 +1261,63 @@ void CISOProperties::OnChangeBannerLang(wxCommandEvent& event)
void CISOProperties::ChangeBannerDetails(int lang)
{
- if (OpenGameListItem->GetCountry() == DiscIO::IVolume::COUNTRY_JAPAN
- || OpenGameListItem->GetCountry() == DiscIO::IVolume::COUNTRY_TAIWAN
- || OpenGameListItem->GetPlatform() == GameListItem::WII_WAD)
- {
+ std::wstring wname;
+ wxString shortName,
+ comment,
+ maker;
+
#ifdef _WIN32
- wxCSConv SJISConv(*(wxCSConv*)wxConvCurrent);
- static bool validCP932 = ::IsValidCodePage(932) != 0;
- if (validCP932)
- {
- SJISConv = wxCSConv(wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS));
- }
- else
- {
- WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932");
- }
+ wxCSConv SJISConv(*(wxCSConv*)wxConvCurrent);
+ static bool validCP932 = ::IsValidCodePage(932) != 0;
+ if (validCP932)
+ {
+ SJISConv = wxCSConv(wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS));
+ }
+ else
+ {
+ WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932");
+ }
#else
- wxCSConv SJISConv(wxFontMapper::GetEncodingName(wxFONTENCODING_EUC_JP));
+ // on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
+ // it returns CP-932, in order to use iconv we need to use CP932
+ wxCSConv SJISConv(wxT("CP932"));
#endif
-
- wxString name = wxString(OpenGameListItem->GetName(0).c_str(), SJISConv);
-
- // Updates the informations shown in the window
- m_ShortName->SetValue(name);
- m_Comment->SetValue(wxString(OpenGameListItem->GetDescription(0).c_str(), SJISConv));
- m_Maker->SetValue(wxString(OpenGameListItem->GetCompany().c_str(), SJISConv));//dev too
-
- std::string filename, extension;
- SplitPath(OpenGameListItem->GetFileName(), 0, &filename, &extension);
-
- // Also sets the window's title
- SetTitle(wxString::Format(wxT("%s%s"),
- wxString(StringFromFormat("%s%s: %s - ", filename.c_str(), extension.c_str(), OpenGameListItem->GetUniqueID().c_str()).c_str(), *wxConvCurrent).c_str(),
- name.c_str()));
- }
- else // Do the same for PAL/US Games (assuming ISO 8859-1)
+ switch (OpenGameListItem->GetCountry())
{
- wxString name = wxString::From8BitData(OpenGameListItem->GetName(lang).c_str());
-
- m_ShortName->SetValue(name);
- m_Comment->SetValue(wxString::From8BitData(OpenGameListItem->GetDescription(lang).c_str()));
- m_Maker->SetValue(wxString::From8BitData(OpenGameListItem->GetCompany().c_str()));//dev too
+ case DiscIO::IVolume::COUNTRY_TAIWAN:
+ case DiscIO::IVolume::COUNTRY_JAPAN:
- std::string filename, extension;
- SplitPath(OpenGameListItem->GetFileName(), 0, &filename, &extension);
+ if (OpenGameListItem->GetName(wname, -1))
+ shortName = wname.c_str();
+ else
+ shortName = wxString(OpenGameListItem->GetName(0).c_str(), SJISConv);
- SetTitle(wxString::Format(wxT("%s%s"),
- wxString::From8BitData(StringFromFormat("%s%s: %s - ", filename.c_str(), extension.c_str(), OpenGameListItem->GetUniqueID().c_str()).c_str()).c_str(),
- name.c_str()));
+ if ((comment = OpenGameListItem->GetDescription().c_str()).size() == 0)
+ comment = wxString(OpenGameListItem->GetDescription(0).c_str(), SJISConv);
+ maker = wxString(OpenGameListItem->GetCompany().c_str(), SJISConv);
+ break;
+ case DiscIO::IVolume::COUNTRY_USA:
+ lang = 0;
+ default:
+ {
+ wxCSConv WindowsCP1252(wxFontMapper::GetEncodingName(wxFONTENCODING_CP1252));
+ if (OpenGameListItem->GetName(wname, lang))
+ shortName = wname.c_str();
+ else
+ shortName = wxString(OpenGameListItem->GetName(lang).c_str(), WindowsCP1252);
+ if ((comment = OpenGameListItem->GetDescription().c_str()).size() == 0)
+ comment = wxString(OpenGameListItem->GetDescription(lang).c_str(), WindowsCP1252);
+ maker = wxString(OpenGameListItem->GetCompany().c_str(), WindowsCP1252);
+ }
+ break;
}
+ // Updates the informations shown in the window
+ m_ShortName->SetValue(shortName);
+ m_Comment->SetValue(comment);
+ m_Maker->SetValue(maker);//dev too
+
+ std::string filename, extension;
+ SplitPath(OpenGameListItem->GetFileName(), 0, &filename, &extension);
+ // Also sets the window's title
+ SetTitle(wxString(StringFromFormat("%s%s: %s - ", filename.c_str(), extension.c_str(), OpenGameListItem->GetUniqueID().c_str()).c_str(), *wxConvCurrent)+shortName);
}
diff --git a/Source/Core/DolphinWX/Src/ISOProperties.h b/Source/Core/DolphinWX/Src/ISOProperties.h
index 0add6e9451..6e72993b42 100644
--- a/Source/Core/DolphinWX/Src/ISOProperties.h
+++ b/Source/Core/DolphinWX/Src/ISOProperties.h
@@ -74,7 +74,7 @@ private:
// Wii
wxCheckBox *EnableProgressiveScan, *EnableWideScreen, *DisableWiimoteSpeaker;
// Video
- wxCheckBox *UseZTPSpeedupHack, *PHackEnable;
+ wxCheckBox *UseZTPSpeedupHack, *PHackEnable, *UseBBox;
wxButton *PHSettings;
wxArrayString arrayStringFor_EmuState;
@@ -133,6 +133,7 @@ private:
ID_DISCSPEED,
ID_MERGEBLOCKS,
ID_AUDIO_DSP_HLE,
+ ID_USE_BBOX,
ID_ZTP_SPEEDUP,
ID_PHACKENABLE,
ID_PHSETTINGS,
diff --git a/Source/Core/DolphinWX/Src/LogConfigWindow.cpp b/Source/Core/DolphinWX/Src/LogConfigWindow.cpp
index f8219b179e..d771a75c30 100644
--- a/Source/Core/DolphinWX/Src/LogConfigWindow.cpp
+++ b/Source/Core/DolphinWX/Src/LogConfigWindow.cpp
@@ -62,6 +62,14 @@ void LogConfigWindow::CreateGUIControls()
_connect_macro_(m_writeConsoleCB, LogConfigWindow::OnWriteConsoleChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
m_writeWindowCB = new wxCheckBox(this, wxID_ANY, _("Write to Window"));
_connect_macro_(m_writeWindowCB, LogConfigWindow::OnWriteWindowChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
+ m_writeDebuggerCB = NULL;
+#ifdef _MSC_VER
+ if (IsDebuggerPresent())
+ {
+ m_writeDebuggerCB = new wxCheckBox(this, wxID_ANY, _("Write to Debugger"));
+ _connect_macro_(m_writeDebuggerCB, LogConfigWindow::OnWriteDebuggerChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
+ }
+#endif
wxButton *btn_toggle_all = new wxButton(this, wxID_ANY, _("Toggle All Log Types"),
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
@@ -75,7 +83,17 @@ void LogConfigWindow::CreateGUIControls()
wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs"));
sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1);
sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1);
- sbOutputs->Add(m_writeWindowCB, 0);
+#ifdef _MSC_VER
+ if (m_writeDebuggerCB)
+ {
+ sbOutputs->Add(m_writeWindowCB, 0, wxDOWN, 1);
+ sbOutputs->Add(m_writeDebuggerCB, 0);
+ }
+ else
+#endif
+ {
+ sbOutputs->Add(m_writeWindowCB, 0);
+ }
wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types"));
sbLogTypes->Add(m_checks, 1, wxEXPAND);
@@ -107,6 +125,17 @@ void LogConfigWindow::LoadSettings()
m_writeConsoleCB->SetValue(m_writeConsole);
ini.Get("Options", "WriteToWindow", &m_writeWindow, true);
m_writeWindowCB->SetValue(m_writeWindow);
+#ifdef _MSC_VER
+ if (IsDebuggerPresent())
+ {
+ ini.Get("Options", "WriteToDebugger", &m_writeDebugger, true);
+ m_writeDebuggerCB->SetValue(m_writeDebugger);
+ }
+ else
+#endif
+ {
+ m_writeDebugger = false;
+ }
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
bool log_enabled;
@@ -125,6 +154,10 @@ void LogConfigWindow::SaveSettings()
ini.Set("Options", "WriteToFile", m_writeFile);
ini.Set("Options", "WriteToConsole", m_writeConsole);
ini.Set("Options", "WriteToWindow", m_writeWindow);
+#ifdef _MSC_VER
+ if (IsDebuggerPresent())
+ ini.Set("Options", "WriteToDebugger", m_writeDebugger);
+#endif
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
ini.Set("Logs", m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i));
ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX));
@@ -183,6 +216,21 @@ void LogConfigWindow::OnWriteWindowChecked(wxCommandEvent& event)
}
}
+void LogConfigWindow::OnWriteDebuggerChecked(wxCommandEvent& event)
+{
+ for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
+ {
+ m_writeDebugger = event.IsChecked();
+ if (m_checks->IsChecked(i))
+ {
+ if (m_writeDebugger)
+ m_LogManager->AddListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogManager->GetDebuggerListener());
+ else
+ m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogManager->GetDebuggerListener());
+ }
+ }
+}
+
void LogConfigWindow::OnToggleAll(wxCommandEvent& WXUNUSED(event))
{
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
@@ -207,12 +255,15 @@ void LogConfigWindow::ToggleLog(int _logType, bool enable)
m_LogManager->AddListener(logType, m_LogManager->GetFileListener());
if (m_writeConsole)
m_LogManager->AddListener(logType, m_LogManager->GetConsoleListener());
+ if (m_writeDebugger)
+ m_LogManager->AddListener(logType, m_LogManager->GetDebuggerListener());
}
else
{
m_LogManager->RemoveListener(logType, (LogListener *)m_LogWindow);
m_LogManager->RemoveListener(logType, m_LogManager->GetFileListener());
m_LogManager->RemoveListener(logType, m_LogManager->GetConsoleListener());
+ m_LogManager->RemoveListener(logType, m_LogManager->GetDebuggerListener());
}
}
diff --git a/Source/Core/DolphinWX/Src/LogConfigWindow.h b/Source/Core/DolphinWX/Src/LogConfigWindow.h
index ac3f4409a2..5a08486409 100644
--- a/Source/Core/DolphinWX/Src/LogConfigWindow.h
+++ b/Source/Core/DolphinWX/Src/LogConfigWindow.h
@@ -37,11 +37,11 @@ public:
private:
LogManager *m_LogManager;
CLogWindow *m_LogWindow;
- bool m_writeFile, m_writeConsole, m_writeWindow;
+ bool m_writeFile, m_writeConsole, m_writeWindow, m_writeDebugger;
bool enableAll;
// Controls
- wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB;
+ wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB, *m_writeDebuggerCB;
wxCheckListBox* m_checks;
wxRadioBox *m_verbosity;
@@ -50,6 +50,7 @@ private:
void OnWriteFileChecked(wxCommandEvent& event);
void OnWriteConsoleChecked(wxCommandEvent& event);
void OnWriteWindowChecked(wxCommandEvent& event);
+ void OnWriteDebuggerChecked(wxCommandEvent& event);
void OnToggleAll(wxCommandEvent& event);
void ToggleLog(int _logType, bool enable);
void OnLogCheck(wxCommandEvent& event);
diff --git a/Source/Core/DolphinWX/Src/LogWindow.cpp b/Source/Core/DolphinWX/Src/LogWindow.cpp
index 94b542eb2f..4c9c495713 100644
--- a/Source/Core/DolphinWX/Src/LogWindow.cpp
+++ b/Source/Core/DolphinWX/Src/LogWindow.cpp
@@ -39,7 +39,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, pos, size, style, name)
, x(0), y(0), winpos(0)
- , Parent(parent) , m_LogAccess(true)
+ , Parent(parent), m_ignoreLogTimer(false), m_LogAccess(true)
, m_Log(NULL), m_cmdline(NULL), m_FontChoice(NULL)
, m_SJISConv(wxT(""))
{
@@ -55,7 +55,9 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
m_SJISConv = *(wxCSConv*)wxConvCurrent;
}
#else
- m_SJISConv = wxCSConv(wxFontMapper::GetEncodingName(wxFONTENCODING_EUC_JP));
+ // on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
+ // it returns CP-932, in order to use iconv we need to use CP932
+ m_SJISConv = wxCSConv(wxT("CP932"));
#endif
m_LogManager = LogManager::GetInstance();
@@ -84,6 +86,16 @@ void CLogWindow::CreateGUIControls()
ini.Get("Options", "WriteToFile", &m_writeFile, false);
ini.Get("Options", "WriteToConsole", &m_writeConsole, true);
ini.Get("Options", "WriteToWindow", &m_writeWindow, true);
+#ifdef _MSC_VER
+ if (IsDebuggerPresent())
+ {
+ ini.Get("Options", "WriteToDebugger", &m_writeDebugger, true);
+ }
+ else
+#endif
+ {
+ m_writeDebugger = false;
+ }
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
bool enable;
@@ -103,6 +115,12 @@ void CLogWindow::CreateGUIControls()
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
else
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
+
+ if (m_writeDebugger && enable)
+ m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetDebuggerListener());
+ else
+ m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetDebuggerListener());
+
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
}
@@ -278,6 +296,7 @@ void CLogWindow::OnWrapLineCheck(wxCommandEvent& event)
void CLogWindow::OnLogTimer(wxTimerEvent& WXUNUSED(event))
{
if (!m_LogAccess) return;
+ if (m_ignoreLogTimer) return;
UpdateLog();
// Scroll to the last line
@@ -293,52 +312,56 @@ void CLogWindow::UpdateLog()
if (!m_LogAccess) return;
if (!m_Log) return;
- m_LogTimer->Stop();
+ // m_LogTimer->Stop();
+ // instead of stopping the timer, let's simply ignore its calls during UpdateLog,
+ // because repeatedly stopping and starting a timer churns memory (and potentially leaks it).
+ m_ignoreLogTimer = true;
+ if (!msgQueue.empty())
{
- std::lock_guard<std::mutex> lk(m_LogSection);
- int msgQueueSize = (int)msgQueue.size();
- for (int i = 0; i < msgQueueSize; i++)
- {
- switch (msgQueue.front().first)
+ std::lock_guard<std::mutex> lk(m_LogSection);
+ int msgQueueSize = (int)msgQueue.size();
+ for (int i = 0; i < msgQueueSize; i++)
{
-
- case ERROR_LEVEL:
- m_Log->SetDefaultStyle(wxTextAttr(*wxRED));
- break;
+ switch (msgQueue.front().first)
+ {
+ case ERROR_LEVEL:
+ m_Log->SetDefaultStyle(wxTextAttr(*wxRED));
+ break;
- case WARNING_LEVEL:
- m_Log->SetDefaultStyle(wxTextAttr(wxColour(255, 255, 0))); // YELLOW
- break;
+ case WARNING_LEVEL:
+ m_Log->SetDefaultStyle(wxTextAttr(wxColour(255, 255, 0))); // YELLOW
+ break;
- case NOTICE_LEVEL:
- m_Log->SetDefaultStyle(wxTextAttr(*wxGREEN));
- break;
+ case NOTICE_LEVEL:
+ m_Log->SetDefaultStyle(wxTextAttr(*wxGREEN));
+ break;
- case INFO_LEVEL:
- m_Log->SetDefaultStyle(wxTextAttr(*wxCYAN));
- break;
+ case INFO_LEVEL:
+ m_Log->SetDefaultStyle(wxTextAttr(*wxCYAN));
+ break;
- case DEBUG_LEVEL:
- m_Log->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY));
- break;
+ case DEBUG_LEVEL:
+ m_Log->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY));
+ break;
- default:
- m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE));
- break;
+ default:
+ m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE));
+ break;
+ }
+ if (msgQueue.front().second.size())
+ {
+ int j = m_Log->GetLastPosition();
+ m_Log->AppendText(msgQueue.front().second);
+ // White timestamp
+ m_Log->SetStyle(j, j + 9, wxTextAttr(*wxWHITE));
+ }
+ msgQueue.pop();
}
- if (msgQueue.front().second.size())
- {
- int j = m_Log->GetLastPosition();
- m_Log->AppendText(msgQueue.front().second);
- // White timestamp
- m_Log->SetStyle(j, j + 9, wxTextAttr(*wxWHITE));
- }
- msgQueue.pop();
- }
} // unlock log
- m_LogTimer->Start(UPDATETIME);
+ // m_LogTimer->Start(UPDATETIME);
+ m_ignoreLogTimer = false;
}
void CLogWindow::Log(LogTypes::LOG_LEVELS level, const char *text)
diff --git a/Source/Core/DolphinWX/Src/LogWindow.h b/Source/Core/DolphinWX/Src/LogWindow.h
index ba5724cb0c..86fd1d3b4f 100644
--- a/Source/Core/DolphinWX/Src/LogWindow.h
+++ b/Source/Core/DolphinWX/Src/LogWindow.h
@@ -62,9 +62,10 @@ private:
wxFont DefaultFont, MonoSpaceFont;
std::vector<wxFont> LogFont;
wxTimer *m_LogTimer;
+ bool m_ignoreLogTimer;
LogManager *m_LogManager;
std::queue<std::pair<u8, wxString> > msgQueue;
- bool m_writeFile, m_writeConsole, m_writeWindow, m_LogAccess;
+ bool m_writeFile, m_writeConsole, m_writeWindow, m_writeDebugger, m_LogAccess;
// Controls
wxBoxSizer *sBottom;
diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp
index b5e9de4960..709c2b4b53 100644
--- a/Source/Core/DolphinWX/Src/Main.cpp
+++ b/Source/Core/DolphinWX/Src/Main.cpp
@@ -510,7 +510,6 @@ void Host_UpdateTitle(const char* title)
wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATETITLE);
event.SetString(wxString::FromAscii(title));
main_frame->GetEventHandler()->AddPendingEvent(event);
- Host_UpdateMainFrame();
}
void Host_UpdateBreakPointView()
diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp
index 7eb0243e2c..98390122e2 100644
--- a/Source/Core/DolphinWX/Src/MemcardManager.cpp
+++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp
@@ -701,10 +701,22 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card)
if (!memoryCard[card]->DEntry_Comment2(j, comment)) comment[0]=0;
bool ascii = memoryCard[card]->IsAsciiEncoding();
+
#ifdef _WIN32
- wxCSConv SJISConv(wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS));
+ wxCSConv SJISConv(*(wxCSConv*)wxConvCurrent);
+ static bool validCP932 = ::IsValidCodePage(932) != 0;
+ if (validCP932)
+ {
+ SJISConv = wxCSConv(wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS));
+ }
+ else
+ {
+ WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932");
+ }
#else
- wxCSConv SJISConv(wxFontMapper::GetEncodingName(wxFONTENCODING_EUC_JP));
+ // on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
+ // it returns CP-932, in order to use iconv we need to use CP932
+ wxCSConv SJISConv(wxT("CP932"));
#endif
wxTitle = wxString(title, ascii ? *wxConvCurrent : SJISConv);
wxComment = wxString(comment, ascii ? *wxConvCurrent : SJISConv);
diff --git a/Source/Core/DolphinWX/Src/MemcardManager.h b/Source/Core/DolphinWX/Src/MemcardManager.h
index e3707f6414..beff71b671 100644
--- a/Source/Core/DolphinWX/Src/MemcardManager.h
+++ b/Source/Core/DolphinWX/Src/MemcardManager.h
@@ -29,7 +29,7 @@
#include "IniFile.h"
#include "FileUtil.h"
-#include "MemoryCards/GCMemcard.h"
+#include "HW/GCMemcard.h"
#undef MEMCARD_MANAGER_STYLE
#define MEMCARD_MANAGER_STYLE wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | wxMAXIMIZE_BOX
diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp
index 45e239a835..75252cdc67 100644
--- a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp
+++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp
@@ -95,7 +95,7 @@ wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to th
wxString efb_copy_desc = wxTRANSLATE("Disable emulation of EFB copies.\nThese are often used for post-processing or render-to-texture effects, so while checking this setting gives a great speedup it almost always also causes issues.\n\nIf unsure, leave this unchecked.");
wxString efb_copy_texture_desc = wxTRANSLATE("Store EFB copies in GPU texture objects.\nThis is not so accurate, but it works well enough for most games and gives a great speedup over EFB to RAM.\n\nIf unsure, leave this checked.");
wxString efb_copy_ram_desc = wxTRANSLATE("Accurately emulate EFB copies.\nSome games depend on this for certain graphical effects or gameplay functionality.\n\nIf unsure, check EFB to Texture instead.");
-wxString stc_desc = wxTRANSLATE("The safer you adjust this, the less likely the emulator will be missing any texture updates from RAM.\n\nIf unsure, use the second-fastest value from the right.");
+wxString stc_desc = wxTRANSLATE("The safer you adjust this, the less likely the emulator will be missing any texture updates from RAM.\n\nIf unsure, use the rightmost value.");
wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked.");
wxString disable_lighting_desc = wxTRANSLATE("Improves performance but causes lighting to disappear in most games.\n\nIf unsure, leave this unchecked.");
wxString disable_textures_desc = wxTRANSLATE("Disable texturing.\n\nIf unsure, leave this unchecked.");
@@ -455,18 +455,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
wxStaticBoxSizer* const szr_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache"));
// TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1
- wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 3, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
+ wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
_connect_macro_(stc_slider, VideoConfigDiag::Event_Stc, wxEVT_COMMAND_SLIDER_UPDATED, this);
RegisterControl(stc_slider, wxGetTranslation(stc_desc));
- if (vconfig.bSafeTextureCache)
- {
- if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
- else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
- else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
- else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
- }
- else stc_slider->SetValue(3);
+ if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
+ else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
+ else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
+ else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5);
szr_safetex->AddStretchSpacer(1);
diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.h b/Source/Core/DolphinWX/Src/VideoConfigDiag.h
index 5765524f03..e6b13a4092 100644
--- a/Source/Core/DolphinWX/Src/VideoConfigDiag.h
+++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.h
@@ -120,12 +120,7 @@ protected:
void Event_Stc(wxCommandEvent &ev)
{
int samples[] = { 0, 512, 128 };
- if (ev.GetInt() < 3)
- {
- vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
- vconfig.bSafeTextureCache = true;
- }
- else vconfig.bSafeTextureCache = false;
+ vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
ev.Skip();
}
diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj
index 80aaeaa140..8eed835b2d 100644
--- a/Source/Core/InputCommon/InputCommon.vcxproj
+++ b/Source/Core/InputCommon/InputCommon.vcxproj
@@ -45,7 +45,6 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +55,6 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
index a995ae415a..82cfe2469e 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
@@ -18,7 +18,10 @@
#include "Thread.h"
-#define INPUT_DETECT_THRESHOLD 0.85f
+namespace
+{
+const float INPUT_DETECT_THRESHOLD = 0.55f;
+}
ControllerInterface g_controller_interface;
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
index e09bd2fdd9..c23e9df17e 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
@@ -51,9 +51,9 @@ std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
if (SUCCEEDED(device->GetProperty(DIPROP_PRODUCTNAME, &str.diph)))
{
- const int size = WideCharToMultiByte(CP_ACP, 0, str.wsz, -1, NULL, 0, NULL, NULL);
+ const int size = WideCharToMultiByte(CP_UTF8, 0, str.wsz, -1, NULL, 0, NULL, NULL);
char* const data = new char[size];
- if (size == WideCharToMultiByte(CP_ACP, 0, str.wsz, -1, data, size, NULL, NULL))
+ if (size == WideCharToMultiByte(CP_UTF8, 0, str.wsz, -1, data, size, NULL, NULL))
out.assign(data);
delete[] data;
}
diff --git a/Source/Core/InputCommon/Src/GCPadStatus.h b/Source/Core/InputCommon/Src/GCPadStatus.h
index 72b790bbc6..835089a70d 100644
--- a/Source/Core/InputCommon/Src/GCPadStatus.h
+++ b/Source/Core/InputCommon/Src/GCPadStatus.h
@@ -51,7 +51,6 @@ typedef struct
unsigned char triggerRight; // 0 <= triggerRight <= 255
unsigned char analogA; // 0 <= analogA <= 255
unsigned char analogB; // 0 <= analogB <= 255
- bool MicButton; // HAX
signed char err; // one of PAD_ERR_* number
} SPADStatus;
diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt
index 481ced250a..d0e28f571c 100644
--- a/Source/Core/VideoCommon/CMakeLists.txt
+++ b/Source/Core/VideoCommon/CMakeLists.txt
@@ -40,6 +40,10 @@ set(SRCS Src/BPFunctions.cpp
Src/memcpy_amd.cpp)
set(LIBS core)
+if(NOT ${CL} STREQUAL CL-NOTFOUND)
+ list(APPEND LIBS ${CL})
+endif()
+
if(wxWidgets_FOUND AND WIN32)
set(SRCS ${SRCS} Src/EmuWindow.cpp)
endif()
diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp
index cfd34e5cdb..670693690b 100644
--- a/Source/Core/VideoCommon/Src/AVIDump.cpp
+++ b/Source/Core/VideoCommon/Src/AVIDump.cpp
@@ -15,6 +15,10 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
+#if defined(__FreeBSD__)
+#define __STDC_CONSTANT_MACROS 1
+#endif
+
#include "AVIDump.h"
#include "HW/VideoInterface.h" //for TargetRefreshRate
#include "VideoConfig.h"
@@ -259,12 +263,10 @@ bool AVIDump::CreateFile()
s_Stream->codec->bit_rate = 400000;
s_Stream->codec->width = s_width;
s_Stream->codec->height = s_height;
- s_Stream->codec->time_base = (AVRational){1, VideoInterface::TargetRefreshRate};
+ s_Stream->codec->time_base = (AVRational){1, static_cast<int>(VideoInterface::TargetRefreshRate)};
s_Stream->codec->gop_size = 12;
s_Stream->codec->pix_fmt = g_Config.bUseFFV1 ? PIX_FMT_BGRA : PIX_FMT_YUV420P;
- av_set_parameters(s_FormatContext, NULL);
-
if (!(codec = avcodec_find_encoder(s_Stream->codec->codec_id)) ||
(avcodec_open(s_Stream->codec, codec) < 0))
{
@@ -283,14 +285,14 @@ bool AVIDump::CreateFile()
s_OutBuffer = new uint8_t[s_size];
NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_FormatContext->filename);
- if (url_fopen(&s_FormatContext->pb, s_FormatContext->filename, URL_WRONLY) < 0)
+ if (avio_open(&s_FormatContext->pb, s_FormatContext->filename, AVIO_FLAG_WRITE) < 0)
{
WARN_LOG(VIDEO, "Could not open %s", s_FormatContext->filename);
CloseFile();
return false;
}
- av_write_header(s_FormatContext);
+ avformat_write_header(s_FormatContext, NULL);
return true;
}
@@ -370,7 +372,7 @@ void AVIDump::CloseFile()
if (s_FormatContext)
{
if (s_FormatContext->pb)
- url_fclose(s_FormatContext->pb);
+ avio_close(s_FormatContext->pb);
av_free(s_FormatContext);
s_FormatContext = NULL;
}
diff --git a/Source/Core/VideoCommon/Src/BPFunctions.cpp b/Source/Core/VideoCommon/Src/BPFunctions.cpp
index f323f03142..4f7315e832 100644
--- a/Source/Core/VideoCommon/Src/BPFunctions.cpp
+++ b/Source/Core/VideoCommon/Src/BPFunctions.cpp
@@ -44,9 +44,24 @@ void SetGenerationMode(const BPCmd &bp)
g_renderer->SetGenerationMode();
}
-void SetScissor(const BPCmd &bp)
+void SetScissor()
{
- g_renderer->SetScissorRect();
+ const int xoff = bpmem.scissorOffset.x * 2 - 342;
+ const int yoff = bpmem.scissorOffset.y * 2 - 342;
+
+ EFBRectangle rc (bpmem.scissorTL.x - xoff - 342, bpmem.scissorTL.y - yoff - 342,
+ bpmem.scissorBR.x - xoff - 341, bpmem.scissorBR.y - yoff - 341);
+
+ if (rc.left < 0) rc.left = 0;
+ if (rc.top < 0) rc.top = 0;
+ if (rc.right > EFB_WIDTH) rc.right = EFB_WIDTH;
+ if (rc.bottom > EFB_HEIGHT) rc.bottom = EFB_HEIGHT;
+
+ if (rc.left > rc.right) rc.right = rc.left;
+ if (rc.top > rc.bottom) rc.bottom = rc.top;
+
+ TargetRectangle trc = g_renderer->ConvertEFBRectangle(rc);
+ g_renderer->SetScissorRect(trc);
}
void SetLineWidth(const BPCmd &bp)
diff --git a/Source/Core/VideoCommon/Src/BPFunctions.h b/Source/Core/VideoCommon/Src/BPFunctions.h
index d104b12751..2b86523687 100644
--- a/Source/Core/VideoCommon/Src/BPFunctions.h
+++ b/Source/Core/VideoCommon/Src/BPFunctions.h
@@ -38,7 +38,7 @@ enum
void FlushPipeline();
void SetGenerationMode(const BPCmd &bp);
-void SetScissor(const BPCmd &bp);
+void SetScissor();
void SetLineWidth(const BPCmd &bp);
void SetDepthMode(const BPCmd &bp);
void SetBlendMode(const BPCmd &bp);
diff --git a/Source/Core/VideoCommon/Src/BPMemory.cpp b/Source/Core/VideoCommon/Src/BPMemory.cpp
index da09893f35..5c4ed457e3 100644
--- a/Source/Core/VideoCommon/Src/BPMemory.cpp
+++ b/Source/Core/VideoCommon/Src/BPMemory.cpp
@@ -61,7 +61,7 @@ void BPReload()
// Cases in which we DON'T want to reload the BP
continue;
default:
- BPCmd bp = {i, 0xFFFFFF, ((u32*)&bpmem)[i]};
+ BPCmd bp = {i, 0xFFFFFF, static_cast<int>(((u32*)&bpmem)[i])};
BPWritten(bp);
}
}
diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h
index 1f6f453a77..0bb2bf9013 100644
--- a/Source/Core/VideoCommon/Src/BPMemory.h
+++ b/Source/Core/VideoCommon/Src/BPMemory.h
@@ -65,10 +65,10 @@
#define BPMEM_UNKOWN_57 0x57
#define BPMEM_REVBITS 0x58
#define BPMEM_SCISSOROFFSET 0x59
-#define BPMEM_UNKNOWN_60 0x60
-#define BPMEM_UNKNOWN_61 0x61
-#define BPMEM_UNKNOWN_62 0x62
-#define BPMEM_TEXMODESYNC 0x63
+#define BPMEM_PRELOAD_ADDR 0x60
+#define BPMEM_PRELOAD_TMEMEVEN 0x61
+#define BPMEM_PRELOAD_TMEMODD 0x62
+#define BPMEM_PRELOAD_MODE 0x63
#define BPMEM_LOADTLUT0 0x64
#define BPMEM_LOADTLUT1 0x65
#define BPMEM_TEXINVALIDATE 0x66
@@ -487,10 +487,10 @@ union TexImage1
{
struct
{
- u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves
- u32 cache_width : 3;
+ u32 tmem_even : 15; // tmem line index for even LODs
+ u32 cache_width : 3;
u32 cache_height : 3;
- u32 image_type : 1;
+ u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes)
};
u32 hex;
};
@@ -499,7 +499,7 @@ union TexImage2
{
struct
{
- u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves
+ u32 tmem_odd : 15; // tmem line index for odd LODs
u32 cache_width : 3;
u32 cache_height : 3;
};
@@ -893,6 +893,25 @@ union UPE_Copy
}
};
+union BPU_PreloadTileInfo
+{
+ u32 hex;
+ struct {
+ u32 count : 15;
+ u32 type : 2;
+ };
+};
+
+struct BPS_TmemConfig
+{
+ u32 preload_addr;
+ u32 preload_tmem_even;
+ u32 preload_tmem_odd;
+ BPU_PreloadTileInfo preload_tile_info;
+ u32 tlut_src;
+ u32 tlut_dest;
+ u32 texinvalidate;
+};
// All of BP memory
@@ -951,10 +970,8 @@ struct BPMemory
u32 boundbox1;//56
u32 unknown7[2];//57,58
X10Y10 scissorOffset; //59
- u32 unknown8[10]; //5a,5b,5c,5d, 5e,5f,60,61, 62, 63 (GXTexModeSync), 0x60-0x63 have to do with preloaded textures?
- u32 tlutXferSrc; //64
- u32 tlutXferDest; //65
- u32 texinvalidate;//66
+ u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f
+ BPS_TmemConfig tmem_config; // 60-66
u32 metric; //67
FieldMode fieldmode;//68
u32 unknown10[7];//69-6F
diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp
index 42b5b2212a..6cb102555b 100644
--- a/Source/Core/VideoCommon/Src/BPStructs.cpp
+++ b/Source/Core/VideoCommon/Src/BPStructs.cpp
@@ -30,6 +30,7 @@
#include "VertexLoader.h"
#include "VertexShaderManager.h"
#include "Thread.h"
+#include "HW/Memmap.h"
using namespace BPFunctions;
@@ -37,6 +38,8 @@ u32 mapTexAddress;
bool mapTexFound;
int numWrites;
+extern volatile bool g_bSkipCurrentFrame;
+
static const float s_gammaLUT[] =
{
1.0f,
@@ -162,7 +165,7 @@ void BPWritten(const BPCmd& bp)
case BPMEM_SCISSORTL: // Scissor Rectable Top, Left
case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right
case BPMEM_SCISSOROFFSET: // Scissor Offset
- SetScissor(bp);
+ SetScissor();
break;
case BPMEM_LINEPTWIDTH: // Line Width
SetLineWidth(bp);
@@ -257,9 +260,8 @@ void BPWritten(const BPCmd& bp)
// We should be able to get away with deactivating the current bbox tracking
// here. Not sure if there's a better spot to put this.
// the number of lines copied is determined by the y scale * source efb height
-#ifdef BBOX_SUPPORT
+
PixelEngine::bbox_active = false;
-#endif
float yScale;
if (PE_copy.scale_invert)
@@ -300,14 +302,14 @@ void BPWritten(const BPCmd& bp)
// TODO - figure out a cleaner way.
if (GetConfig(CONFIG_ISWII))
- ptr = GetPointer(bpmem.tlutXferSrc << 5);
+ ptr = GetPointer(bpmem.tmem_config.tlut_src << 5);
else
- ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
+ ptr = GetPointer((bpmem.tmem_config.tlut_src & 0xFFFFF) << 5);
if (ptr)
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
else
- PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
+ PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tmem_config.tlut_src, bpmem.tmem_config.tlut_src << 5, (bpmem.tmem_config.tlut_src & 0xFFFFF)<< 5);
// TODO(ector) : kill all textures that use this palette
// Not sure if it's a good idea, though. For now, we hash texture palettes
@@ -400,28 +402,31 @@ void BPWritten(const BPCmd& bp)
case BPMEM_CLEARBBOX1:
case BPMEM_CLEARBBOX2:
{
-#ifdef BBOX_SUPPORT
- // which is which? these are GUESSES!
- if (bp.address == BPMEM_CLEARBBOX1) {
- int right = bp.newvalue >> 10;
- int left = bp.newvalue & 0x3ff;
+ if(g_ActiveConfig.bUseBBox)
+ {
+ // Don't compute bounding box if this frame is being skipped!
+ // Wrong but valid values are better than bogus values...
+ if(g_bSkipCurrentFrame)
+ break;
+
+ if (bp.address == BPMEM_CLEARBBOX1) {
+ int right = bp.newvalue >> 10;
+ int left = bp.newvalue & 0x3ff;
- // We should only set these if bbox is calculated properly.
- PixelEngine::bbox[0] = left;
- PixelEngine::bbox[1] = right;
- PixelEngine::bbox_active = true;
- // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right);
- } else {
- int bottom = bp.newvalue >> 10;
- int top = bp.newvalue & 0x3ff;
-
- // We should only set these if bbox is calculated properly.
- PixelEngine::bbox[2] = top;
- PixelEngine::bbox[3] = bottom;
- PixelEngine::bbox_active = true;
- // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom);
+ // We should only set these if bbox is calculated properly.
+ PixelEngine::bbox[0] = left;
+ PixelEngine::bbox[1] = right;
+ PixelEngine::bbox_active = true;
+ } else {
+ int bottom = bp.newvalue >> 10;
+ int top = bp.newvalue & 0x3ff;
+
+ // We should only set these if bbox is calculated properly.
+ PixelEngine::bbox[2] = top;
+ PixelEngine::bbox[3] = bottom;
+ PixelEngine::bbox_active = true;
+ }
}
-#endif
}
break;
case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow
@@ -462,14 +467,22 @@ void BPWritten(const BPCmd& bp)
DEBUG_LOG(VIDEO, "Uknown BP Reg 0x57: %08x", bp.newvalue);
break;
- case BPMEM_UNKNOWN_60:
- case BPMEM_UNKNOWN_61:
- case BPMEM_UNKNOWN_62:
- // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90
- // Are these related to BBox?
+ case BPMEM_PRELOAD_ADDR:
+ case BPMEM_PRELOAD_TMEMEVEN:
+ case BPMEM_PRELOAD_TMEMODD: // Used when PRELOAD_MODE is set
break;
- case BPMEM_TEXMODESYNC: // Always set to 0 when GX_TexModeSync() is called.
+ case BPMEM_PRELOAD_MODE: // Set to 0 when GX_TexModeSync() is called.
+ // if this is different from 0, manual TMEM management is used.
+ if (bp.newvalue != 0)
+ {
+ // NOTE(neobrain): Apparently tmemodd doesn't affect hardware behavior at all (libogc uses it just as a buffer and switches its contents with tmemeven whenever this is called)
+ BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
+ u8* ram_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5);
+ u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
+ u32 size = tmem_cfg.preload_tile_info.count * 32;
+ memcpy(texMem + tmem_addr, ram_ptr, size);
+ }
break;
// ------------------------------------------------
diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp
index ad05a9797e..a4dddf537f 100644
--- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp
+++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp
@@ -56,11 +56,12 @@ static bool bProcessFifoToLoWatermark = false;
static bool bProcessFifoAllDistance = false;
volatile bool isPossibleWaitingSetDrawDone = false;
+volatile bool isHiWatermarkActive = false;
volatile bool interruptSet= false;
volatile bool interruptWaiting= false;
volatile bool interruptTokenWaiting = false;
volatile bool interruptFinishWaiting = false;
-volatile bool OnOverflow = false;
+volatile bool waitingForPEInterruptDisable = false;
bool IsOnThread()
{
@@ -86,13 +87,12 @@ void DoState(PointerWrap &p)
p.Do(bProcessFifoToLoWatermark);
p.Do(bProcessFifoAllDistance);
-
+ p.Do(isHiWatermarkActive);
p.Do(isPossibleWaitingSetDrawDone);
p.Do(interruptSet);
p.Do(interruptWaiting);
p.Do(interruptTokenWaiting);
p.Do(interruptFinishWaiting);
- p.Do(OnOverflow);
}
inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::AtomicStore(_reg,(_reg & 0xFFFF0000) | lowbits);}
@@ -109,6 +109,8 @@ void Init()
m_CPCtrlReg.Hex = 0;
+ m_CPClearReg.Hex = 0;
+
m_bboxleft = 0;
m_bboxtop = 0;
m_bboxright = 640;
@@ -130,14 +132,17 @@ void Init()
interruptFinishWaiting = false;
interruptTokenWaiting = false;
+ bProcessFifoToLoWatermark = false;
+ bProcessFifoAllDistance = false;
+ isPossibleWaitingSetDrawDone = false;
+ isHiWatermarkActive = false;
+
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
}
void Read16(u16& _rReturnValue, const u32 _Address)
{
-
INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
- ProcessFifoEvents();
switch (_Address & 0xFFF)
{
case STATUS_REGISTER:
@@ -166,11 +171,23 @@ void Read16(u16& _rReturnValue, const u32 _Address)
case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return;
case FIFO_RW_DISTANCE_LO:
- _rReturnValue = ReadLow (fifo.CPReadWriteDistance);
+ if (IsOnThread())
+ if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
+ _rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer);
+ else
+ _rReturnValue = ReadLow (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
+ else
+ _rReturnValue = ReadLow (fifo.CPReadWriteDistance);
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue);
return;
case FIFO_RW_DISTANCE_HI:
- _rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
+ if (IsOnThread())
+ if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
+ _rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer);
+ else
+ _rReturnValue = ReadHigh (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
+ else
+ _rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue);
return;
case FIFO_WRITE_POINTER_LO:
@@ -304,6 +321,7 @@ void Write16(const u16 _Value, const u32 _Address)
UCPClearReg tmpCtrl(_Value);
m_CPClearReg.Hex = tmpCtrl.Hex;
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x", _Value);
+ SetCpClearRegister();
}
break;
@@ -350,6 +368,7 @@ void Write16(const u16 _Value, const u32 _Address)
break;
case FIFO_READ_POINTER_HI:
WriteHigh((u32 &)fifo.CPReadPointer, _Value);
+ fifo.SafeCPReadPointer = fifo.CPReadPointer;
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value);
break;
@@ -382,10 +401,6 @@ void Write16(const u16 _Value, const u32 _Address)
case FIFO_RW_DISTANCE_HI:
WriteHigh((u32 &)fifo.CPReadWriteDistance, _Value);
- DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
- break;
- case FIFO_RW_DISTANCE_LO:
- WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
if (fifo.CPReadWriteDistance == 0)
{
GPFifo::ResetGatherPipe();
@@ -395,6 +410,10 @@ void Write16(const u16 _Value, const u32 _Address)
ResetVideoBuffer();
}
IncrementCheckContextId();
+ DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
+ break;
+ case FIFO_RW_DISTANCE_LO:
+ WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_LO : %04x", _Value);
break;
@@ -404,7 +423,6 @@ void Write16(const u16 _Value, const u32 _Address)
if (!IsOnThread())
RunGpu();
- ProcessFifoEvents();
}
void Read32(u32& _rReturnValue, const u32 _Address)
@@ -426,6 +444,19 @@ void STACKALIGN GatherPipeBursted()
{
if (!IsOnThread())
RunGpu();
+ else
+ {
+ // In multibuffer mode is not allowed write in the same fifo attached to the GPU.
+ // Fix Pokemon XD in DC mode.
+ if((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && (ProcessorInterface::Fifo_CPUBase == fifo.CPBase)
+ && fifo.CPReadWriteDistance > 0)
+ {
+ waitingForPEInterruptDisable = true;
+ ProcessFifoAllDistance();
+ waitingForPEInterruptDisable = false;
+ }
+
+ }
return;
}
@@ -441,26 +472,7 @@ void STACKALIGN GatherPipeBursted()
Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE);
if (!IsOnThread())
- {
RunGpu();
- }
- else
- {
- if(fifo.CPReadWriteDistance == fifo.CPEnd - fifo.CPBase - 32)
- {
- if(!OnOverflow)
- NOTICE_LOG(COMMANDPROCESSOR,"FIFO is almost in overflown, BreakPoint: %i", fifo.bFF_Breakpoint);
- OnOverflow = true;
- while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
- fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase - 64)
- Common::YieldCPU();
- }
- else
- {
- OnOverflow = false;
- }
- }
-
_assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase,
"FIFO is overflown by GatherPipe !\nCPU thread is too fast!");
@@ -501,17 +513,15 @@ void AbortFrame()
void SetOverflowStatusFromGatherPipe()
{
- if (!fifo.bFF_HiWatermarkInt) return;
-
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
- fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
-
- bool interrupt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt &&
- m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable;
+ isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable;
- if (interrupt != interruptSet && interrupt)
- CommandProcessor::UpdateInterrupts(true);
-
+ if (isHiWatermarkActive)
+ {
+ interruptSet = true;
+ INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
+ ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
+ }
}
void SetCpStatus()
@@ -519,14 +529,12 @@ void SetCpStatus()
// overflow & underflow check
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
-
- // breakpoint
+ // breakpoint
if (fifo.bFF_BPEnable)
{
if (fifo.CPBreakpoint == fifo.CPReadPointer)
- {
-
+ {
if (!fifo.bFF_Breakpoint)
{
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
@@ -554,13 +562,18 @@ void SetCpStatus()
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
+ isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable;
+
if (interrupt != interruptSet && !interruptWaiting)
{
u64 userdata = interrupt?1:0;
if (IsOnThread())
{
- interruptWaiting = true;
- CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
+ if(!interrupt || bpInt || undfInt)
+ {
+ interruptWaiting = true;
+ CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
+ }
}
else
CommandProcessor::UpdateInterrupts(userdata);
@@ -583,7 +596,7 @@ void ProcessFifoAllDistance()
if (IsOnThread())
{
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
- fifo.CPReadWriteDistance && !AtBreakpoint())
+ fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
Common::YieldCPU();
}
bProcessFifoAllDistance = false;
@@ -603,13 +616,16 @@ void Shutdown()
void SetCpStatusRegister()
{
// Here always there is one fifo attached to the GPU
-
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
- m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint);
+ m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance;
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
+ // HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect
+ if (IsOnThread())
+ PixelEngine::ResumeWaitingForPEInterrupt();
+
INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex);
DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s"
, m_CPStatusReg.Breakpoint ? "ON" : "OFF"
@@ -622,14 +638,14 @@ void SetCpStatusRegister()
void SetCpControlRegister()
{
-
// If the new fifo is being attached We make sure there wont be SetFinish event pending.
// This protection fix eternal darkness booting, because the second SetFinish event when it is booting
// seems invalid or has a bug and hang the game.
if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable)
{
- PixelEngine::ResetSetFinish();
+ ProcessFifoEvents();
+ PixelEngine::ResetSetFinish();
}
fifo.bFF_BPInt = m_CPCtrlReg.BPInt;
@@ -644,9 +660,6 @@ void SetCpControlRegister()
ProcessorInterface::Fifo_CPUBase = fifo.CPBase;
ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd;
}
- // If overflown happens process the fifo to LoWatemark
- if (bProcessFifoToLoWatermark)
- ProcessFifoToLoWatermark();
if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable)
{
@@ -658,7 +671,6 @@ void SetCpControlRegister()
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable;
}
-
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s"
, fifo.bFF_GPReadEnable ? "ON" : "OFF"
, fifo.bFF_BPEnable ? "ON" : "OFF"
@@ -670,13 +682,15 @@ void SetCpControlRegister()
}
+// NOTE: The implementation of this function should be correct, but we intentionally aren't using it at the moment.
+// We don't emulate proper GP timing anyway at the moment, so this code would just slow down emulation.
void SetCpClearRegister()
{
- if (IsOnThread())
- {
- if (!m_CPClearReg.ClearFifoUnderflow && m_CPClearReg.ClearFifoOverflow)
- bProcessFifoToLoWatermark = true;
- }
+// if (IsOnThread())
+// {
+// if (!m_CPClearReg.ClearFifoUnderflow && m_CPClearReg.ClearFifoOverflow)
+// bProcessFifoToLoWatermark = true;
+// }
}
} // end of namespace CommandProcessor
diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h
index 7fb4e5a45f..5d31453537 100644
--- a/Source/Core/VideoCommon/Src/CommandProcessor.h
+++ b/Source/Core/VideoCommon/Src/CommandProcessor.h
@@ -25,18 +25,18 @@ class PointerWrap;
extern bool MT;
-
namespace CommandProcessor
{
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread.
+extern volatile bool isHiWatermarkActive;
extern volatile bool interruptSet;
extern volatile bool interruptWaiting;
extern volatile bool interruptTokenWaiting;
extern volatile bool interruptFinishWaiting;
-extern volatile bool OnOverflow;
-
+extern volatile bool waitingForPEInterruptDisable;
+
// internal hardware addresses
enum
{
@@ -158,6 +158,7 @@ void UpdateInterruptsFromVideoBackend(u64 userdata);
bool AllowIdleSkipping();
+void SetCpClearRegister();
void SetCpControlRegister();
void SetCpStatusRegister();
void SetOverflowStatusFromGatherPipe();
diff --git a/Source/Core/VideoCommon/Src/EmuWindow.cpp b/Source/Core/VideoCommon/Src/EmuWindow.cpp
index ff96887a32..30dca24cb1 100644
--- a/Source/Core/VideoCommon/Src/EmuWindow.cpp
+++ b/Source/Core/VideoCommon/Src/EmuWindow.cpp
@@ -36,6 +36,9 @@ WNDCLASSEX wndClass;
const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
int g_winstyle;
static volatile bool s_sizing;
+static const int TITLE_TEXT_BUF_SIZE = 1024;
+TCHAR m_titleTextBuffer[TITLE_TEXT_BUF_SIZE];
+static const int WM_SETTEXT_CUSTOM = WM_USER + WM_SETTEXT;
bool IsSizing()
{
@@ -225,6 +228,10 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
PostMessage(m_hParent, WM_USER, WM_USER_SETCURSOR, 0);
return true;
+ case WM_SETTEXT_CUSTOM:
+ SendMessage(hWnd, WM_SETTEXT, wParam, lParam);
+ break;
+
default:
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
@@ -357,4 +364,27 @@ void SetSize(int width, int height)
MoveWindow(m_hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
}
+void SetWindowText(const TCHAR* text)
+{
+ // the simple way.
+ // we don't do this because it's a blocking call and the GUI thread might be waiting for us.
+ //::SetWindowText(m_hWnd, text);
+
+ // copy to m_titleTextBuffer in such a way that
+ // it remains null-terminated and without garbage data at every point in time,
+ // in case another thread reads it while we're doing this.
+ for (int i = 0; i < TITLE_TEXT_BUF_SIZE-1; ++i)
+ {
+ m_titleTextBuffer[i+1] = 0;
+ TCHAR c = text[i];
+ m_titleTextBuffer[i] = c;
+ if (!c)
+ break;
+ }
+
+ // the OS doesn't allow posting WM_SETTEXT,
+ // so we post our own message and convert it to that in WndProc
+ PostMessage(m_hWnd, WM_SETTEXT_CUSTOM, 0, (LPARAM)m_titleTextBuffer);
+}
+
}
diff --git a/Source/Core/VideoCommon/Src/EmuWindow.h b/Source/Core/VideoCommon/Src/EmuWindow.h
index 1403ffcf57..bf5aa73cdf 100644
--- a/Source/Core/VideoCommon/Src/EmuWindow.h
+++ b/Source/Core/VideoCommon/Src/EmuWindow.h
@@ -14,6 +14,7 @@ void Close();
void SetSize(int displayWidth, int displayHeight);
bool IsSizing();
void OSDMenu(WPARAM wParam);
+void SetWindowText(const TCHAR* text);
}
diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp
index 842ff49e78..2e60055c97 100644
--- a/Source/Core/VideoCommon/Src/Fifo.cpp
+++ b/Source/Core/VideoCommon/Src/Fifo.cpp
@@ -22,6 +22,7 @@
#include "Atomic.h"
#include "OpcodeDecoding.h"
#include "CommandProcessor.h"
+#include "PixelEngine.h"
#include "ChunkFile.h"
#include "Fifo.h"
#include "HW/Memmap.h"
@@ -137,8 +138,7 @@ void RunGpuLoop()
CommandProcessor::SetCpStatus();
// check if we are able to run this buffer
- while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
- fifo.CPReadWriteDistance && (!AtBreakpoint() || CommandProcessor::OnOverflow))
+ while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
{
if (!GpuRunningState) break;
diff --git a/Source/Core/VideoCommon/Src/ImageWrite.h b/Source/Core/VideoCommon/Src/ImageWrite.h
index 962ee5b5e7..9ea6cab859 100644
--- a/Source/Core/VideoCommon/Src/ImageWrite.h
+++ b/Source/Core/VideoCommon/Src/ImageWrite.h
@@ -21,7 +21,6 @@
#include "Common.h"
bool SaveTGA(const char* filename, int width, int height, void* pdata);
-bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
bool SaveData(const char* filename, const char* pdata);
#endif // _IMAGEWRITE_H
diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp
index 6824fbd2fc..a506acadfc 100644
--- a/Source/Core/VideoCommon/Src/LightingShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/LightingShaderGen.cpp
@@ -21,6 +21,21 @@
#define WRITE p+=sprintf
+int GetLightingShaderId(u32* out)
+{
+ for (int i = 0; i < xfregs.numChan.numColorChans; ++i)
+ {
+ out[i] = xfregs.color[i].enablelighting ?
+ (u32)xfregs.color[i].hex :
+ (u32)xfregs.color[i].matsource;
+ out[i] |= (xfregs.alpha[i].enablelighting ?
+ (u32)xfregs.alpha[i].hex :
+ (u32)xfregs.alpha[i].matsource) << 15;
+ }
+ _assert_(xfregs.numChan.numColorChans <= 2);
+ return xfregs.numChan.numColorChans;
+}
+
// coloralpha - 1 if color, 2 if alpha
char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char* lightsName, int coloralpha)
{
diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.h b/Source/Core/VideoCommon/Src/LightingShaderGen.h
index 21da8ca01a..e72623a4d2 100644
--- a/Source/Core/VideoCommon/Src/LightingShaderGen.h
+++ b/Source/Core/VideoCommon/Src/LightingShaderGen.h
@@ -18,6 +18,9 @@
#ifndef _LIGHTINGSHADERGEN_H_
#define _LIGHTINGSHADERGEN_H_
+#include "CommonTypes.h"
+
+int GetLightingShaderId(u32* out);
char *GenerateLightingShader(char *p, int components, const char* materialsName, const char* lightsName, const char* inColorName, const char* dest);
#endif // _LIGHTINGSHADERGEN_H_
diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp
index 1fc8b15bec..0b1258a662 100644
--- a/Source/Core/VideoCommon/Src/MainBase.cpp
+++ b/Source/Core/VideoCommon/Src/MainBase.cpp
@@ -171,6 +171,18 @@ u32 VideoBackendHardware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32
static volatile u32 s_doStateRequested = false;
+void VideoBackendHardware::InitializeShared()
+{
+ VideoCommon_Init();
+
+ s_swapRequested = 0;
+ s_efbAccessRequested = 0;
+ s_FifoShuttingDown = 0;
+ memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs));
+ memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs));
+ s_AccessEFBResult = 0;
+}
+
static volatile struct
{
unsigned char **ptr;
@@ -238,6 +250,11 @@ bool VideoBackendHardware::Video_IsPossibleWaitingSetDrawDone()
return CommandProcessor::isPossibleWaitingSetDrawDone;
}
+bool VideoBackendHardware::Video_IsHiWatermarkActive()
+{
+ return CommandProcessor::isHiWatermarkActive;
+}
+
void VideoBackendHardware::Video_AbortFrame()
{
CommandProcessor::AbortFrame();
diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp
index 2a328de95d..03a3a7547a 100644
--- a/Source/Core/VideoCommon/Src/PixelEngine.cpp
+++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp
@@ -31,6 +31,7 @@
#include "CommandProcessor.h"
#include "HW/ProcessorInterface.h"
#include "DLCache.h"
+#include "State.h"
namespace PixelEngine
{
@@ -154,6 +155,16 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
void Init()
{
m_Control.Hex = 0;
+ m_ZConf.Hex = 0;
+ m_AlphaConf.Hex = 0;
+ m_DstAlphaConf.Hex = 0;
+ m_AlphaModeConf.Hex = 0;
+ m_AlphaRead.Hex = 0;
+
+ g_bSignalTokenInterrupt = false;
+ g_bSignalFinishInterrupt = false;
+ interruptSetToken = false;
+ interruptSetFinish = false;
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
@@ -169,7 +180,6 @@ void Init()
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
DEBUG_LOG(PIXELENGINE, "(r16) 0x%08x", _iAddress);
- CommandProcessor::ProcessFifoEvents();
switch (_iAddress & 0xFFF)
{
// CPU Direct Access EFB Raster State Config
@@ -205,14 +215,45 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
INFO_LOG(PIXELENGINE, "(r16) TOKEN_REG : %04x", _uReturnValue);
break;
- // The return values for these BBOX registers need to be gotten from the bounding box of the object.
- // See http://code.google.com/p/dolphin-emu/issues/detail?id=360#c74 for more details.
+ case PE_BBOX_LEFT:
+ {
+ // Left must be even and 606px max
+ _uReturnValue = std::min((u16) 606, bbox[0]) & ~1;
+
+ INFO_LOG(PIXELENGINE, "R: BBOX_LEFT = %i", _uReturnValue);
+ bbox_active = false;
+ break;
+ }
+
+ case PE_BBOX_RIGHT:
+ {
+ // Right must be odd and 607px max
+ _uReturnValue = std::min((u16) 607, bbox[1]) | 1;
+
+ INFO_LOG(PIXELENGINE, "R: BBOX_RIGHT = %i", _uReturnValue);
+ bbox_active = false;
+ break;
+ }
+
+ case PE_BBOX_TOP:
+ {
+ // Top must be even and 478px max
+ _uReturnValue = std::min((u16) 478, bbox[2]) & ~1;
+
+ INFO_LOG(PIXELENGINE, "R: BBOX_TOP = %i", _uReturnValue);
+ bbox_active = false;
+ break;
+ }
+
+ case PE_BBOX_BOTTOM:
+ {
+ // Bottom must be odd and 479px max
+ _uReturnValue = std::min((u16) 479, bbox[3]) | 1;
- // 0x80, 0xa0, 0x80, 0xa0 makes Paper Mario happy.
- case PE_BBOX_LEFT: _uReturnValue = bbox[0]; INFO_LOG(PIXELENGINE, "R: BBOX_LEFT = %i", bbox[0]); bbox_active = false; break;
- case PE_BBOX_RIGHT: _uReturnValue = bbox[1]; INFO_LOG(PIXELENGINE, "R: BBOX_RIGHT = %i", bbox[1]); bbox_active = false; break;
- case PE_BBOX_TOP: _uReturnValue = bbox[2]; INFO_LOG(PIXELENGINE, "R: BBOX_TOP = %i", bbox[2]); bbox_active = false; break;
- case PE_BBOX_BOTTOM: _uReturnValue = bbox[3]; INFO_LOG(PIXELENGINE, "R: BBOX_BOTTOM = %i", bbox[3]); bbox_active = false; break;
+ INFO_LOG(PIXELENGINE, "R: BBOX_BOTTOM = %i", _uReturnValue);
+ bbox_active = false;
+ break;
+ }
case PE_PERF_0L:
case PE_PERF_0H:
@@ -227,6 +268,10 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
case PE_PERF_5L:
case PE_PERF_5H:
INFO_LOG(PIXELENGINE, "(r16) perf counter @ %08x", _iAddress);
+ // git r90a2096a24f4 (svn r3663) added the PE_PERF cases, without setting
+ // _uReturnValue to anything, this reverts to the previous behaviour which allows
+ // The timer in SMS:Scrubbing Serena Beach to countdown correctly
+ _uReturnValue = 1;
break;
default:
@@ -281,7 +326,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
break;
case PE_TOKEN_REG:
- //LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue);
PanicAlert("(w16) WTF? PowerPC program wrote token: %i", _iValue);
//only the gx pipeline is supposed to be able to write here
//g_token = _iValue;
@@ -292,7 +336,6 @@ void Write16(const u16 _iValue, const u32 _iAddress)
break;
}
- CommandProcessor::ProcessFifoEvents();
}
void Write32(const u32 _iValue, const u32 _iAddress)
@@ -316,20 +359,16 @@ void UpdateInterrupts()
void UpdateTokenInterrupt(bool active)
{
- if(interruptSetToken != active)
- {
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active);
interruptSetToken = active;
- }
}
void UpdateFinishInterrupt(bool active)
{
- if(interruptSetFinish != active)
- {
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
interruptSetFinish = active;
- }
+ if (active)
+ State::ProcessRequestedStates(0);
}
// TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate).
@@ -348,8 +387,6 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate)
CommandProcessor::interruptTokenWaiting = false;
IncrementCheckContextId();
//}
- //else
- // LOGV(PIXELENGINE, 1, "VIDEO Backend wrote token: %i", CommandProcessor::fifo.PEToken);
}
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
@@ -426,4 +463,17 @@ void ResetSetToken()
}
CommandProcessor::interruptTokenWaiting = false;
}
+
+bool WaitingForPEInterrupt()
+{
+ return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken);
+}
+
+void ResumeWaitingForPEInterrupt()
+{
+ interruptSetFinish = false;
+ interruptSetToken = false;
+ CommandProcessor::interruptFinishWaiting = false;
+ CommandProcessor::interruptTokenWaiting = false;
+}
} // end of namespace PixelEngine
diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h
index dd0304fbe1..64f959009f 100644
--- a/Source/Core/VideoCommon/Src/PixelEngine.h
+++ b/Source/Core/VideoCommon/Src/PixelEngine.h
@@ -80,7 +80,8 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
void ResetSetFinish(void);
void ResetSetToken(void);
-bool AllowIdleSkipping();
+bool WaitingForPEInterrupt();
+void ResumeWaitingForPEInterrupt();
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
extern u16 bbox[4];
diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
index ec4eb2c70b..46ac264889 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
@@ -27,129 +27,264 @@
#include "VideoConfig.h"
#include "NativeVertexFormat.h"
-PIXELSHADERUID last_pixel_shader_uid;
+static int AlphaPreTest();
+
+static void StageHash(int stage, u32* out)
+{
+ out[0] |= bpmem.combiners[stage].colorC.hex & 0xFFFFFF; // 24
+ u32 alphaC = bpmem.combiners[stage].alphaC.hex & 0xFFFFF0; // 24, strip out tswap and rswap for now
+ out[0] |= (alphaC&0xF0) << 24; // 8
+ out[1] |= alphaC >> 8; // 16
+
+ // reserve 3 bits for bpmem.tevorders[stage/2].getTexMap
+ out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 19; // 3
+ out[1] |= bpmem.tevorders[stage/2].getEnable(stage&1) << 22; // 1
+ // reserve 3 bits for bpmem.tevorders[stage/2].getColorChan
+
+ bool bHasIndStage = bpmem.tevind[stage].IsActive() && bpmem.tevind[stage].bt < bpmem.genMode.numindstages;
+ out[2] |= bHasIndStage << 2; // 1
+
+ bool needstexcoord = false;
+
+ if (bHasIndStage)
+ {
+ out[2] |= (bpmem.tevind[stage].hex & 0x17FFFF) << 3; // 21, TODO: needs an explanation
+ needstexcoord = true;
+ }
+
+
+ TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stage].colorC;
+ TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stage].alphaC;
+
+ if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC
+ || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC
+ || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC
+ || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC
+ || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA
+ || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA)
+ {
+ out[0] |= bpmem.combiners[stage].alphaC.rswap;
+ out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap1 << 24; // 2
+ out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2].swap2 << 26; // 2
+ out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap1 << 28; // 2
+ out[2] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.rswap*2+1].swap2 << 30; // 2
+ out[1] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&1) << 23;
+ out[2] |= (bpmem.tevorders[stage/2].getColorChan(stage&1)&0x6) >> 1;
+ }
+
+ out[3] |= bpmem.tevorders[stage/2].getEnable(stage&1);
+ if (bpmem.tevorders[stage/2].getEnable(stage&1))
+ {
+ if (bHasIndStage) needstexcoord = true;
+
+ out[0] |= bpmem.combiners[stage].alphaC.tswap;
+ out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap1 << 1; // 2
+ out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2].swap2 << 3; // 2
+ out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap1 << 5; // 2
+ out[3] |= bpmem.tevksel[bpmem.combiners[stage].alphaC.tswap*2+1].swap2 << 7; // 2
+ out[1] |= bpmem.tevorders[stage/2].getTexMap(stage&1) << 16;
+ }
+
+ if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST
+ || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST)
+ {
+ out[3] |= bpmem.tevksel[stage/2].getKC(stage&1) << 9; // 5
+ out[3] |= bpmem.tevksel[stage/2].getKA(stage&1) << 14; // 5
+ }
+
+ if (needstexcoord)
+ {
+ out[1] |= bpmem.tevorders[stage/2].getTexCoord(stage&1) << 16;
+ }
+}
// Mash together all the inputs that contribute to the code of a generated pixel shader into
// a unique identifier, basically containing all the bits. Yup, it's a lot ....
// It would likely be a lot more efficient to build this incrementally as the attributes
// are set...
-void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode)
+void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components)
{
- u32 numstages = bpmem.genMode.numtevstages + 1;
- u32 projtexcoords = 0;
- for (u32 i = 0; i < numstages; i++)
+ memset(uid->values, 0, sizeof(uid->values));
+ uid->values[0] |= bpmem.genMode.numtevstages; // 4
+ uid->values[0] |= bpmem.genMode.numtexgens << 4; // 4
+ uid->values[0] |= dstAlphaMode << 8; // 2
+
+ bool DepthTextureEnable = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth;
+
+ uid->values[0] |= DepthTextureEnable << 10; // 1
+
+ bool enablePL = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting;
+ uid->values[0] |= enablePL << 11; // 1
+
+ if (!enablePL) uid->values[0] |= xfregs.numTexGen.numTexGens << 12; // 4
+ u32 alphaPreTest = AlphaPreTest()+1;
+
+ uid->values[0] |= alphaPreTest << 16; // 2
+
+ if (alphaPreTest == 1 || (alphaPreTest && !DepthTextureEnable && dstAlphaMode == DSTALPHA_ALPHA_PASS))
{
- if (bpmem.tevorders[i/2].getEnable(i & 1))
- {
- int texcoord = bpmem.tevorders[i / 2].getTexCoord(i & 1);
- if (xfregs.texMtxInfo[i].projection)
- projtexcoords |= 1 << texcoord;
- }
+ // Courtesy of PreAlphaTest, we're done already ;)
+ // NOTE: The comment header of generated shaders depends on the value of bpmem.genmode.numindstages.. shouldnt really bother about that though.
+ uid->num_values = 1;
+ return;
}
- uid->values[0] = (u32)bpmem.genMode.numtevstages |
- ((u32)bpmem.genMode.numindstages << 4) |
- ((u32)bpmem.genMode.numtexgens << 7) |
- ((u32)dstAlphaMode << 11) |
- ((u32)((bpmem.alphaFunc.hex >> 16) & 0xff) << 13) |
- (projtexcoords << 21) |
- ((u32)bpmem.ztex2.op << 29);
- // swap table
- for (int i = 0; i < 8; i += 2)
- ((u8*)&uid->values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4);
+ for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i)
+ {
+ if (18+i < 32)
+ uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1
+ else
+ uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1
+ }
- u32 enableZTexture = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) || g_ActiveConfig.bEnablePerPixelDepth ? 1 : 0;
+ uid->values[1] = bpmem.genMode.numindstages << 2; // 3
+ u32 indirectStagesUsed = 0;
+ for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i)
+ if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
+ indirectStagesUsed |= (1 << bpmem.tevind[i].bt);
- uid->values[2] = (u32)bpmem.fog.c_proj_fsel.fsel |
- ((u32)bpmem.fog.c_proj_fsel.proj << 3) |
- ((u32)enableZTexture << 4) | ((u32)bpmem.fogRange.Base.Enabled << 5) |
- ((u32)bpmem.zcontrol.zcomploc << 6);
+ assert(indirectStagesUsed == (indirectStagesUsed & 0xF));
- if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
+ uid->values[1] |= indirectStagesUsed << 5; // 4;
+
+ for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i)
{
- for (int i = 0; i < 2; ++i) {
- uid->values[3 + i] = xfregs.color[i].enablelighting ?
- (u32)xfregs.color[i].hex :
- (u32)xfregs.color[i].matsource;
- uid->values[3 + i] |= (xfregs.alpha[i].enablelighting ?
- (u32)xfregs.alpha[i].hex :
- (u32)xfregs.alpha[i].matsource) << 15;
+ if (indirectStagesUsed & (1 << i))
+ {
+ uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1
+ if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens)
+ uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2
}
}
- uid->values[4] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31;
- int hdr = 5;
- u32 *pcurvalue = &uid->values[hdr];
- for (u32 i = 0; i < numstages; ++i)
+ u32* ptr = &uid->values[2];
+ for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i)
{
- TevStageCombiner::ColorCombiner &cc = bpmem.combiners[i].colorC;
- TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[i].alphaC;
-
- u32 val0 = cc.hex & 0xffffff;
- u32 val1 = ac.hex & 0xffffff;
- val0 |= bpmem.tevksel[i / 2].getKC(i & 1) << 24;
- val1 |= bpmem.tevksel[i / 2].getKA(i & 1) << 24;
- pcurvalue[0] = val0;
- pcurvalue[1] = val1;
- pcurvalue += 2;
+ StageHash(i, ptr);
+ ptr += 4; // max: ptr = &uid->values[66]
}
- for (u32 i = 0; i < numstages / 2; ++i)
- {
- u32 val0, val1;
- if (bpmem.tevorders[i].hex & 0x40)
- val0 = bpmem.tevorders[i].hex & 0x3ff;
- else
- val0 = bpmem.tevorders[i].hex & 0x380;
- if (bpmem.tevorders[i].hex & 0x40000)
- val1 = (bpmem.tevorders[i].hex & 0x3ff000) >> 12;
- else
- val1 = (bpmem.tevorders[i].hex & 0x380000) >> 12;
+ ptr[0] |= bpmem.alphaFunc.comp0; // 3
+ ptr[0] |= bpmem.alphaFunc.comp1 << 3; // 3
+ ptr[0] |= bpmem.alphaFunc.logic << 6; // 2
- switch (i % 3) {
- case 0: pcurvalue[0] = val0|(val1<<10); break;
- case 1: pcurvalue[0] |= val0<<20; pcurvalue[1] = val1; pcurvalue++; break;
- case 2: pcurvalue[1] |= (val0<<10)|(val1<<20); pcurvalue++; break;
- default: PanicAlert("Unknown case for Tev Stages / 2: %08x", (i % 3));
+ if (alphaPreTest == 0 || alphaPreTest == 2)
+ {
+ ptr[0] |= bpmem.fog.c_proj_fsel.fsel << 8; // 3
+ if (DepthTextureEnable)
+ {
+ ptr[0] |= bpmem.ztex2.op << 11; // 2
+ ptr[0] |= bpmem.zcontrol.zcomploc << 13; // 1
+ ptr[0] |= bpmem.zmode.testenable << 14; // 1
+ ptr[0] |= bpmem.zmode.updateenable << 15; // 1
}
}
- if (numstages & 1) { // odd
- u32 val0;
- if (bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x40)
- val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x3ff;
- else
- val0 = bpmem.tevorders[bpmem.genMode.numtevstages/2].hex & 0x380;
-
- switch (bpmem.genMode.numtevstages % 3)
+ if (dstAlphaMode != DSTALPHA_ALPHA_PASS)
+ {
+ if (bpmem.fog.c_proj_fsel.fsel != 0)
{
- case 0: pcurvalue[0] = val0; break;
- case 1: pcurvalue[0] |= val0 << 20; break;
- case 2: pcurvalue[1] |= val0 << 10; pcurvalue++; break;
- default: PanicAlert("Unknown case for Tev Stages: %08x", bpmem.genMode.numtevstages % 3);
+ ptr[0] |= bpmem.fog.c_proj_fsel.proj << 16; // 1
+ ptr[0] |= bpmem.fogRange.Base.Enabled << 17; // 1
}
}
- if ((bpmem.genMode.numtevstages % 3) != 2)
- ++pcurvalue;
+ ++ptr;
+ if (enablePL)
+ {
+ ptr += GetLightingShaderId(ptr);
+ *ptr++ = components;
+ }
- uid->tevstages = (u32)(pcurvalue - &uid->values[0] - hdr);
+ uid->num_values = ptr - uid->values;
+}
- for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
+void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components)
+{
+ memset(uid->values, 0, sizeof(uid->values));
+ u32* ptr = uid->values;
+ *ptr++ = dstAlphaMode; // 0
+ *ptr++ = bpmem.genMode.hex; // 1
+ *ptr++ = bpmem.ztex2.hex; // 2
+ *ptr++ = bpmem.zcontrol.hex; // 3
+ *ptr++ = bpmem.zmode.hex; // 4
+ *ptr++ = g_ActiveConfig.bEnablePerPixelDepth; // 5
+ *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; // 6
+ *ptr++ = xfregs.numTexGen.hex; // 7
+
+ if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
{
- u32 val = bpmem.tevind[i].hex & 0x1fffff; // 21 bits
- switch (i % 3)
- {
- case 0: pcurvalue[0] = val; break;
- case 1: pcurvalue[0] |= val << 21; pcurvalue[1] = val >> 11; ++pcurvalue; break;
- case 2: pcurvalue[0] |= val << 10; ++pcurvalue; break;
- default: PanicAlert("Unknown case for Ind Stages: %08x", (i % 3));
- }
+ *ptr++ = xfregs.color[0].hex;
+ *ptr++ = xfregs.alpha[0].hex;
+ *ptr++ = xfregs.color[1].hex;
+ *ptr++ = xfregs.alpha[1].hex;
+ *ptr++ = components;
+ }
+
+ for (unsigned int i = 0; i < 8; ++i)
+ *ptr++ = xfregs.texMtxInfo[i].hex; // 8-15
+
+ for (unsigned int i = 0; i < 16; ++i)
+ *ptr++ = bpmem.tevind[i].hex; // 16-31
+
+ *ptr++ = bpmem.tevindref.hex; // 32
+
+ for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) // up to 16 times
+ {
+ *ptr++ = bpmem.combiners[i].colorC.hex; // 33+5*i
+ *ptr++ = bpmem.combiners[i].alphaC.hex; // 34+5*i
+ *ptr++ = bpmem.tevind[i].hex; // 35+5*i
+ *ptr++ = bpmem.tevksel[i/2].hex; // 36+5*i
+ *ptr++ = bpmem.tevorders[i/2].hex; // 37+5*i
}
- // yeah, well ....
- uid->indstages = (u32)(pcurvalue - &uid->values[0] - (hdr - 1) - uid->tevstages);
+ ptr = &uid->values[113];
+
+ *ptr++ = bpmem.alphaFunc.hex; // 113
+ *ptr++ = bpmem.fog.c_proj_fsel.hex; // 114
+ *ptr++ = bpmem.fogRange.Base.hex; // 115
+
+ _assert_((ptr - uid->values) == uid->GetNumValues());
+}
+
+void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components)
+{
+ if (!g_ActiveConfig.bEnableShaderDebugging)
+ return;
+
+ PIXELSHADERUIDSAFE new_id;
+ GetSafePixelShaderId(&new_id, dstAlphaMode, components);
+
+ if (!(old_id == new_id))
+ {
+ std::string new_code(GeneratePixelShaderCode(dstAlphaMode, api, components));
+ if (old_code != new_code)
+ {
+ _assert_(old_id.GetNumValues() == new_id.GetNumValues());
+
+ char msg[8192];
+ char* ptr = msg;
+ ptr += sprintf(ptr, "Pixel shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n");
+ const int N = new_id.GetNumValues();
+ for (int i = 0; i < N/2; ++i)
+ ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1],
+ new_id.values[2*i], new_id.values[2*i+1]);
+ if (N % 2)
+ ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]);
+
+ static int num_failures = 0;
+ char szTemp[MAX_PATH];
+ sprintf(szTemp, "%spsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
+ std::ofstream file(szTemp);
+ file << msg;
+ file << "\n\nOld shader code:\n" << old_code;
+ file << "\n\nNew shader code:\n" << new_code;
+ file.close();
+
+ PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp);
+ }
+ }
}
// old tev->pixelshader notes
@@ -166,7 +301,6 @@ static void SampleTexture(char *&p, const char *destination, const char *texcoor
// static void WriteAlphaCompare(char *&p, int num, int comp);
static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode);
static void WriteFog(char *&p);
-static int AlphaPreTest();
static const char *tevKSelTableC[] = // KCSEL
{
@@ -334,12 +468,6 @@ static const char *tevRasTable[] =
"float4(0.0f, 0.0f, 0.0f, 0.0f)", // zero
};
-static const char *alphaRef[2] =
-{
- I_ALPHA"[0].r",
- I_ALPHA"[0].g"
-};
-
//static const char *tevTexFunc[] = { "tex2D", "texRECT" };
static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" };
@@ -354,23 +482,14 @@ static const char *tevIndFmtScale[] = {"255.0f", "31.0f", "15.0f", "7.0f" };
#define WRITE p+=sprintf
-static const char *swapColors = "rgba";
static char swapModeTable[4][5];
static char text[16384];
static bool DepthTextureEnable;
-struct RegisterState
-{
- bool ColorNeedOverflowControl;
- bool AlphaNeedOverflowControl;
- bool AuxStored;
-};
-
-static RegisterState RegisterStates[4];
-
static void BuildSwapModeTable()
{
+ static const char *swapColors = "rgba";
for (int i = 0; i < 4; i++)
{
swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1];
@@ -386,14 +505,14 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
setlocale(LC_NUMERIC, "C"); // Reset locale for compilation
text[sizeof(text) - 1] = 0x7C; // canary
- BuildSwapModeTable();
+ BuildSwapModeTable(); // Needed for WriteStage
int numStages = bpmem.genMode.numtevstages + 1;
int numTexgen = bpmem.genMode.numtexgens;
char *p = text;
WRITE(p, "//Pixel Shader for TEV stages\n");
- WRITE(p, "//%i TEV stages, %i texgens, %i IND stages\n",
- numStages, numTexgen, bpmem.genMode.numindstages);
+ WRITE(p, "//%i TEV stages, %i texgens, XXX IND stages\n",
+ numStages, numTexgen/*, bpmem.genMode.numindstages*/);
int nIndirectStagesUsed = 0;
if (bpmem.genMode.numindstages > 0)
@@ -441,6 +560,10 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS);
WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA);
WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS);
+ if (ApiType & API_D3D9)
+ {
+ WRITE(p, "uniform float4 "I_VTEXSCALE"[4] : register(c%d);\n", C_VTEXSCALE);
+ }
WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS);
WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE);
WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX);
@@ -506,10 +629,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
{
// alpha test will always fail, so restart the shader and just make it an empty function
WRITE(p, "ocol0 = 0;\n");
- if(DepthTextureEnable)
- WRITE(p, "depth = 1.f;\n");
- if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND)
- WRITE(p, "ocol1 = 0;\n");
WRITE(p, "discard;\n");
if(ApiType != API_D3D11)
WRITE(p, "return;\n");
@@ -524,10 +643,12 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"
" float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n"
- " float4 alphabump=0;\n"
- " float3 tevcoord;\n"
- " float2 wrappedcoord, tempcoord;\n"
- " float4 cc0, cc1, cc2, cprev,crastemp,ckonsttemp;\n\n");
+ " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n"
+ " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n"
+ " float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f);\n"
+ " float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f);\n"
+ " float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f);\n"
+ " float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f);\n\n");
if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
{
@@ -593,16 +714,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
}
}
- RegisterStates[0].AlphaNeedOverflowControl = false;
- RegisterStates[0].ColorNeedOverflowControl = false;
- RegisterStates[0].AuxStored = false;
- for(int i = 1; i < 4; i++)
- {
- RegisterStates[i].AlphaNeedOverflowControl = true;
- RegisterStates[i].ColorNeedOverflowControl = true;
- RegisterStates[i].AuxStored = false;
- }
-
for (int i = 0; i < numStages; i++)
WriteStage(p, i, ApiType); //build the equation for this stage
@@ -610,23 +721,13 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
{
// The results of the last texenv stage are put onto the screen,
// regardless of the used destination register
- if(bpmem.combiners[numStages - 1].colorC.dest != 0)
- {
- bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].AuxStored;
- WRITE(p, "prev.rgb = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]);
- RegisterStates[0].ColorNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].colorC.dest].ColorNeedOverflowControl;
- }
- if(bpmem.combiners[numStages - 1].alphaC.dest != 0)
- {
- bool retrieveFromAuxRegister = !RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl && RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AuxStored;
- WRITE(p, "prev.a = %s%s;\n", retrieveFromAuxRegister ? "c" : "" , tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]);
- RegisterStates[0].AlphaNeedOverflowControl = RegisterStates[bpmem.combiners[numStages - 1].alphaC.dest].AlphaNeedOverflowControl;
- }
+ WRITE(p, "prev.rgb = %s;\n",tevCOutputTable[bpmem.combiners[numStages-1].colorC.dest]);
+ WRITE(p, "prev.a = %s;\n",tevAOutputTable[bpmem.combiners[numStages-1].alphaC.dest]);
}
- // emulation of unisgned 8 overflow when casting if needed
- if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
- WRITE(p, "prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
+ // emulation of unsigned 8 overflow when casting
+ WRITE(p, "prev = frac(4.0f + prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
+ // TODO: Why are we doing a second alpha pretest here?
if (!WriteAlphaTest(p, ApiType, dstAlphaMode))
{
// alpha test will always fail, so restart the shader and just make it an empty function
@@ -741,10 +842,6 @@ static const char *TEVCMPAlphaOPTable[16] =
static void WriteStage(char *&p, int n, API_TYPE ApiType)
{
- char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap];
- char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap];
-
-
int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1);
bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens;
bool bHasIndStage = bpmem.tevind[n].IsActive() && bpmem.tevind[n].bt < bpmem.genMode.numindstages;
@@ -753,8 +850,11 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
if (!bHasTexCoord)
texcoord = 0;
+ WRITE(p, "// TEV stage %d\n", n);
+
if (bHasIndStage)
{
+ WRITE(p, "// indirect op\n");
// perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords
if (bpmem.tevind[n].bs != ITBA_OFF)
{
@@ -781,11 +881,13 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
}
else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord)
{ // s matrix
+ _assert_(bpmem.tevind[n].mid >= 5);
int mtxidx = 2*(bpmem.tevind[n].mid-5);
WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n);
}
else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord)
{ // t matrix
+ _assert_(bpmem.tevind[n].mid >= 9);
int mtxidx = 2*(bpmem.tevind[n].mid-9);
WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n);
}
@@ -824,11 +926,15 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC;
TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC;
- bool bCRas = cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC;
- bool bARas = ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA;
-
- if(bCRas || bARas)
+ // blah1
+ if(cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC
+ || cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC
+ || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC
+ || cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC
+ || ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA
+ || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA)
{
+ char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap];
WRITE(p, "rastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap);
WRITE(p, "crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f);\n");
}
@@ -836,7 +942,6 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
if (bpmem.tevorders[n/2].getEnable(n&1))
{
- int texmap = bpmem.tevorders[n/2].getTexMap(n&1);
if(!bHasIndStage)
{
// calc tevcord
@@ -846,20 +951,20 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
WRITE(p, "tevcoord.xy = float2(0.0f, 0.0f);\n");
}
+ char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap];
+ int texmap = bpmem.tevorders[n/2].getTexMap(n&1);
SampleTexture(p, "textemp", "tevcoord", texswap, texmap, ApiType);
}
else
WRITE(p, "textemp = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
- int kc = bpmem.tevksel[n / 2].getKC(n & 1);
- int ka = bpmem.tevksel[n / 2].getKA(n & 1);
-
-
- bool bCKonst = cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST;
- bool bAKonst = ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST;
- if (bCKonst || bAKonst )
+ // blah2
+ if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST
+ || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST)
{
+ int kc = bpmem.tevksel[n / 2].getKC(n & 1);
+ int ka = bpmem.tevksel[n / 2].getKA(n & 1);
WRITE(p, "konsttemp = float4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]);
if(kc > 7 || ka > 7)
{
@@ -871,100 +976,35 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
}
}
- if(cc.a == TEVCOLORARG_CPREV
- || cc.a == TEVCOLORARG_APREV
- || cc.b == TEVCOLORARG_CPREV
- || cc.b == TEVCOLORARG_APREV
- || cc.c == TEVCOLORARG_CPREV
- || cc.c == TEVCOLORARG_APREV
- || ac.a == TEVALPHAARG_APREV
- || ac.b == TEVALPHAARG_APREV
- || ac.c == TEVALPHAARG_APREV)
- {
- if(RegisterStates[0].AlphaNeedOverflowControl || RegisterStates[0].ColorNeedOverflowControl)
- {
- WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- RegisterStates[0].AlphaNeedOverflowControl = false;
- RegisterStates[0].ColorNeedOverflowControl = false;
- }
- else
- {
- WRITE(p, "cprev = prev;\n");
- }
- RegisterStates[0].AuxStored = true;
- }
+ if(cc.a == TEVCOLORARG_CPREV || cc.a == TEVCOLORARG_APREV
+ || cc.b == TEVCOLORARG_CPREV || cc.b == TEVCOLORARG_APREV
+ || cc.c == TEVCOLORARG_CPREV || cc.c == TEVCOLORARG_APREV
+ || ac.a == TEVALPHAARG_APREV || ac.b == TEVALPHAARG_APREV || ac.c == TEVALPHAARG_APREV)
+ WRITE(p, "cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- if(cc.a == TEVCOLORARG_C0
- || cc.a == TEVCOLORARG_A0
- || cc.b == TEVCOLORARG_C0
- || cc.b == TEVCOLORARG_A0
- || cc.c == TEVCOLORARG_C0
- || cc.c == TEVCOLORARG_A0
- || ac.a == TEVALPHAARG_A0
- || ac.b == TEVALPHAARG_A0
- || ac.c == TEVALPHAARG_A0)
- {
- if(RegisterStates[1].AlphaNeedOverflowControl || RegisterStates[1].ColorNeedOverflowControl)
- {
- WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- RegisterStates[1].AlphaNeedOverflowControl = false;
- RegisterStates[1].ColorNeedOverflowControl = false;
- }
- else
- {
- WRITE(p, "cc0 = c0;\n");
- }
- RegisterStates[1].AuxStored = true;
- }
- if(cc.a == TEVCOLORARG_C1
- || cc.a == TEVCOLORARG_A1
- || cc.b == TEVCOLORARG_C1
- || cc.b == TEVCOLORARG_A1
- || cc.c == TEVCOLORARG_C1
- || cc.c == TEVCOLORARG_A1
- || ac.a == TEVALPHAARG_A1
- || ac.b == TEVALPHAARG_A1
- || ac.c == TEVALPHAARG_A1)
- {
- if(RegisterStates[2].AlphaNeedOverflowControl || RegisterStates[2].ColorNeedOverflowControl)
- {
- WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- RegisterStates[2].AlphaNeedOverflowControl = false;
- RegisterStates[2].ColorNeedOverflowControl = false;
- }
- else
- {
- WRITE(p, "cc1 = c1;\n");
- }
- RegisterStates[2].AuxStored = true;
- }
+ if(cc.a == TEVCOLORARG_C0 || cc.a == TEVCOLORARG_A0
+ || cc.b == TEVCOLORARG_C0 || cc.b == TEVCOLORARG_A0
+ || cc.c == TEVCOLORARG_C0 || cc.c == TEVCOLORARG_A0
+ || ac.a == TEVALPHAARG_A0 || ac.b == TEVALPHAARG_A0 || ac.c == TEVALPHAARG_A0)
+ WRITE(p, "cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- if(cc.a == TEVCOLORARG_C2
- || cc.a == TEVCOLORARG_A2
- || cc.b == TEVCOLORARG_C2
- || cc.b == TEVCOLORARG_A2
- || cc.c == TEVCOLORARG_C2
- || cc.c == TEVCOLORARG_A2
- || ac.a == TEVALPHAARG_A2
- || ac.b == TEVALPHAARG_A2
- || ac.c == TEVALPHAARG_A2)
- {
- if(RegisterStates[3].AlphaNeedOverflowControl || RegisterStates[3].ColorNeedOverflowControl)
- {
+
+ if(cc.a == TEVCOLORARG_C1 || cc.a == TEVCOLORARG_A1
+ || cc.b == TEVCOLORARG_C1 || cc.b == TEVCOLORARG_A1
+ || cc.c == TEVCOLORARG_C1 || cc.c == TEVCOLORARG_A1
+ || ac.a == TEVALPHAARG_A1 || ac.b == TEVALPHAARG_A1 || ac.c == TEVALPHAARG_A1)
+ WRITE(p, "cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
+
+
+ if(cc.a == TEVCOLORARG_C2 || cc.a == TEVCOLORARG_A2
+ || cc.b == TEVCOLORARG_C2 || cc.b == TEVCOLORARG_A2
+ || cc.c == TEVCOLORARG_C2 || cc.c == TEVCOLORARG_A2
+ || ac.a == TEVALPHAARG_A2 || ac.b == TEVALPHAARG_A2 || ac.c == TEVALPHAARG_A2)
WRITE(p, "cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f);\n");
- RegisterStates[3].AlphaNeedOverflowControl = false;
- RegisterStates[3].ColorNeedOverflowControl = false;
- }
- else
- {
- WRITE(p, "cc2 = c2;\n");
- }
- RegisterStates[3].AuxStored = true;
- }
- RegisterStates[cc.dest].ColorNeedOverflowControl = (cc.clamp == 0);
- RegisterStates[cc.dest].AuxStored = false;
+
+ WRITE(p, "// color combine\n");
if (cc.clamp)
WRITE(p, "%s = saturate(", tevCOutputTable[cc.dest]);
else
@@ -995,7 +1035,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
WRITE(p, "%s", tevBiasTable[cc.bias]);
- if (cc.shift > 0)
+ if (cc.shift > TEVSCALE_1)
WRITE(p, ")");
}
else
@@ -1011,8 +1051,7 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
WRITE(p, ")");
WRITE(p,";\n");
- RegisterStates[ac.dest].AlphaNeedOverflowControl = (ac.clamp == 0);
- RegisterStates[ac.dest].AuxStored = false;
+ WRITE(p, "// alpha combine\n");
// combine the alpha channel
if (ac.clamp)
WRITE(p, "%s = saturate(", tevAOutputTable[ac.dest]);
@@ -1058,14 +1097,21 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
if (ac.clamp)
WRITE(p, ")");
WRITE(p, ";\n\n");
+ WRITE(p, "// TEV done\n");
}
void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType)
{
if (ApiType == API_D3D11)
- WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap);
+ WRITE(p, "%s=Tex%d.Sample(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap);
+ else if (ApiType & API_D3D9)
+ {
+ // D3D9 uses different pixel to texel mapping, so we need to offset our sampling address by half a pixel (assuming native and virtual texture dimensions match each other, otherwise some math is involved).
+ // Read the MSDN article "Directly Mapping Texels to Pixels (Direct3D 9)" for further info.
+ WRITE(p, "%s=tex2D(samp%d, (%s.xy + 0.5f*"I_VTEXSCALE"[%d].%s) * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap/2, (texmap&1)?"zw":"xy", texmap, texswap);
+ }
else
- WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap);
+ WRITE(p, "%s=tex2D(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap);
}
static const char *tevAlphaFuncsTable[] =
@@ -1123,6 +1169,11 @@ static int AlphaPreTest()
static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode)
{
+ static const char *alphaRef[2] =
+ {
+ I_ALPHA"[0].r",
+ I_ALPHA"[0].g"
+ };
int Pretest = AlphaPreTest();
if(Pretest >= 0)
diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h
index b495703a13..7374251c96 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderGen.h
+++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h
@@ -24,64 +24,63 @@
#define I_KCOLORS "k"
#define I_ALPHA "alphaRef"
#define I_TEXDIMS "texdim"
+#define I_VTEXSCALE "vtexscale"
#define I_ZBIAS "czbias"
#define I_INDTEXSCALE "cindscale"
#define I_INDTEXMTX "cindmtx"
#define I_FOG "cfog"
#define I_PLIGHTS "cLights"
-#define I_PMATERIALS "cmtrl"
+#define I_PMATERIALS "cmtrl"
#define C_COLORMATRIX 0 // 0
#define C_COLORS 0 // 0
#define C_KCOLORS (C_COLORS + 4) // 4
#define C_ALPHA (C_KCOLORS + 4) // 8
#define C_TEXDIMS (C_ALPHA + 1) // 9
-#define C_ZBIAS (C_TEXDIMS + 8) //17
-#define C_INDTEXSCALE (C_ZBIAS + 2) //19
-#define C_INDTEXMTX (C_INDTEXSCALE + 2) //21
-#define C_FOG (C_INDTEXMTX + 6) //27
-
-#define C_PLIGHTS (C_FOG + 3)
-#define C_PMATERIALS (C_PLIGHTS + 40)
-#define C_PENVCONST_END (C_PMATERIALS + 4)
-#define PIXELSHADERUID_MAX_VALUES (5 + 32 + 6 + 11 + 2)
+#define C_VTEXSCALE (C_TEXDIMS + 8) //17 - virtual texture scaling factor (e.g. custom textures, scaled EFB copies)
+#define C_ZBIAS (C_VTEXSCALE + 4) //21
+#define C_INDTEXSCALE (C_ZBIAS + 2) //23
+#define C_INDTEXMTX (C_INDTEXSCALE + 2) //25
+#define C_FOG (C_INDTEXMTX + 6) //31
+#define C_PLIGHTS (C_FOG + 3) //34
+#define C_PMATERIALS (C_PLIGHTS + 40) //74
+#define C_PENVCONST_END (C_PMATERIALS + 4) //78
+#define PIXELSHADERUID_MAX_VALUES 70
+#define PIXELSHADERUID_MAX_VALUES_SAFE 120
// DO NOT make anything in this class virtual.
-class PIXELSHADERUID
+template<bool safe>
+class _PIXELSHADERUID
{
public:
- u32 values[PIXELSHADERUID_MAX_VALUES];
- u16 tevstages, indstages;
+ u32 values[safe ? PIXELSHADERUID_MAX_VALUES_SAFE : PIXELSHADERUID_MAX_VALUES];
+ int num_values;
- PIXELSHADERUID()
+ _PIXELSHADERUID()
{
- memset(values, 0, PIXELSHADERUID_MAX_VALUES * 4);
- tevstages = indstages = 0;
}
- PIXELSHADERUID(const PIXELSHADERUID& r)
+ _PIXELSHADERUID(const _PIXELSHADERUID& r)
{
- tevstages = r.tevstages;
- indstages = r.indstages;
- int N = GetNumValues();
- _assert_(N <= PIXELSHADERUID_MAX_VALUES);
- for (int i = 0; i < N; ++i)
- values[i] = r.values[i];
+ num_values = r.num_values;
+ if (safe) memcpy(values, r.values, PIXELSHADERUID_MAX_VALUES_SAFE);
+ else memcpy(values, r.values, r.GetNumValues() * sizeof(values[0]));
}
int GetNumValues() const
{
- return tevstages + indstages + 4;
+ if (safe) return (sizeof(values) / sizeof(u32));
+ else return num_values;
}
- bool operator <(const PIXELSHADERUID& _Right) const
+ bool operator <(const _PIXELSHADERUID& _Right) const
{
- if (values[0] < _Right.values[0])
+ int N = GetNumValues();
+ if (N < _Right.GetNumValues())
return true;
- else if (values[0] > _Right.values[0])
+ else if (N > _Right.GetNumValues())
return false;
- int N = GetNumValues();
- for (int i = 1; i < N; ++i)
+ for (int i = 0; i < N; ++i)
{
if (values[i] < _Right.values[i])
return true;
@@ -91,12 +90,12 @@ public:
return false;
}
- bool operator ==(const PIXELSHADERUID& _Right) const
+ bool operator ==(const _PIXELSHADERUID& _Right) const
{
- if (values[0] != _Right.values[0])
- return false;
int N = GetNumValues();
- for (int i = 1; i < N; ++i)
+ if (N != _Right.GetNumValues())
+ return false;
+ for (int i = 0; i < N; ++i)
{
if (values[i] != _Right.values[i])
return false;
@@ -104,6 +103,8 @@ public:
return true;
}
};
+typedef _PIXELSHADERUID<false> PIXELSHADERUID;
+typedef _PIXELSHADERUID<true> PIXELSHADERUIDSAFE;
// Different ways to achieve rendering with destination alpha
enum DSTALPHA_MODE
@@ -114,8 +115,11 @@ enum DSTALPHA_MODE
};
const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components);
-void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode);
-extern PIXELSHADERUID last_pixel_shader_uid;
+void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
+void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
+
+// Used to make sure that our optimized pixel shader IDs don't lose any possible shader code changes
+void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components);
#endif // GCOGL_PIXELSHADER_H
diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
index 2521f80500..3e0f6d73c4 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
+++ b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp
@@ -36,9 +36,11 @@ static bool s_bFogRangeAdjustChanged;
static int nLightsChanged[2]; // min,max
static float lastRGBAfull[2][4][4];
static u8 s_nTexDimsChanged;
+static u8 s_nVirtualTexScalesChanged;
static u8 s_nIndTexScaleChanged;
static u32 lastAlpha;
static u32 lastTexDims[8]; // width | height << 16 | wrap_s << 28 | wrap_t << 30
+static float lastVirtualTexScales[16]; // even fields: width ratio; odd fields: height ratio
static u32 lastZBias;
static int nMaterialsChanged;
@@ -61,6 +63,7 @@ void PixelShaderManager::Init()
{
lastAlpha = 0;
memset(lastTexDims, 0, sizeof(lastTexDims));
+ memset(lastVirtualTexScales, 0, sizeof(lastVirtualTexScales));
lastZBias = 0;
memset(lastRGBAfull, 0, sizeof(lastRGBAfull));
Dirty();
@@ -70,6 +73,7 @@ void PixelShaderManager::Dirty()
{
s_nColorsChanged[0] = s_nColorsChanged[1] = 15;
s_nTexDimsChanged = 0xFF;
+ s_nVirtualTexScalesChanged = 0xFF;
s_nIndTexScaleChanged = 0xFF;
s_nIndTexMtxChanged = 15;
s_bAlphaChanged = s_bZBiasChanged = s_bZTextureTypeChanged = s_bDepthRangeChanged = true;
@@ -83,7 +87,7 @@ void PixelShaderManager::Shutdown()
}
-void PixelShaderManager::SetConstants()
+void PixelShaderManager::SetConstants(API_TYPE api_type)
{
for (int i = 0; i < 2; ++i)
{
@@ -109,6 +113,16 @@ void PixelShaderManager::SetConstants()
s_nTexDimsChanged = 0;
}
+ if ((api_type & API_D3D9) && s_nVirtualTexScalesChanged)
+ {
+ for (int i = 0; i < 8; i += 2)
+ {
+ if (s_nVirtualTexScalesChanged & (3<<i))
+ SetPSVirtualTexScalePair(i/2);
+ }
+ s_nVirtualTexScalesChanged = 0;
+ }
+
if (s_bAlphaChanged)
{
SetPSConstant4f(C_ALPHA, (lastAlpha&0xff)/255.0f, ((lastAlpha>>8)&0xff)/255.0f, 0, ((lastAlpha>>16)&0xff)/255.0f);
@@ -338,6 +352,13 @@ void PixelShaderManager::SetPSTextureDims(int texid)
SetPSConstant4fv(C_TEXDIMS + texid, fdims);
}
+void PixelShaderManager::SetPSVirtualTexScalePair(int texpairid)
+{
+ PRIM_LOG("vtexscale%d: %f %f %f %f\n", texpairid, lastVirtualTexScales[texpairid*4], lastVirtualTexScales[texpairid*4+1],
+ lastVirtualTexScales[texpairid*4+2], lastVirtualTexScales[texpairid*4+3]);
+ SetPSConstant4fv(C_VTEXSCALE + texpairid, &lastVirtualTexScales[texpairid*4]);
+}
+
// This one is high in profiles (0.5%). TODO: Move conversion out, only store the raw color value
// and update it when the shader constant is set, only.
void PixelShaderManager::SetColorChanged(int type, int num, bool high)
@@ -376,14 +397,25 @@ void PixelShaderManager::SetDestAlpha(const ConstantAlpha& alpha)
}
}
-void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt)
+void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type)
{
u32 wh = width | (height << 16) | (wraps << 28) | (wrapt << 30);
- if (lastTexDims[texmapid] != wh)
+
+ bool refresh = lastTexDims[texmapid] != wh;
+ if (api_type & API_D3D9)
{
- lastTexDims[texmapid] = wh;
+ refresh |= (lastVirtualTexScales[texmapid*2] != (float)width / (float)virtual_width);
+ refresh |= (lastVirtualTexScales[texmapid*2+1] != (float)height / (float)virtual_height);
+ }
+
+ if (refresh)
+ {
+ lastTexDims[texmapid] = wh;
+ lastVirtualTexScales[texmapid*2] = (float)width / (float)virtual_width;
+ lastVirtualTexScales[texmapid*2+1] = (float)height / (float)virtual_height;
s_nTexDimsChanged |= 1 << texmapid;
- }
+ s_nVirtualTexScalesChanged |= 1 << texmapid;
+ }
}
void PixelShaderManager::SetZTextureBias(u32 bias)
diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.h b/Source/Core/VideoCommon/Src/PixelShaderManager.h
index 2d1c01cad6..5cbe86cae4 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderManager.h
+++ b/Source/Core/VideoCommon/Src/PixelShaderManager.h
@@ -26,18 +26,20 @@
class PixelShaderManager
{
static void SetPSTextureDims(int texid);
+ static void SetPSVirtualTexScalePair(int texpairid);
+
public:
static void Init();
static void Dirty();
static void Shutdown();
- static void SetConstants(); // sets pixel shader constants
+ static void SetConstants(API_TYPE api_type); // sets pixel shader constants
// constant management, should be called after memory is committed
static void SetColorChanged(int type, int index, bool high);
static void SetAlpha(const AlphaFunc& alpha);
static void SetDestAlpha(const ConstantAlpha& alpha);
- static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt);
+ static void SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type);
static void SetZTextureBias(u32 bias);
static void SetViewportChanged();
static void SetIndMatrixChanged(int matrixidx);
diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp
index d89e582860..3b06bbb1c0 100644
--- a/Source/Core/VideoCommon/Src/RenderBase.cpp
+++ b/Source/Core/VideoCommon/Src/RenderBase.cpp
@@ -42,6 +42,7 @@
#include "Host.h"
#include "XFMemory.h"
#include "FifoPlayer/FifoRecorder.h"
+#include "AVIDump.h"
#include <cmath>
#include <string>
@@ -52,7 +53,6 @@ int OSDChoice, OSDTime;
Renderer *g_renderer = NULL;
-bool s_bLastFrameDumped = false;
std::mutex Renderer::s_criticalScreenshot;
std::string Renderer::s_sScreenshotName;
@@ -81,15 +81,28 @@ bool Renderer::s_EnableDLCachingAfterRecording;
unsigned int Renderer::prev_efb_format = (unsigned int)-1;
-Renderer::Renderer()
+Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false)
{
UpdateActiveConfig();
+
+#if defined _WIN32 || defined HAVE_LIBAV
+ bAVIDumping = false;
+#endif
}
Renderer::~Renderer()
{
// invalidate previous efb format
prev_efb_format = (unsigned int)-1;
+
+#if defined _WIN32 || defined HAVE_LIBAV
+ if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && bAVIDumping)
+ AVIDump::Stop();
+#else
+ if (pFrameDump.IsOpen())
+ pFrameDump.Close();
+#endif
+ delete[] frame_data;
}
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)
diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h
index 17132ebb8c..e8d4c55a20 100644
--- a/Source/Core/VideoCommon/Src/RenderBase.h
+++ b/Source/Core/VideoCommon/Src/RenderBase.h
@@ -41,7 +41,7 @@
extern int frameCount;
extern int OSDChoice, OSDTime;
-extern bool s_bLastFrameDumped;
+extern bool bLastFrameDumped;
// Renderer really isn't a very good name for this class - it's more like "Misc".
// The long term goal is to get rid of this class and replace it with others that make
@@ -54,7 +54,7 @@ public:
virtual void SetColorMask() = 0;
virtual void SetBlendMode(bool forceUpdate) = 0;
- virtual bool SetScissorRect() = 0;
+ virtual void SetScissorRect(const TargetRectangle& rc) = 0;
virtual void SetGenerationMode() = 0;
virtual void SetDepthMode() = 0;
virtual void SetLogicOpMode() = 0;
@@ -132,9 +132,6 @@ public:
protected:
- static std::mutex s_criticalScreenshot;
- static std::string s_sScreenshotName;
-
static void CalculateTargetScale(int x, int y, int &scaledX, int &scaledY);
static bool CalculateTargetSize(int multiplier = 1);
static void CalculateXYScale(const TargetRectangle& dst_rect);
@@ -143,6 +140,16 @@ protected:
static void RecordVideoMemory();
static volatile bool s_bScreenshot;
+ static std::mutex s_criticalScreenshot;
+ static std::string s_sScreenshotName;
+
+#if defined _WIN32 || defined HAVE_LIBAV
+ bool bAVIDumping;
+#else
+ File::IOFile pFrameDump;
+#endif
+ char* frame_data;
+ bool bLastFrameDumped;
// The framebuffer size
static int s_target_width;
@@ -175,16 +182,4 @@ extern Renderer *g_renderer;
void UpdateViewport(Matrix44& vpCorrection);
-template <typename R>
-void GetScissorRect(MathUtil::Rectangle<R> &rect)
-{
- const int xoff = bpmem.scissorOffset.x * 2 - 342;
- const int yoff = bpmem.scissorOffset.y * 2 - 342;
-
- rect.left = (R)(bpmem.scissorTL.x - xoff - 342);
- rect.top = (R)(bpmem.scissorTL.y - yoff - 342);
- rect.right = (R)(bpmem.scissorBR.x - xoff - 341);
- rect.bottom = (R)(bpmem.scissorBR.y - yoff - 341);
-}
-
#endif // _COMMON_RENDERBASE_H_
diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
index d3b7ca14ba..00ff9610be 100644
--- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
@@ -1,3 +1,19 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
#include "MemoryUtil.h"
@@ -23,28 +39,19 @@ enum
TextureCache *g_texture_cache;
- GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
+GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
TextureCache::TexCache TextureCache::textures;
bool TextureCache::DeferredInvalidate;
TextureCache::TCacheEntryBase::~TCacheEntryBase()
{
- if (0 == addr)
- return;
-
- if (!isRenderTarget && !g_ActiveConfig.bSafeTextureCache)
- {
- u32 *const ptr = (u32*)Memory::GetPointer(addr);
- if (ptr && *ptr == hash)
- *ptr = oldpixel;
- }
}
TextureCache::TextureCache()
{
if (!temp)
- temp =(u8*) AllocateAlignedMemory(TEMP_SIZE,16);
+ temp = (u8*)AllocateAlignedMemory(TEMP_SIZE,16);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures)
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
@@ -88,12 +95,11 @@ TextureCache::~TextureCache()
void TextureCache::Cleanup()
{
- TexCache::iterator
- iter = textures.begin(),
- tcend = textures.end();
+ TexCache::iterator iter = textures.begin();
+ TexCache::iterator tcend = textures.end();
while (iter != tcend)
{
- if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
+ if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) // TODO: Deleting EFB copies might not be a good idea here...
{
delete iter->second;
textures.erase(iter++);
@@ -135,7 +141,7 @@ void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
if (0 == rangePosition)
{
- iter->second->hash = 0;
+ iter->second->SetHashes(TEXHASH_INVALID);
}
}
}
@@ -166,20 +172,19 @@ void TextureCache::ClearRenderTargets()
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
+
for (; iter!=tcend; ++iter)
- iter->second->isRenderTarget = false;
+ if (iter->second->type != TCET_EC_DYNAMIC)
+ iter->second->type = TCET_NORMAL;
}
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
u32 address, unsigned int width, unsigned int height, int texformat,
- unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel)
+ unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem)
{
- // necessary?
if (0 == address)
return NULL;
- u8* ptr = Memory::GetPointer(address);
-
// TexelSizeInNibbles(format)*width*height/16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
@@ -188,111 +193,85 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int expandedHeight = (height + bsh) & (~bsh);
const unsigned int nativeW = width;
const unsigned int nativeH = height;
- bool isPow2;
- u64 hash_value = 0;
- u64 texHash = 0;
u32 texID = address;
+ u64 tex_hash = TEXHASH_INVALID; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
+ u64 tlut_hash = TEXHASH_INVALID;
+
u32 full_format = texformat;
- const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
- const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
- bool texture_is_dynamic = false;
- unsigned int texLevels;
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);
-
if (isPaletteTexture)
full_format = texformat | (tlutfmt << 16);
- // hires texture loading and texture dumping require accurate hashes
- if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
- {
- texHash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
-
- if (isPaletteTexture)
- {
- // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
- // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
- // This trick (to change the texID depending on the TLUT addr) is a trick to get around
- // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
- // each other stored in a single texture, and uses the palette to make different characters
- // visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
- // we must make sure that texture with different tluts get different IDs.
-
- const u64 tlutHash = GetHash64(texMem + tlutaddr, palette_size,
- g_ActiveConfig.iSafeTextureCache_ColorSamples);
-
- texHash ^= tlutHash;
-
- if (g_ActiveConfig.bSafeTextureCache)
- texID ^= ((u32)tlutHash) ^ (u32)(tlutHash >> 32);
- }
+ const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
+ u8* src_data;
+ if (from_tmem) src_data = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE];
+ else src_data = Memory::GetPointer(address);
- if (g_ActiveConfig.bSafeTextureCache)
- hash_value = texHash;
+ tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
+ if (isPaletteTexture)
+ {
+ const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
+ tlut_hash = GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
+
+ // NOTE: For non-paletted textures, texID is equal to the texture address.
+ // A paletted texture, however, may have multiple texIDs assigned though depending on the currently used tlut.
+ // This (changing texID depending on the tlut_hash) is a trick to get around
+ // an issue with Metroid Prime's fonts (it has multiple sets of fonts on each other
+ // stored in a single texture and uses the palette to make different characters
+ // visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
+ // we must make sure that a paletted texture gets assigned multiple IDs for each tlut used.
+ //
+ // TODO: Because texID isn't always the same as the address now, CopyRenderTargetToTexture might be broken now
+ texID ^= ((u32)tlut_hash) ^(u32)(tlut_hash >> 32);
+ tex_hash ^= tlut_hash;
}
TCacheEntryBase *entry = textures[texID];
if (entry)
{
- if (!g_ActiveConfig.bSafeTextureCache)
+ // 1. Calculate reference hash:
+ // calculated from RAM texture data for normal textures. Hashes for paletted textures are modified by tlut_hash. 0 for virtual EFB copies.
+ if (g_ActiveConfig.bCopyEFBToTexture && entry->IsEfbCopy())
+ tex_hash = TEXHASH_INVALID;
+
+ // 2. a) For EFB copies, only the hash and the texture address need to match
+ if (entry->IsEfbCopy() && tex_hash == entry->hash && address == entry->addr)
{
- if (entry->isRenderTarget || entry->isDynamic)
- {
- if (!g_ActiveConfig.bCopyEFBToTexture)
- {
- hash_value = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
+ if (entry->type != TCET_EC_VRAM)
+ entry->type = TCET_NORMAL;
- if (isPaletteTexture)
- {
- hash_value ^= GetHash64(&texMem[tlutaddr], palette_size,
- g_ActiveConfig.iSafeTextureCache_ColorSamples);
- }
- }
- else
- {
- hash_value = 0;
- }
- }
- else
- {
- hash_value = *(u32*)ptr;
- }
+ // TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
+ goto return_entry;
}
- else if ((entry->isRenderTarget || entry->isDynamic) && g_ActiveConfig.bCopyEFBToTexture)
+
+ // 2. b) For normal textures, all texture parameters need to match
+ if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
+ entry->num_mipmaps == maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
{
- hash_value = 0;
+ goto return_entry;
}
- if (((entry->isRenderTarget || entry->isDynamic) && hash_value == entry->hash && address == entry->addr)
- || ((address == entry->addr) && (hash_value == entry->hash) && full_format == entry->format && entry->mipLevels == maxlevel))
+ // 3. If we reach this line, we'll have to upload the new texture data to VRAM.
+ // If we're lucky, the texture parameters didn't change and we can reuse the internal texture object instead of destroying and recreating it.
+ //
+ // TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
+ // TODO: Actually, it should be enough if the internal texture format matches...
+ if ((entry->type == TCET_NORMAL && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
+ || (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
{
- entry->isDynamic = false;
- goto return_entry;
+ // reuse the texture
}
else
{
- // Let's reload the new texture data into the same texture,
- // instead of destroying it and having to create a new one.
- // Might speed up movie playback very, very slightly.
- texture_is_dynamic = (entry->isRenderTarget || entry->isDynamic) && !g_ActiveConfig.bCopyEFBToTexture;
-
- if (!entry->isRenderTarget &&
- ((!entry->isDynamic && width == entry->realW && height == entry->realH && full_format == entry->format && entry->mipLevels == maxlevel)
- || (entry->isDynamic && entry->realW == width && entry->realH == height)))
- {
- // reuse the texture
- }
- else
- {
- // delete the texture and make a new one
- delete entry;
- entry = NULL;
- }
+ // delete the texture and make a new one
+ delete entry;
+ entry = NULL;
}
}
-
+
if (g_ActiveConfig.bHiresTextures)
{
// Load Custom textures
@@ -301,23 +280,24 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int newWidth = width;
unsigned int newHeight = height;
- sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
+ sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
pcfmt = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, temp);
if (pcfmt != PC_TEX_FMT_NONE)
{
expandedWidth = width = newWidth;
expandedHeight = height = newHeight;
-
- // TODO: shouldn't generating mips be forced on now?
- // native mips with a custom texture wouldn't make sense
}
}
+ // TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled
if (pcfmt == PC_TEX_FMT_NONE)
- pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth,
- expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
+ pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
+ expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
+ bool isPow2;
+ unsigned int texLevels;
+ UseNativeMips = UseNativeMips && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
isPow2 = !((width & (width - 1)) || (height & (height - 1)));
texLevels = (isPow2 && UseNativeMips && maxlevel) ?
GetPow2(std::max(width, height)) : !isPow2;
@@ -329,40 +309,27 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
if (NULL == entry) {
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
- // Sometimes, we can get around recreating a texture if only the number of mip levels gets changes
+ // Sometimes, we can get around recreating a texture if only the number of mip levels changes
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
- entry->mipLevels = maxlevel;
+ //
+ // TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
+ entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
+ entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
}
- entry->addr = address;
- entry->format = full_format;
- entry->size_in_bytes = texture_size;
-
- entry->virtualW = width;
- entry->virtualH = height;
-
- entry->realW = nativeW;
- entry->realH = nativeH;
-
- entry->isRenderTarget = false;
- entry->isNonPow2 = false;
- entry->isDynamic = texture_is_dynamic;
-
- entry->oldpixel = *(u32*)ptr;
-
- if (g_ActiveConfig.bSafeTextureCache || entry->isDynamic)
- entry->hash = hash_value;
- else
- // don't like rand() here
- entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
+ entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
+ entry->SetDimensions(nativeW, nativeH, width, height);
+ entry->hash = tex_hash;
+ if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_EC_DYNAMIC;
+ else entry->type = TCET_NORMAL;
// load texture
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
- // load mips
+ // load mips - TODO: Loading mipmaps from tmem is untested!
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
{
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
@@ -370,20 +337,31 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int level = 1;
unsigned int mipWidth = (width + 1) >> 1;
unsigned int mipHeight = (height + 1) >> 1;
- ptr += texture_size;
+
+ u8* ptr_even = NULL, *ptr_odd = NULL;
+ if (from_tmem)
+ {
+ ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
+ ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
+ }
+ src_data += texture_size;
while ((mipHeight || mipWidth) && (level < texLevels))
{
+ u8** ptr;
+ if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even;
+ else ptr = &src_data;
+
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
expandedWidth = (currentWidth + bsw) & (~bsw);
expandedHeight = (currentHeight + bsh) & (~bsh);
- TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
- entry->Load(currentWidth, currentHeight, expandedWidth, level);
+ TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
+ entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
- ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
+ *ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
mipWidth >>= 1;
mipHeight >>= 1;
++level;
@@ -404,7 +382,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(),
- (u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
+ (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
if (false == File::Exists(szTemp))
entry->Save(szTemp);
@@ -426,10 +404,49 @@ return_entry:
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
+ // Emulation methods:
+ // - EFB to RAM:
+ // Encodes the requested EFB data at its native resolution to the emulated RAM using shaders.
+ // Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being used as a texture again.
+ // Advantage: CPU can read data from the EFB copy and we don't lose any important updates to the texture
+ // Disadvantage: Encoding+decoding steps often are redundant because only some games read or modify EFB copies before using them as textures.
+ // - EFB to texture:
+ // Copies the requested EFB data to a texture object in VRAM, performing any color conversion using shaders.
+ // Advantage: Works for many games, since in most cases EFB copies aren't read or modified at all before being used as a texture again.
+ // Since we don't do any further encoding or decoding here, this method is much faster.
+ // It also allows enhancing the visual quality by doing scaled EFB copies.
+ // - hybrid EFB copies:
+ // 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to RAM)
+ // 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address range.
+ // If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB copies.
+ // 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB copy was triggered to that address before):
+ // 2a) Entry doesn't exist:
+ // - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture)
+ // - Create a texture cache entry for the target (type = TCET_EC_VRAM)
+ // - Store a hash of the encoded RAM data in the texcache entry.
+ // 2b) Entry exists AND type is TCET_EC_VRAM:
+ // - Like case 2a, but reuse the old texcache entry instead of creating a new one.
+ // 2c) Entry exists AND type is TCET_EC_DYNAMIC:
+ // - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in the existing texcache entry.
+ // - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up deleting it and reloading the data from RAM anyway.
+ // 3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you stored when encoding the EFB data to RAM.
+ // 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created
+ // 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to TCET_EC_DYNAMIC.
+ // Redecode the source RAM data to a VRAM object. The entry basically behaves like a normal texture now.
+ // 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture.
+ // Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture.
+ // Compatibility is as good as EFB to RAM.
+ // Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM.
+ // EFB copy cache depends on accurate texture hashing being enabled. However, with accurate hashing you end up being as slow as without a copy cache anyway.
+ //
+ // Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush which stalls any further CPU processing.
+ //
+ // For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies.
+
float colmat[28] = {0};
float *const fConstAdd = colmat + 16;
float *const ColorMask = colmat + 20;
- ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f;
+ ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f;
ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f;
unsigned int cbufid = -1;
@@ -437,7 +454,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
{
switch (dstFormat)
{
- case 0: // Z4
+ case 0: // Z4
colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f;
cbufid = 0;
break;
@@ -447,7 +464,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
cbufid = 1;
break;
- case 3: // Z16
+ case 3: // Z16
colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
cbufid = 24;
break;
@@ -472,8 +489,10 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
cbufid = 5;
break;
- case 12: // Z16L
- colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
+ case 12: // Z16L - copy lower 16 depth bits
+ // expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha)
+ // Used e.g. in Zelda: Skyward Sword
+ colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
cbufid = 6;
break;
@@ -483,7 +502,6 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
cbufid = 7;
break;
}
-
}
else if (isIntensity)
{
@@ -627,15 +645,18 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w;
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;
- bool texture_is_dynamic = false;
TCacheEntryBase *entry = textures[dstAddr];
if (entry)
{
- if ((entry->isRenderTarget && entry->virtualW == scaled_tex_w && entry->virtualH == scaled_tex_h)
- || (entry->isDynamic && entry->realW == tex_w && entry->realH == tex_h))
+ if ((entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h)
+ || (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h))
{
- texture_is_dynamic = entry->isDynamic;
+ if (entry->type == TCET_EC_DYNAMIC)
+ {
+ scaled_tex_w = tex_w;
+ scaled_tex_h = tex_h;
+ }
}
else
{
@@ -645,32 +666,16 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
}
}
- if (texture_is_dynamic)
- {
- scaled_tex_w = tex_w;
- scaled_tex_h = tex_h;
- }
-
if (NULL == entry)
{
// create the texture
textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
- entry->addr = dstAddr;
- entry->hash = 0;
-
- entry->realW = tex_w;
- entry->realH = tex_h;
-
- entry->virtualW = scaled_tex_w;
- entry->virtualH = scaled_tex_h;
-
- entry->format = dstFormat;
- entry->mipLevels = 0;
-
- entry->isRenderTarget = true;
- entry->isNonPow2 = true;
- entry->isDynamic = false;
+ // TODO: Using the wrong dstFormat, dumb...
+ entry->SetGeneralParameters(dstAddr, 0, dstFormat, 0);
+ entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
+ entry->SetHashes(TEXHASH_INVALID);
+ entry->type = TCET_EC_VRAM;
}
entry->frameCount = frameCount;
diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h
index 1c86e64006..2924c5871f 100644
--- a/Source/Core/VideoCommon/Src/TextureCacheBase.h
+++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h
@@ -1,3 +1,19 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
#ifndef _TEXTURECACHEBASE_H
#define _TEXTURECACHEBASE_H
@@ -14,47 +30,56 @@
class TextureCache
{
public:
+ enum TexCacheEntryType
+ {
+ TCET_NORMAL,
+ TCET_EC_VRAM, // EFB copy which sits in VRAM and is ready to be used
+ TCET_EC_DYNAMIC, // EFB copy which sits in RAM and needs to be decoded before being used
+ };
+
struct TCacheEntryBase
{
- // TODO: organize
+#define TEXHASH_INVALID 0
+
+ // common members
u32 addr;
u32 size_in_bytes;
u64 hash;
- //u32 paletteHash;
- u32 oldpixel;
+ //u32 pal_hash;
u32 format;
-
+
+ enum TexCacheEntryType type;
+
+ unsigned int num_mipmaps;
+ unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
+ unsigned int virtual_width, virtual_height; // Texture dimensions from OUR point of view - for hires textures or scaled EFB copies
+
+ // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames
int frameCount;
- unsigned int realW, realH; // Texture dimensions from the GameCube's point of view
- unsigned int virtualW, virtualH; // Texture dimensions from OUR point of view
- // Real and virtual dimensions are usually the same, but may be
- // different if e.g. we use high-res textures. Then, realW,realH will
- // be the dimensions of the original GameCube texture and
- // virtualW,virtualH will be the dimensions of the high-res texture.
-
- unsigned int mipLevels;
-
- bool isRenderTarget; // copied from EFB
- bool isDynamic; // Used for hybrid EFB copies to enable checks for CPU modifications
- bool isNonPow2; // doesn't seem to be used anywhere
-
- //TCacheEntryBase()
- //{
- // // TODO: remove these
- // isRenderTarget = 0;
- // hash = 0;
- // //paletteHash = 0;
- // oldpixel = 0;
- // addr = 0;
- // size_in_bytes = 0;
- // frameCount = 0;
- // isNonPow2 = true;
- // w = 0;
- // h = 0;
- // scaledW = 0;
- // scaledH = 0;
- //}
+
+ void SetGeneralParameters(u32 addr, u32 size, u32 format, unsigned int num_mipmaps)
+ {
+ this->addr = addr;
+ this->size_in_bytes = size;
+ this->format = format;
+ this->num_mipmaps = num_mipmaps;
+ }
+
+ void SetDimensions(unsigned int native_width, unsigned int native_height, unsigned int virtual_width, unsigned int virtual_height)
+ {
+ this->native_width = native_width;
+ this->native_height = native_height;
+ this->virtual_width = virtual_width;
+ this->virtual_height = virtual_height;
+ }
+
+ void SetHashes(u64 hash/*, u32 pal_hash*/)
+ {
+ this->hash = hash;
+ //this->pal_hash = pal_hash;
+ }
+
virtual ~TCacheEntryBase();
@@ -62,13 +87,15 @@ public:
virtual bool Save(const char filename[]) = 0;
virtual void Load(unsigned int width, unsigned int height,
- unsigned int expanded_width, unsigned int level, bool autogen_mips = false) = 0;
+ unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat) = 0;
int IntersectsMemoryRange(u32 range_address, u32 range_size) const;
+
+ bool IsEfbCopy() { return (type == TCET_EC_VRAM || type == TCET_EC_DYNAMIC); }
};
virtual ~TextureCache(); // needs virtual for DX11 dtor
@@ -87,7 +114,7 @@ public:
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
- int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel);
+ int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
diff --git a/Source/Core/VideoCommon/Src/TextureDecoder.h b/Source/Core/VideoCommon/Src/TextureDecoder.h
index d990d21545..1901c86d27 100644
--- a/Source/Core/VideoCommon/Src/TextureDecoder.h
+++ b/Source/Core/VideoCommon/Src/TextureDecoder.h
@@ -20,8 +20,8 @@
#include "Hash.h"
enum
{
- TMEM_SIZE = 1024*1024,
- HALFTMEM_SIZE = 512*1024
+ TMEM_SIZE = 1024*1024,
+ TMEM_LINE_SIZE = 32,
};
extern GC_ALIGNED16(u8 texMem[TMEM_SIZE]);
diff --git a/Source/Core/VideoCommon/Src/VertexLoader.cpp b/Source/Core/VideoCommon/Src/VertexLoader.cpp
index ce9e81219d..fb34ce1bc1 100644
--- a/Source/Core/VideoCommon/Src/VertexLoader.cpp
+++ b/Source/Core/VideoCommon/Src/VertexLoader.cpp
@@ -101,7 +101,7 @@ void LOADERDECL PosMtx_Write()
void LOADERDECL UpdateBoundingBox()
{
- if (!PixelEngine::bbox_active)
+ if (!PixelEngine::bbox_active)
return;
// Truly evil hack, reading backwards from the write pointer. If we were writing to write-only
@@ -111,7 +111,7 @@ void LOADERDECL UpdateBoundingBox()
// Then convert to screen space and update the bounding box.
float p[3] = {data[0], data[1], data[2]};
- const float *world_matrix = (float*)xfmem + MatrixIndexA.PosNormalMtxIdx * 4;
+ const float *world_matrix = (float*)xfmem + MatrixIndexA.PosNormalMtxIdx * 4;
const float *proj_matrix = &g_fProjectionMatrix[0];
float t[3];
@@ -119,40 +119,23 @@ void LOADERDECL UpdateBoundingBox()
t[1] = p[0] * world_matrix[4] + p[1] * world_matrix[5] + p[2] * world_matrix[6] + world_matrix[7];
t[2] = p[0] * world_matrix[8] + p[1] * world_matrix[9] + p[2] * world_matrix[10] + world_matrix[11];
- float o[4];
- o[2] = t[0] * proj_matrix[8] + t[1] * proj_matrix[9] + t[2] * proj_matrix[10] + proj_matrix[11];
- // Depth culling
- if (o[2] < 0.0) {
- // No pixels are likely to be drawn - don't update bounding box.
- return;
- }
+ float o[3];
o[0] = t[0] * proj_matrix[0] + t[1] * proj_matrix[1] + t[2] * proj_matrix[2] + proj_matrix[3];
o[1] = t[0] * proj_matrix[4] + t[1] * proj_matrix[5] + t[2] * proj_matrix[6] + proj_matrix[7];
- o[3] = t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15];
-
- o[0] /= o[3];
- o[1] /= o[3];
-
- // should possibly adjust for viewport?
- o[0] = (o[0] + 1.0f) * 320.0f;
- o[1] = (o[1] + 1.0f) * 240.0f;
-
- if (o[0] < PixelEngine::bbox[0]) PixelEngine::bbox[0] = (u16)std::max(0.0f, o[0]);
- if (o[0] > PixelEngine::bbox[1]) PixelEngine::bbox[1] = (u16)std::min(640.0f, o[0]);
- if (o[1] < PixelEngine::bbox[2]) PixelEngine::bbox[2] = (u16)std::max(0.0f, o[1]);
- if (o[1] > PixelEngine::bbox[3]) PixelEngine::bbox[3] = (u16)std::min(480.0f, o[1]);
-
- // Hardware tests bounding boxes in 2x2 blocks => left and top are even, right and bottom are odd
- PixelEngine::bbox[0] &= ~1;
- PixelEngine::bbox[1] |= 1;
- PixelEngine::bbox[2] &= ~1;
- PixelEngine::bbox[3] |= 1;
-
- /*
- if (GetAsyncKeyState(VK_LSHIFT)) {
- ERROR_LOG(VIDEO, "XForm: %f %f %f to %f %f", p[0], p[1], p[2], o[0], o[1]);
- ERROR_LOG(VIDEO, "%i %i %i %i", g_VideoInitialize.pBBox[0], g_VideoInitialize.pBBox[1], g_VideoInitialize.pBBox[2], g_VideoInitialize.pBBox[3]);
- }*/
+ o[2] = t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15];
+
+ o[0] /= o[2];
+ o[1] /= o[2];
+
+ // Max width seems to be 608, while max height is 480
+ // Here height is set to 484 as BBox bottom always seems to be off by a few pixels
+ o[0] = (o[0] + 1.0f) * 304.0f;
+ o[1] = (1.0f - o[1]) * 242.0f;
+
+ if (o[0] < PixelEngine::bbox[0]) PixelEngine::bbox[0] = (u16) std::max(0.0f, o[0]);
+ if (o[0] > PixelEngine::bbox[1]) PixelEngine::bbox[1] = (u16) o[0];
+ if (o[1] < PixelEngine::bbox[2]) PixelEngine::bbox[2] = (u16) std::max(0.0f, o[1]);
+ if (o[1] > PixelEngine::bbox[3]) PixelEngine::bbox[3] = (u16) o[1];
}
void LOADERDECL TexMtx_ReadDirect_UByte()
@@ -290,9 +273,8 @@ void VertexLoader::CompileVertexTranslator()
// OK, so we just got a point. Let's go back and read it for the bounding box.
-#ifdef BBOX_SUPPORT
- WriteCall(UpdateBoundingBox);
-#endif
+ if(g_ActiveConfig.bUseBBox)
+ WriteCall(UpdateBoundingBox);
// Normals
vtx_decl.num_normals = 0;
diff --git a/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp b/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp
index b8483b119c..06481f9ddf 100644
--- a/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp
+++ b/Source/Core/VideoCommon/Src/VertexLoader_Position.cpp
@@ -179,8 +179,8 @@ void Pos_ReadIndex_Float_SSSE3(int Index)
if(Index < MaxSize)
{
const u32* pData = (const u32 *)(cached_arraybases[ARRAY_POSITION] + (Index * arraystrides[ARRAY_POSITION]));
- const __m128i a = _mm_loadu_si128((__m128i*)pData);
- __m128i b = _mm_shuffle_epi8(a, three ? kMaskSwap32_3 : kMaskSwap32_2);
+ GC_ALIGNED128(const __m128i a = _mm_loadu_si128((__m128i*)pData));
+ GC_ALIGNED128(__m128i b = _mm_shuffle_epi8(a, three ? kMaskSwap32_3 : kMaskSwap32_2));
_mm_storeu_si128((__m128i*)VertexManager::s_pCurBufferPointer, b);
LOG_VTX();
VertexManager::s_pCurBufferPointer += 12;
diff --git a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp
index de853081ed..ba3bb73f43 100644
--- a/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp
+++ b/Source/Core/VideoCommon/Src/VertexLoader_TextCoord.cpp
@@ -353,8 +353,8 @@ void LOADERDECL TexCoord_ReadIndex16_Float2_SSSE3()
{
u16 Index = DataReadU16();
const u32 *pData = (const u32 *)(cached_arraybases[ARRAY_TEXCOORD0+tcIndex] + (Index * arraystrides[ARRAY_TEXCOORD0+tcIndex]));
- const __m128i a = _mm_loadl_epi64((__m128i*)pData);
- const __m128i b = _mm_shuffle_epi8(a, kMaskSwap32);
+ GC_ALIGNED128(const __m128i a = _mm_loadl_epi64((__m128i*)pData));
+ GC_ALIGNED128(const __m128i b = _mm_shuffle_epi8(a, kMaskSwap32));
u8* p = VertexManager::s_pCurBufferPointer;
_mm_storel_epi64((__m128i*)p, b);
LOG_TEX2();
diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
index 747b95c0da..5076f9f044 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
@@ -26,25 +26,19 @@
#include "VertexShaderGen.h"
#include "VideoConfig.h"
-VERTEXSHADERUID last_vertex_shader_uid;
-
// Mash together all the inputs that contribute to the code of a generated vertex shader into
// a unique identifier, basically containing all the bits. Yup, it's a lot ....
void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components)
{
+ memset(uid->values, 0, sizeof(uid->values));
uid->values[0] = components |
(xfregs.numTexGen.numTexGens << 23) |
(xfregs.numChan.numColorChans << 27) |
(xfregs.dualTexTrans.enabled << 29);
- for (int i = 0; i < 2; ++i) {
- uid->values[1+i] = xfregs.color[i].enablelighting ?
- (u32)xfregs.color[i].hex :
- (u32)xfregs.color[i].matsource;
- uid->values[1+i] |= (xfregs.alpha[i].enablelighting ?
- (u32)xfregs.alpha[i].hex :
- (u32)xfregs.alpha[i].matsource) << 15;
- }
+ // TODO: If pixel lighting is enabled, do we even have to bother about storing lighting related registers here?
+ GetLightingShaderId(&uid->values[1]);
+
uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31;
u32 *pcurvalue = &uid->values[3];
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) {
@@ -69,6 +63,69 @@ void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components)
}
}
+void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components)
+{
+ // Just store all used registers here without caring whether we need all bits or less.
+ memset(uid->values, 0, sizeof(uid->values));
+ u32* ptr = uid->values;
+ *ptr++ = components;
+ *ptr++ = xfregs.numTexGen.hex;
+ *ptr++ = xfregs.numChan.hex;
+ *ptr++ = xfregs.dualTexTrans.hex;
+
+ for (int i = 0; i < 2; ++i) {
+ *ptr++ = xfregs.color[i].hex;
+ *ptr++ = xfregs.alpha[i].hex;
+ }
+ *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting;
+ for (unsigned int i = 0; i < 8; ++i) {
+ *ptr++ = xfregs.texMtxInfo[i].hex;
+ *ptr++ = xfregs.postMtxInfo[i].hex;
+ }
+ _assert_((ptr - uid->values) == uid->GetNumValues());
+}
+
+
+void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components)
+{
+ if (!g_ActiveConfig.bEnableShaderDebugging)
+ return;
+
+ VERTEXSHADERUIDSAFE new_id;
+ GetSafeVertexShaderId(&new_id, components);
+
+ if (!(old_id == new_id))
+ {
+ std::string new_code(GenerateVertexShaderCode(components, api));
+ if (old_code != new_code)
+ {
+ _assert_(old_id.GetNumValues() == new_id.GetNumValues());
+
+ char msg[8192];
+ char* ptr = msg;
+ ptr += sprintf(ptr, "Vertex shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n");
+ const int N = new_id.GetNumValues();
+ for (int i = 0; i < N/2; ++i)
+ ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1],
+ new_id.values[2*i], new_id.values[2*i+1]);
+ if (N % 2)
+ ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]);
+
+ static int num_failures = 0;
+ char szTemp[MAX_PATH];
+ sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
+ std::ofstream file(szTemp);
+ file << msg;
+ file << "\n\nOld shader code:\n" << old_code;
+ file << "\n\nNew shader code:\n" << new_code;
+ file.close();
+
+ PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp);
+ }
+ }
+}
+
+
static char text[16384];
#define WRITE p+=sprintf
@@ -244,7 +301,8 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type)
else
WRITE(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
}
-
+
+ // TODO: This probably isn't necessary if pixel lighting is enabled.
p = GenerateLightingShader(p, components, I_MATERIALS, I_LIGHTS, "color", "o.colors_");
if(xfregs.numChan.numColorChans < 2)
diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h
index d7bf362213..0c522286b1 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderGen.h
+++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h
@@ -48,17 +48,18 @@
#define C_DEPTHPARAMS (C_POSTTRANSFORMMATRICES + 64)
#define C_VENVCONST_END (C_DEPTHPARAMS + 4)
-class VERTEXSHADERUID
+template<bool safe>
+class _VERTEXSHADERUID
{
+#define NUM_VSUID_VALUES_SAFE 25
public:
- u32 values[9];
+ u32 values[safe ? NUM_VSUID_VALUES_SAFE : 9];
- VERTEXSHADERUID()
+ _VERTEXSHADERUID()
{
- memset(values, 0, sizeof(values));
}
- VERTEXSHADERUID(const VERTEXSHADERUID& r)
+ _VERTEXSHADERUID(const _VERTEXSHADERUID& r)
{
for (size_t i = 0; i < sizeof(values) / sizeof(u32); ++i)
values[i] = r.values[i];
@@ -66,10 +67,11 @@ public:
int GetNumValues() const
{
- return (((values[0] >> 23) & 0xf) * 3 + 3) / 4 + 3; // numTexGens*3/4+1
+ if (safe) return NUM_VSUID_VALUES_SAFE;
+ else return (((values[0] >> 23) & 0xf) * 3 + 3) / 4 + 3; // numTexGens*3/4+1
}
- bool operator <(const VERTEXSHADERUID& _Right) const
+ bool operator <(const _VERTEXSHADERUID& _Right) const
{
if (values[0] < _Right.values[0])
return true;
@@ -86,7 +88,7 @@ public:
return false;
}
- bool operator ==(const VERTEXSHADERUID& _Right) const
+ bool operator ==(const _VERTEXSHADERUID& _Right) const
{
if (values[0] != _Right.values[0])
return false;
@@ -99,14 +101,18 @@ public:
return true;
}
};
-
+typedef _VERTEXSHADERUID<false> VERTEXSHADERUID;
+typedef _VERTEXSHADERUID<true> VERTEXSHADERUIDSAFE;
// components is included in the uid.
char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type);
const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type);
+
void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components);
+void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components);
-extern VERTEXSHADERUID last_vertex_shader_uid;
+// Used to make sure that our optimized vertex shader IDs don't lose any possible shader code changes
+void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components);
#endif // GCOGL_VERTEXSHADER_H
diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
index a18829fde2..d7d25c5c85 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
+++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp
@@ -150,6 +150,12 @@ void VertexShaderManager::Init()
memset(&xfregs, 0, sizeof(xfregs));
memset(xfmem, 0, sizeof(xfmem));
ResetView();
+
+ // TODO: should these go inside ResetView()?
+ Matrix44::LoadIdentity(s_viewportCorrection);
+ memset(g_fProjectionMatrix, 0, sizeof(g_fProjectionMatrix));
+ for (int i = 0; i < 4; ++i)
+ g_fProjectionMatrix[i*5] = 1.0f;
}
void VertexShaderManager::Shutdown()
diff --git a/Source/Core/VideoCommon/Src/VideoCommon.h b/Source/Core/VideoCommon/Src/VideoCommon.h
index 030c1f0b32..9f6dd59cd3 100644
--- a/Source/Core/VideoCommon/Src/VideoCommon.h
+++ b/Source/Core/VideoCommon/Src/VideoCommon.h
@@ -56,12 +56,6 @@ enum
MAX_XFB_HEIGHT = 574
};
-// If this is enabled, bounding boxes will be computed for everything drawn.
-// This can theoretically have a big speed hit in some geom heavy games. Needs more work.
-// Helps some effects in Paper Mario (but they aren't quite right yet).
-// Do testing to figure out if the speed hit is bad?
-// #define BBOX_SUPPORT
-
// Logging
// ----------
void HandleGLError();
@@ -70,8 +64,7 @@ void HandleGLError();
// This structure should only be used to represent a rectangle in EFB
// coordinates, where the origin is at the upper left and the frame dimensions
// are 640 x 528.
-struct EFBRectangle : public MathUtil::Rectangle<int>
-{};
+typedef MathUtil::Rectangle<int> EFBRectangle;
// This structure should only be used to represent a rectangle in standard target
// coordinates, where the origin is at the lower left and the frame dimensions
diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp
index 8bad7b005a..5bb6e4dd99 100644
--- a/Source/Core/VideoCommon/Src/VideoConfig.cpp
+++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp
@@ -57,12 +57,8 @@ void VideoConfig::Load(const char *ini_file)
iniFile.Get("Settings", "Crop", &bCrop, false);
iniFile.Get("Settings", "UseXFB", &bUseXFB, 0);
iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0);
- iniFile.Get("Settings", "UseNativeMips", &bUseNativeMips, false);
-
- iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, true); // Settings
- //Safe texture cache params
+ iniFile.Get("Settings", "UseNativeMips", &bUseNativeMips, false);
iniFile.Get("Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples,128);
-
iniFile.Get("Settings", "ShowFPS", &bShowFPS, false); // Settings
iniFile.Get("Settings", "ShowInputDisplay", &bShowInputDisplay, false);
iniFile.Get("Settings", "OverlayStats", &bOverlayStats, false);
@@ -96,6 +92,8 @@ void VideoConfig::Load(const char *ini_file)
iniFile.Get("Settings", "EnableOpenCL", &bEnableOpenCL, false);
iniFile.Get("Settings", "OMPDecoder", &bOMPDecoder, false);
+ iniFile.Get("Settings", "EnableShaderDebugging", &bEnableShaderDebugging, false);
+
iniFile.Get("Enhancements", "ForceFiltering", &bForceFiltering, 0);
iniFile.Get("Enhancements", "MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x)
iniFile.Get("Enhancements", "PostProcessingShader", &sPostProcessingShader, "");
@@ -132,7 +130,6 @@ void VideoConfig::GameIniLoad(const char *ini_file)
iniFile.GetIfExists("Video_Settings", "UseXFB", &bUseXFB);
iniFile.GetIfExists("Video_Settings", "UseRealXFB", &bUseRealXFB);
iniFile.GetIfExists("Video_Settings", "UseNativeMips", &bUseNativeMips);
- iniFile.GetIfExists("Video_Settings", "SafeTextureCache", &bSafeTextureCache);
iniFile.GetIfExists("Video_Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples);
iniFile.GetIfExists("Video_Settings", "DLOptimize", &iCompileDLsLevel);
iniFile.GetIfExists("Video_Settings", "HiresTextures", &bHiresTextures);
@@ -170,6 +167,7 @@ void VideoConfig::GameIniLoad(const char *ini_file)
iniFile.GetIfExists("Video", "PH_ZNear", &sPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]);
iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack);
+ iniFile.GetIfExists("Video", "UseBBox", &bUseBBox);
}
void VideoConfig::VerifyValidity()
@@ -193,11 +191,7 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Settings", "UseXFB", bUseXFB);
iniFile.Set("Settings", "UseRealXFB", bUseRealXFB);
iniFile.Set("Settings", "UseNativeMips", bUseNativeMips);
-
- iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache);
- //safe texture cache params
iniFile.Set("Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
-
iniFile.Set("Settings", "ShowFPS", bShowFPS);
iniFile.Set("Settings", "ShowInputDisplay", bShowInputDisplay);
iniFile.Set("Settings", "OverlayStats", bOverlayStats);
@@ -231,6 +225,8 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Settings", "EnableOpenCL", bEnableOpenCL);
iniFile.Set("Settings", "OMPDecoder", bOMPDecoder);
+ iniFile.Set("Settings", "EnableShaderDebugging", bEnableShaderDebugging);
+
iniFile.Set("Enhancements", "ForceFiltering", bForceFiltering);
iniFile.Set("Enhancements", "MaxAnisotropy", iMaxAnisotropy);
iniFile.Set("Enhancements", "PostProcessingShader", sPostProcessingShader);
@@ -274,7 +270,6 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
SET_IF_DIFFERS("Video_Settings", "UseXFB", bUseXFB);
SET_IF_DIFFERS("Video_Settings", "UseRealXFB", bUseRealXFB);
SET_IF_DIFFERS("Video_Settings", "UseNativeMips", bUseNativeMips);
- SET_IF_DIFFERS("Video_Settings", "SafeTextureCache", bSafeTextureCache);
SET_IF_DIFFERS("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
SET_IF_DIFFERS("Video_Settings", "DLOptimize", iCompileDLsLevel);
SET_IF_DIFFERS("Video_Settings", "HiresTextures", bHiresTextures);
diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h
index 92a8b67741..7c846676bb 100644
--- a/Source/Core/VideoCommon/Src/VideoConfig.h
+++ b/Source/Core/VideoCommon/Src/VideoConfig.h
@@ -129,12 +129,12 @@ struct VideoConfig
bool bOSDHotKey;
bool bCopyEFBToTexture;
bool bCopyEFBScaled;
- bool bSafeTextureCache;
int iSafeTextureCache_ColorSamples;
int iPhackvalue[4];
std::string sPhackvalue[2];
float fAspectRatioHackW, fAspectRatioHackH;
bool bZTPSpeedHack; // The Legend of Zelda: Twilight Princess
+ bool bUseBBox;
bool bEnablePixelLighting;
bool bEnablePerPixelDepth;
@@ -147,6 +147,9 @@ struct VideoConfig
// D3D only config, mostly to be merged into the above
int iAdapter;
+ // Debugging
+ bool bEnableShaderDebugging;
+
// Static config per API
// TODO: Move this out of VideoConfig
struct
diff --git a/Source/Core/VideoCommon/Src/VideoState.cpp b/Source/Core/VideoCommon/Src/VideoState.cpp
index 1a23410fcc..b1c1ed0889 100644
--- a/Source/Core/VideoCommon/Src/VideoState.cpp
+++ b/Source/Core/VideoCommon/Src/VideoState.cpp
@@ -60,3 +60,14 @@ void VideoCommon_RunLoop(bool enable)
{
EmulatorState(enable);
}
+
+void VideoCommon_Init()
+{
+ memset(arraybases, 0, sizeof(arraybases));
+ memset(arraystrides, 0, sizeof(arraystrides));
+ memset(&MatrixIndexA, 0, sizeof(MatrixIndexA));
+ memset(&MatrixIndexB, 0, sizeof(MatrixIndexB));
+ memset(&g_VtxDesc, 0, sizeof(g_VtxDesc));
+ memset(g_VtxAttr, 0, sizeof(g_VtxAttr));
+ memset(texMem, 0, TMEM_SIZE);
+}
diff --git a/Source/Core/VideoCommon/Src/VideoState.h b/Source/Core/VideoCommon/Src/VideoState.h
index b29cf17257..e596d9ad05 100644
--- a/Source/Core/VideoCommon/Src/VideoState.h
+++ b/Source/Core/VideoCommon/Src/VideoState.h
@@ -23,5 +23,6 @@
void VideoCommon_DoState(PointerWrap &p);
void VideoCommon_RunLoop(bool enable);
+void VideoCommon_Init();
#endif // _VIDEOSTATE_H
diff --git a/Source/Core/VideoCommon/Src/XFStructs.cpp b/Source/Core/VideoCommon/Src/XFStructs.cpp
index b4afdf3d6b..ec3975cb07 100644
--- a/Source/Core/VideoCommon/Src/XFStructs.cpp
+++ b/Source/Core/VideoCommon/Src/XFStructs.cpp
@@ -154,6 +154,8 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
case XFMEM_SETTEXMTXINFO+5:
case XFMEM_SETTEXMTXINFO+6:
case XFMEM_SETTEXMTXINFO+7:
+ VertexManager::Flush();
+
nextAddress = XFMEM_SETTEXMTXINFO + 8;
break;
@@ -165,6 +167,8 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData)
case XFMEM_SETPOSMTXINFO+5:
case XFMEM_SETPOSMTXINFO+6:
case XFMEM_SETPOSMTXINFO+7:
+ VertexManager::Flush();
+
nextAddress = XFMEM_SETPOSMTXINFO + 8;
break;
diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj
index cf6d8c28a6..dd29d29ccb 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcxproj
+++ b/Source/Core/VideoCommon/VideoCommon.vcxproj
@@ -45,7 +45,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -56,7 +56,6 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>