mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
include clearing
This commit is contained in:
parent
102f8cf993
commit
861ce9e733
@ -5,11 +5,10 @@
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
//#define re(val) MemoryBase::Reverse(val)
|
||||
#define re64(val) MemoryBase::Reverse64(val)
|
||||
#define re32(val) MemoryBase::Reverse32(val)
|
||||
#define re16(val) MemoryBase::Reverse16(val)
|
||||
#define re128(val) MemoryBase::Reverse128(val)
|
||||
#define re16(val) _byteswap_ushort(val)
|
||||
#define re32(val) _byteswap_ulong(val)
|
||||
#define re64(val) _byteswap_uint64(val)
|
||||
#define re128(val) u128::byteswap(val)
|
||||
|
||||
template<typename T, int size = sizeof(T)> struct se_t;
|
||||
template<typename T> struct se_t<T, 1> { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } };
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "Emu/ARMv7/ARMv7Opcodes.h"
|
||||
#include "Emu/CPU/CPUDisAsm.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
static const char* g_arm_cond_name[16] =
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPCThread.h"
|
||||
|
||||
#include "ARMv7Thread.h"
|
||||
#include "ARMv7Decoder.h"
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/DbgCommand.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
|
||||
#include "CPUThread.h"
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/DbgCommand.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "PPCDecoder.h"
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/PPUOpcodes.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
|
@ -1,7 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
#include "PPUProgramCompiler.h"
|
||||
|
||||
using namespace PPU_instr;
|
||||
@ -83,7 +80,7 @@ SectionInfo::SectionInfo(const std::string& _name)
|
||||
void SectionInfo::SetDataSize(u32 size, u32 align)
|
||||
{
|
||||
if(align) shdr.sh_addralign = align;
|
||||
if(shdr.sh_addralign) size = Memory.AlignAddr(size, shdr.sh_addralign);
|
||||
if(shdr.sh_addralign) size = AlignAddr(size, shdr.sh_addralign);
|
||||
|
||||
if(!code.empty())
|
||||
{
|
||||
@ -987,7 +984,7 @@ void CompilePPUProgram::Compile()
|
||||
elf_info.e_shnum = 15;
|
||||
elf_info.e_shstrndx = elf_info.e_shnum - 1;
|
||||
elf_info.e_phoff = elf_info.e_ehsize;
|
||||
u32 section_offset = Memory.AlignAddr(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100);
|
||||
u32 section_offset = AlignAddr(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100);
|
||||
|
||||
static const u32 sceStub_text_block = 8 * 4;
|
||||
|
||||
@ -1145,7 +1142,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_sceStub_text;
|
||||
memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr));
|
||||
s_sceStub_text.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_sceStub_text.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_sceStub_text.sh_addralign);
|
||||
s_sceStub_text.sh_type = 1;
|
||||
s_sceStub_text.sh_offset = section_offset;
|
||||
s_sceStub_text.sh_addr = section_offset + 0x10000;
|
||||
@ -1169,7 +1166,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_lib_stub_top;
|
||||
memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr));
|
||||
s_lib_stub_top.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_lib_stub_top.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_lib_stub_top.sh_addralign);
|
||||
s_lib_stub_top.sh_type = 1;
|
||||
s_lib_stub_top.sh_name = section_name_offset;
|
||||
s_lib_stub_top.sh_offset = section_offset;
|
||||
@ -1209,7 +1206,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_rodata_sceFNID;
|
||||
memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr));
|
||||
s_rodata_sceFNID.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_rodata_sceFNID.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_rodata_sceFNID.sh_addralign);
|
||||
s_rodata_sceFNID.sh_type = 1;
|
||||
s_rodata_sceFNID.sh_name = section_name_offset;
|
||||
s_rodata_sceFNID.sh_offset = section_offset;
|
||||
@ -1223,7 +1220,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_rodata_sceResident;
|
||||
memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr));
|
||||
s_rodata_sceResident.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_rodata_sceResident.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_rodata_sceResident.sh_addralign);
|
||||
s_rodata_sceResident.sh_type = 1;
|
||||
s_rodata_sceResident.sh_name = section_name_offset;
|
||||
s_rodata_sceResident.sh_offset = section_offset;
|
||||
@ -1234,7 +1231,7 @@ void CompilePPUProgram::Compile()
|
||||
{
|
||||
s_rodata_sceResident.sh_size += module.m_name.length() + 1;
|
||||
}
|
||||
s_rodata_sceResident.sh_size = Memory.AlignAddr(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign);
|
||||
s_rodata_sceResident.sh_size = AlignAddr(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign);
|
||||
sections_names.push_back(".rodata.sceResident");
|
||||
section_name_offset += std::string(".rodata.sceResident").length() + 1;
|
||||
section_offset += s_rodata_sceResident.sh_size;
|
||||
@ -1242,7 +1239,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_lib_ent_top;
|
||||
memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr));
|
||||
s_lib_ent_top.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_lib_ent_top.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_lib_ent_top.sh_addralign);
|
||||
s_lib_ent_top.sh_size = 4;
|
||||
s_lib_ent_top.sh_flags = 2;
|
||||
s_lib_ent_top.sh_type = 1;
|
||||
@ -1269,7 +1266,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_sys_proc_prx_param;
|
||||
memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr));
|
||||
s_sys_proc_prx_param.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_sys_proc_prx_param.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_sys_proc_prx_param.sh_addralign);
|
||||
s_sys_proc_prx_param.sh_type = 1;
|
||||
s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param);
|
||||
s_sys_proc_prx_param.sh_name = section_name_offset;
|
||||
@ -1282,14 +1279,14 @@ void CompilePPUProgram::Compile()
|
||||
|
||||
const u32 prog_load_0_end = section_offset;
|
||||
|
||||
section_offset = Memory.AlignAddr(section_offset + 0x10000, 0x10000);
|
||||
section_offset = AlignAddr(section_offset + 0x10000, 0x10000);
|
||||
const u32 prog_load_1_start = section_offset;
|
||||
|
||||
Elf64_Shdr s_data_sceFStub;
|
||||
memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr));
|
||||
s_data_sceFStub.sh_name = section_name_offset;
|
||||
s_data_sceFStub.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_data_sceFStub.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_data_sceFStub.sh_addralign);
|
||||
s_data_sceFStub.sh_flags = 3;
|
||||
s_data_sceFStub.sh_type = 1;
|
||||
s_data_sceFStub.sh_offset = section_offset;
|
||||
@ -1302,7 +1299,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_tbss;
|
||||
memset(&s_tbss, 0, sizeof(Elf64_Shdr));
|
||||
s_tbss.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_tbss.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_tbss.sh_addralign);
|
||||
s_tbss.sh_size = 4;
|
||||
s_tbss.sh_flags = 0x403;
|
||||
s_tbss.sh_type = 8;
|
||||
@ -1316,7 +1313,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_opd;
|
||||
memset(&s_opd, 0, sizeof(Elf64_Shdr));
|
||||
s_opd.sh_addralign = 8;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_opd.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_opd.sh_addralign);
|
||||
s_opd.sh_size = 2*4;
|
||||
s_opd.sh_type = 1;
|
||||
s_opd.sh_offset = section_offset;
|
||||
@ -1477,7 +1474,7 @@ void CompilePPUProgram::Compile()
|
||||
|
||||
if(!m_file_path.empty() && !m_analyze && !m_error)
|
||||
{
|
||||
s_opd.sh_size = Memory.AlignAddr(s_opd.sh_size, s_opd.sh_addralign);
|
||||
s_opd.sh_size = AlignAddr(s_opd.sh_size, s_opd.sh_addralign);
|
||||
section_offset += s_opd.sh_size;
|
||||
|
||||
const u32 prog_load_1_end = section_offset;
|
||||
@ -1485,7 +1482,7 @@ void CompilePPUProgram::Compile()
|
||||
Elf64_Shdr s_shstrtab;
|
||||
memset(&s_shstrtab, 0, sizeof(Elf64_Shdr));
|
||||
s_shstrtab.sh_addralign = 1;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_shstrtab.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_shstrtab.sh_addralign);
|
||||
s_shstrtab.sh_name = section_name_offset;
|
||||
s_shstrtab.sh_type = 3;
|
||||
s_shstrtab.sh_offset = section_offset;
|
||||
@ -1507,7 +1504,7 @@ void CompilePPUProgram::Compile()
|
||||
elf_info.e_machine = MACHINE_PPC64; //PowerPC64
|
||||
elf_info.e_version = 1; //ver 1
|
||||
elf_info.e_flags = 0x0;
|
||||
elf_info.e_shoff = Memory.AlignAddr(section_offset, 4);
|
||||
elf_info.e_shoff = AlignAddr(section_offset, 4);
|
||||
|
||||
u8* opd_data = new u8[s_opd.sh_size];
|
||||
u32 entry_point = s_text.sh_addr;
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
#include "Emu/Cell/PPUDecoder.h"
|
||||
#include "Emu/Cell/PPUInterpreter.h"
|
||||
#include "Emu/Cell/PPUDisAsm.h"
|
||||
|
||||
#include <thread>
|
||||
#include <cmath>
|
||||
@ -57,7 +56,7 @@ void PPUThread::DoReset()
|
||||
void PPUThread::AddArgv(const std::string& arg)
|
||||
{
|
||||
m_stack_point -= arg.length() + 1;
|
||||
m_stack_point = Memory.AlignAddr(m_stack_point, 0x10) - 0x10;
|
||||
m_stack_point = AlignAddr(m_stack_point, 0x10) - 0x10;
|
||||
m_argv_addr.push_back(m_stack_point);
|
||||
Memory.WriteString(m_stack_point, arg);
|
||||
}
|
||||
@ -94,7 +93,7 @@ void PPUThread::InitRegs()
|
||||
}
|
||||
*/
|
||||
|
||||
m_stack_point = Memory.AlignAddr(m_stack_point, 0x200) - 0x200;
|
||||
m_stack_point = AlignAddr(m_stack_point, 0x200) - 0x200;
|
||||
|
||||
GPR[1] = m_stack_point;
|
||||
GPR[2] = rtoc;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
|
||||
@ -149,7 +148,7 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RunCtrl, 0x%x): unknown value", m_index, value);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -6,11 +6,6 @@ __forceinline static u32 GetRawSPURegAddrByNum(int num, int offset)
|
||||
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;
|
||||
}
|
||||
|
||||
__forceinline static u32 GetRawSPURegAddrById(int id, int offset)
|
||||
{
|
||||
return GetRawSPURegAddrByNum(Emu.GetCPU().GetThreadNumById(CPU_THREAD_RAW_SPU, id), offset);
|
||||
}
|
||||
|
||||
class RawSPUThread
|
||||
: public SPUThread
|
||||
, public MemoryBlock
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "PPCInstrTable.h"
|
||||
#include "PPCDecoder.h"
|
||||
#include "SPUOpcodes.h"
|
||||
|
||||
|
@ -1,20 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Crypto/sha1.h"
|
||||
|
||||
#define UNIMPLEMENTED() UNK(__FUNCTION__)
|
||||
|
||||
/* typedef union _CRT_ALIGN(16) __u32x4 {
|
||||
u32 _u32[4];
|
||||
__m128i m128i;
|
||||
__m128 m128;
|
||||
__m128d m128d;
|
||||
} __u32x4; */
|
||||
|
||||
#define MEM_AND_REG_HASH() \
|
||||
unsigned char mem_h[20]; sha1(&Memory[CPU.dmac.ls_offset], 256*1024, mem_h); \
|
||||
unsigned char reg_h[20]; sha1((const unsigned char*)CPU.GPR, sizeof(CPU.GPR), reg_h); \
|
||||
|
@ -3,8 +3,12 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "Emu/SysCalls/lv2/sys_time.h"
|
||||
|
||||
#include "SPUInstrTable.h"
|
||||
#include "SPUDisAsm.h"
|
||||
|
||||
#include "SPUThread.h"
|
||||
#include "SPUInterpreter.h"
|
||||
#include "SPURecompiler.h"
|
||||
|
||||
|
@ -2,6 +2,13 @@
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "Emu/SysCalls/ErrorCodes.h"
|
||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event_flag.h"
|
||||
#include "Emu/SysCalls/lv2/sys_time.h"
|
||||
#include "Emu/Event.h"
|
||||
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/SPUDecoder.h"
|
||||
#include "Emu/Cell/SPUInterpreter.h"
|
||||
@ -140,3 +147,908 @@ void SPUThread::DoClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPUThread::WriteSNR(bool number, u32 value)
|
||||
{
|
||||
if (cfg.value & ((u64)1 << (u64)number))
|
||||
{
|
||||
SPU.SNR[number].PushUncond_OR(value); // logical OR
|
||||
}
|
||||
else
|
||||
{
|
||||
SPU.SNR[number].PushUncond(value); // overwrite
|
||||
}
|
||||
}
|
||||
|
||||
#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size)
|
||||
|
||||
void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||
{
|
||||
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
|
||||
|
||||
if (ea >= SYS_SPU_THREAD_BASE_LOW)
|
||||
{
|
||||
if (ea >= 0x100000000)
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid external address");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
else if (group)
|
||||
{
|
||||
// SPU Thread Group MMIO (LS and SNR)
|
||||
u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group
|
||||
if (num >= group->list.size() || !group->list[num])
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]);
|
||||
|
||||
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET;
|
||||
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
|
||||
{
|
||||
// LS access
|
||||
ea = spu->dmac.ls_offset + addr;
|
||||
}
|
||||
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
|
||||
{
|
||||
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (ea >= RAW_SPU_BASE_ADDR && size == 4)
|
||||
{
|
||||
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
{
|
||||
Memory.Write32(ea, ReadLS32(lsa));
|
||||
return;
|
||||
}
|
||||
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
WriteLS32(lsa, Memory.Read32(ea));
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
{
|
||||
memcpy(Memory + ea, Memory + (dmac.ls_offset + lsa), size);
|
||||
return;
|
||||
}
|
||||
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
memcpy(Memory + (dmac.ls_offset + lsa), Memory + ea, size);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_CMD
|
||||
|
||||
void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
|
||||
{
|
||||
u32 list_addr = ea & 0x3ffff;
|
||||
u32 list_size = size / 8;
|
||||
lsa &= 0x3fff0;
|
||||
|
||||
struct list_element
|
||||
{
|
||||
be_t<u16> s; // Stall-and-Notify bit (0x8000)
|
||||
be_t<u16> ts; // List Transfer Size
|
||||
be_t<u32> ea; // External Address Low
|
||||
};
|
||||
|
||||
u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||
|
||||
for (u32 i = 0; i < list_size; i++)
|
||||
{
|
||||
mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
|
||||
|
||||
u32 size = rec->ts;
|
||||
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size);
|
||||
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
u32 addr = rec->ea;
|
||||
ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
|
||||
|
||||
if (Ini.HLELogging.GetValue() || rec->s)
|
||||
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
|
||||
i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
|
||||
|
||||
lsa += std::max(size, (u32)16);
|
||||
|
||||
if (rec->s & se16(0x8000))
|
||||
{
|
||||
StallStat.PushUncond_OR(1 << tag);
|
||||
|
||||
if (StallList[tag].MFCArgs)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag);
|
||||
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
break;
|
||||
}
|
||||
StallList[tag].MFCArgs = &MFCArgs;
|
||||
StallList[tag].cmd = cmd;
|
||||
StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
|
||||
StallList[tag].lsa = lsa;
|
||||
StallList[tag].size = (list_size - i - 1) * 8;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MFCArgs.CMDStatus.SetValue(result);
|
||||
}
|
||||
|
||||
void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||
{
|
||||
u32 cmd = MFCArgs.CMDStatus.GetValue();
|
||||
u16 op = cmd & MFC_MASK_CMD;
|
||||
|
||||
u32 lsa = MFCArgs.LSA.GetValue();
|
||||
u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32);
|
||||
u32 size_tag = MFCArgs.Size_Tag.GetValue();
|
||||
u16 tag = (u16)size_tag;
|
||||
u16 size = size_tag >> 16;
|
||||
|
||||
switch (op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_PUTR_CMD: // ???
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "R" : ""),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
(op & MFC_FENCE_MASK ? "F" : ""),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
ProcessCmd(cmd, tag, lsa, ea, size);
|
||||
MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
|
||||
}
|
||||
break;
|
||||
|
||||
case MFC_PUTL_CMD:
|
||||
case MFC_PUTRL_CMD: // ???
|
||||
case MFC_GETL_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "RL" : "L"),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
(op & MFC_FENCE_MASK ? "F" : ""),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
|
||||
}
|
||||
break;
|
||||
|
||||
case MFC_GETLLAR_CMD:
|
||||
case MFC_PUTLLC_CMD:
|
||||
case MFC_PUTLLUC_CMD:
|
||||
case MFC_PUTQLLUC_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x",
|
||||
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
|
||||
op == MFC_PUTLLC_CMD ? "PUTLLC" :
|
||||
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
if (op == MFC_GETLLAR_CMD) // get reservation
|
||||
{
|
||||
if (R_ADDR)
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
}
|
||||
|
||||
R_ADDR = ea;
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
R_DATA[i] = *(u64*)&Memory[R_ADDR + i * 8];
|
||||
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = R_DATA[i];
|
||||
}
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
|
||||
}
|
||||
else if (op == MFC_PUTLLC_CMD) // store conditional
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
|
||||
|
||||
if (R_ADDR == ea)
|
||||
{
|
||||
u32 changed = 0, mask = 0;
|
||||
u64 buf[16];
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
buf[i] = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
|
||||
if (buf[i] != R_DATA[i])
|
||||
{
|
||||
changed++;
|
||||
mask |= (0x3 << (i * 2));
|
||||
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
R_ADDR = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (buf[i] != R_DATA[i])
|
||||
{
|
||||
if (InterlockedCompareExchange64((volatile long long*)(Memory + (ea + i * 8)), buf[i], R_DATA[i]) != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
|
||||
if (changed > 1)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
changed, mask, op, cmd, lsa, ea, tag, size);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed > 1)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
changed, mask, op, cmd, lsa, ea, tag, size);
|
||||
|
||||
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
||||
for (s32 i = PC; i < PC + 4 * 7; i += 4)
|
||||
{
|
||||
dis_asm.dump_pc = i;
|
||||
dis_asm.offset = Memory.GetMemFromAddr(dmac.ls_offset);
|
||||
const u32 opcode = Memory.Read32(i + dmac.ls_offset);
|
||||
(*SPU_instr::rrr_list)(&dis_asm, opcode);
|
||||
if (i >= 0 && i < 0x40000)
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "*** %s", dis_asm.last_opcode.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
}
|
||||
R_ADDR = 0;
|
||||
}
|
||||
else // store unconditional
|
||||
{
|
||||
if (R_ADDR)
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
}
|
||||
|
||||
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
|
||||
if (op == MFC_PUTLLUC_CMD)
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
|
||||
}
|
||||
R_ADDR = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
op, cmd, lsa, ea, tag, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SPUThread::CheckEvents()
|
||||
{
|
||||
// checks events:
|
||||
// SPU_EVENT_LR:
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
R_ADDR = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (m_events & m_event_mask) != 0;
|
||||
}
|
||||
|
||||
u32 SPUThread::GetChannelCount(u32 ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
|
||||
case SPU_WrOutIntrMbox: return SPU.Out_IntrMBox.GetFreeCount();
|
||||
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
|
||||
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
|
||||
case MFC_RdListStallStat: return StallStat.GetCount();
|
||||
case MFC_WrTagUpdate: return MFC1.TagStatus.GetCount(); // hack
|
||||
case SPU_RdSigNotify1: return SPU.SNR[0].GetCount();
|
||||
case SPU_RdSigNotify2: return SPU.SNR[1].GetCount();
|
||||
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
|
||||
case SPU_RdEventStat: return CheckEvents() ? 1 : 0;
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).",
|
||||
__FUNCTION__, ch, spu_ch_name[ch]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPUThread::WriteChannel(u32 ch, const SPU_GPR_hdr& r)
|
||||
{
|
||||
const u32 v = r._u32[3];
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case SPU_WrOutIntrMbox:
|
||||
{
|
||||
if (!group) // if RawSPU
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
|
||||
while (!SPU.Out_IntrMBox.Push(v))
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_intrtag[2].stat |= 1;
|
||||
if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
|
||||
{
|
||||
if (t->GetType() == CPU_THREAD_PPU && !t->IsAlive())
|
||||
{
|
||||
PPUThread& ppu = *(PPUThread*)t;
|
||||
ppu.FastStop();
|
||||
ppu.Run();
|
||||
ppu.FastCall(ppu.PC, ppu.GPR[2], ppu.m_interrupt_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u8 code = v >> 24;
|
||||
if (code < 64)
|
||||
{
|
||||
/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */
|
||||
|
||||
u8 spup = code & 63;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
|
||||
}
|
||||
|
||||
EventPort& port = SPUPs[spup];
|
||||
|
||||
std::lock_guard<std::mutex> lock(port.m_mutex);
|
||||
|
||||
if (!port.eq)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
|
||||
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
|
||||
return;
|
||||
}
|
||||
|
||||
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
|
||||
{
|
||||
SPU.In_MBox.PushUncond(CELL_EBUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
return;
|
||||
}
|
||||
else if (code < 128)
|
||||
{
|
||||
/* ===== sys_spu_thread_throw_event ===== */
|
||||
|
||||
const u8 spup = code & 63;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
|
||||
}
|
||||
|
||||
EventPort& port = SPUPs[spup];
|
||||
|
||||
std::lock_guard<std::mutex> lock(port.m_mutex);
|
||||
|
||||
if (!port.eq)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: check passing spup value
|
||||
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (code == 128)
|
||||
{
|
||||
/* ===== sys_event_flag_set_bit ===== */
|
||||
u32 flag = v & 0xffffff;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!Emu.GetIdManager().GetIDData(data, ef))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
|
||||
SPU.In_MBox.PushUncond(CELL_ESRCH);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentCPUThread()->GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= (u64)1 << flag;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
return;
|
||||
}
|
||||
else if (code == 192)
|
||||
{
|
||||
/* ===== sys_event_flag_set_bit_impatient ===== */
|
||||
u32 flag = v & 0xffffff;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag);
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!Emu.GetIdManager().GetIDData(data, ef))
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentCPUThread()->GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= (u64)1 << flag;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 data;
|
||||
if (SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
|
||||
}
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrOutMbox:
|
||||
{
|
||||
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrTagMask:
|
||||
{
|
||||
MFC1.QueryMask.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrTagUpdate:
|
||||
{
|
||||
MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_LSA:
|
||||
{
|
||||
MFC1.LSA.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_EAH:
|
||||
{
|
||||
MFC1.EAH.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_EAL:
|
||||
{
|
||||
MFC1.EAL.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_Size:
|
||||
{
|
||||
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_TagID:
|
||||
{
|
||||
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case MFC_Cmd:
|
||||
{
|
||||
MFC1.CMDStatus.SetValue(v);
|
||||
EnqMfcCmd(MFC1);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrListStallAck:
|
||||
{
|
||||
if (v >= 32)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v);
|
||||
return;
|
||||
}
|
||||
StalledList temp = StallList[v];
|
||||
if (!temp.MFCArgs)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v);
|
||||
return;
|
||||
}
|
||||
StallList[v].MFCArgs = nullptr;
|
||||
ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrDec:
|
||||
{
|
||||
m_dec_start = get_time();
|
||||
m_dec_value = v;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrEventMask:
|
||||
{
|
||||
m_event_mask = v;
|
||||
if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)");
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrEventAck:
|
||||
{
|
||||
m_events &= ~v;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
}
|
||||
|
||||
void SPUThread::ReadChannel(SPU_GPR_hdr& r, u32 ch)
|
||||
{
|
||||
r.Reset();
|
||||
u32& v = r._u32[3];
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case SPU_RdInMbox:
|
||||
{
|
||||
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdTagStat:
|
||||
{
|
||||
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdTagMask:
|
||||
{
|
||||
v = MFC1.QueryMask.GetValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify1:
|
||||
{
|
||||
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify2:
|
||||
{
|
||||
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdAtomicStat:
|
||||
{
|
||||
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdListStallStat:
|
||||
{
|
||||
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdDec:
|
||||
{
|
||||
v = m_dec_value - (u32)(get_time() - m_dec_start);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdEventMask:
|
||||
{
|
||||
v = m_event_mask;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdEventStat:
|
||||
{
|
||||
while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
v = m_events & m_event_mask;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdMachStat:
|
||||
{
|
||||
v = 1; // hack (not isolated, interrupts enabled)
|
||||
// TODO: check value
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
}
|
||||
|
||||
void SPUThread::StopAndSignal(u32 code)
|
||||
{
|
||||
SetExitStatus(code); // exit code (not status)
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
|
||||
{
|
||||
u32 spuq = 0;
|
||||
if (!SPU.Out_MBox.Pop(spuq))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox");
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
||||
return;
|
||||
}
|
||||
|
||||
if (SPU.In_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
|
||||
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
|
||||
return;
|
||||
}
|
||||
|
||||
if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||
}
|
||||
|
||||
EventQueue* eq;
|
||||
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
|
||||
{
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetId();
|
||||
|
||||
eq->sq.push(tid); // add thread to sleep queue
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (eq->owner.trylock(tid))
|
||||
{
|
||||
case SMR_OK:
|
||||
if (!eq->events.count())
|
||||
{
|
||||
eq->owner.unlock(tid);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
|
||||
if (next != tid)
|
||||
{
|
||||
eq->owner.unlock(tid, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SMR_SIGNAL:
|
||||
{
|
||||
sys_event_data event;
|
||||
eq->events.pop(event);
|
||||
eq->owner.unlock(tid);
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
SPU.In_MBox.PushUncond(event.data1);
|
||||
SPU.In_MBox.PushUncond(event.data2);
|
||||
SPU.In_MBox.PushUncond(event.data3);
|
||||
return;
|
||||
}
|
||||
case SMR_FAILED: break;
|
||||
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
|
||||
eq->sq.invalidate(tid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x102:
|
||||
if (!SPU.Out_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_exit (no status, code 0x102)");
|
||||
}
|
||||
else if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
// the real exit status
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue());
|
||||
}
|
||||
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
|
||||
Stop();
|
||||
break;
|
||||
default:
|
||||
if (!SPU.Out_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue());
|
||||
}
|
||||
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,13 +1,7 @@
|
||||
#pragma once
|
||||
#include "PPUThread.h"
|
||||
#include "SPUInstrTable.h"
|
||||
#include "SPUDisAsm.h"
|
||||
#include "PPCThread.h"
|
||||
#include "Emu/Event.h"
|
||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event_flag.h"
|
||||
#include "Emu/SysCalls/lv2/sys_time.h"
|
||||
#include "MFC.h"
|
||||
#include "Emu/SysCalls/ErrorCodes.h"
|
||||
#include <mutex>
|
||||
|
||||
enum SPUchannels
|
||||
@ -163,7 +157,7 @@ public:
|
||||
return this->low >> 22 & 0x3;
|
||||
|
||||
default:
|
||||
LOG_ERROR(SPU, "Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice);
|
||||
throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -246,6 +240,8 @@ union SPU_SNRConfig_hdr
|
||||
}
|
||||
};
|
||||
|
||||
struct SpuGroupInfo;
|
||||
|
||||
class SPUThread : public PPCThread
|
||||
{
|
||||
public:
|
||||
@ -499,17 +495,7 @@ public:
|
||||
Channel<1> SNR[2];
|
||||
} SPU;
|
||||
|
||||
void WriteSNR(bool number, u32 value)
|
||||
{
|
||||
if (cfg.value & ((u64)1 << (u64)number))
|
||||
{
|
||||
SPU.SNR[number].PushUncond_OR(value); // logical OR
|
||||
}
|
||||
else
|
||||
{
|
||||
SPU.SNR[number].PushUncond(value); // overwrite
|
||||
}
|
||||
}
|
||||
void WriteSNR(bool number, u32 value);
|
||||
|
||||
u32 LSA;
|
||||
|
||||
@ -521,897 +507,21 @@ public:
|
||||
|
||||
DMAC dmac;
|
||||
|
||||
#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size)
|
||||
void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size);
|
||||
|
||||
void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||
{
|
||||
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
|
||||
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs);
|
||||
|
||||
if (ea >= SYS_SPU_THREAD_BASE_LOW)
|
||||
{
|
||||
if (ea >= 0x100000000)
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid external address");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
else if (group)
|
||||
{
|
||||
// SPU Thread Group MMIO (LS and SNR)
|
||||
u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group
|
||||
if (num >= group->list.size() || !group->list[num])
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
void EnqMfcCmd(MFCReg& MFCArgs);
|
||||
|
||||
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]);
|
||||
bool CheckEvents();
|
||||
|
||||
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET;
|
||||
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
|
||||
{
|
||||
// LS access
|
||||
ea = spu->dmac.ls_offset + addr;
|
||||
}
|
||||
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
|
||||
{
|
||||
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (ea >= RAW_SPU_BASE_ADDR && size == 4)
|
||||
{
|
||||
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
{
|
||||
Memory.Write32(ea, ReadLS32(lsa));
|
||||
return;
|
||||
}
|
||||
u32 GetChannelCount(u32 ch);
|
||||
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
WriteLS32(lsa, Memory.Read32(ea));
|
||||
return;
|
||||
}
|
||||
void WriteChannel(u32 ch, const SPU_GPR_hdr& r);
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ReadChannel(SPU_GPR_hdr& r, u32 ch);
|
||||
|
||||
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
{
|
||||
memcpy(Memory + ea, Memory + (dmac.ls_offset + lsa), size);
|
||||
return;
|
||||
}
|
||||
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
memcpy(Memory + (dmac.ls_offset + lsa), Memory + ea, size);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_CMD
|
||||
|
||||
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
|
||||
{
|
||||
u32 list_addr = ea & 0x3ffff;
|
||||
u32 list_size = size / 8;
|
||||
lsa &= 0x3fff0;
|
||||
|
||||
struct list_element
|
||||
{
|
||||
be_t<u16> s; // Stall-and-Notify bit (0x8000)
|
||||
be_t<u16> ts; // List Transfer Size
|
||||
be_t<u32> ea; // External Address Low
|
||||
};
|
||||
|
||||
u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||
|
||||
for (u32 i = 0; i < list_size; i++)
|
||||
{
|
||||
mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
|
||||
|
||||
u32 size = rec->ts;
|
||||
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size);
|
||||
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
u32 addr = rec->ea;
|
||||
ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
|
||||
|
||||
if (Ini.HLELogging.GetValue() || rec->s)
|
||||
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
|
||||
i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
|
||||
|
||||
lsa += std::max(size, (u32)16);
|
||||
|
||||
if (rec->s & se16(0x8000))
|
||||
{
|
||||
StallStat.PushUncond_OR(1 << tag);
|
||||
|
||||
if (StallList[tag].MFCArgs)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag);
|
||||
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
break;
|
||||
}
|
||||
StallList[tag].MFCArgs = &MFCArgs;
|
||||
StallList[tag].cmd = cmd;
|
||||
StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
|
||||
StallList[tag].lsa = lsa;
|
||||
StallList[tag].size = (list_size - i - 1) * 8;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MFCArgs.CMDStatus.SetValue(result);
|
||||
}
|
||||
|
||||
void EnqMfcCmd(MFCReg& MFCArgs)
|
||||
{
|
||||
u32 cmd = MFCArgs.CMDStatus.GetValue();
|
||||
u16 op = cmd & MFC_MASK_CMD;
|
||||
|
||||
u32 lsa = MFCArgs.LSA.GetValue();
|
||||
u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32);
|
||||
u32 size_tag = MFCArgs.Size_Tag.GetValue();
|
||||
u16 tag = (u16)size_tag;
|
||||
u16 size = size_tag >> 16;
|
||||
|
||||
switch(op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_PUTR_CMD: // ???
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "R" : ""),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
(op & MFC_FENCE_MASK ? "F" : ""),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
ProcessCmd(cmd, tag, lsa, ea, size);
|
||||
MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
|
||||
}
|
||||
break;
|
||||
|
||||
case MFC_PUTL_CMD:
|
||||
case MFC_PUTRL_CMD: // ???
|
||||
case MFC_GETL_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||
(op & MFC_PUT_CMD ? "PUT" : "GET"),
|
||||
(op & MFC_RESULT_MASK ? "RL" : "L"),
|
||||
(op & MFC_BARRIER_MASK ? "B" : ""),
|
||||
(op & MFC_FENCE_MASK ? "F" : ""),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
|
||||
}
|
||||
break;
|
||||
|
||||
case MFC_GETLLAR_CMD:
|
||||
case MFC_PUTLLC_CMD:
|
||||
case MFC_PUTLLUC_CMD:
|
||||
case MFC_PUTQLLUC_CMD:
|
||||
{
|
||||
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x",
|
||||
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
|
||||
op == MFC_PUTLLC_CMD ? "PUTLLC" :
|
||||
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
|
||||
lsa, ea, tag, size, cmd);
|
||||
|
||||
if (op == MFC_GETLLAR_CMD) // get reservation
|
||||
{
|
||||
if (R_ADDR)
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
}
|
||||
|
||||
R_ADDR = ea;
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
R_DATA[i] = *(u64*)&Memory[R_ADDR + i * 8];
|
||||
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = R_DATA[i];
|
||||
}
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
|
||||
}
|
||||
else if (op == MFC_PUTLLC_CMD) // store conditional
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
|
||||
|
||||
if (R_ADDR == ea)
|
||||
{
|
||||
u32 changed = 0, mask = 0;
|
||||
u64 buf[16];
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
buf[i] = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
|
||||
if (buf[i] != R_DATA[i])
|
||||
{
|
||||
changed++;
|
||||
mask |= (0x3 << (i * 2));
|
||||
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
R_ADDR = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (buf[i] != R_DATA[i])
|
||||
{
|
||||
if (InterlockedCompareExchange64((volatile long long*)(Memory + (ea + i * 8)), buf[i], R_DATA[i]) != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
|
||||
if (changed > 1)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
changed, mask, op, cmd, lsa, ea, tag, size);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed > 1)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
changed, mask, op, cmd, lsa, ea, tag, size);
|
||||
|
||||
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
||||
for (s32 i = PC; i < PC + 4 * 7; i += 4)
|
||||
{
|
||||
dis_asm.dump_pc = i;
|
||||
dis_asm.offset = Memory.GetMemFromAddr(dmac.ls_offset);
|
||||
const u32 opcode = Memory.Read32(i + dmac.ls_offset);
|
||||
(*SPU_instr::rrr_list)(&dis_asm, opcode);
|
||||
if (i >= 0 && i < 0x40000)
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "*** %s", dis_asm.last_opcode.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
||||
}
|
||||
R_ADDR = 0;
|
||||
}
|
||||
else // store unconditional
|
||||
{
|
||||
if (R_ADDR)
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
}
|
||||
|
||||
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
|
||||
if (op == MFC_PUTLLUC_CMD)
|
||||
{
|
||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
|
||||
}
|
||||
R_ADDR = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR( Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||
op, cmd, lsa, ea, tag, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckEvents() // checks events
|
||||
{
|
||||
// SPU_EVENT_LR:
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
|
||||
{
|
||||
m_events |= SPU_EVENT_LR;
|
||||
R_ADDR = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (m_events & m_event_mask) != 0;
|
||||
}
|
||||
|
||||
u32 GetChannelCount(u32 ch)
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
|
||||
case SPU_WrOutIntrMbox: return SPU.Out_IntrMBox.GetFreeCount();
|
||||
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
|
||||
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
|
||||
case MFC_RdListStallStat: return StallStat.GetCount();
|
||||
case MFC_WrTagUpdate: return MFC1.TagStatus.GetCount(); // hack
|
||||
case SPU_RdSigNotify1: return SPU.SNR[0].GetCount();
|
||||
case SPU_RdSigNotify2: return SPU.SNR[1].GetCount();
|
||||
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
|
||||
case SPU_RdEventStat: return CheckEvents() ? 1 : 0;
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).",
|
||||
__FUNCTION__, ch, spu_ch_name[ch]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteChannel(u32 ch, const SPU_GPR_hdr& r)
|
||||
{
|
||||
const u32 v = r._u32[3];
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case SPU_WrOutIntrMbox:
|
||||
{
|
||||
if (!group) // if RawSPU
|
||||
{
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
|
||||
while (!SPU.Out_IntrMBox.Push(v))
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_intrtag[2].stat |= 1;
|
||||
if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
|
||||
{
|
||||
if (t->GetType() == CPU_THREAD_PPU && !t->IsAlive())
|
||||
{
|
||||
PPUThread& ppu = *(PPUThread*)t;
|
||||
ppu.FastStop();
|
||||
ppu.Run();
|
||||
ppu.FastCall(ppu.PC, ppu.GPR[2], ppu.m_interrupt_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u8 code = v >> 24;
|
||||
if (code < 64)
|
||||
{
|
||||
/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */
|
||||
|
||||
u8 spup = code & 63;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
|
||||
}
|
||||
|
||||
EventPort& port = SPUPs[spup];
|
||||
|
||||
std::lock_guard<std::mutex> lock(port.m_mutex);
|
||||
|
||||
if (!port.eq)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
|
||||
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
|
||||
return;
|
||||
}
|
||||
|
||||
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
|
||||
{
|
||||
SPU.In_MBox.PushUncond(CELL_EBUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
return;
|
||||
}
|
||||
else if (code < 128)
|
||||
{
|
||||
/* ===== sys_spu_thread_throw_event ===== */
|
||||
|
||||
const u8 spup = code & 63;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
|
||||
}
|
||||
|
||||
EventPort& port = SPUPs[spup];
|
||||
|
||||
std::lock_guard<std::mutex> lock(port.m_mutex);
|
||||
|
||||
if (!port.eq)
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: check passing spup value
|
||||
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (code == 128)
|
||||
{
|
||||
/* ===== sys_event_flag_set_bit ===== */
|
||||
u32 flag = v & 0xffffff;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!Emu.GetIdManager().GetIDData(data, ef))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
|
||||
SPU.In_MBox.PushUncond(CELL_ESRCH);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentCPUThread()->GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= (u64)1 << flag;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
return;
|
||||
}
|
||||
else if (code == 192)
|
||||
{
|
||||
/* ===== sys_event_flag_set_bit_impatient ===== */
|
||||
u32 flag = v & 0xffffff;
|
||||
|
||||
u32 data;
|
||||
if (!SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag);
|
||||
}
|
||||
|
||||
EventFlag* ef;
|
||||
if (!Emu.GetIdManager().GetIDData(data, ef))
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetCurrentCPUThread()->GetId();
|
||||
|
||||
ef->m_mutex.lock(tid);
|
||||
ef->flags |= (u64)1 << flag;
|
||||
if (u32 target = ef->check())
|
||||
{
|
||||
// if signal, leave both mutexes locked...
|
||||
ef->signal.lock(target);
|
||||
ef->m_mutex.unlock(tid, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ef->m_mutex.unlock(tid);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 data;
|
||||
if (SPU.Out_MBox.Pop(data))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
|
||||
}
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrOutMbox:
|
||||
{
|
||||
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrTagMask:
|
||||
{
|
||||
MFC1.QueryMask.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrTagUpdate:
|
||||
{
|
||||
MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_LSA:
|
||||
{
|
||||
MFC1.LSA.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_EAH:
|
||||
{
|
||||
MFC1.EAH.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_EAL:
|
||||
{
|
||||
MFC1.EAL.SetValue(v);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_Size:
|
||||
{
|
||||
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_TagID:
|
||||
{
|
||||
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case MFC_Cmd:
|
||||
{
|
||||
MFC1.CMDStatus.SetValue(v);
|
||||
EnqMfcCmd(MFC1);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_WrListStallAck:
|
||||
{
|
||||
if (v >= 32)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v);
|
||||
return;
|
||||
}
|
||||
StalledList temp = StallList[v];
|
||||
if (!temp.MFCArgs)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v);
|
||||
return;
|
||||
}
|
||||
StallList[v].MFCArgs = nullptr;
|
||||
ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrDec:
|
||||
{
|
||||
m_dec_start = get_time();
|
||||
m_dec_value = v;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrEventMask:
|
||||
{
|
||||
m_event_mask = v;
|
||||
if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)");
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_WrEventAck:
|
||||
{
|
||||
m_events &= ~v;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
}
|
||||
|
||||
void ReadChannel(SPU_GPR_hdr& r, u32 ch)
|
||||
{
|
||||
r.Reset();
|
||||
u32& v = r._u32[3];
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case SPU_RdInMbox:
|
||||
{
|
||||
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdTagStat:
|
||||
{
|
||||
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdTagMask:
|
||||
{
|
||||
v = MFC1.QueryMask.GetValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify1:
|
||||
{
|
||||
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify2:
|
||||
{
|
||||
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdAtomicStat:
|
||||
{
|
||||
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_RdListStallStat:
|
||||
{
|
||||
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdDec:
|
||||
{
|
||||
v = m_dec_value - (u32)(get_time() - m_dec_start);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdEventMask:
|
||||
{
|
||||
v = m_event_mask;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdEventStat:
|
||||
{
|
||||
while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
v = m_events & m_event_mask;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdMachStat:
|
||||
{
|
||||
v = 1; // hack (not isolated, interrupts enabled)
|
||||
// TODO: check value
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||
}
|
||||
|
||||
void StopAndSignal(u32 code)
|
||||
{
|
||||
SetExitStatus(code); // exit code (not status)
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
|
||||
{
|
||||
u32 spuq = 0;
|
||||
if (!SPU.Out_MBox.Pop(spuq))
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox");
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
||||
return;
|
||||
}
|
||||
|
||||
if (SPU.In_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
|
||||
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
|
||||
return;
|
||||
}
|
||||
|
||||
if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||
}
|
||||
|
||||
EventQueue* eq;
|
||||
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
|
||||
{
|
||||
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
|
||||
return;
|
||||
}
|
||||
|
||||
u32 tid = GetId();
|
||||
|
||||
eq->sq.push(tid); // add thread to sleep queue
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (eq->owner.trylock(tid))
|
||||
{
|
||||
case SMR_OK:
|
||||
if (!eq->events.count())
|
||||
{
|
||||
eq->owner.unlock(tid);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
|
||||
if (next != tid)
|
||||
{
|
||||
eq->owner.unlock(tid, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SMR_SIGNAL:
|
||||
{
|
||||
sys_event_data event;
|
||||
eq->events.pop(event);
|
||||
eq->owner.unlock(tid);
|
||||
SPU.In_MBox.PushUncond(CELL_OK);
|
||||
SPU.In_MBox.PushUncond(event.data1);
|
||||
SPU.In_MBox.PushUncond(event.data2);
|
||||
SPU.In_MBox.PushUncond(event.data3);
|
||||
return;
|
||||
}
|
||||
case SMR_FAILED: break;
|
||||
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
|
||||
eq->sq.invalidate(tid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x102:
|
||||
if (!SPU.Out_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "sys_spu_thread_exit (no status, code 0x102)");
|
||||
}
|
||||
else if (Ini.HLELogging.GetValue())
|
||||
{
|
||||
// the real exit status
|
||||
LOG_NOTICE(Log::SPU, "sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue());
|
||||
}
|
||||
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
|
||||
Stop();
|
||||
break;
|
||||
default:
|
||||
if (!SPU.Out_MBox.GetCount())
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue());
|
||||
}
|
||||
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
|
||||
Stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
void StopAndSignal(u32 code);
|
||||
|
||||
virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); }
|
||||
virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include <memory>
|
||||
|
||||
#include "VFS.h"
|
||||
#include "Emu/HDD/HDD.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "vfsDir.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "vfsFile.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "vfsStreamMemory.h"
|
||||
|
||||
|
@ -2,6 +2,337 @@
|
||||
#include "Utilities/Log.h"
|
||||
#include "HDD.h"
|
||||
|
||||
void vfsHDDManager::CreateBlock(vfsHDD_Block& block)
|
||||
{
|
||||
block.is_used = true;
|
||||
block.next_block = 0;
|
||||
}
|
||||
|
||||
void vfsHDDManager::CreateEntry(vfsHDD_Entry& entry)
|
||||
{
|
||||
memset(&entry, 0, sizeof(vfsHDD_Entry));
|
||||
u64 ctime = time(nullptr);
|
||||
entry.atime = ctime;
|
||||
entry.ctime = ctime;
|
||||
entry.mtime = ctime;
|
||||
entry.access = vfsReadWrite;
|
||||
CreateBlock(entry);
|
||||
}
|
||||
|
||||
void vfsHDDManager::CreateHDD(const std::string& path, u64 size, u64 block_size)
|
||||
{
|
||||
rFile f(path, rFile::write);
|
||||
|
||||
static const u64 cur_dir_block = 1;
|
||||
|
||||
vfsHDD_Hdr hdr;
|
||||
CreateBlock(hdr);
|
||||
hdr.next_block = cur_dir_block;
|
||||
hdr.magic = g_hdd_magic;
|
||||
hdr.version = g_hdd_version;
|
||||
hdr.block_count = (size + block_size) / block_size;
|
||||
hdr.block_size = block_size;
|
||||
f.Write(&hdr, sizeof(vfsHDD_Hdr));
|
||||
|
||||
{
|
||||
vfsHDD_Entry entry;
|
||||
CreateEntry(entry);
|
||||
entry.type = vfsHDD_Entry_Dir;
|
||||
entry.data_block = hdr.next_block;
|
||||
entry.next_block = 0;
|
||||
|
||||
f.Seek(cur_dir_block * hdr.block_size);
|
||||
f.Write(&entry, sizeof(vfsHDD_Entry));
|
||||
f.Write(".");
|
||||
}
|
||||
|
||||
u8 null = 0;
|
||||
f.Seek(hdr.block_count * hdr.block_size - sizeof(null));
|
||||
f.Write(&null, sizeof(null));
|
||||
}
|
||||
|
||||
void vfsHDDManager::Format()
|
||||
{
|
||||
}
|
||||
|
||||
void vfsHDDManager::AppendEntry(vfsHDD_Entry entry)
|
||||
{
|
||||
}
|
||||
|
||||
bool vfsHDDFile::goto_block(u64 n)
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
|
||||
if (m_info.data_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hdd.Seek(m_info.data_block * m_hdd_info.block_size);
|
||||
block_info.next_block = m_info.data_block;
|
||||
|
||||
for (u64 i = 0; i<n; ++i)
|
||||
{
|
||||
if (!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hdd.Seek(block_info.next_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&block_info, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vfsHDDFile::RemoveBlocks(u64 start_block)
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
block_info.next_block = start_block;
|
||||
|
||||
while (block_info.next_block && block_info.is_used)
|
||||
{
|
||||
u64 offset = block_info.next_block * m_hdd_info.block_size;
|
||||
|
||||
ReadBlock(offset, block_info);
|
||||
WriteBlock(offset, g_null_block);
|
||||
}
|
||||
}
|
||||
|
||||
void vfsHDDFile::WriteBlock(u64 block, const vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void vfsHDDFile::ReadBlock(u64 block, vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void vfsHDDFile::ReadEntry(u64 block, std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
|
||||
m_hdd.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
|
||||
}
|
||||
|
||||
void vfsHDDFile::Open(u64 info_block)
|
||||
{
|
||||
m_info_block = info_block;
|
||||
ReadEntry(m_info_block, m_info);
|
||||
m_position = 0;
|
||||
m_cur_block = m_info.data_block;
|
||||
}
|
||||
|
||||
u64 vfsHDDFile::FindFreeBlock()
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
|
||||
for (u64 i = 0; i<m_hdd_info.block_count; ++i)
|
||||
{
|
||||
ReadBlock(i, block_info);
|
||||
|
||||
if (!block_info.is_used)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vfsHDDFile::Seek(u64 pos)
|
||||
{
|
||||
if (!goto_block(pos / m_hdd_info.block_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_position = pos % m_hdd_info.block_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void vfsHDDFile::SaveInfo()
|
||||
{
|
||||
m_hdd.Seek(m_info_block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&m_info, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
u64 vfsHDDFile::Read(void* dst, u64 size)
|
||||
{
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
//vfsDeviceLocker lock(m_hdd);
|
||||
|
||||
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
|
||||
u64 rsize = std::min<u64>(block_size - m_position, size);
|
||||
|
||||
vfsHDD_Block cur_block_info;
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block)+m_position);
|
||||
m_hdd.Read(dst, rsize);
|
||||
size -= rsize;
|
||||
m_position += rsize;
|
||||
if (!size)
|
||||
{
|
||||
return rsize;
|
||||
}
|
||||
|
||||
u64 offset = rsize;
|
||||
|
||||
for (; size; size -= rsize, offset += rsize)
|
||||
{
|
||||
if (!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
m_cur_block = cur_block_info.next_block;
|
||||
rsize = std::min<u64>(block_size, size);
|
||||
|
||||
m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
|
||||
|
||||
if (m_hdd.Read((u8*)dst + offset, rsize) != rsize)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
m_position = rsize;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
u64 vfsHDDFile::Write(const void* src, u64 size)
|
||||
{
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
//vfsDeviceLocker lock(m_hdd);
|
||||
|
||||
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
|
||||
|
||||
if (!m_cur_block)
|
||||
{
|
||||
if (!m_info.data_block)
|
||||
{
|
||||
u64 new_block = FindFreeBlock();
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
WriteBlock(new_block, g_used_block);
|
||||
m_info.data_block = new_block;
|
||||
m_info.size = 0;
|
||||
SaveInfo();
|
||||
}
|
||||
|
||||
m_cur_block = m_info.data_block;
|
||||
m_position = 0;
|
||||
}
|
||||
|
||||
u64 wsize = std::min<u64>(block_size - m_position, size);
|
||||
|
||||
vfsHDD_Block block_info;
|
||||
ReadBlock(m_cur_block, block_info);
|
||||
|
||||
if (wsize)
|
||||
{
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block)+m_position);
|
||||
m_hdd.Write(src, wsize);
|
||||
size -= wsize;
|
||||
m_info.size += wsize;
|
||||
m_position += wsize;
|
||||
SaveInfo();
|
||||
|
||||
if (!size)
|
||||
return wsize;
|
||||
}
|
||||
|
||||
u64 last_block = m_cur_block;
|
||||
block_info.is_used = true;
|
||||
u64 offset = wsize;
|
||||
|
||||
for (; size; size -= wsize, offset += wsize, m_info.size += wsize)
|
||||
{
|
||||
u64 new_block = FindFreeBlock();
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
m_cur_block = new_block;
|
||||
wsize = std::min<u64>(block_size, size);
|
||||
|
||||
block_info.next_block = m_cur_block;
|
||||
m_hdd.Seek(last_block * m_hdd_info.block_size);
|
||||
if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
block_info.next_block = 0;
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
|
||||
if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
if ((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize)
|
||||
{
|
||||
m_info.size += wsize;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
last_block = m_cur_block;
|
||||
}
|
||||
|
||||
SaveInfo();
|
||||
m_position = wsize;
|
||||
return offset;
|
||||
}
|
||||
|
||||
vfsDeviceHDD::vfsDeviceHDD(const std::string& hdd_path) : m_hdd_path(hdd_path)
|
||||
{
|
||||
}
|
||||
@ -15,3 +346,438 @@ vfsDirBase* vfsDeviceHDD::GetNewDirStream()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vfsHDD::vfsHDD(vfsDevice* device, const std::string& hdd_path)
|
||||
: m_hdd_file(device)
|
||||
, m_file(m_hdd_file, m_hdd_info)
|
||||
, m_hdd_path(hdd_path)
|
||||
, vfsFileBase(device)
|
||||
{
|
||||
m_hdd_file.Open(hdd_path, vfsReadWrite);
|
||||
m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr));
|
||||
m_cur_dir_block = m_hdd_info.next_block;
|
||||
if (!m_hdd_info.block_size)
|
||||
{
|
||||
LOG_ERROR(HLE, "Bad block size!");
|
||||
m_hdd_info.block_size = 2048;
|
||||
}
|
||||
m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
bool vfsHDD::SearchEntry(const std::string& name, u64& entry_block, u64* parent_block)
|
||||
{
|
||||
u64 last_block = 0;
|
||||
u64 block = m_cur_dir_block;
|
||||
vfsHDD_Entry entry;
|
||||
std::string buf;
|
||||
|
||||
while (block)
|
||||
{
|
||||
ReadEntry(block, entry, buf);
|
||||
|
||||
if (fmt::CmpNoCase(name, buf) == 0)
|
||||
{
|
||||
entry_block = block;
|
||||
if (parent_block)
|
||||
*parent_block = last_block;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
last_block = block;
|
||||
block = entry.is_used ? entry.next_block : 0ULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int vfsHDD::OpenDir(const std::string& name)
|
||||
{
|
||||
LOG_WARNING(HLE, "OpenDir(%s)", name.c_str());
|
||||
u64 entry_block;
|
||||
if (!SearchEntry(name, entry_block))
|
||||
return -1;
|
||||
|
||||
m_hdd_file.Seek(entry_block * m_hdd_info.block_size);
|
||||
vfsHDD_Entry entry;
|
||||
m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry));
|
||||
if (entry.type == vfsHDD_Entry_File)
|
||||
return 1;
|
||||
|
||||
m_cur_dir_block = entry.data_block;
|
||||
ReadEntry(m_cur_dir_block, m_cur_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool vfsHDD::Rename(const std::string& from, const std::string& to)
|
||||
{
|
||||
u64 entry_block;
|
||||
if (!SearchEntry(from, entry_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vfsHDD_Entry entry;
|
||||
ReadEntry(entry_block, entry);
|
||||
WriteEntry(entry_block, entry, to);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 vfsHDD::FindFreeBlock()
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
|
||||
for (u64 i = 0; i<m_hdd_info.block_count; ++i)
|
||||
{
|
||||
ReadBlock(i, block_info);
|
||||
|
||||
if (!block_info.is_used)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vfsHDD::WriteBlock(u64 block, const vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void vfsHDD::ReadBlock(u64 block, vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd_file.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void vfsHDD::ReadEntry(u64 block, std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd_file.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
|
||||
m_hdd_file.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
|
||||
}
|
||||
|
||||
bool vfsHDD::Create(vfsHDD_EntryType type, const std::string& name)
|
||||
{
|
||||
if (HasEntry(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 new_block = FindFreeBlock();
|
||||
if (!new_block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block);
|
||||
WriteBlock(new_block, g_used_block);
|
||||
|
||||
{
|
||||
vfsHDD_Entry new_entry;
|
||||
vfsHDDManager::CreateEntry(new_entry);
|
||||
new_entry.next_block = 0;
|
||||
new_entry.type = type;
|
||||
|
||||
if (type == vfsHDD_Entry_Dir)
|
||||
{
|
||||
u64 block_cur = FindFreeBlock();
|
||||
|
||||
if (!block_cur)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteBlock(block_cur, g_used_block);
|
||||
|
||||
u64 block_last = FindFreeBlock();
|
||||
|
||||
if (!block_last)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteBlock(block_last, g_used_block);
|
||||
|
||||
vfsHDD_Entry entry_cur, entry_last;
|
||||
vfsHDDManager::CreateEntry(entry_cur);
|
||||
vfsHDDManager::CreateEntry(entry_last);
|
||||
|
||||
entry_cur.type = vfsHDD_Entry_Dir;
|
||||
entry_cur.data_block = block_cur;
|
||||
entry_cur.next_block = block_last;
|
||||
|
||||
entry_last.type = vfsHDD_Entry_Dir;
|
||||
entry_last.data_block = m_cur_dir_block;
|
||||
entry_last.next_block = 0;
|
||||
|
||||
new_entry.data_block = block_cur;
|
||||
|
||||
WriteEntry(block_cur, entry_cur, ".");
|
||||
WriteEntry(block_last, entry_last, "..");
|
||||
}
|
||||
|
||||
WriteEntry(new_block, new_entry, name);
|
||||
}
|
||||
|
||||
{
|
||||
u64 block = m_cur_dir_block;
|
||||
|
||||
vfsHDD_Block tmp;
|
||||
while (block)
|
||||
{
|
||||
ReadBlock(block, tmp);
|
||||
|
||||
if (!tmp.next_block)
|
||||
break;
|
||||
|
||||
block = tmp.next_block;
|
||||
}
|
||||
|
||||
tmp.next_block = new_block;
|
||||
WriteBlock(block, tmp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfsHDD::GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
|
||||
{
|
||||
if (!m_cur_dir_block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadEntry(m_cur_dir_block, entry, name);
|
||||
block = entry.is_used ? entry.next_block : 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfsHDD::GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
|
||||
{
|
||||
if (!block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadEntry(block, entry, name);
|
||||
|
||||
block = entry.is_used ? entry.next_block : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfsHDD::Open(const std::string& path, vfsOpenMode mode)
|
||||
{
|
||||
const char* s = path.c_str();
|
||||
u64 from = 0;
|
||||
u64 pos = 0;
|
||||
u64 file_pos = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if (s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ???
|
||||
{
|
||||
if (file_pos != -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (from != -1)
|
||||
{
|
||||
if (pos - from > 1)
|
||||
{
|
||||
int res = OpenDir(std::string(s + from, pos));
|
||||
if (res == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
file_pos = from;
|
||||
}
|
||||
}
|
||||
|
||||
from = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = pos;
|
||||
}
|
||||
}
|
||||
} while (s[pos++] != '\0');
|
||||
|
||||
if (file_pos == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 file_block;
|
||||
if (!SearchEntry(std::string(s + file_pos), file_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block);
|
||||
m_file.Open(file_block);
|
||||
|
||||
return vfsFileBase::Open(path, mode);
|
||||
}
|
||||
|
||||
bool vfsHDD::HasEntry(const std::string& name)
|
||||
{
|
||||
u64 file_block;
|
||||
if (!SearchEntry(name, file_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vfsHDD::RemoveBlocksDir(u64 start_block)
|
||||
{
|
||||
std::string name;
|
||||
u64 block = start_block;
|
||||
vfsHDD_Entry entry;
|
||||
|
||||
while (block)
|
||||
{
|
||||
ReadEntry(block, entry, name);
|
||||
WriteBlock(block, g_null_block);
|
||||
|
||||
if (entry.type == vfsHDD_Entry_Dir && name != "." && name != "..")
|
||||
{
|
||||
LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str());
|
||||
RemoveBlocksDir(entry.data_block);
|
||||
}
|
||||
else if (entry.type == vfsHDD_Entry_File)
|
||||
{
|
||||
RemoveBlocksFile(entry.data_block);
|
||||
}
|
||||
|
||||
block = entry.next_block;
|
||||
}
|
||||
}
|
||||
|
||||
void vfsHDD::RemoveBlocksFile(u64 start_block)
|
||||
{
|
||||
u64 block = start_block;
|
||||
vfsHDD_Block block_data;
|
||||
|
||||
while (block)
|
||||
{
|
||||
ReadBlock(block, block_data);
|
||||
WriteBlock(block, g_null_block);
|
||||
|
||||
block = block_data.next_block;
|
||||
}
|
||||
}
|
||||
|
||||
bool vfsHDD::RemoveEntry(const std::string& name)
|
||||
{
|
||||
u64 entry_block, parent_entry;
|
||||
if (!SearchEntry(name, entry_block, &parent_entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vfsHDD_Entry entry;
|
||||
ReadEntry(entry_block, entry);
|
||||
if (entry.type == vfsHDD_Entry_Dir)
|
||||
{
|
||||
RemoveBlocksDir(entry.data_block);
|
||||
}
|
||||
else if (entry.type == vfsHDD_Entry_File)
|
||||
{
|
||||
RemoveBlocksFile(entry.data_block);
|
||||
}
|
||||
|
||||
if (parent_entry)
|
||||
{
|
||||
u64 next = entry.next_block;
|
||||
ReadEntry(parent_entry, entry);
|
||||
entry.next_block = next;
|
||||
WriteEntry(parent_entry, entry);
|
||||
}
|
||||
WriteBlock(entry_block, g_null_block);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfsHDD::Create(const std::string& path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 vfsHDD::Write(const void* src, u32 size)
|
||||
{
|
||||
return vfsFileBase::Write(src, m_file.Write(src, size));
|
||||
}
|
||||
|
||||
u32 vfsHDD::Read(void* dst, u32 size)
|
||||
{
|
||||
return vfsFileBase::Read(dst, m_file.Read(dst, size));
|
||||
}
|
||||
|
||||
u64 vfsHDD::Seek(s64 offset, vfsSeekMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case vfsSeekCur:
|
||||
m_file.Seek(Tell() + offset);
|
||||
break;
|
||||
|
||||
case vfsSeekSet:
|
||||
m_file.Seek(offset);
|
||||
break;
|
||||
|
||||
case vfsSeekEnd:
|
||||
m_file.Seek(m_file.GetSize() + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return vfsFileBase::Seek(offset, mode);
|
||||
}
|
||||
|
||||
bool vfsHDD::Eof()
|
||||
{
|
||||
return m_file.Eof();
|
||||
}
|
||||
|
||||
u64 vfsHDD::GetSize()
|
||||
{
|
||||
return m_file.GetSize();
|
||||
}
|
@ -44,62 +44,15 @@ struct vfsHDD_Entry : public vfsHDD_Block
|
||||
class vfsHDDManager
|
||||
{
|
||||
public:
|
||||
static void CreateBlock(vfsHDD_Block& block)
|
||||
{
|
||||
block.is_used = true;
|
||||
block.next_block = 0;
|
||||
}
|
||||
static void CreateBlock(vfsHDD_Block& block);
|
||||
|
||||
static void CreateEntry(vfsHDD_Entry& entry)
|
||||
{
|
||||
memset(&entry, 0, sizeof(vfsHDD_Entry));
|
||||
u64 ctime = time(nullptr);
|
||||
entry.atime = ctime;
|
||||
entry.ctime = ctime;
|
||||
entry.mtime = ctime;
|
||||
entry.access = vfsReadWrite;
|
||||
CreateBlock(entry);
|
||||
}
|
||||
static void CreateEntry(vfsHDD_Entry& entry);
|
||||
|
||||
static void CreateHDD(const std::string& path, u64 size, u64 block_size)
|
||||
{
|
||||
rFile f(path, rFile::write);
|
||||
static void CreateHDD(const std::string& path, u64 size, u64 block_size);
|
||||
|
||||
static const u64 cur_dir_block = 1;
|
||||
void Format();
|
||||
|
||||
vfsHDD_Hdr hdr;
|
||||
CreateBlock(hdr);
|
||||
hdr.next_block = cur_dir_block;
|
||||
hdr.magic = g_hdd_magic;
|
||||
hdr.version = g_hdd_version;
|
||||
hdr.block_count = (size + block_size) / block_size;
|
||||
hdr.block_size = block_size;
|
||||
f.Write(&hdr, sizeof(vfsHDD_Hdr));
|
||||
|
||||
{
|
||||
vfsHDD_Entry entry;
|
||||
CreateEntry(entry);
|
||||
entry.type = vfsHDD_Entry_Dir;
|
||||
entry.data_block = hdr.next_block;
|
||||
entry.next_block = 0;
|
||||
|
||||
f.Seek(cur_dir_block * hdr.block_size);
|
||||
f.Write(&entry, sizeof(vfsHDD_Entry));
|
||||
f.Write(".");
|
||||
}
|
||||
|
||||
u8 null = 0;
|
||||
f.Seek(hdr.block_count * hdr.block_size - sizeof(null));
|
||||
f.Write(&null, sizeof(null));
|
||||
}
|
||||
|
||||
void Format()
|
||||
{
|
||||
}
|
||||
|
||||
void AppendEntry(vfsHDD_Entry entry)
|
||||
{
|
||||
}
|
||||
void AppendEntry(vfsHDD_Entry entry);
|
||||
};
|
||||
|
||||
|
||||
@ -112,91 +65,23 @@ class vfsHDDFile
|
||||
u32 m_position;
|
||||
u64 m_cur_block;
|
||||
|
||||
bool goto_block(u64 n)
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
bool goto_block(u64 n);
|
||||
|
||||
if(m_info.data_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void RemoveBlocks(u64 start_block);
|
||||
|
||||
m_hdd.Seek(m_info.data_block * m_hdd_info.block_size);
|
||||
block_info.next_block = m_info.data_block;
|
||||
void WriteBlock(u64 block, const vfsHDD_Block& data);
|
||||
|
||||
for(u64 i=0; i<n; ++i)
|
||||
{
|
||||
if(!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void ReadBlock(u64 block, vfsHDD_Block& data);
|
||||
|
||||
m_hdd.Seek(block_info.next_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&block_info, sizeof(vfsHDD_Block));
|
||||
}
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data);
|
||||
|
||||
return true;
|
||||
}
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data);
|
||||
|
||||
void RemoveBlocks(u64 start_block)
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
block_info.next_block = start_block;
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name);
|
||||
|
||||
while(block_info.next_block && block_info.is_used)
|
||||
{
|
||||
u64 offset = block_info.next_block * m_hdd_info.block_size;
|
||||
void ReadEntry(u64 block, std::string& name);
|
||||
|
||||
ReadBlock(offset, block_info);
|
||||
WriteBlock(offset, g_null_block);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteBlock(u64 block, const vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void ReadBlock(u64 block, vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void ReadEntry(u64 block, std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
|
||||
{
|
||||
m_hdd.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
|
||||
m_hdd.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
|
||||
}
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name);
|
||||
|
||||
__forceinline u32 GetMaxNameLen() const
|
||||
{
|
||||
@ -214,198 +99,22 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void Open(u64 info_block)
|
||||
{
|
||||
m_info_block = info_block;
|
||||
ReadEntry(m_info_block, m_info);
|
||||
m_position = 0;
|
||||
m_cur_block = m_info.data_block;
|
||||
}
|
||||
void Open(u64 info_block);
|
||||
|
||||
u64 FindFreeBlock()
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
|
||||
for(u64 i = 0; i<m_hdd_info.block_count; ++i)
|
||||
{
|
||||
ReadBlock(i, block_info);
|
||||
|
||||
if(!block_info.is_used)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
u64 FindFreeBlock();
|
||||
|
||||
u64 GetSize() const
|
||||
{
|
||||
return m_info.size;
|
||||
}
|
||||
|
||||
bool Seek(u64 pos)
|
||||
{
|
||||
if(!goto_block(pos / m_hdd_info.block_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Seek(u64 pos);
|
||||
|
||||
m_position = pos % m_hdd_info.block_size;
|
||||
return true;
|
||||
}
|
||||
void SaveInfo();
|
||||
|
||||
void SaveInfo()
|
||||
{
|
||||
m_hdd.Seek(m_info_block * m_hdd_info.block_size);
|
||||
m_hdd.Write(&m_info, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
u64 Read(void* dst, u64 size);
|
||||
|
||||
u64 Read(void* dst, u64 size)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
|
||||
//vfsDeviceLocker lock(m_hdd);
|
||||
|
||||
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
|
||||
u64 rsize = std::min<u64>(block_size - m_position, size);
|
||||
|
||||
vfsHDD_Block cur_block_info;
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position);
|
||||
m_hdd.Read(dst, rsize);
|
||||
size -= rsize;
|
||||
m_position += rsize;
|
||||
if(!size)
|
||||
{
|
||||
return rsize;
|
||||
}
|
||||
|
||||
u64 offset = rsize;
|
||||
|
||||
for(; size; size -= rsize, offset += rsize)
|
||||
{
|
||||
if(!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
m_cur_block = cur_block_info.next_block;
|
||||
rsize = std::min<u64>(block_size, size);
|
||||
|
||||
m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size);
|
||||
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
|
||||
|
||||
if(m_hdd.Read((u8*)dst + offset, rsize) != rsize)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
m_position = rsize;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
u64 Write(const void* src, u64 size)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
|
||||
//vfsDeviceLocker lock(m_hdd);
|
||||
|
||||
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
|
||||
|
||||
if(!m_cur_block)
|
||||
{
|
||||
if(!m_info.data_block)
|
||||
{
|
||||
u64 new_block = FindFreeBlock();
|
||||
|
||||
if(!new_block)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
WriteBlock(new_block, g_used_block);
|
||||
m_info.data_block = new_block;
|
||||
m_info.size = 0;
|
||||
SaveInfo();
|
||||
}
|
||||
|
||||
m_cur_block = m_info.data_block;
|
||||
m_position = 0;
|
||||
}
|
||||
|
||||
u64 wsize = std::min<u64>(block_size - m_position, size);
|
||||
|
||||
vfsHDD_Block block_info;
|
||||
ReadBlock(m_cur_block, block_info);
|
||||
|
||||
if(wsize)
|
||||
{
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position);
|
||||
m_hdd.Write(src, wsize);
|
||||
size -= wsize;
|
||||
m_info.size += wsize;
|
||||
m_position += wsize;
|
||||
SaveInfo();
|
||||
|
||||
if(!size)
|
||||
return wsize;
|
||||
}
|
||||
|
||||
u64 last_block = m_cur_block;
|
||||
block_info.is_used = true;
|
||||
u64 offset = wsize;
|
||||
|
||||
for(; size; size -= wsize, offset += wsize, m_info.size += wsize)
|
||||
{
|
||||
u64 new_block = FindFreeBlock();
|
||||
|
||||
if(!new_block)
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
m_cur_block = new_block;
|
||||
wsize = std::min<u64>(block_size, size);
|
||||
|
||||
block_info.next_block = m_cur_block;
|
||||
m_hdd.Seek(last_block * m_hdd_info.block_size);
|
||||
if(m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
block_info.next_block = 0;
|
||||
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
|
||||
if(m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
|
||||
{
|
||||
m_position = 0;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
if((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize)
|
||||
{
|
||||
m_info.size += wsize;
|
||||
SaveInfo();
|
||||
return offset;
|
||||
}
|
||||
|
||||
last_block = m_cur_block;
|
||||
}
|
||||
|
||||
SaveInfo();
|
||||
m_position = wsize;
|
||||
return offset;
|
||||
}
|
||||
u64 Write(const void* src, u64 size);
|
||||
|
||||
bool Eof() const
|
||||
{
|
||||
@ -434,444 +143,60 @@ class vfsHDD : public vfsFileBase
|
||||
vfsHDDFile m_file;
|
||||
|
||||
public:
|
||||
vfsHDD(vfsDevice* device, const std::string& hdd_path)
|
||||
: m_hdd_file(device)
|
||||
, m_file(m_hdd_file, m_hdd_info)
|
||||
, m_hdd_path(hdd_path)
|
||||
, vfsFileBase(device)
|
||||
{
|
||||
m_hdd_file.Open(hdd_path, vfsReadWrite);
|
||||
m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr));
|
||||
m_cur_dir_block = m_hdd_info.next_block;
|
||||
if(!m_hdd_info.block_size)
|
||||
{
|
||||
LOG_ERROR(HLE, "Bad block size!");
|
||||
m_hdd_info.block_size = 2048;
|
||||
}
|
||||
m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
vfsHDD(vfsDevice* device, const std::string& hdd_path);
|
||||
|
||||
__forceinline u32 GetMaxNameLen() const
|
||||
{
|
||||
return m_hdd_info.block_size - sizeof(vfsHDD_Entry);
|
||||
}
|
||||
|
||||
bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr)
|
||||
{
|
||||
u64 last_block = 0;
|
||||
u64 block = m_cur_dir_block;
|
||||
vfsHDD_Entry entry;
|
||||
std::string buf;
|
||||
bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr);
|
||||
|
||||
while(block)
|
||||
{
|
||||
ReadEntry(block, entry, buf);
|
||||
int OpenDir(const std::string& name);
|
||||
|
||||
if (fmt::CmpNoCase(name,buf) == 0)
|
||||
{
|
||||
entry_block = block;
|
||||
if(parent_block)
|
||||
*parent_block = last_block;
|
||||
bool Rename(const std::string& from, const std::string& to);
|
||||
|
||||
return true;
|
||||
}
|
||||
u64 FindFreeBlock();
|
||||
|
||||
last_block = block;
|
||||
block = entry.is_used ? entry.next_block : 0ULL;
|
||||
}
|
||||
void WriteBlock(u64 block, const vfsHDD_Block& data);
|
||||
|
||||
return false;
|
||||
}
|
||||
void ReadBlock(u64 block, vfsHDD_Block& data);
|
||||
|
||||
int OpenDir(const std::string& name)
|
||||
{
|
||||
LOG_WARNING(HLE, "OpenDir(%s)", name.c_str());
|
||||
u64 entry_block;
|
||||
if(!SearchEntry(name, entry_block))
|
||||
return -1;
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data);
|
||||
|
||||
m_hdd_file.Seek(entry_block * m_hdd_info.block_size);
|
||||
vfsHDD_Entry entry;
|
||||
m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry));
|
||||
if(entry.type == vfsHDD_Entry_File)
|
||||
return 1;
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data);
|
||||
|
||||
m_cur_dir_block = entry.data_block;
|
||||
ReadEntry(m_cur_dir_block, m_cur_dir);
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void ReadEntry(u64 block, std::string& name);
|
||||
|
||||
bool Rename(const std::string& from, const std::string& to)
|
||||
{
|
||||
u64 entry_block;
|
||||
if(!SearchEntry(from, entry_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name);
|
||||
|
||||
vfsHDD_Entry entry;
|
||||
ReadEntry(entry_block, entry);
|
||||
WriteEntry(entry_block, entry, to);
|
||||
bool Create(vfsHDD_EntryType type, const std::string& name);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name);
|
||||
|
||||
u64 FindFreeBlock()
|
||||
{
|
||||
vfsHDD_Block block_info;
|
||||
bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name);
|
||||
|
||||
for(u64 i = 0; i<m_hdd_info.block_count; ++i)
|
||||
{
|
||||
ReadBlock(i, block_info);
|
||||
virtual bool Open(const std::string& path, vfsOpenMode mode = vfsRead);
|
||||
|
||||
if(!block_info.is_used)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
bool HasEntry(const std::string& name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void RemoveBlocksDir(u64 start_block);
|
||||
|
||||
void WriteBlock(u64 block, const vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
void RemoveBlocksFile(u64 start_block);
|
||||
|
||||
void ReadBlock(u64 block, vfsHDD_Block& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Block));
|
||||
}
|
||||
bool RemoveEntry(const std::string& name);
|
||||
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
virtual bool Create(const std::string& path);
|
||||
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
|
||||
}
|
||||
virtual u32 Write(const void* src, u32 size);
|
||||
|
||||
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd_file.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
virtual u32 Read(void* dst, u32 size);
|
||||
|
||||
void ReadEntry(u64 block, std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
|
||||
name.resize(GetMaxNameLen());
|
||||
m_hdd_file.Read(&name.front(), GetMaxNameLen());
|
||||
}
|
||||
virtual u64 Seek(s64 offset, vfsSeekMode mode = vfsSeekSet);
|
||||
|
||||
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
|
||||
{
|
||||
m_hdd_file.Seek(block * m_hdd_info.block_size);
|
||||
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
|
||||
m_hdd_file.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
|
||||
}
|
||||
virtual bool Eof();
|
||||
|
||||
bool Create(vfsHDD_EntryType type, const std::string& name)
|
||||
{
|
||||
if(HasEntry(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 new_block = FindFreeBlock();
|
||||
if(!new_block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block);
|
||||
WriteBlock(new_block, g_used_block);
|
||||
|
||||
{
|
||||
vfsHDD_Entry new_entry;
|
||||
vfsHDDManager::CreateEntry(new_entry);
|
||||
new_entry.next_block = 0;
|
||||
new_entry.type = type;
|
||||
|
||||
if(type == vfsHDD_Entry_Dir)
|
||||
{
|
||||
u64 block_cur = FindFreeBlock();
|
||||
|
||||
if(!block_cur)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteBlock(block_cur, g_used_block);
|
||||
|
||||
u64 block_last = FindFreeBlock();
|
||||
|
||||
if(!block_last)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteBlock(block_last, g_used_block);
|
||||
|
||||
vfsHDD_Entry entry_cur, entry_last;
|
||||
vfsHDDManager::CreateEntry(entry_cur);
|
||||
vfsHDDManager::CreateEntry(entry_last);
|
||||
|
||||
entry_cur.type = vfsHDD_Entry_Dir;
|
||||
entry_cur.data_block = block_cur;
|
||||
entry_cur.next_block = block_last;
|
||||
|
||||
entry_last.type = vfsHDD_Entry_Dir;
|
||||
entry_last.data_block = m_cur_dir_block;
|
||||
entry_last.next_block = 0;
|
||||
|
||||
new_entry.data_block = block_cur;
|
||||
|
||||
WriteEntry(block_cur, entry_cur, ".");
|
||||
WriteEntry(block_last, entry_last, "..");
|
||||
}
|
||||
|
||||
WriteEntry(new_block, new_entry, name);
|
||||
}
|
||||
|
||||
{
|
||||
u64 block = m_cur_dir_block;
|
||||
|
||||
vfsHDD_Block tmp;
|
||||
while(block)
|
||||
{
|
||||
ReadBlock(block, tmp);
|
||||
|
||||
if(!tmp.next_block)
|
||||
break;
|
||||
|
||||
block = tmp.next_block;
|
||||
}
|
||||
|
||||
tmp.next_block = new_block;
|
||||
WriteBlock(block, tmp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
|
||||
{
|
||||
if(!m_cur_dir_block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadEntry(m_cur_dir_block, entry, name);
|
||||
block = entry.is_used ? entry.next_block : 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
|
||||
{
|
||||
if(!block)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadEntry(block, entry, name);
|
||||
|
||||
block = entry.is_used ? entry.next_block : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Open(const std::string& path, vfsOpenMode mode = vfsRead)
|
||||
{
|
||||
const char* s = path.c_str();
|
||||
u64 from = 0;
|
||||
u64 pos = 0;
|
||||
u64 file_pos = -1;
|
||||
|
||||
do
|
||||
{
|
||||
if(s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ???
|
||||
{
|
||||
if(file_pos != -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(from != -1)
|
||||
{
|
||||
if(pos - from > 1)
|
||||
{
|
||||
int res = OpenDir(std::string(s + from, pos));
|
||||
if(res == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(res == 1)
|
||||
{
|
||||
file_pos = from;
|
||||
}
|
||||
}
|
||||
|
||||
from = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(s[pos++] != '\0');
|
||||
|
||||
if(file_pos == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 file_block;
|
||||
if(!SearchEntry(std::string(s + file_pos), file_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block);
|
||||
m_file.Open(file_block);
|
||||
|
||||
return vfsFileBase::Open(path, mode);
|
||||
}
|
||||
|
||||
bool HasEntry(const std::string& name)
|
||||
{
|
||||
u64 file_block;
|
||||
if(!SearchEntry(name, file_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoveBlocksDir(u64 start_block)
|
||||
{
|
||||
std::string name;
|
||||
u64 block = start_block;
|
||||
vfsHDD_Entry entry;
|
||||
|
||||
while(block)
|
||||
{
|
||||
ReadEntry(block, entry, name);
|
||||
WriteBlock(block, g_null_block);
|
||||
|
||||
if(entry.type == vfsHDD_Entry_Dir && name != "." && name != "..")
|
||||
{
|
||||
LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str());
|
||||
RemoveBlocksDir(entry.data_block);
|
||||
}
|
||||
else if(entry.type == vfsHDD_Entry_File)
|
||||
{
|
||||
RemoveBlocksFile(entry.data_block);
|
||||
}
|
||||
|
||||
block = entry.next_block;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveBlocksFile(u64 start_block)
|
||||
{
|
||||
u64 block = start_block;
|
||||
vfsHDD_Block block_data;
|
||||
|
||||
while(block)
|
||||
{
|
||||
ReadBlock(block, block_data);
|
||||
WriteBlock(block, g_null_block);
|
||||
|
||||
block = block_data.next_block;
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoveEntry(const std::string& name)
|
||||
{
|
||||
u64 entry_block, parent_entry;
|
||||
if(!SearchEntry(name, entry_block, &parent_entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vfsHDD_Entry entry;
|
||||
ReadEntry(entry_block, entry);
|
||||
if(entry.type == vfsHDD_Entry_Dir)
|
||||
{
|
||||
RemoveBlocksDir(entry.data_block);
|
||||
}
|
||||
else if(entry.type == vfsHDD_Entry_File)
|
||||
{
|
||||
RemoveBlocksFile(entry.data_block);
|
||||
}
|
||||
|
||||
if(parent_entry)
|
||||
{
|
||||
u64 next = entry.next_block;
|
||||
ReadEntry(parent_entry, entry);
|
||||
entry.next_block = next;
|
||||
WriteEntry(parent_entry, entry);
|
||||
}
|
||||
WriteBlock(entry_block, g_null_block);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Create(const std::string& path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual u32 Write(const void* src, u32 size)
|
||||
{
|
||||
return vfsFileBase::Write(src, m_file.Write(src, size));
|
||||
}
|
||||
|
||||
virtual u32 Read(void* dst, u32 size)
|
||||
{
|
||||
return vfsFileBase::Read(dst, m_file.Read(dst, size));
|
||||
}
|
||||
|
||||
virtual u64 Seek(s64 offset, vfsSeekMode mode = vfsSeekSet)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case vfsSeekCur:
|
||||
m_file.Seek(Tell() + offset);
|
||||
break;
|
||||
|
||||
case vfsSeekSet:
|
||||
m_file.Seek(offset);
|
||||
break;
|
||||
|
||||
case vfsSeekEnd:
|
||||
m_file.Seek(m_file.GetSize() + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return vfsFileBase::Seek(offset, mode);
|
||||
}
|
||||
|
||||
virtual bool Eof()
|
||||
{
|
||||
return m_file.Eof();
|
||||
}
|
||||
|
||||
virtual u64 GetSize()
|
||||
{
|
||||
return m_file.GetSize();
|
||||
}
|
||||
virtual u64 GetSize();
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "Keyboard.h"
|
||||
#include "Null/NullKeyboardHandler.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "Mouse.h"
|
||||
#include "Null/NullMouseHandler.h"
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "Pad.h"
|
||||
#include "Null/NullPadHandler.h"
|
||||
|
@ -4,7 +4,15 @@
|
||||
#include "Utilities/Log.h"
|
||||
#include "Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Ini.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
MemoryBase Memory;
|
||||
|
||||
@ -535,12 +543,6 @@ bool MemoryBlockLE::Write128(const u64 addr, const u128 value)
|
||||
return true;
|
||||
}
|
||||
|
||||
// MemoryBase
|
||||
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(), m_reserve_size(0)
|
||||
{
|
||||
}
|
||||
|
@ -1,17 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "MemoryBlock.h"
|
||||
#include "Emu/SysCalls/Callback.h"
|
||||
|
||||
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
using std::nullptr_t;
|
||||
|
||||
#define safe_delete(x) do {delete (x);(x)=nullptr;} while(0)
|
||||
@ -112,36 +103,6 @@ public:
|
||||
|
||||
void UnregisterPages(u64 addr, u32 size);
|
||||
|
||||
static __forceinline u16 Reverse16(const u16 val)
|
||||
{
|
||||
return _byteswap_ushort(val);
|
||||
}
|
||||
|
||||
static __forceinline u32 Reverse32(const u32 val)
|
||||
{
|
||||
return _byteswap_ulong(val);
|
||||
}
|
||||
|
||||
static __forceinline u64 Reverse64(const u64 val)
|
||||
{
|
||||
return _byteswap_uint64(val);
|
||||
}
|
||||
|
||||
static __forceinline u128 Reverse128(const u128 val)
|
||||
{
|
||||
u128 ret;
|
||||
ret.lo = _byteswap_uint64(val.hi);
|
||||
ret.hi = _byteswap_uint64(val.lo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<int size> static __forceinline u64 ReverseData(u64 val);
|
||||
|
||||
template<typename T> static __forceinline T Reverse(T val)
|
||||
{
|
||||
return (T)ReverseData<sizeof(T)>(val);
|
||||
};
|
||||
|
||||
template<typename T> u8* GetMemFromAddr(const T addr)
|
||||
{
|
||||
if ((u32)addr == addr)
|
||||
@ -435,11 +396,6 @@ public:
|
||||
strcpy((char*)GetMemFromAddr<T>(addr), str.c_str());
|
||||
}
|
||||
|
||||
static u64 AlignAddr(const u64 addr, const u64 align)
|
||||
{
|
||||
return (addr + (align-1)) & ~(align-1);
|
||||
}
|
||||
|
||||
u32 GetUserMemTotalSize()
|
||||
{
|
||||
return UserMemory->GetSize();
|
||||
|
@ -1,7 +1,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
#include "LogBase.h"
|
||||
|
||||
bool LogBase::CheckLogging() const
|
||||
{
|
||||
return Ini.HLELogging.GetValue();
|
||||
}
|
||||
|
||||
void LogBase::LogNotice(const std::string& text)
|
||||
{
|
||||
LOG_NOTICE(HLE, "%s", text.c_str());
|
||||
|
@ -4,6 +4,7 @@ class LogBase
|
||||
{
|
||||
bool m_logging;
|
||||
|
||||
bool CheckLogging() const;
|
||||
void LogNotice(const std::string& text);
|
||||
void LogWarning(const std::string& text);
|
||||
void LogError(const std::string& text);
|
||||
@ -33,7 +34,7 @@ public:
|
||||
|
||||
template<typename... Targs> __forceinline void Log(const char* fmt, Targs... args)
|
||||
{
|
||||
if (m_logging)
|
||||
if (CheckLogging())
|
||||
{
|
||||
Notice(fmt, args...);
|
||||
}
|
||||
@ -41,7 +42,7 @@ public:
|
||||
|
||||
template<typename... Targs> __forceinline void Log(const u32 id, const char* fmt, Targs... args)
|
||||
{
|
||||
if (m_logging)
|
||||
if (CheckLogging())
|
||||
{
|
||||
Notice(id, fmt, args...);
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
|
||||
#include "sys_event.h"
|
||||
|
||||
@ -90,7 +86,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(HLE, "sys_event_queue_destroy(equeue=%d) aborted", equeue_id);
|
||||
sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -203,7 +199,7 @@ s32 sys_event_queue_receive(u32 equeue_id, mem_ptr_t<sys_event_data> event, u64
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
if (counter++ > timeout || Emu.IsStopped())
|
||||
{
|
||||
if (Emu.IsStopped()) LOG_WARNING(HLE, "sys_event_queue_receive(equeue=%d) aborted", equeue_id);
|
||||
if (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id);
|
||||
eq->sq.invalidate(tid);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/SMutex.h"
|
||||
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_WAITER_SINGLE = 0x10000,
|
||||
|
@ -25,13 +25,13 @@ s32 sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_a
|
||||
{
|
||||
default:
|
||||
case SYS_MEMORY_PAGE_SIZE_1M:
|
||||
if(Memory.AlignAddr(size, alignment) & 0xfffff)
|
||||
if(AlignAddr(size, alignment) & 0xfffff)
|
||||
return CELL_EALIGN;
|
||||
addr = Memory.Alloc(size, 0x100000);
|
||||
break;
|
||||
|
||||
case SYS_MEMORY_PAGE_SIZE_64K:
|
||||
if(Memory.AlignAddr(size, alignment) & 0xffff)
|
||||
if(AlignAddr(size, alignment) & 0xffff)
|
||||
return CELL_EALIGN;
|
||||
addr = Memory.Alloc(size, 0x10000);
|
||||
break;
|
||||
|
@ -1,12 +1,8 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
#include "sys_spu.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/SC_FUNC.h"
|
||||
#include "Loader/ELF.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include <atomic>
|
||||
@ -450,7 +446,7 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status)
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::SPU, "sys_spu_thread_group_join(id=%d) aborted", id);
|
||||
sc_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id);
|
||||
return CELL_OK;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
@ -842,7 +838,7 @@ s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, m
|
||||
eq->ports.add(&(t->SPUPs[i]));
|
||||
t->SPUPs[i].eq = eq;
|
||||
}
|
||||
LOG_NOTICE(HLE, "*** spup -> %d", i);
|
||||
sc_spu.Warning("*** spup -> %d", i);
|
||||
spup = (u8)i;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "Emu/RSX/GSManager.h"
|
||||
#include "Emu/Audio/AudioManager.h"
|
||||
#include "Emu/FS/VFS.h"
|
||||
#include "Emu/Event.h"
|
||||
#include "Loader/Loader.h"
|
||||
|
||||
enum Status
|
||||
|
@ -147,6 +147,14 @@ union u128
|
||||
{
|
||||
return From128(~hi, ~lo);
|
||||
}
|
||||
|
||||
static __forceinline u128 byteswap(const u128 val)
|
||||
{
|
||||
u128 ret;
|
||||
ret.lo = _byteswap_uint64(val.hi);
|
||||
ret.hi = _byteswap_uint64(val.lo);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
union s128
|
||||
@ -238,6 +246,8 @@ struct u128
|
||||
};
|
||||
*/
|
||||
|
||||
#define AlignAddr(addr, align) (((addr) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Utilities/GNU.h"
|
||||
#include "Utilities/BEType.h"
|
||||
|
Loading…
Reference in New Issue
Block a user