diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 6fcea3252f..40622641fe 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -509,3 +509,186 @@ template<> __forceinline u64 MemoryBase::ReverseData<1>(u64 val) { return val; } template<> __forceinline u64 MemoryBase::ReverseData<2>(u64 val) { return Reverse16(val); } template<> __forceinline u64 MemoryBase::ReverseData<4>(u64 val) { return Reverse32(val); } template<> __forceinline u64 MemoryBase::ReverseData<8>(u64 val) { return Reverse64(val); } + +VirtualMemoryBlock::VirtualMemoryBlock() : MemoryBlock() +{ +} + +bool VirtualMemoryBlock::IsInMyRange(const u64 addr) +{ + return addr >= GetStartAddr() && addr < GetStartAddr() + GetSize(); +} + +bool VirtualMemoryBlock::IsInMyRange(const u64 addr, const u32 size) +{ + return IsInMyRange(addr) && IsInMyRange(addr + size - 1); +} + +bool VirtualMemoryBlock::IsMyAddress(const u64 addr) +{ + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) + { + return true; + } + } + + return false; +} + +u64 VirtualMemoryBlock::Map(u64 realaddr, u32 size, u64 addr) +{ + if(addr) + { + if(!IsInMyRange(addr, size) && (IsMyAddress(addr) || IsMyAddress(addr + size - 1))) + return 0; + + m_mapped_memory.Move(new VirtualMemInfo(addr, realaddr, size)); + return addr; + } + else + { + for(u64 addr = GetStartAddr(); addr <= GetEndAddr() - size;) + { + bool is_good_addr = true; + + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) || + (m_mapped_memory[i].addr >= addr && m_mapped_memory[i].addr < addr + size)) + { + is_good_addr = false; + addr = m_mapped_memory[i].addr + m_mapped_memory[i].size; + break; + } + } + + if(!is_good_addr) continue; + + m_mapped_memory.Move(new VirtualMemInfo(addr, realaddr, size)); + + return addr; + } + + return 0; + } +} + +bool VirtualMemoryBlock::UnmapRealAddress(u64 realaddr) +{ + for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) + { + return m_mapped_memory[i].realAddress + (addr - m_mapped_memory[i].addr); + } + } + + return 0; +} + +void VirtualMemoryBlock::Delete() +{ + m_mapped_memory.Clear(); + + MemoryBlock::Delete(); +} \ No newline at end of file diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 34b1426e52..919f2588c4 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -24,6 +24,7 @@ public: DynamicMemoryBlock StackMem; MemoryBlock SpuRawMem; MemoryBlock SpuThrMem; + VirtualMemoryBlock RSXIOMem; struct { diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index 7d497bb1c4..ad06f14c33 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -40,6 +40,23 @@ struct MemBlockInfo : public MemInfo } }; +struct VirtualMemInfo : public MemInfo +{ + u64 realAddress; + + VirtualMemInfo(u64 _addr, u64 _realaddr, u32 _size) + : MemInfo(_addr, _size) + , realAddress(_realaddr) + { + } + + VirtualMemInfo() + : MemInfo(0, 0) + , realAddress(0) + { + } +}; + class MemoryBlock { protected: @@ -206,6 +223,44 @@ private: void AppendLockedMem(u64 addr, u32 size); }; +class VirtualMemoryBlock : public MemoryBlock +{ + Array m_mapped_memory; + +public: + VirtualMemoryBlock(); + + virtual bool IsInMyRange(const u64 addr); + virtual bool IsInMyRange(const u64 addr, const u32 size); + virtual bool IsMyAddress(const u64 addr); + virtual void Delete(); + + // maps real address to virtual address space, returns the mapped address or 0 on failure (if no address is specified the + // first mappable space is used) + virtual u64 Map(u64 realaddr, u32 size, u64 addr = 0); + + // Unmap real address (please specify only starting point, no midway memory will be unmapped) + virtual bool UnmapRealAddress(u64 realaddr); + + // Unmap address (please specify only starting point, no midway memory will be unmapped) + virtual bool UnmapAddress(u64 addr); + + virtual bool Read8(const u64 addr, u8* value); + virtual bool Read16(const u64 addr, u16* value); + virtual bool Read32(const u64 addr, u32* value); + virtual bool Read64(const u64 addr, u64* value); + virtual bool Read128(const u64 addr, u128* value); + + virtual bool Write8(const u64 addr, const u8 value); + virtual bool Write16(const u64 addr, const u16 value); + virtual bool Write32(const u64 addr, const u32 value); + virtual bool Write64(const u64 addr, const u64 value); + virtual bool Write128(const u64 addr, const u128 value); + + // return the real address given a mapped address, if not mapped return 0 + u64 getRealAddr(u64 addr); +}; + #include "DynamicMemoryBlockBase.inl" typedef DynamicMemoryBlockBase DynamicMemoryBlock; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 0eef3bd6c8..1458bd2da2 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -6,6 +6,9 @@ void cellGcmSys_init(); Module cellGcmSys(0x0010, cellGcmSys_init); +u32 local_size = 0; +u32 local_addr = NULL; + enum { CELL_GCM_ERROR_FAILURE = 0x802100ff, @@ -19,10 +22,12 @@ CellGcmContextData current_context; gcmInfo gcm_info; struct gcm_offset { - u16 ea; - u16 offset; + mem_ptr_t io; + mem_ptr_t ea; }; +//gcm_offset offsetTable; + u32 map_offset_addr = 0; u32 map_offset_pos = 0; @@ -42,6 +47,9 @@ int cellGcmMapMainMemory(u32 address, u32 size, mem32_t offset) int cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size) { cellGcmSys.Warning("cellGcmMapEaIoAddress(ea=0x%x, io=0x%x, size=0x%x)", ea, io, size); + + if(io % 0x100000 != 0 || size % 0x100000 != 0) return CELL_GCM_ERROR_FAILURE; + //Memory.Map(io, ea, size); //Emu.GetGSManager().GetRender().m_ioAddress = io; Emu.GetGSManager().GetRender().m_report_main_addr = ea; @@ -52,8 +60,12 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) { cellGcmSys.Warning("cellGcmInit(context_addr=0x%x,cmdSize=0x%x,ioSize=0x%x,ioAddress=0x%x)", context_addr, cmdSize, ioSize, ioAddress); - const u32 local_size = 0xf900000; //TODO - const u32 local_addr = Memory.RSXFBMem.GetStartAddr(); + if(!local_size && !local_addr) + { + u32 local_size = 0xf900000; //TODO + u32 local_addr = Memory.RSXFBMem.GetStartAddr(); + Memory.RSXFBMem.Alloc(local_size); + } cellGcmSys.Warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size); @@ -66,8 +78,9 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress) current_config.memoryFrequency = re32(650000000); current_config.coreFrequency = re32(500000000); - Memory.RSXFBMem.Alloc(local_size); Memory.RSXCMDMem.Alloc(cmdSize); + Memory.MemoryBlocks.Add(Memory.RSXIOMem.SetRange(0xD0000000, 0x10000000/*256MB*/)); + Memory.RSXIOMem.Map(ioAddress, ioSize); u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; @@ -112,57 +125,6 @@ int cellGcmGetConfiguration(mem_ptr_t config) return CELL_OK; } -int cellGcmAddressToOffset(u32 address, mem32_t offset) -{ - cellGcmSys.Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.GetAddr()); - if(!offset.IsGood()) return CELL_EFAULT; - - if(!map_offset_addr) - { - map_offset_addr = Memory.Alloc(4*50, 4); - } - - u32 sa; - bool is_main_mem = false; - const auto& main_mem_info = Emu.GetGSManager().GetRender().m_main_mem_info; - for(u32 i=0; i= main_mem_info[i].addr && address < main_mem_info[i].addr + main_mem_info[i].size) - { - is_main_mem = true; - break; - } - } - - if(is_main_mem) - { - //main - sa = Emu.GetGSManager().GetRender().m_main_mem_addr; - //ConLog.Warning("cellGcmAddressToOffset: main memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - else if(Memory.RSXFBMem.IsMyAddress(address)) - { - //local - sa = Emu.GetGSManager().GetRender().m_local_mem_addr; - //ConLog.Warning("cellGcmAddressToOffset: local memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - else - { - //io - sa = Emu.GetGSManager().GetRender().m_ioAddress; - //ConLog.Warning("cellGcmAddressToOffset: io memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); - } - - offset = address - sa; - //ConLog.Warning("Address To Offset: 0x%x -> 0x%x", address, address - sa); - //Memory.Write16(map_offset_addr + map_offset_pos + 0, ea); - //Memory.Write16(map_offset_addr + map_offset_pos + 2, offset); - //map_offset_pos += 4; - - return CELL_OK; -} - int cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height) { cellGcmSys.Warning("cellGcmSetDisplayBuffer(id=0x%x,offset=0x%x,pitch=%d,width=%d,height=%d)", @@ -573,13 +535,154 @@ int cellGcmSetSecondVFrequency (u32 freq) return CELL_OK; } +/*------------------------------------------------------------ + Memory Mapping +------------------------------------------------------------*/ + +int cellGcmAddressToOffset(u32 address, mem32_t offset) +{ + cellGcmSys.Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.GetAddr()); + if(!offset.IsGood()) return CELL_EFAULT; + + if(!map_offset_addr) + { + map_offset_addr = Memory.Alloc(4*50, 4); + } + + u32 sa; + bool is_main_mem = false; + const auto& main_mem_info = Emu.GetGSManager().GetRender().m_main_mem_info; + for(u32 i=0; i= main_mem_info[i].addr && address < main_mem_info[i].addr + main_mem_info[i].size) + { + is_main_mem = true; + break; + } + } + + if(is_main_mem) + { + //main + sa = Emu.GetGSManager().GetRender().m_main_mem_addr; + //ConLog.Warning("cellGcmAddressToOffset: main memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + else if(Memory.RSXFBMem.IsMyAddress(address)) + { + //local + sa = Emu.GetGSManager().GetRender().m_local_mem_addr; + //ConLog.Warning("cellGcmAddressToOffset: local memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + else + { + //io + sa = Emu.GetGSManager().GetRender().m_ioAddress; + //ConLog.Warning("cellGcmAddressToOffset: io memory: offset = 0x%x - 0x%x = 0x%x", address, sa, address - sa); + } + + offset = address - sa; + //ConLog.Warning("Address To Offset: 0x%x -> 0x%x", address, address - sa); + //Memory.Write16(map_offset_addr + map_offset_pos + 0, ea); + //Memory.Write16(map_offset_addr + map_offset_pos + 2, offset); + //map_offset_pos += 4; + + return CELL_OK; +} + +u32 cellGcmGetMaxIoMapSize() +{ + UNIMPLEMENTED_FUNC(cellGcmSys); + return 0x10000000;//256MB TODO +} + +void cellGcmGetOffsetTable(mem_ptr_t table) +{ + static gcm_offset temp = {NULL, NULL}; + + if(!temp.io.IsGood()) + { + u32 mem = Memory.Alloc(sizeof(u16) * 0xBFF, 1); + + for(int i=0; i<0xBFF; i++) + { + Memory.Write16(mem + i*sizeof(u16), 0xFFFF); + } + + temp.io = re(mem); + } + + if(!temp.ea.IsGood()) + { + u32 mem = Memory.Alloc(sizeof(u16) * 511, 1); + + for(int i=0; i<511; i++) + { + Memory.Write16(mem + i*sizeof(u16), 0xFFFF); + } + + temp.ea = re(mem); + } + + *table = temp; + + if(!current_config.localAddress) + { + /*Memory.Write16((table->io), 0xFFFF); + Memory.Write16(table->io + (uint)2, 0xFFFF);*/ + } + + if(!current_config.ioAddress) + { + /*Memory.Write16(table->ea, 0xFFFF); + Memory.Write16(table->ea + (uint)2, 0xFFFF);*/ + } + + UNIMPLEMENTED_FUNC(cellGcmSys); +} + +int32_t cellGcmIoOffsetToAddress(u32 ioOffset, mem_ptr_t address) +{ + u64 realAddr; + + realAddr = Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ioOffset); + + if(!realAddr) + return CELL_GCM_ERROR_FAILURE; + + Memory.Write64(address, realAddr); + + return CELL_OK; +} + +int32_t cellGcmMapLocalMemory(mem_ptr_t address, mem_ptr_t size) +{ + if(!local_size && !local_addr) + { + u32 local_size = 0xf900000; //TODO + u32 local_addr = Memory.RSXFBMem.GetStartAddr(); + Memory.RSXFBMem.Alloc(local_size); + Memory.Write32(address.GetAddr(), local_addr); + Memory.Write32(size.GetAddr(), local_size); + } + else + { + printf("RSX local memory already mapped"); + return CELL_GCM_ERROR_FAILURE; + } + + return CELL_OK; +} + void cellGcmSys_init() { + current_config.ioAddress = NULL; + current_config.localAddress = NULL; + cellGcmSys.AddFunc(0x055bd74d, cellGcmGetTiledPitchSize); cellGcmSys.AddFunc(0x06edea9e, cellGcmSetUserHandler); cellGcmSys.AddFunc(0x15bae46b, cellGcmInit); cellGcmSys.AddFunc(0x21397818, cellGcmSetFlipCommand); - cellGcmSys.AddFunc(0x21ac3697, cellGcmAddressToOffset); cellGcmSys.AddFunc(0x3a33c1fd, cellGcmFunc15); cellGcmSys.AddFunc(0x4ae8d215, cellGcmSetFlipMode); cellGcmSys.AddFunc(0x63441cb4, cellGcmMapEaIoAddress); @@ -622,4 +725,11 @@ void cellGcmSys_init() cellGcmSys.AddFunc(0x4d7ce993, cellGcmSetSecondVFrequency); cellGcmSys.AddFunc(0xdc09357e, cellGcmSetFlip); cellGcmSys.AddFunc(0x983fb9aa, cellGcmSetWaitFlip); + cellGcmSys.AddFunc(0xdb769b32, cellGcmMapLocalMemory); + + //Memory Mapping + cellGcmSys.AddFunc(0x21ac3697, cellGcmAddressToOffset); + cellGcmSys.AddFunc(0xfb81c03e, cellGcmGetMaxIoMapSize); + cellGcmSys.AddFunc(0x2922aed0, cellGcmGetOffsetTable); + cellGcmSys.AddFunc(0x2a6fba9c, cellGcmIoOffsetToAddress); }