mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	CPU: HLE implementation of PCDrv (host file access)
This commit is contained in:
		
							parent
							
								
									5439718ec3
								
							
						
					
					
						commit
						84e5fbe0c6
					
				|  | @ -76,6 +76,8 @@ add_library(core | |||
|     negcon.h | ||||
|     pad.cpp | ||||
|     pad.h | ||||
|     pcdrv.cpp | ||||
|     pcdrv.h | ||||
|     pgxp.cpp | ||||
|     pgxp.h | ||||
|     playstation_mouse.cpp | ||||
|  |  | |||
|  | @ -2019,6 +2019,27 @@ bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value) | |||
|   return true; | ||||
| } | ||||
| 
 | ||||
| bool SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length /*= 1024*/) | ||||
| { | ||||
|   value->clear(); | ||||
| 
 | ||||
|   u8 ch; | ||||
|   while (SafeReadMemoryByte(addr, &ch)) | ||||
|   { | ||||
|     if (ch == 0) | ||||
|       return true; | ||||
| 
 | ||||
|     value->push_back(ch); | ||||
|     if (value->size() >= max_length) | ||||
|       return true; | ||||
| 
 | ||||
|     addr++; | ||||
|   } | ||||
| 
 | ||||
|   value->clear(); | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| bool SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value) | ||||
| { | ||||
|   u32 temp = ZeroExtend32(value); | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ | |||
|     <ClCompile Include="negcon.cpp" /> | ||||
|     <ClCompile Include="pad.cpp" /> | ||||
|     <ClCompile Include="controller.cpp" /> | ||||
|     <ClCompile Include="pcdrv.cpp" /> | ||||
|     <ClCompile Include="pgxp.cpp" /> | ||||
|     <ClCompile Include="playstation_mouse.cpp" /> | ||||
|     <ClCompile Include="psf_loader.cpp" /> | ||||
|  | @ -139,6 +140,7 @@ | |||
|     <ClInclude Include="negcon.h" /> | ||||
|     <ClInclude Include="pad.h" /> | ||||
|     <ClInclude Include="controller.h" /> | ||||
|     <ClInclude Include="pcdrv.h" /> | ||||
|     <ClInclude Include="pgxp.h" /> | ||||
|     <ClInclude Include="playstation_mouse.h" /> | ||||
|     <ClInclude Include="psf_loader.h" /> | ||||
|  |  | |||
|  | @ -59,6 +59,7 @@ | |||
|     <ClCompile Include="gpu_hw_d3d12.cpp" /> | ||||
|     <ClCompile Include="host.cpp" /> | ||||
|     <ClCompile Include="game_database.cpp" /> | ||||
|     <ClCompile Include="pcdrv.cpp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="types.h" /> | ||||
|  | @ -125,5 +126,6 @@ | |||
|     <ClInclude Include="achievements.h" /> | ||||
|     <ClInclude Include="game_database.h" /> | ||||
|     <ClInclude Include="input_types.h" /> | ||||
|     <ClInclude Include="pcdrv.h" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
|  | @ -11,6 +11,7 @@ | |||
| #include "cpu_recompiler_thunks.h" | ||||
| #include "gte.h" | ||||
| #include "host.h" | ||||
| #include "pcdrv.h" | ||||
| #include "pgxp.h" | ||||
| #include "settings.h" | ||||
| #include "system.h" | ||||
|  | @ -293,6 +294,20 @@ void RaiseException(Exception excode) | |||
|                  g_state.current_instruction_pc, GetExceptionVector()); | ||||
| } | ||||
| 
 | ||||
| void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits) | ||||
| { | ||||
|   if (PCDrv::HandleSyscall(instruction_bits, g_state.regs)) | ||||
|   { | ||||
|     // immediately return
 | ||||
|     g_state.regs.npc = EPC + 4; | ||||
|     FlushPipeline(); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   // normal exception
 | ||||
|   RaiseException(CAUSE_bits, EPC, GetExceptionVector()); | ||||
| } | ||||
| 
 | ||||
| void SetExternalInterrupt(u8 bit) | ||||
| { | ||||
|   g_state.cop0_regs.cause.Ip |= static_cast<u8>(1u << bit); | ||||
|  | @ -1109,7 +1124,10 @@ restart_instruction: | |||
| 
 | ||||
|         case InstructionFunct::break_: | ||||
|         { | ||||
|           RaiseException(Exception::BP); | ||||
|           RaiseBreakException(Cop0Registers::CAUSE::MakeValueForException( | ||||
|                                 Exception::BP, g_state.current_instruction_in_branch_delay_slot, | ||||
|                                 g_state.current_instruction_was_branch_taken, g_state.current_instruction.cop.cop_n), | ||||
|                               g_state.current_instruction_pc, g_state.current_instruction.bits); | ||||
|         } | ||||
|         break; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include "types.h" | ||||
| #include <array> | ||||
| #include <optional> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| class StateWrapper; | ||||
|  | @ -147,6 +148,7 @@ ALWAYS_INLINE bool InKernelMode() | |||
| bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value); | ||||
| bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value); | ||||
| bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value); | ||||
| bool SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length = 1024); | ||||
| bool SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value); | ||||
| bool SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value); | ||||
| bool SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value); | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ namespace CPU { | |||
| // exceptions
 | ||||
| void RaiseException(Exception excode); | ||||
| void RaiseException(u32 CAUSE_bits, u32 EPC); | ||||
| void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits); | ||||
| 
 | ||||
| ALWAYS_INLINE bool HasPendingInterrupt() | ||||
| { | ||||
|  |  | |||
|  | @ -931,8 +931,17 @@ void CodeGenerator::GenerateExceptionExit(const CodeBlockInstruction& cbi, Excep | |||
|     m_register_cache.FlushAllGuestRegisters(true, true); | ||||
|     m_register_cache.FlushLoadDelay(true); | ||||
| 
 | ||||
|     EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32)>(&CPU::RaiseException), CAUSE_bits, | ||||
|                      GetCurrentInstructionPC()); | ||||
|     if (excode == Exception::BP) | ||||
|     { | ||||
|       EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32, u32)>(&CPU::RaiseBreakException), CAUSE_bits, | ||||
|                        GetCurrentInstructionPC(), Value::FromConstantU32(cbi.instruction.bits)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       EmitFunctionCall(nullptr, static_cast<void (*)(u32, u32)>(&CPU::RaiseException), CAUSE_bits, | ||||
|                        GetCurrentInstructionPC()); | ||||
|     } | ||||
| 
 | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										330
									
								
								src/core/pcdrv.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								src/core/pcdrv.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,330 @@ | |||
| // SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
 | ||||
| // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
 | ||||
| 
 | ||||
| #include "pcdrv.h" | ||||
| #include "common/file_system.h" | ||||
| #include "common/log.h" | ||||
| #include "common/path.h" | ||||
| #include "common/string_util.h" | ||||
| #include "cpu_core.h" | ||||
| #include "settings.h" | ||||
| Log_SetChannel(PCDrv); | ||||
| 
 | ||||
| static constexpr u32 MAX_FILES = 100; | ||||
| 
 | ||||
| static std::vector<FileSystem::ManagedCFilePtr> s_files; | ||||
| 
 | ||||
| enum PCDrvAttribute : u32 | ||||
| { | ||||
|   PCDRV_ATTRIBUTE_READ_ONLY = (1 << 0), | ||||
|   PCDRV_ATTRIBUTE_HIDDEN = (1 << 1), | ||||
|   PCDRV_ATTRIBUTE_SYSTEM = (1 << 2), | ||||
|   PCDRV_ATTRIBUTE_DIRECTORY = (1 << 4), | ||||
|   PCDRV_ATTRIBUTE_ARCHIVE = (1 << 5), | ||||
| }; | ||||
| 
 | ||||
| static s32 GetFreeFileHandle() | ||||
| { | ||||
|   for (s32 i = 0; i < static_cast<s32>(s_files.size()); i++) | ||||
|   { | ||||
|     if (!s_files[i]) | ||||
|       return i; | ||||
|   } | ||||
| 
 | ||||
|   if (s_files.size() >= MAX_FILES) | ||||
|   { | ||||
|     Log_ErrorPrint("Too many open files."); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   const s32 index = static_cast<s32>(s_files.size()); | ||||
|   s_files.emplace_back(nullptr, [](std::FILE*) {}); | ||||
|   return index; | ||||
| } | ||||
| 
 | ||||
| static void CloseAllFiles() | ||||
| { | ||||
|   if (!s_files.empty()) | ||||
|     Log_DevPrintf("Closing %zu open files.", s_files.size()); | ||||
| 
 | ||||
|   s_files.clear(); | ||||
| } | ||||
| 
 | ||||
| static FILE* GetFileFromHandle(u32 handle) | ||||
| { | ||||
|   if (handle >= static_cast<u32>(s_files.size()) || !s_files[handle]) | ||||
|   { | ||||
|     Log_ErrorPrintf("Invalid file handle %d", static_cast<s32>(handle)); | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   return s_files[handle].get(); | ||||
| } | ||||
| 
 | ||||
| static bool CloseFileHandle(u32 handle) | ||||
| { | ||||
|   if (handle >= static_cast<u32>(s_files.size()) || !s_files[handle]) | ||||
|   { | ||||
|     Log_ErrorPrintf("Invalid file handle %d", static_cast<s32>(handle)); | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   s_files[handle].reset(); | ||||
|   while (!s_files.empty() && !s_files.back()) | ||||
|     s_files.pop_back(); | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| static std::string ResolveHostPath(const std::string& path) | ||||
| { | ||||
|   // Double-check that it falls within the directory of the elf.
 | ||||
|   // Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code!
 | ||||
|   const std::string& root = g_settings.pcdrv_root; | ||||
|   std::string canonicalized_path = Path::Canonicalize(Path::Combine(root, path)); | ||||
|   if (canonicalized_path.length() < root.length() ||                      // Length has to be longer (a file),
 | ||||
|       !StringUtil::StartsWith(canonicalized_path, root) ||                // and start with the host root,
 | ||||
|       canonicalized_path[root.length()] != FS_OSPATH_SEPARATOR_CHARACTER) // and we can't access a sibling.
 | ||||
|   { | ||||
|     Log_ErrorPrintf("Denying access to path outside of PCDrv directory. Requested path: '%s', " | ||||
|                     "Resolved path: '%s', Root directory: '%s'", | ||||
|                     path.c_str(), root.c_str(), canonicalized_path.c_str()); | ||||
|     canonicalized_path.clear(); | ||||
|   } | ||||
| 
 | ||||
|   return canonicalized_path; | ||||
| } | ||||
| 
 | ||||
| void PCDrv::Initialize() | ||||
| { | ||||
|   if (!g_settings.pcdrv_enable) | ||||
|     return; | ||||
| 
 | ||||
|   Log_WarningPrintf("%s PCDrv is enabled at '%s'", g_settings.pcdrv_enable_writes ? "Read/Write" : "Read-Only", | ||||
|                     g_settings.pcdrv_root.c_str()); | ||||
| } | ||||
| 
 | ||||
| void PCDrv::Reset() | ||||
| { | ||||
|   CloseAllFiles(); | ||||
| } | ||||
| 
 | ||||
| void PCDrv::Shutdown() | ||||
| { | ||||
|   CloseAllFiles(); | ||||
| } | ||||
| 
 | ||||
| bool PCDrv::HandleSyscall(u32 instruction_bits, CPU::Registers& regs) | ||||
| { | ||||
|   // Based on https://problemkaputt.de/psxspx-bios-pc-file-server.htm
 | ||||
| 
 | ||||
| #define RETURN_ERROR()                                                                                                 \ | ||||
|   regs.v0 = 0xffffffff;                                                                                                \ | ||||
|   regs.v1 = 0xffffffff; // error code
 | ||||
| 
 | ||||
|   if (!g_settings.pcdrv_enable) | ||||
|     return false; | ||||
| 
 | ||||
|   const u32 code = (instruction_bits >> 6) & 0xfffff; // 20 bits, funct = 0
 | ||||
|   switch (code) | ||||
|   { | ||||
|     case 0x101: // PCinit
 | ||||
|     { | ||||
|       Log_DevPrintf("PCinit"); | ||||
|       CloseAllFiles(); | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = 0; | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     case 0x102: // PCcreat
 | ||||
|     case 0x103: // PCopen
 | ||||
|     { | ||||
|       const bool is_open = (code == 0x103); | ||||
|       const char* func = (code == 0x102) ? "PCcreat" : "PCopen"; | ||||
|       const u32 mode = regs.a2; | ||||
|       std::string filename; | ||||
|       if (!CPU::SafeReadMemoryCString(regs.a1, &filename)) | ||||
|       { | ||||
|         Log_ErrorPrintf("%s: Invalid string", func); | ||||
|         return false; | ||||
|       } | ||||
| 
 | ||||
|       Log_DebugPrintf("%s: '%s' mode %u", func, filename.c_str(), mode); | ||||
|       if ((filename = ResolveHostPath(filename)).empty()) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       if (!is_open && !g_settings.pcdrv_enable_writes) | ||||
|       { | ||||
|         Log_ErrorPrintf("%s: Writes are not enabled", func); | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       // Directories are unsupported for now, ignore other attributes
 | ||||
|       if (mode & PCDRV_ATTRIBUTE_DIRECTORY) | ||||
|       { | ||||
|         Log_ErrorPrintf("%s: Directories are unsupported", func); | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       // Create empty file, truncate if exists.
 | ||||
|       const s32 handle = GetFreeFileHandle(); | ||||
|       if (handle < 0) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       s_files[handle] = FileSystem::OpenManagedCFile(filename.c_str(), | ||||
|                                                      is_open ? (g_settings.pcdrv_enable_writes ? "r+b" : "rb") : "w+b"); | ||||
|       if (!s_files[handle]) | ||||
|       { | ||||
|         Log_ErrorPrintf("%s: Failed to open '%s'", func, filename.c_str()); | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       Log_DebugPrintf("PCDrv: Opened '%s' => %d", filename.c_str(), handle); | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = static_cast<u32>(handle); | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     case 0x104: // PCclose
 | ||||
|     { | ||||
|       Log_DebugPrintf("PCclose(%u)", regs.a1); | ||||
| 
 | ||||
|       if (!CloseFileHandle(regs.a1)) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = 0; | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     case 0x105: // PCread
 | ||||
|     { | ||||
|       Log_DebugPrintf("PCread(%u, %u, 0x%08x)", regs.a1, regs.a2, regs.a3); | ||||
| 
 | ||||
|       std::FILE* fp = GetFileFromHandle(regs.a1); | ||||
|       if (!fp) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       const u32 count = regs.a2; | ||||
|       u32 dstaddr = regs.a3; | ||||
|       for (u32 i = 0; i < count; i++) | ||||
|       { | ||||
|         // Certainly less than optimal, but it's not like you're going to be reading megabytes of data here.
 | ||||
|         u8 val; | ||||
|         if (std::fread(&val, 1, 1, fp) != 1) | ||||
|         { | ||||
|           // Does not stop at EOF according to psx-spx.
 | ||||
|           if (std::ferror(fp) != 0) | ||||
|           { | ||||
|             RETURN_ERROR(); | ||||
|             return true; | ||||
|           } | ||||
| 
 | ||||
|           val = 0; | ||||
|         } | ||||
| 
 | ||||
|         CPU::SafeWriteMemoryByte(dstaddr, val); | ||||
|         dstaddr++; | ||||
|       } | ||||
| 
 | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = count; | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     case 0x106: // PCwrite
 | ||||
|     { | ||||
|       Log_DebugPrintf("PCwrite(%u, %u, 0x%08x)", regs.a1, regs.a2, regs.a3); | ||||
| 
 | ||||
|       std::FILE* fp = GetFileFromHandle(regs.a1); | ||||
|       if (!fp) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       const u32 count = regs.a2; | ||||
|       u32 srcaddr = regs.a3; | ||||
|       u32 written = 0; | ||||
|       for (u32 i = 0; i < count; i++) | ||||
|       { | ||||
|         u8 val; | ||||
|         if (!CPU::SafeReadMemoryByte(srcaddr, &val)) | ||||
|           break; | ||||
| 
 | ||||
|         if (std::fwrite(&val, 1, 1, fp) != 1) | ||||
|         { | ||||
|           RETURN_ERROR(); | ||||
|           return true; | ||||
|         } | ||||
| 
 | ||||
|         srcaddr++; | ||||
|         written++; | ||||
|       } | ||||
| 
 | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = written; | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     case 0x107: // PClseek
 | ||||
|     { | ||||
|       Log_DebugPrintf("PClseek(%u, %u, %u)", regs.a1, regs.a2, regs.a3); | ||||
| 
 | ||||
|       std::FILE* fp = GetFileFromHandle(regs.a1); | ||||
|       if (!fp) | ||||
|       { | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       const s32 offset = static_cast<s32>(regs.a2); | ||||
|       const u32 mode = regs.a3; | ||||
|       int hmode; | ||||
|       switch (mode) | ||||
|       { | ||||
|         case 0: | ||||
|           hmode = SEEK_SET; | ||||
|           break; | ||||
|         case 1: | ||||
|           hmode = SEEK_CUR; | ||||
|           break; | ||||
|         case 2: | ||||
|           hmode = SEEK_END; | ||||
|           break; | ||||
|         default: | ||||
|           RETURN_ERROR(); | ||||
|           return true; | ||||
|       } | ||||
| 
 | ||||
|       if (FileSystem::FSeek64(fp, offset, hmode) != 0) | ||||
|       { | ||||
|         Log_ErrorPrintf("FSeek for PCDrv failed: %d %u", offset, hmode); | ||||
|         RETURN_ERROR(); | ||||
|         return true; | ||||
|       } | ||||
| 
 | ||||
|       regs.v0 = 0; | ||||
|       regs.v1 = static_cast<u32>(static_cast<s32>(FileSystem::FTell64(fp))); | ||||
|       return true; | ||||
|     } | ||||
| 
 | ||||
|     default: | ||||
|       return false; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										18
									
								
								src/core/pcdrv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/core/pcdrv.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| // SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
 | ||||
| // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include "cpu_types.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| //////////////////////////////////////////////////////////////////////////
 | ||||
| // HLE Implementation of PCDrv
 | ||||
| //////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| namespace PCDrv { | ||||
| void Initialize(); | ||||
| void Reset(); | ||||
| void Shutdown(); | ||||
| 
 | ||||
| bool HandleSyscall(u32 instruction_bits, CPU::Registers& regs); | ||||
| } | ||||
|  | @ -303,6 +303,9 @@ void Settings::Load(SettingsInterface& si) | |||
|   audio_dump_on_boot = si.GetBoolValue("Audio", "DumpOnBoot", false); | ||||
| 
 | ||||
|   use_old_mdec_routines = si.GetBoolValue("Hacks", "UseOldMDECRoutines", false); | ||||
|   pcdrv_enable = si.GetBoolValue("PCDrv", "Enabled", false); | ||||
|   pcdrv_enable_writes = si.GetBoolValue("PCDrv", "EnableWrites", false); | ||||
|   pcdrv_root = si.GetStringValue("PCDrv", "Root"); | ||||
| 
 | ||||
|   dma_max_slice_ticks = si.GetIntValue("Hacks", "DMAMaxSliceTicks", DEFAULT_DMA_MAX_SLICE_TICKS); | ||||
|   dma_halt_ticks = si.GetIntValue("Hacks", "DMAHaltTicks", DEFAULT_DMA_HALT_TICKS); | ||||
|  | @ -522,6 +525,10 @@ void Settings::Save(SettingsInterface& si) const | |||
|   si.SetIntValue("Hacks", "GPUFIFOSize", gpu_fifo_size); | ||||
|   si.SetIntValue("Hacks", "GPUMaxRunAhead", gpu_max_run_ahead); | ||||
| 
 | ||||
|   si.SetBoolValue("PCDrv", "Enabled", pcdrv_enable); | ||||
|   si.SetBoolValue("PCDrv", "EnableWrites", pcdrv_enable_writes); | ||||
|   si.SetStringValue("PCDrv", "Root", pcdrv_root.c_str()); | ||||
| 
 | ||||
|   si.SetBoolValue("BIOS", "PatchTTYEnable", bios_patch_tty_enable); | ||||
|   si.SetBoolValue("BIOS", "PatchFastBoot", bios_patch_fast_boot); | ||||
| 
 | ||||
|  | @ -610,10 +617,17 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages) | |||
|     g_settings.cdrom_mute_cd_audio = false; | ||||
|     g_settings.texture_replacements.enable_vram_write_replacements = false; | ||||
|     g_settings.use_old_mdec_routines = false; | ||||
|     g_settings.pcdrv_enable = false; | ||||
|     g_settings.bios_patch_fast_boot = false; | ||||
|     g_settings.bios_patch_tty_enable = false; | ||||
|   } | ||||
| 
 | ||||
|   if (g_settings.pcdrv_enable && g_settings.pcdrv_root.empty()) | ||||
|   { | ||||
|     Log_WarningPrintf("Disabling PCDrv because no root directory is specified."); | ||||
|     g_settings.pcdrv_enable = false; | ||||
|   } | ||||
| 
 | ||||
|   if (g_settings.display_integer_scaling && g_settings.display_linear_filtering) | ||||
|   { | ||||
|     Log_WarningPrintf("Disabling linear filter due to integer upscaling."); | ||||
|  |  | |||
|  | @ -170,6 +170,7 @@ struct Settings | |||
|   bool audio_dump_on_boot = false; | ||||
| 
 | ||||
|   bool use_old_mdec_routines = false; | ||||
|   bool pcdrv_enable = false; | ||||
| 
 | ||||
|   // timing hacks section
 | ||||
|   TickCount dma_max_slice_ticks = DEFAULT_DMA_MAX_SLICE_TICKS; | ||||
|  | @ -228,8 +229,6 @@ struct Settings | |||
|     } | ||||
|   } texture_replacements; | ||||
| 
 | ||||
|   // TODO: Controllers, memory cards, etc.
 | ||||
| 
 | ||||
|   bool bios_patch_tty_enable = false; | ||||
|   bool bios_patch_fast_boot = DEFAULT_FAST_BOOT_VALUE; | ||||
|   bool enable_8mb_ram = false; | ||||
|  | @ -243,6 +242,9 @@ struct Settings | |||
| 
 | ||||
|   MultitapMode multitap_mode = DEFAULT_MULTITAP_MODE; | ||||
| 
 | ||||
|   std::string pcdrv_root; | ||||
|   bool pcdrv_enable_writes = false; | ||||
| 
 | ||||
|   std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> GeneratePortLabels() const; | ||||
| 
 | ||||
|   LOGLEVEL log_level = DEFAULT_LOG_LEVEL; | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ | |||
| #include "memory_card.h" | ||||
| #include "multitap.h" | ||||
| #include "pad.h" | ||||
| #include "pcdrv.h" | ||||
| #include "pgxp.h" | ||||
| #include "psf_loader.h" | ||||
| #include "save_state_version.h" | ||||
|  | @ -1424,6 +1425,7 @@ bool System::Initialize(bool force_software_renderer) | |||
|   SPU::Initialize(); | ||||
|   MDEC::Initialize(); | ||||
|   SIO::Initialize(); | ||||
|   PCDrv::Initialize(); | ||||
| 
 | ||||
|   static constexpr float WARNING_DURATION = 15.0f; | ||||
| 
 | ||||
|  | @ -1479,6 +1481,7 @@ void System::DestroySystem() | |||
| 
 | ||||
|   g_texture_replacements.Shutdown(); | ||||
| 
 | ||||
|   PCDrv::Shutdown(); | ||||
|   SIO::Shutdown(); | ||||
|   MDEC::Shutdown(); | ||||
|   SPU::Shutdown(); | ||||
|  | @ -1832,6 +1835,7 @@ void System::InternalReset() | |||
|   SPU::Reset(); | ||||
|   MDEC::Reset(); | ||||
|   SIO::Reset(); | ||||
|   PCDrv::Reset(); | ||||
|   s_frame_number = 1; | ||||
|   s_internal_frame_number = 0; | ||||
|   TimingEvents::Reset(); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Stenzek
						Stenzek