Merge remote-tracking branch 'upstream/master' into spurs_taskset

This commit is contained in:
S Gopal Rajagopal 2015-02-11 15:00:46 +05:30
commit 853234f7d7
47 changed files with 3235 additions and 801 deletions

View File

@ -109,7 +109,15 @@ struct FileListener : LogListener
if (mPrependChannelName)
{
text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
if (msg.mType == Log::TTY)
{
text = fmt::escape(text);
if (text[text.length() - 1] != '\n')
{
text += '\n';
}
}
}
mFile.Write(text);
}

View File

@ -179,7 +179,7 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co
pos += to.length();
}
return src;
return target;
}
//TODO: move this wx Stuff somewhere else
@ -339,3 +339,34 @@ std::string fmt::tolower(std::string source)
return source;
}
std::string fmt::toupper(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), ::toupper);
return source;
}
std::string fmt::escape(std::string source)
{
const std::pair<std::string, std::string> escape_list[] =
{
{ "\\", "\\\\" },
{ "\a", "\\a" },
{ "\b", "\\b" },
{ "\f", "\\f" },
{ "\n", "\\n\n" },
{ "\r", "\\r" },
{ "\t", "\\t" },
{ "\v", "\\v" },
};
source = fmt::replace_all(source, escape_list);
for (char c = 0; c < 32; c++)
{
if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::Format("\\x%02X", c));
}
return source;
}

View File

@ -177,6 +177,8 @@ namespace fmt
std::string to_udec(u64 value);
std::string to_sdec(s64 value);
std::string toupper(std::string source);
namespace detail
{
size_t get_fmt_start(const char* fmt, size_t len);
@ -198,6 +200,10 @@ namespace fmt
{
return to_hex(arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
{
return to_udec(arg);
@ -218,6 +224,10 @@ namespace fmt
{
return to_hex(arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
{
return to_udec(arg);
@ -238,6 +248,10 @@ namespace fmt
{
return to_hex(arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
{
return to_udec(arg);
@ -258,6 +272,10 @@ namespace fmt
{
return to_hex(arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex(arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
{
return to_udec(arg);
@ -278,6 +296,10 @@ namespace fmt
{
return to_hex((u8)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u8)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd')
{
return to_sdec(arg);
@ -298,6 +320,10 @@ namespace fmt
{
return to_hex((u16)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u16)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd')
{
return to_sdec(arg);
@ -318,6 +344,10 @@ namespace fmt
{
return to_hex((u32)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u32)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd')
{
return to_sdec(arg);
@ -338,6 +368,10 @@ namespace fmt
{
return to_hex((u64)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u64)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'd')
{
return to_sdec(arg);
@ -358,6 +392,10 @@ namespace fmt
{
return to_hex((u32&)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u32&)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'f')
{
return std::to_string(arg);
@ -378,6 +416,10 @@ namespace fmt
{
return to_hex((u64&)arg, get_fmt_precision(fmt, len));
}
else if (fmt[len - 1] == 'X')
{
return fmt::toupper(to_hex((u64&)arg, get_fmt_precision(fmt, len)));
}
else if (fmt[len - 1] == 'f')
{
return std::to_string(arg);
@ -394,7 +436,7 @@ namespace fmt
{
static std::string text(const char* fmt, size_t len, bool arg)
{
if (fmt[len - 1] == 'x')
if (fmt[len - 1] == 'x' || fmt[len - 1] == 'X')
{
return to_hex(arg, get_fmt_precision(fmt, len));
}
@ -579,4 +621,6 @@ namespace fmt
std::string merge(std::vector<std::string> source, const std::string& separator);
std::string merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator);
std::string tolower(std::string source);
std::string toupper(std::string source);
std::string escape(std::string source);
}

View File

@ -213,9 +213,10 @@ static const reg_table_t reg_table[17] =
#endif
bool handle_access_violation(const u32 addr, x64_context* context)
bool handle_access_violation(const u32 addr, bool is_writing, x64_context* context)
{
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers
// check if address is RawSPU MMIO register
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
{
// one x64 instruction is manually decoded and interpreted
x64_op_t op;
@ -277,6 +278,12 @@ bool handle_access_violation(const u32 addr, x64_context* context)
return true;
}
// check if fault is caused by reservation
if (vm::reservation_query(addr, is_writing))
{
return true;
}
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory
return false;
}
@ -285,38 +292,49 @@ bool handle_access_violation(const u32 addr, x64_context* context)
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
{
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr;
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64)
{
if (handle_access_violation((u32)addr64, pExp->ContextRecord))
{
// restore context (further code shouldn't be reached)
RtlRestoreContext(pExp->ContextRecord, nullptr);
// it's dangerous because destructors won't be executed
}
throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64);
}
// else some fatal error (should crash)
}
const PVOID exception_handler = (atexit([]{ RemoveVectoredExceptionHandler(exception_handler); }), AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG
{
const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::g_base_addr;
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
(u32)addr64 == addr64 &&
GetCurrentNamedThread() &&
handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else
{
return EXCEPTION_CONTINUE_SEARCH;
}
}));
#else
void signal_handler(int sig, siginfo_t* info, void* uct)
{
const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr();
const u64 addr64 = (u64)info->si_addr - (u64)vm::g_base_addr;
const bool is_writing = ((ucontext_t*)uct)->uc_mcontext.gregs[REG_ERR] & 0x2;
if ((u32)addr64 == addr64 && GetCurrentNamedThread())
{
if (handle_access_violation((u32)addr64, (ucontext_t*)uct))
if (handle_access_violation((u32)addr64, is_writing, (ucontext_t*)uct))
{
return; // proceed execution
}
// TODO: this may be wrong
throw fmt::format("Access violation at location 0x%llx", addr64);
throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64);
}
// else some fatal error
@ -352,6 +370,11 @@ void SetCurrentNamedThread(NamedThreadBase* value)
return;
}
if (old_value)
{
vm::reservation_free();
}
if (value && value->m_tls_assigned.exchange(true))
{
LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName());
@ -421,8 +444,17 @@ void ThreadBase::Start()
#ifdef _WIN32
auto old_se_translator = _set_se_translator(_se_translator);
if (!exception_handler)
{
LOG_ERROR(GENERAL, "exception_handler not set");
return;
}
#else
if (sigaction_result == -1) assert(!"sigaction() failed");
if (sigaction_result == -1)
{
printf("sigaction() failed");
exit(EXIT_FAILURE);
}
#endif
SetCurrentNamedThread(this);
@ -560,8 +592,6 @@ void thread_t::start(std::function<void()> func)
#ifdef _WIN32
auto old_se_translator = _set_se_translator(_se_translator);
#else
if (sigaction_result == -1) assert(!"sigaction() failed");
#endif
NamedThreadBase info(name);

View File

@ -120,7 +120,7 @@ set_source_files_properties(${RPCS3_SRC_DIR}/Emu/Cell/PPULLVMRecompiler.cpp PROP
add_executable(rpcs3 ${RPCS3_SRC})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_BINARY_DIR}/../asmjit/") #hack because the asmjit cmake file force fno exceptions
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES} libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${LLVM_LIBS})
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES} libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES} ${LLVM_LIBS} rt)
set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h")
cotire(rpcs3)

View File

@ -10,17 +10,15 @@ enum ARMv7InstructionSet
ThumbEE
};
enum armv7_debug_flags : u32
{
DF_DISASM = 1 << 0,
DF_PRINT = 1 << 1,
DF_NO_EXE = 1 << 2,
};
struct ARMv7Context
{
ARMv7Thread& thread;
ARMv7Context(ARMv7Thread& thread) : thread(thread) {}
void write_pc(u32 value);
u32 read_pc();
u32 get_stack_arg(u32 pos);
void fast_call(u32 addr);
union
{
u32 GPR[15];
@ -116,9 +114,6 @@ struct ARMv7Context
u32 TLS;
u32 R_ADDR;
u64 R_DATA;
struct perf_counter
{
u32 event;
@ -127,6 +122,18 @@ struct ARMv7Context
std::array<perf_counter, 6> counters;
ARMv7Thread& thread;
u32 debug; // debug flags
std::string debug_str;
ARMv7Context(ARMv7Thread& thread) : thread(thread), debug(/*DF_DISASM | DF_PRINT*/ 0) {}
void write_pc(u32 value);
u32 read_pc();
u32 get_stack_arg(u32 pos);
void fast_call(u32 addr);
void write_gpr(u32 n, u32 value)
{
assert(n < 16);

View File

@ -30,137 +30,147 @@ struct ARMv7_opcode_t
const ARMv7_opcode_t ARMv7_opcode_table[] =
{
ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK), // "Undefined" Thumb opcode used
ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK, nullptr), // "Undefined" Thumb opcode used
ARMv7_OP4(0x0ff0, 0x00f0, 0x0070, 0x0090, A1, HACK), // "Undefined" ARM opcode used
ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM),
ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM, nullptr),
ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM),
ARMv7_OP2(0xffc0, 0x4040, T1, ADC_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG),
ARMv7_OP2(0xffc0, 0x4140, T1, ADC_REG, nullptr),
ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG, nullptr),
ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR),
ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM),
ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM),
ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM, nullptr),
ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM, nullptr),
ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )),
ARMv7_OP4(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM, SKIP_IF( (BF(16, 19) & 13) == 13 )),
ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM),
ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG),
ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG, nullptr),
ARMv7_OP2(0xff00, 0x4400, T2, ADD_REG, SKIP_IF( (c & 0x87) == 0x85 || BF(3, 6) == 13 )),
ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG, SKIP_IF( (BF(8, 11) == 15 && BT(20)) || BF(16, 19) == 13 )),
ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR),
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI),
ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI),
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI, nullptr),
ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI, nullptr),
ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI, SKIP_IF( BF(8, 11) == 15 && BT(20) )),
ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI),
ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI, nullptr),
ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI),
ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR),
ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR, nullptr),
ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR, SKIP_IF( BF(3, 6) == 13 )),
ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR),
ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR, nullptr),
ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR),
ARMv7_OP2(0xf800, 0xa000, T1, ADR),
ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR),
ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR),
ARMv7_OP2(0xf800, 0xa000, T1, ADR, nullptr),
ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR, nullptr),
ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR, nullptr),
ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR),
ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, ADR),
ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM),
ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )),
ARMv7_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM),
ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG),
ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG, nullptr),
ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )),
ARMv7_OP4(0x0fe0, 0x0010, 0x0000, 0x0000, A1, AND_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR),
ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM),
ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM),
ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM, nullptr),
ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM, nullptr),
ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM),
ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG),
ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG),
ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG, nullptr),
ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG, nullptr),
ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG),
ARMv7_OP2(0xf000, 0xd000, T1, B),
ARMv7_OP2(0xf800, 0xe000, T2, B),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B),
ARMv7_OP2(0xf000, 0xd000, T1, B, SKIP_IF( BF(9, 11) == 0x7 )),
ARMv7_OP2(0xf800, 0xe000, T2, B, nullptr),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B, SKIP_IF( BF(23, 25) == 0x7 )),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B, nullptr),
ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B),
ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC),
ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC, nullptr),
ARMv7_OP4(0x0fe0, 0x007f, 0x07c0, 0x001f, A1, BFC),
ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI),
ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI, SKIP_IF( BF(16, 19) == 15 )),
ARMv7_OP4(0x0fe0, 0x0070, 0x07c0, 0x0010, A1, BFI),
ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM),
ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM, nullptr),
ARMv7_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM),
ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG),
ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG, nullptr),
ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG, nullptr),
ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR),
ARMv7_OP2(0xff00, 0xbe00, T1, BKPT),
ARMv7_OP2(0xff00, 0xbe00, T1, BKPT, nullptr),
ARMv7_OP4(0x0ff0, 0x00f0, 0x0120, 0x0070, A1, BKPT),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL),
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL, nullptr),
ARMv7_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL),
ARMv7_OP2(0xff80, 0x4780, T1, BLX),
ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX),
ARMv7_OP2(0xff80, 0x4780, T1, BLX, nullptr),
ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX, nullptr),
ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX),
ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, BLX),
ARMv7_OP2(0xff87, 0x4700, T1, BX),
ARMv7_OP2(0xff87, 0x4700, T1, BX, nullptr),
ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff10, A1, BX),
ARMv7_OP2(0xf500, 0xb100, T1, CB_Z),
ARMv7_OP2(0xf500, 0xb100, T1, CB_Z, nullptr),
ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ),
ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ, nullptr),
ARMv7_OP4(0x0fff, 0x0ff0, 0x016f, 0x0f10, A1, CLZ),
ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM),
ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM, nullptr),
ARMv7_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM),
ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG),
ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG),
ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG, nullptr),
ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG, nullptr),
ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG),
ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR),
ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM),
ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM),
ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM, nullptr),
ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM, nullptr),
ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM),
ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG),
ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG),
ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG),
ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG, nullptr),
ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG, nullptr),
ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG, nullptr),
ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG),
ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR),
ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM),
ARMv7_OP4(0xffff, 0xfff0, 0xf3af, 0x80f0, T1, DBG, nullptr),
ARMv7_OP4(0x0fff, 0xfff0, 0x0320, 0xf0f0, A1, DBG),
ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f50, T1, DMB, nullptr),
ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf050, A1, DMB),
ARMv7_OP4(0xffff, 0xfff0, 0xf3bf, 0x8f40, T1, DSB, nullptr),
ARMv7_OP4(0xffff, 0xfff0, 0xf57f, 0xf040, A1, DSB),
ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM, SKIP_IF( BF(8, 11) == 15 && BT(20) )),
ARMv7_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM),
ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG),
ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG, nullptr),
ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG, SKIP_IF( BF(8, 11) == 15 && BT(20) )),
ARMv7_OP4(0x0fe0, 0x0010, 0x0020, 0x0000, A1, EOR_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR),
ARMv7_OP2(0xff00, 0xbf00, T1, IT, SKIP_IF( BF(0, 3) == 0 )),
ARMv7_OP2(0xf800, 0xc800, T1, LDM),
ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM),
ARMv7_OP2(0xf800, 0xc800, T1, LDM, nullptr),
ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM, SKIP_IF( BT(21) && BF(16, 19) == 13 )),
ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM),
ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA),
ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB),
ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB, nullptr),
ARMv7_OP4(0x0fd0, 0x0000, 0x0910, 0x0000, A1, LDMDB),
ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB),
ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM),
ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM),
ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM),
ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM),
ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM, nullptr),
ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM, nullptr),
ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM, SKIP_IF( BF(16, 19) == 15 )),
ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM, SKIP_IF( BF(16, 19) == 15 || BF(8, 10) == 6 || (c & 0xf07ff) == 0xd0304 || (c & 0x500) == 0 )),
ARMv7_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM),
ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT),
ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT),
ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT, nullptr),
ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT, nullptr),
ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT),
ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG),
ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG),
ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG, nullptr),
ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG, SKIP_IF( BF(16, 19) == 15 )),
ARMv7_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG),
ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM),
ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM),
ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, LDRB_IMM),
@ -280,7 +290,7 @@ const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM),
ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM),
ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG),
ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG, SKIP_IF( BF(16, 19) == 15 )),
ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG),
ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR),
@ -1105,6 +1115,7 @@ const ARMv7_opcode_t ARMv7_opcode_table[] =
struct ARMv7_op2_table_t
{
const ARMv7_opcode_t* data[0x10000];
u32 null_ops;
ARMv7_op2_table_t()
{
@ -1123,6 +1134,8 @@ struct ARMv7_op2_table_t
}
}
null_ops = 0x10000;
for (u32 i = 0; i < 0x10000; i++)
{
data[i] = nullptr;
@ -1132,6 +1145,7 @@ struct ARMv7_op2_table_t
if (((i << 16) & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(i)))
{
data[i] = opcode;
null_ops--;
break;
}
}
@ -1201,11 +1215,12 @@ std::unordered_map<u32, const ARMv7_opcode_t*> g_opct;
void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
{
// 1. Find every 4-byte thumb instruction and cache it
// 1. Find every 4-byte Thumb instruction and cache it
// 2. If some instruction is not recognized, print the error
// 3. Possibly print disasm
g_opct.clear();
//g_opct.clear();
//g_opct.reserve(end_addr - addr);
while (addr < end_addr)
{
@ -1266,7 +1281,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1;
const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1);
const u32 instr = vm::psv::read32(target);
const u32 instr = Memory.IsGoodAddr(target, 4) ? vm::psv::read32(target) : 0;
// possibly a call to imported function:
if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090)
@ -1297,7 +1312,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
addr += found->length;
}
LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", (u64)g_opct.size());
LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld, g_op2t.null_ops=0x%x", (u64)g_opct.size(), g_op2t.null_ops);
}
u32 ARMv7Decoder::DecodeMemory(const u32 address)

File diff suppressed because it is too large Load Diff

View File

@ -18,12 +18,11 @@ enum ARMv7_encoding
enum SRType : u32
{
SRType_None,
SRType_LSL,
SRType_LSR,
SRType_ASR,
SRType_ROR,
SRType_RRX
SRType_RRX,
};
namespace ARMv7_instrs
@ -79,6 +78,10 @@ namespace ARMv7_instrs
void CMP_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void CMP_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void DBG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void DMB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void DSB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void EOR_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void EOR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
void EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);

View File

@ -18,7 +18,7 @@ void ARMv7Context::write_pc(u32 value)
u32 ARMv7Context::read_pc()
{
return thread.PC;
return ISET == ARM ? thread.PC + 8 : thread.PC + 4;
}
u32 ARMv7Context::get_stack_arg(u32 pos)
@ -118,7 +118,7 @@ void ARMv7Thread::InitRegs()
context.ITSTATE.IT = 0;
context.SP = m_stack_addr + m_stack_size;
context.TLS = armv7_get_tls(GetId());
context.R_ADDR = 0;
context.debug |= DF_DISASM | DF_PRINT;
}
void ARMv7Thread::InitStack()
@ -230,14 +230,14 @@ void ARMv7Thread::FastStop()
m_status = Stopped;
}
armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio)
armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio)
{
thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
thread->SetName(name);
thread->SetEntry(entry);
thread->SetStackSize(stack_size ? stack_size : Emu.GetInfo().GetProcParam().primary_stacksize);
thread->SetPrio(prio ? prio : Emu.GetInfo().GetProcParam().primary_prio);
thread->SetStackSize(stack_size);
thread->SetPrio(prio);
argc = 0;
}

View File

@ -39,7 +39,7 @@ class armv7_thread : cpu_thread
u32 argc;
public:
armv7_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0);
armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio);
cpu_thread& args(std::initializer_list<std::string> values) override;

View File

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/ARMv7/PSVObjectList.h"
#include "sceLibKernel.h"
#include "psv_cond.h"
psv_cond_t::psv_cond_t(const char* name, u32 attr, s32 mutexId)
: attr(attr)
, mutexId(mutexId)
{
strcpy_trunc(this->name, name);
}

View File

@ -0,0 +1,24 @@
#pragma once
struct psv_cond_t
{
char name[32];
u32 attr;
s32 mutexId;
private:
psv_cond_t() = delete;
psv_cond_t(const psv_cond_t&) = delete;
psv_cond_t(psv_cond_t&&) = delete;
psv_cond_t& operator =(const psv_cond_t&) = delete;
psv_cond_t& operator =(psv_cond_t&&) = delete;
public:
psv_cond_t(const char* name, u32 attr, s32 mutexId);
void on_init(s32 id) {}
void on_stop() {}
};
extern psv_object_list_t<psv_cond_t, SCE_KERNEL_THREADMGR_UID_CLASS_COND> g_psv_cond_list;

View File

@ -16,6 +16,9 @@ private:
public:
psv_event_flag_t(const char* name, u32 attr, u32 pattern);
void on_init(s32 id) {}
void on_stop() {}
};
extern psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> g_psv_ef_list;

View File

@ -0,0 +1,13 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/ARMv7/PSVObjectList.h"
#include "sceLibKernel.h"
#include "psv_mutex.h"
psv_mutex_t::psv_mutex_t(const char* name, u32 attr, s32 count)
: attr(attr)
, count(count)
{
strcpy_trunc(this->name, name);
}

View File

@ -0,0 +1,24 @@
#pragma once
struct psv_mutex_t
{
char name[32];
u32 attr;
s32 count;
private:
psv_mutex_t() = delete;
psv_mutex_t(const psv_mutex_t&) = delete;
psv_mutex_t(psv_mutex_t&&) = delete;
psv_mutex_t& operator =(const psv_mutex_t&) = delete;
psv_mutex_t& operator =(psv_mutex_t&&) = delete;
public:
psv_mutex_t(const char* name, u32 attr, s32 count);
void on_init(s32 id) {}
void on_stop() {}
};
extern psv_object_list_t<psv_mutex_t, SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX> g_psv_mutex_list;

View File

@ -17,6 +17,8 @@ private:
public:
psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value);
void on_init(s32 id) {}
void on_stop() {}
};

View File

@ -10,6 +10,8 @@
#include "sceLibKernel.h"
#include "psv_sema.h"
#include "psv_event_flag.h"
#include "psv_mutex.h"
#include "psv_cond.h"
#define RETURN_ERROR(code) { Emu.Pause(); sceLibKernel.Error("%s() failed: %s", __FUNCTION__, #code); return code; }
@ -522,7 +524,13 @@ s32 sceKernelGetSemaInfo(s32 semaId, vm::psv::ptr<SceKernelSemaInfo> pInfo)
s32 sceKernelCreateMutex(vm::psv::ptr<const char> pName, u32 attr, s32 initCount, vm::psv::ptr<const SceKernelMutexOptParam> pOptParam)
{
throw __FUNCTION__;
sceLibKernel.Error("sceKernelCreateMutex(pName=0x%x, attr=0x%x, initCount=%d, pOptParam=0x%x)", pName, attr, initCount, pOptParam);
std::shared_ptr<psv_mutex_t> mutex(new psv_mutex_t(pName.get_ptr(), attr, initCount));
const s32 id = g_psv_mutex_list.add(mutex);
return id;
}
s32 sceKernelDeleteMutex(s32 mutexId)
@ -616,7 +624,13 @@ s32 sceKernelGetLwMutexInfoById(s32 lwMutexId, vm::psv::ptr<SceKernelLwMutexInfo
s32 sceKernelCreateCond(vm::psv::ptr<const char> pName, u32 attr, s32 mutexId, vm::psv::ptr<const SceKernelCondOptParam> pOptParam)
{
throw __FUNCTION__;
sceLibKernel.Error("sceKernelCreateCond(pName=0x%x, attr=0x%x, mutexId=0x%x, pOptParam=0x%x)", pName, attr, mutexId, pOptParam);
std::shared_ptr<psv_cond_t> cond(new psv_cond_t(pName.get_ptr(), attr, mutexId));
const s32 id = g_psv_cond_list.add(cond);
return id;
}
s32 sceKernelDeleteCond(s32 condId)

View File

@ -2,6 +2,7 @@
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/ARMv7Callback.h"
extern psv_log_base sceLibc;
@ -12,6 +13,139 @@ typedef void(atexit_func_t)(vm::psv::ptr<void>);
std::vector<std::function<void(ARMv7Context&)>> g_atexit;
std::string armv7_fmt(ARMv7Context& context, vm::psv::ptr<const char> fmt, u32 g_count, u32 f_count, u32 v_count)
{
std::string result;
for (char c = *fmt++; c; c = *fmt++)
{
switch (c)
{
case '%':
{
const auto start = fmt - 1;
// read flags
const bool plus_sign = *fmt == '+' ? fmt++, true : false;
const bool minus_sign = *fmt == '-' ? fmt++, true : false;
const bool space_sign = *fmt == ' ' ? fmt++, true : false;
const bool number_sign = *fmt == '#' ? fmt++, true : false;
const bool zero_padding = *fmt == '0' ? fmt++, true : false;
// read width
const u32 width = [&]() -> u32
{
u32 width = 0;
if (*fmt == '*')
{
fmt++;
return context.get_next_gpr_arg(g_count, f_count, v_count);
}
while (*fmt - '0' < 10)
{
width = width * 10 + (*fmt++ - '0');
}
return width;
}();
// read precision
const u32 prec = [&]() -> u32
{
u32 prec = 0;
if (*fmt != '.')
{
return 0;
}
if (*++fmt == '*')
{
fmt++;
return context.get_next_gpr_arg(g_count, f_count, v_count);
}
while (*fmt - '0' < 10)
{
prec = prec * 10 + (*fmt++ - '0');
}
return prec;
}();
switch (char cf = *fmt++)
{
case '%':
{
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += '%';
continue;
}
case 'd':
case 'i':
{
// signed decimal
const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += fmt::to_sdec(value);
continue;
}
case 'x':
case 'X':
{
// hexadecimal
const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
if (plus_sign || minus_sign || space_sign || prec) break;
if (number_sign && value)
{
result += cf == 'x' ? "0x" : "0X";
}
const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value));
if (hex.length() >= width)
{
result += hex;
}
else if (zero_padding)
{
result += std::string(width - hex.length(), '0') + hex;
}
else
{
result += hex + std::string(width - hex.length(), ' ');
}
continue;
}
case 's':
{
// string
auto string = vm::psv::ptr<const char>::make(context.get_next_gpr_arg(g_count, f_count, v_count));
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
result += string.get_ptr();
continue;
}
}
throw fmt::format("armv7_fmt(): unknown formatting: '%s'", start.get_ptr());
}
}
result += c;
}
return result;
}
namespace sce_libc_func
{
void __cxa_atexit(vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> arg, vm::psv::ptr<void> dso)
@ -59,80 +193,24 @@ namespace sce_libc_func
});
}
std::string armv7_fmt(ARMv7Context& context, vm::psv::ptr<const char> fmt, u32 g_count, u32 f_count, u32 v_count)
{
std::string result;
for (char c = *fmt++; c; c = *fmt++)
{
switch (c)
{
case '%':
{
const auto start = fmt - 1;
const bool number_sign = *fmt == '#' ? fmt++, true : false;
switch (*fmt++)
{
case '%':
{
result += '%';
continue;
}
case 'd':
case 'i':
{
// signed decimal
const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
result += fmt::to_sdec(value);
continue;
}
case 'x':
{
// hexadecimal
const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
if (number_sign && value)
{
result += "0x";
}
result += fmt::to_hex(value);
continue;
}
default:
{
throw fmt::Format("armv7_fmt(): unknown formatting: '%s'", start.get_ptr());
}
}
}
}
result += c;
}
return result;
}
void printf(ARMv7Context& context, vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Warning("printf(fmt=0x%x)", fmt);
sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr());
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
const std::string& result = armv7_fmt(context, fmt, 1, 0, 0);
sceLibc.Log("*** -> '%s'", result);
LOG_NOTICE(TTY, armv7_fmt(context, fmt, 1, 0, 0));
LOG_NOTICE(TTY, result);
}
void sprintf(ARMv7Context& context, vm::psv::ptr<char> str, vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Warning("sprintf(str=0x%x, fmt=0x%x)", str, fmt);
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr());
const std::string& result = armv7_fmt(context, fmt, 2, 0, 0);
sceLibc.Notice("*** res -> '%s'", result);
sceLibc.Log("*** -> '%s'", result);
::memcpy(str.get_ptr(), result.c_str(), result.size() + 1);
}
@ -158,11 +236,12 @@ namespace sce_libc_func
::memset(dst.get_ptr(), value, size);
}
void _Assert(vm::psv::ptr<const char> text, vm::psv::ptr<const char> func)
void _Assert(ARMv7Context& context, vm::psv::ptr<const char> text, vm::psv::ptr<const char> func)
{
sceLibc.Warning("_Assert(text=0x%x, func=0x%x)", text, func);
sceLibc.Error("_Assert(text=0x%x, func=0x%x)", text, func);
LOG_ERROR(TTY, "%s : %s\n", func.get_ptr(), text.get_ptr());
LOG_NOTICE(ARMv7, context.thread.RegsToString());
Emu.Pause();
}
}

View File

@ -134,6 +134,11 @@ s32 scePerfArmPmonSelectEvent(ARMv7Context& context, s32 threadId, u32 counter,
case SCE_PERF_ARM_PMON_BRANCH_MISPREDICT:
case SCE_PERF_ARM_PMON_DCACHE_MISS:
case SCE_PERF_ARM_PMON_DCACHE_STALL:
case SCE_PERF_ARM_PMON_ICACHE_STALL:
case SCE_PERF_ARM_PMON_DATA_EVICTION:
case SCE_PERF_ARM_PMON_WRITE_STALL:
case SCE_PERF_ARM_PMON_MAINTLB_STALL:
case SCE_PERF_ARM_PMON_UNALIGNED:
{
value = 1; // these events will probably never be implemented

View File

@ -6,21 +6,21 @@ extern psv_log_base sceSysmodule;
s32 sceSysmoduleLoadModule(u16 id)
{
sceSysmodule.Error("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id);
sceSysmodule.Warning("sceSysmoduleLoadModule(id=0x%04x) -> SCE_OK", id);
return SCE_OK; // loading succeeded
}
s32 sceSysmoduleUnloadModule(u16 id)
{
sceSysmodule.Error("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id);
sceSysmodule.Warning("sceSysmoduleUnloadModule(id=0x%04x) -> SCE_OK", id);
return SCE_OK; // unloading succeeded
}
s32 sceSysmoduleIsLoaded(u16 id)
{
sceSysmodule.Error("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id);
sceSysmodule.Warning("sceSysmoduleIsLoaded(id=0x%04x) -> SCE_OK", id);
return SCE_OK; // module is loaded
}

View File

@ -10,7 +10,7 @@ void add_psv_func(psv_func& data)
g_psv_func_list.push_back(data);
}
psv_func* get_psv_func_by_nid(u32 nid)
const psv_func* get_psv_func_by_nid(u32 nid)
{
for (auto& f : g_psv_func_list)
{
@ -23,7 +23,7 @@ psv_func* get_psv_func_by_nid(u32 nid)
return nullptr;
}
u32 get_psv_func_index(psv_func* func)
u32 get_psv_func_index(const psv_func* func)
{
auto res = func - g_psv_func_list.data();
@ -32,14 +32,21 @@ u32 get_psv_func_index(psv_func* func)
return (u32)res;
}
void execute_psv_func_by_index(ARMv7Context& context, u32 index)
const psv_func* get_psv_func_by_index(u32 index)
{
assert(index < g_psv_func_list.size());
return &g_psv_func_list[index];
}
void execute_psv_func_by_index(ARMv7Context& context, u32 index)
{
auto func = get_psv_func_by_index(index);
auto old_last_syscall = context.thread.m_last_syscall;
context.thread.m_last_syscall = g_psv_func_list[index].nid;
context.thread.m_last_syscall = func->nid;
(*g_psv_func_list[index].func)(context);
(*func->func)(context);
context.thread.m_last_syscall = old_last_syscall;
}
@ -174,7 +181,7 @@ void initialize_psv_modules()
// setup special functions (without NIDs)
psv_func unimplemented;
unimplemented.nid = 0;
unimplemented.name = "Special function (unimplemented stub)";
unimplemented.name = "UNIMPLEMENTED";
unimplemented.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
{
context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4);
@ -184,7 +191,7 @@ void initialize_psv_modules()
psv_func hle_return;
hle_return.nid = 1;
hle_return.name = "Special function (return from HLE)";
hle_return.name = "HLE_RETURN";
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
{
context.thread.FastStop();

View File

@ -492,9 +492,11 @@ template<typename RT, typename... T> void reg_psv_func(u32 nid, psv_log_base* mo
add_psv_func(f);
}
// Find registered HLE function by its ID
psv_func* get_psv_func_by_nid(u32 nid);
const psv_func* get_psv_func_by_nid(u32 nid);
// Get index of registered HLE function
u32 get_psv_func_index(psv_func* func);
u32 get_psv_func_index(const psv_func* func);
// Find registered HLE function by its index
const psv_func* get_psv_func_by_index(u32 index);
// Execute registered HLE function by its index
void execute_psv_func_by_index(ARMv7Context& context, u32 index);
// Register all HLE functions

View File

@ -5,12 +5,18 @@
#include "Modules/sceLibKernel.h"
#include "Modules/psv_sema.h"
#include "Modules/psv_event_flag.h"
#include "Modules/psv_mutex.h"
#include "Modules/psv_cond.h"
psv_object_list_t<psv_sema_t, SCE_KERNEL_THREADMGR_UID_CLASS_SEMA> g_psv_sema_list;
psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> g_psv_ef_list;
psv_object_list_t<psv_mutex_t, SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX> g_psv_mutex_list;
psv_object_list_t<psv_cond_t, SCE_KERNEL_THREADMGR_UID_CLASS_COND> g_psv_cond_list;
void clear_all_psv_objects()
{
g_psv_sema_list.clear();
g_psv_ef_list.clear();
g_psv_mutex_list.clear();
g_psv_cond_list.clear();
}

View File

@ -25,8 +25,18 @@ template<typename T, u32 type>
class psv_object_list_t // Class for managing object data
{
std::array<std::shared_ptr<T>, 0x8000> m_data;
std::atomic<u32> m_hint; // guessing next free position
std::mutex m_mutex; // TODO: remove it when shared_ptr atomic ops are fully available
public:
psv_object_list_t() : m_hint(0) {}
psv_object_list_t(const psv_object_list_t&) = delete;
psv_object_list_t(psv_object_list_t&&) = delete;
psv_object_list_t& operator =(const psv_object_list_t&) = delete;
psv_object_list_t& operator =(psv_object_list_t&&) = delete;
public:
static const u32 uid_class = type;
@ -60,18 +70,18 @@ public:
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& value : m_data)
for (u32 i = 0, j = m_hint % m_data.size(); i < m_data.size(); i++, j = (j + 1) % m_data.size())
{
// find an empty position and move the pointer
//std::shared_ptr<T> old_ptr = nullptr;
//if (std::atomic_compare_exchange_strong(&value, &old_ptr, data))
if (!value)
// find an empty position and copy the pointer
if (!m_data[j])
{
value = data;
m_data[j] = data;
m_hint = j + 1; // guess next position
psv_uid_t id = psv_uid_t::make(1); // odd number
id.type = uid_class; // set type
id.number = &value - m_data.data(); // set position
return id.uid;
id.number = j; // set position
data->on_init(id.uid); // save UID
return id.uid; // return UID
}
}
@ -86,12 +96,14 @@ public:
return nullptr;
}
const u32 pos = psv_uid_t::make(uid).number;
std::lock_guard<std::mutex> lock(m_mutex);
std::shared_ptr<T> old_ptr = nullptr;
m_data[psv_uid_t::make(uid).number].swap(old_ptr);
m_data[pos].swap(old_ptr);
m_hint = pos;
return old_ptr;
//return std::atomic_exchange<std::shared_ptr<T>>(&m_data[psv_uid_t::make(uid).number], nullptr);
}
// remove all objects
@ -99,10 +111,17 @@ public:
{
std::lock_guard<std::mutex> lock(m_mutex);
for (auto& value : m_data)
for (auto& object : m_data)
{
value = nullptr;
if (object)
{
object->on_stop();
}
object = nullptr;
}
m_hint = 0;
}
};

View File

@ -18,7 +18,7 @@ public:
CPUThread& AddThread(CPUThreadType type);
void RemoveThread(const u32 id);
std::vector<std::shared_ptr<CPUThread>> GetThreads() { return m_threads; }
std::vector<std::shared_ptr<CPUThread>> GetThreads() { std::lock_guard<std::mutex> lock(m_mtx_thread); return m_threads; }
s32 GetThreadNumById(CPUThreadType type, u32 id);
std::shared_ptr<CPUThread> GetThread(u32 id);
std::shared_ptr<CPUThread> GetThread(u32 id, CPUThreadType type);

View File

@ -2500,39 +2500,16 @@ private:
}
void MFOCRF(u32 a, u32 rd, u32 crm)
{
/*
if(a)
{
u32 n = 0, count = 0;
for(u32 i = 0; i < 8; ++i)
{
if(crm & (1 << i))
{
n = i;
count++;
}
}
if(count == 1)
{
//RD[32+4*n : 32+4*n+3] = CR[4*n : 4*n+3];
u8 offset = n * 4;
CPU.GPR[rd] = (CPU.GPR[rd] & ~(0xf << offset)) | ((u32)CPU.GetCR(7 - n) << offset);
}
else
CPU.GPR[rd] = 0;
}
else
{
*/
CPU.GPR[rd] = CPU.CR.CR;
//}
}
void LWARX(u32 rd, u32 ra, u32 rb)
{
CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.R_VALUE = vm::get_ref<u32>(vm::cast(CPU.R_ADDR));
CPU.GPR[rd] = re32((u32)CPU.R_VALUE);
const u32 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
be_t<u32> value;
vm::reservation_acquire(&value, vm::cast(addr), sizeof(value));
CPU.GPR[rd] = value;
}
void LDX(u32 rd, u32 ra, u32 rb)
{
@ -2682,9 +2659,12 @@ private:
}
void LDARX(u32 rd, u32 ra, u32 rb)
{
CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.R_VALUE = vm::get_ref<u64>(vm::cast(CPU.R_ADDR));
CPU.GPR[rd] = re64(CPU.R_VALUE);
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
be_t<u64> value;
vm::reservation_acquire(&value, vm::cast(addr), sizeof(value));
CPU.GPR[rd] = value;
}
void DCBF(u32 ra, u32 rb)
{
@ -2800,15 +2780,8 @@ private:
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
if (CPU.R_ADDR == addr)
{
CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr<volatile u32>(vm::cast(CPU.R_ADDR)), re32((u32)CPU.GPR[rs]), (u32)CPU.R_VALUE) == (u32)CPU.R_VALUE);
}
else
{
CPU.SetCR_EQ(0, false);
}
CPU.R_ADDR = 0;
const be_t<u32> value = be_t<u32>::make((u32)CPU.GPR[rs]);
CPU.SetCR_EQ(0, vm::reservation_update(vm::cast(addr), &value, sizeof(value)));
}
void STWX(u32 rs, u32 ra, u32 rb)
{
@ -2859,15 +2832,8 @@ private:
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
if (CPU.R_ADDR == addr)
{
CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr<volatile u64>(vm::cast(CPU.R_ADDR)), re64(CPU.GPR[rs]), CPU.R_VALUE) == CPU.R_VALUE);
}
else
{
CPU.SetCR_EQ(0, false);
}
CPU.R_ADDR = 0;
const be_t<u64> value = be_t<u64>::make(CPU.GPR[rs]);
CPU.SetCR_EQ(0, vm::reservation_update(vm::cast(addr), &value, sizeof(value)));
}
void STBX(u32 rs, u32 ra, u32 rb)
{
@ -2945,9 +2911,7 @@ private:
}
void ECIWX(u32 rd, u32 ra, u32 rb)
{
//HACK!
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::read32(vm::cast(addr));
throw __FUNCTION__;
}
void LHZUX(u32 rd, u32 ra, u32 rb)
{
@ -3020,9 +2984,7 @@ private:
}
void ECOWX(u32 rs, u32 ra, u32 rb)
{
//HACK!
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]);
throw __FUNCTION__;
}
void STHUX(u32 rs, u32 ra, u32 rb)
{

View File

@ -2463,25 +2463,27 @@ void Compiler::MFOCRF(u32 a, u32 rd, u32 crm) {
}
void Compiler::LWARX(u32 rd, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
auto resv_val_i32 = ReadMemory(addr_i64, 32, 4, false, false);
auto resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty());
auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8);
//auto resv_val_i32 = ReadMemory(addr_i64, 32, 4, false, false);
//auto resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty());
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
//auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8);
resv_val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), resv_val_i32);
resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty());
SetGpr(rd, resv_val_i64);
//resv_val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), resv_val_i32);
//resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty());
//SetGpr(rd, resv_val_i64);
}
void Compiler::LDX(u32 rd, u32 ra, u32 rb) {
@ -2739,23 +2741,25 @@ void Compiler::MULHW(u32 rd, u32 ra, u32 rb, bool rc) {
}
void Compiler::LDARX(u32 rd, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
auto resv_val_i64 = ReadMemory(addr_i64, 64, 8, false);
auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8);
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
resv_val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), resv_val_i64);
SetGpr(rd, resv_val_i64);
//auto resv_val_i64 = ReadMemory(addr_i64, 64, 8, false);
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
//auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//m_ir_builder->CreateAlignedStore(resv_val_i64, resv_val_i64_ptr, 8);
//resv_val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), resv_val_i64);
//SetGpr(rd, resv_val_i64);
}
void Compiler::DCBF(u32 ra, u32 rb) {
@ -2919,45 +2923,47 @@ void Compiler::STDX(u32 rs, u32 ra, u32 rb) {
}
void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
//auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
m_ir_builder->SetInsertPoint(then_bb);
auto rs_i32 = GetGpr(rs, 32);
rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32);
resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
auto resv_addr_val_i32_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt32Ty()->getPointerTo());
auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
auto resv_val_i32_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
auto resv_val_i32 = m_ir_builder->CreateAlignedLoad(resv_val_i32_ptr, 8);
//auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
//auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
//auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
//m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
auto cr_i32 = GetCr();
cr_i32 = SetBit(cr_i32, 2, success_i1);
SetCr(cr_i32);
m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(then_bb);
//auto rs_i32 = GetGpr(rs, 32);
//rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32);
//resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
//auto resv_addr_val_i32_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt32Ty()->getPointerTo());
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
//auto resv_val_i32_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
//auto resv_val_i32 = m_ir_builder->CreateAlignedLoad(resv_val_i32_ptr, 8);
m_ir_builder->SetInsertPoint(else_bb);
cr_i32 = GetCr();
cr_i32 = ClrBit(cr_i32, 2);
SetCr(cr_i32);
m_ir_builder->CreateBr(merge_bb);
m_ir_builder->SetInsertPoint(merge_bb);
//auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
//auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
//auto cr_i32 = GetCr();
//cr_i32 = SetBit(cr_i32, 2, success_i1);
//SetCr(cr_i32);
//m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
//m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(else_bb);
//cr_i32 = GetCr();
//cr_i32 = ClrBit(cr_i32, 2);
//SetCr(cr_i32);
//m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(merge_bb);
}
void Compiler::STWX(u32 rs, u32 ra, u32 rb) {
@ -3060,45 +3066,47 @@ void Compiler::SUBFZE(u32 rd, u32 ra, u32 oe, bool rc) {
}
void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
//auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
m_ir_builder->SetInsertPoint(then_bb);
auto rs_i64 = GetGpr(rs, 64);
rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64);
resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
auto resv_addr_val_i64_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt64Ty()->getPointerTo());
auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
auto resv_val_i64 = m_ir_builder->CreateAlignedLoad(resv_val_i64_ptr, 8);
//auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
//auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
//auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
//m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
auto cr_i32 = GetCr();
cr_i32 = SetBit(cr_i32, 2, success_i1);
SetCr(cr_i32);
m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(then_bb);
//auto rs_i64 = GetGpr(rs, 64);
//rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64);
//resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
//auto resv_addr_val_i64_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt64Ty()->getPointerTo());
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
//auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
//auto resv_val_i64 = m_ir_builder->CreateAlignedLoad(resv_val_i64_ptr, 8);
m_ir_builder->SetInsertPoint(else_bb);
cr_i32 = GetCr();
cr_i32 = ClrBit(cr_i32, 2);
SetCr(cr_i32);
m_ir_builder->CreateBr(merge_bb);
m_ir_builder->SetInsertPoint(merge_bb);
//auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
//auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
//auto cr_i32 = GetCr();
//cr_i32 = SetBit(cr_i32, 2, success_i1);
//SetCr(cr_i32);
//m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
//m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(else_bb);
//cr_i32 = GetCr();
//cr_i32 = ClrBit(cr_i32, 2);
//SetCr(cr_i32);
//m_ir_builder->CreateBr(merge_bb);
//m_ir_builder->SetInsertPoint(merge_bb);
}
void Compiler::STBX(u32 rs, u32 ra, u32 rb) {
@ -3263,15 +3271,16 @@ void Compiler::EQV(u32 ra, u32 rs, u32 rb, bool rc) {
}
void Compiler::ECIWX(u32 rd, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
auto mem_i32 = ReadMemory(addr_i64, 32);
auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty());
SetGpr(rd, mem_i64);
//auto mem_i32 = ReadMemory(addr_i64, 32);
//auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty());
//SetGpr(rd, mem_i64);
}
void Compiler::LHZUX(u32 rd, u32 ra, u32 rb) {
@ -3422,13 +3431,14 @@ void Compiler::ORC(u32 ra, u32 rs, u32 rb, bool rc) {
}
void Compiler::ECOWX(u32 rs, u32 ra, u32 rb) {
auto addr_i64 = GetGpr(rb);
if (ra) {
auto ra_i64 = GetGpr(ra);
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
}
throw __FUNCTION__;
//auto addr_i64 = GetGpr(rb);
//if (ra) {
// auto ra_i64 = GetGpr(ra);
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
//}
WriteMemory(addr_i64, GetGpr(rs, 32));
//WriteMemory(addr_i64, GetGpr(rs, 32));
}
void Compiler::STHUX(u32 rs, u32 ra, u32 rb) {

View File

@ -59,10 +59,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
/// Time base register
u64 TB;
/// Reservations
u64 R_ADDR;
u64 R_VALUE;
/// Memory block
u32 address;
u64 mem_block[64];
@ -86,9 +82,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
CTR = ppu.CTR;
TB = ppu.TB;
R_ADDR = ppu.R_ADDR;
R_VALUE = ppu.R_VALUE;
address = addr;
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
mem_block[i] = vm::read64(address + (i * 8));
@ -114,9 +107,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
ppu.CTR = CTR;
ppu.TB = TB;
ppu.R_ADDR = R_ADDR;
ppu.R_VALUE = R_VALUE;
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
vm::write64(address + (i * 8), mem_block[i]);
}
@ -151,8 +141,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
LR = rng();
CTR = rng();
TB = rng();
R_ADDR = rng();
R_VALUE = rng();
address = addr;
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
@ -187,7 +175,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
// fmt::by_value(FPSCR.VXZDZ), fmt::by_value(FPSCR.VXIDI), fmt::by_value(FPSCR.VXISI), fmt::by_value(FPSCR.VXSNAN),
// fmt::by_value(FPSCR.XX), fmt::by_value(FPSCR.ZX), fmt::by_value(FPSCR.UX), fmt::by_value(FPSCR.OX), fmt::by_value(FPSCR.VX), fmt::by_value(FPSCR.FEX), fmt::by_value(FPSCR.FX));
//ret += fmt::Format("VSCR = 0x%08x [NJ=%d | SAT=%d]\n", VSCR.VSCR, fmt::by_value(VSCR.NJ), fmt::by_value(VSCR.SAT)); // TODO: Uncomment after implementing VSCR.SAT
ret += fmt::Format("R_ADDR = 0x%016llx R_VALUE = 0x%016llx\n", R_ADDR, R_VALUE);
for (int i = 0; i < (sizeof(mem_block) / 8); i += 2) {
ret += fmt::Format("mem_block[%d] = 0x%016llx mem_block[%d] = 0x%016llx\n", i, mem_block[i], i + 1, mem_block[i + 1]);
@ -724,8 +711,6 @@ void Compiler::RunAllTests() {
input.GPR[14] = 10;
input.GPR[21] = 15;
input.GPR[23] = 0x10000;
input.R_ADDR = 0x10000;
input.R_VALUE = 0x1122334455667788;
input.mem_block[0] = 0x8877665544332211;
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZ, 0, input, 5, 0, 0x10000);
@ -739,8 +724,8 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZU, 0, input, 5, 14, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 0, input, 5, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 1, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 0, input, 5, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 1, input, 5, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 0, input, 5, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 1, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZUX, 0, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 0, input, 5, 0, 0x100F0);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 1, input, 5, 14, 0x100F0);
@ -780,10 +765,10 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDX, 0, input, 5, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDX, 1, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDUX, 0, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 0, input, 5, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 1, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 0, input, 5, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 1, input, 5, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 0, input, 5, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 1, input, 5, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 0, input, 5, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 1, input, 5, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 0, input, 5, 23, 0);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 1, input, 5, 23, 2);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 2, input, 5, 23, 7);
@ -819,8 +804,8 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 0, input, 3, 0, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 1, input, 3, 14, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBU, 0, input, 3, 14, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 1, input, 3, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 0, input, 3, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBUX, 0, input, 3, 14, 23);
@ -829,8 +814,8 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHU, 0, input, 3, 14, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 1, input, 3, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 0, input, 3, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHUX, 0, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHBRX, 0, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STW, 0, input, 3, 0, 0x10000);
@ -848,8 +833,8 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDU, 0, input, 3, 14, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 0, input, 3, 0, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 1, input, 3, 14, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 0, input, 3, 0, 23);
//VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 1, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDUX, 0, input, 3, 14, 23);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 0, input, 3, 0, 0x10000);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 1, input, 3, 14, 0x10000);

View File

@ -536,11 +536,6 @@ public:
//TBR : Time-Base Registers
u64 TB; //TBR 0x10C - 0x10D
u64 cycle;
u64 R_ADDR; // reservation address
u64 R_VALUE; // reservation value (BE)
u32 owned_mutexes;
std::function<void(PPUThread& CPU)> custom_task;

View File

@ -99,8 +99,6 @@ void SPUThread::InitRegs()
m_event_mask = 0;
m_events = 0;
R_ADDR = 0;
}
void SPUThread::InitStack()
@ -437,103 +435,48 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
if (op == MFC_GETLLAR_CMD) // get reservation
{
if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
R_ADDR = ea;
for (u32 i = 0; i < 16; i++)
vm::reservation_acquire(vm::get_ptr(ls_offset + lsa), ea, 128, [this]()
{
R_DATA[i] = vm::get_ptr<u64>((u32)R_ADDR)[i];
vm::get_ptr<u64>(ls_offset + lsa)[i] = R_DATA[i];
}
//std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(tid);
//if (t && (t->GetType() == CPU_THREAD_SPU || t->GetType() == CPU_THREAD_RAW_SPU))
//{
// SPUThread& spu = static_cast<SPUThread&>(*t);
// spu.m_events |= SPU_EVENT_LR; // TODO: atomic op
// spu.Notify();
//}
m_events |= SPU_EVENT_LR; // TODO: atomic op
Notify();
});
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
if (R_ADDR == ea)
if (vm::reservation_update(ea, vm::get_ptr(ls_offset + lsa), 128))
{
u32 changed = 0, mask = 0;
u64 buf[16];
for (u32 i = 0; i < 16; i++)
{
buf[i] = vm::get_ptr<u64>(ls_offset + lsa)[i];
if (buf[i] != R_DATA[i])
{
changed++;
mask |= (0x3 << (i * 2));
if (vm::get_ptr<u64>((u32)R_ADDR)[i] != 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 (InterlockedCompareExchange(&vm::get_ptr<volatile u64>((u32)R_ADDR)[i], 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 = (s32)PC; i < (s32)PC + 4 * 7; i += 4)
{
dis_asm.dump_pc = i;
dis_asm.offset = vm::get_ptr<u8>(ls_offset);
const u32 opcode = vm::read32(i + 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());
}
}
}
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
R_ADDR = 0;
}
else // store unconditional
else // store unconditional (may be wrong)
{
if (R_ADDR) // may be wrong
vm::reservation_op(ea, 128, [this, tag, lsa, ea]()
{
m_events |= SPU_EVENT_LR;
}
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
});
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
}
R_ADDR = 0;
}
break;
}
@ -548,19 +491,6 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
bool SPUThread::CheckEvents()
{
// checks events:
// SPU_EVENT_LR:
if (R_ADDR)
{
for (u32 i = 0; i < 16; i++)
{
if (vm::get_ptr<u64>((u32)R_ADDR)[i] != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
R_ADDR = 0;
break;
}
}
}
return (m_events & m_event_mask) != 0;
}

View File

@ -295,9 +295,6 @@ public:
u32 SRR0;
SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
u64 R_ADDR; // reservation address
u64 R_DATA[16]; // lock line data (BE)
std::shared_ptr<EventPort> SPUPs[64]; // SPU Thread Event Ports
EventManager SPUQs; // SPU Queue Mapping
std::shared_ptr<SpuGroupInfo> group; // associated SPU Thread Group (null for raw spu)

View File

@ -102,20 +102,17 @@ void MemoryBase::Init(MemoryType type)
memset(m_pages, 0, sizeof(m_pages));
memset(RawSPUMem, 0, sizeof(RawSPUMem));
LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx, priv_addr = 0x%llx", (u64)vm::g_base_addr, (u64)vm::g_priv_addr);
#ifdef _WIN32
if (!vm::g_base_addr)
if (!vm::g_base_addr || !vm::g_priv_addr)
#else
if ((s64)vm::g_base_addr == (s64)-1)
if ((s64)vm::g_base_addr == (s64)-1 || (s64)vm::g_priv_addr == (s64)-1)
#endif
{
LOG_ERROR(MEMORY, "Initializing memory failed");
assert(0);
return;
}
else
{
LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx", (u64)vm::g_base_addr);
}
switch (type)
{
@ -207,7 +204,7 @@ bool MemoryBase::Map(const u64 addr, const u32 size)
}
MemoryBlocks.push_back((new MemoryBlock())->SetRange(addr, size));
LOG_WARNING(MEMORY, "Memory mapped at 0x%llx: size=0x%x", addr, size);
return true;
}
@ -231,20 +228,14 @@ bool MemoryBase::Unmap(const u64 addr)
MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
: MemInfo(_addr, PAGE_4K(_size))
{
void* real_addr = (void*)((u64)Memory.GetBaseAddr() + _addr);
void* real_addr = vm::get_ptr(vm::cast(_addr));
void* priv_addr = vm::get_priv_ptr(vm::cast(_addr));
#ifdef _WIN32
mem = VirtualAlloc(real_addr, size, MEM_COMMIT, PAGE_READWRITE);
if (!VirtualAlloc(priv_addr, size, MEM_COMMIT, PAGE_READWRITE) || !VirtualAlloc(real_addr, size, MEM_COMMIT, PAGE_READWRITE))
#else
if (::mprotect(real_addr, size, PROT_READ | PROT_WRITE))
{
mem = nullptr;
}
else
{
mem = real_addr;
}
if (mprotect(real_addr, size, PROT_READ | PROT_WRITE) || mprotect(priv_addr, size, PROT_READ | PROT_WRITE))
#endif
if (mem != real_addr)
{
LOG_ERROR(MEMORY, "Memory allocation failed (addr=0x%llx, size=0x%x)", addr, size);
Emu.Pause();
@ -252,7 +243,9 @@ MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
else
{
Memory.RegisterPages(_addr, PAGE_4K(_size));
memset(mem, 0, size);
mem = real_addr;
memset(mem, 0, size); // ???
}
}
@ -262,9 +255,11 @@ void MemBlockInfo::Free()
{
Memory.UnregisterPages(addr, size);
#ifdef _WIN32
if (!VirtualFree(mem, size, MEM_DECOMMIT))
DWORD old;
if (!VirtualProtect(mem, size, PAGE_NOACCESS, &old) || !VirtualProtect(vm::get_priv_ptr(vm::cast(addr)), size, PAGE_NOACCESS, &old))
#else
if (::mprotect(mem, size, PROT_NONE))
if (mprotect(mem, size, PROT_NONE) || mprotect(vm::get_priv_ptr(vm::cast(addr)), size, PROT_NONE))
#endif
{
LOG_ERROR(MEMORY, "Memory deallocation failed (addr=0x%llx, size=0x%x)", addr, size);
@ -437,7 +432,7 @@ u64 DynamicMemoryBlockBase::AllocAlign(u32 size, u32 align)
LOG_ERROR(MEMORY, "DynamicMemoryBlockBase::AllocAlign(size=0x%x, align=0x%x): memory block not initialized", size, align);
return 0;
}
size = PAGE_4K(size);
u32 exsize;
@ -715,4 +710,4 @@ bool VirtualMemoryBlock::Unreserve(u32 size)
u32 VirtualMemoryBlock::GetReservedAmount()
{
return m_reserve_size;
}
}

View File

@ -72,11 +72,6 @@ public:
Close();
}
static void* const GetBaseAddr()
{
return vm::g_base_addr;
}
void RegisterPages(u64 addr, u32 size);
void UnregisterPages(u64 addr, u32 size);

View File

@ -1,24 +1,339 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Memory.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/SysCalls/lv2/sys_time.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
namespace vm
{
#ifdef _WIN32
#include <Windows.h>
void* const g_base_addr = VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS);
#else
#include <sys/mman.h>
#ifdef _WIN32
HANDLE g_memory_handle;
#endif
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
void* g_priv_addr;
void* const g_base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
#endif
void* initialize()
{
#ifdef _WIN32
g_memory_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0x1, 0x0, NULL);
void* base_addr = MapViewOfFile(g_memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000); // main memory
g_priv_addr = MapViewOfFile(g_memory_handle, FILE_MAP_WRITE, 0, 0, 0x100000000); // memory mirror for privileged access
return base_addr;
//return VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS);
#else
//shm_unlink("/rpcs3_vm");
int memory_handle = shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, 0);
if (memory_handle == -1)
{
printf("shm_open() failed\n");
return (void*)-1;
}
ftruncate(memory_handle, 0x100000000);
void* base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0);
g_priv_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_SHARED, memory_handle, 0);
shm_unlink("/rpcs3_vm");
return base_addr;
//return mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
#endif
}
void finalize()
{
#ifdef _WIN32
UnmapViewOfFile(g_base_addr);
UnmapViewOfFile(g_priv_addr);
CloseHandle(g_memory_handle);
#else
munmap(g_base_addr, 0x100000000);
munmap(g_priv_addr, 0x100000000);
#endif
}
void* const g_base_addr = (atexit(finalize), initialize());
class reservation_mutex_t
{
std::atomic<NamedThreadBase*> m_owner;
std::condition_variable m_cv;
std::mutex m_cv_mutex;
public:
reservation_mutex_t()
: m_owner(nullptr)
{
}
bool do_notify;
__noinline void lock()
{
NamedThreadBase* owner = GetCurrentNamedThread();
NamedThreadBase* old = nullptr;
while (!m_owner.compare_exchange_strong(old, owner))
{
std::unique_lock<std::mutex> cv_lock(m_cv_mutex);
m_cv.wait_for(cv_lock, std::chrono::milliseconds(1));
if (old == owner)
{
throw __FUNCTION__;
}
old = nullptr;
}
do_notify = true;
}
__noinline void unlock()
{
NamedThreadBase* owner = GetCurrentNamedThread();
if (!m_owner.compare_exchange_strong(owner, nullptr))
{
throw __FUNCTION__;
}
if (do_notify)
{
m_cv.notify_one();
}
}
};
std::function<void()> g_reservation_cb = nullptr;
NamedThreadBase* g_reservation_owner = nullptr;
u32 g_reservation_addr = 0;
u32 g_reservation_size = 0;
reservation_mutex_t g_reservation_mutex;
void _reservation_set(u32 addr, bool no_access = false)
{
//const auto stamp0 = get_time();
#ifdef _WIN32
DWORD old;
if (!VirtualProtect(vm::get_ptr(addr & ~0xfff), 4096, no_access ? PAGE_NOACCESS : PAGE_READONLY, &old))
#else
if (mprotect(vm::get_ptr(addr & ~0xfff), 4096, no_access ? PROT_NONE : PROT_READ))
#endif
{
throw fmt::format("vm::_reservation_set() failed (addr=0x%x)", addr);
}
//LOG_NOTICE(MEMORY, "VirtualProtect: %f us", (get_time() - stamp0) / 80.f);
}
bool _reservation_break(u32 addr)
{
if (g_reservation_addr >> 12 == addr >> 12)
{
//const auto stamp0 = get_time();
#ifdef _WIN32
DWORD old;
if (!VirtualProtect(vm::get_ptr(addr & ~0xfff), 4096, PAGE_READWRITE, &old))
#else
if (mprotect(vm::get_ptr(addr & ~0xfff), 4096, PROT_READ | PROT_WRITE))
#endif
{
throw fmt::format("vm::_reservation_break() failed (addr=0x%x)", addr);
}
//LOG_NOTICE(MEMORY, "VirtualAlloc: %f us", (get_time() - stamp0) / 80.f);
if (g_reservation_cb)
{
g_reservation_cb();
g_reservation_cb = nullptr;
}
g_reservation_owner = nullptr;
g_reservation_addr = 0;
g_reservation_size = 0;
return true;
}
return false;
}
bool reservation_break(u32 addr)
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
return _reservation_break(addr);
}
bool reservation_acquire(void* data, u32 addr, u32 size, const std::function<void()>& callback)
{
//const auto stamp0 = get_time();
bool broken = false;
assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128);
assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff));
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
// silent unlocking to prevent priority boost for threads going to break reservation
//g_reservation_mutex.do_notify = false;
// break previous reservation
if (g_reservation_owner)
{
broken = _reservation_break(g_reservation_addr);
}
// change memory protection to read-only
_reservation_set(addr);
// may not be necessary
_mm_mfence();
// set additional information
g_reservation_addr = addr;
g_reservation_size = size;
g_reservation_owner = GetCurrentNamedThread();
g_reservation_cb = callback;
// copy data
memcpy(data, vm::get_ptr(addr), size);
}
return broken;
}
bool reservation_update(u32 addr, const void* data, u32 size)
{
assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128);
assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff));
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
if (g_reservation_owner != GetCurrentNamedThread() || g_reservation_addr != addr || g_reservation_size != size)
{
// atomic update failed
return false;
}
// change memory protection to no access
_reservation_set(addr, true);
// update memory using privileged access
memcpy(vm::get_priv_ptr(addr), data, size);
// remove callback to not call it on successful update
g_reservation_cb = nullptr;
// free the reservation and restore memory protection
_reservation_break(addr);
// atomic update succeeded
return true;
}
bool reservation_query(u32 addr, bool is_writing)
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
{
LV2_LOCK(0);
if (!Memory.IsGoodAddr(addr))
{
return false;
}
}
if (is_writing)
{
// break the reservation
_reservation_break(addr);
}
return true;
}
void reservation_free()
{
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
if (g_reservation_owner == GetCurrentNamedThread())
{
_reservation_break(g_reservation_addr);
}
}
void reservation_op(u32 addr, u32 size, std::function<void()> proc)
{
assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 128);
assert((addr + size - 1 & ~0xfff) == (addr & ~0xfff));
std::lock_guard<reservation_mutex_t> lock(g_reservation_mutex);
// break previous reservation
if (g_reservation_owner != GetCurrentNamedThread() || g_reservation_addr != addr || g_reservation_size != size)
{
if (g_reservation_owner)
{
_reservation_break(g_reservation_addr);
}
}
// change memory protection to no access
_reservation_set(addr, true);
// set additional information
g_reservation_addr = addr;
g_reservation_size = size;
g_reservation_owner = GetCurrentNamedThread();
g_reservation_cb = nullptr;
// may not be necessary
_mm_mfence();
// do the operation
proc();
// remove the reservation
_reservation_break(addr);
}
bool check_addr(u32 addr)
{
@ -62,8 +377,12 @@ namespace vm
{
return res;
}
assert(!real_pointer);
if (real_pointer)
{
throw fmt::format("vm::get_addr(0x%016llx) failed: not a part of virtual memory", (u64)real_pointer);
}
return 0;
}
@ -263,4 +582,4 @@ namespace vm
}
}
}
}
}

View File

@ -21,7 +21,24 @@ namespace vm
static void set_stack_size(u32 size) {}
static void initialize_stack() {}
#ifdef _WIN32
extern HANDLE g_memory_handle;
#endif
extern void* g_priv_addr;
extern void* const g_base_addr;
// break the reservation, return true if it was successfully broken
bool reservation_break(u32 addr);
// read memory and reserve it for further atomic update, return true if the previous reservation was broken
bool reservation_acquire(void* data, u32 addr, u32 size, const std::function<void()>& callback = nullptr);
// attempt to atomically update reserved memory
bool reservation_update(u32 addr, const void* data, u32 size);
bool reservation_query(u32 addr, bool is_writing);
void reservation_free();
// perform complete operation
void reservation_op(u32 addr, u32 size, std::function<void()> proc);
bool map(u32 addr, u32 size, u32 flags);
bool unmap(u32 addr, u32 size = 0, u32 flags = 0);
u32 alloc(u32 size, memory_location location = user_space);
@ -40,6 +57,18 @@ namespace vm
return *get_ptr<T>(addr);
}
template<typename T = void>
T* const get_priv_ptr(u32 addr)
{
return reinterpret_cast<T*>(static_cast<u8*>(g_priv_addr) + addr);
}
template<typename T>
T& get_priv_ref(u32 addr)
{
return *get_priv_ptr<T>(addr);
}
u32 get_addr(const void* real_pointer);
__noinline void error(const u64 addr, const char* func);

View File

@ -213,6 +213,11 @@ namespace vm
{
return vm::get_ptr<T>(vm::cast(m_addr));
}
T* get_priv_ptr() const
{
return vm::get_priv_ptr<T>(vm::cast(m_addr));
}
static const _ptr_base make(const AT& addr)
{
@ -243,6 +248,11 @@ namespace vm
return vm::get_ptr<void>(vm::cast(m_addr));
}
void* get_priv_ptr() const
{
return vm::get_priv_ptr<void>(vm::cast(m_addr));
}
explicit operator void*() const
{
return get_ptr();
@ -301,6 +311,11 @@ namespace vm
return vm::get_ptr<const void>(vm::cast(m_addr));
}
const void* get_priv_ptr() const
{
return vm::get_priv_ptr<const void>(vm::cast(m_addr));
}
explicit operator const void*() const
{
return get_ptr();

View File

@ -11,6 +11,11 @@
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/SysCalls/lv2/sys_time.h"
extern "C"
{
#include "libswscale/swscale.h"
}
#define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].value())
#define CMD_DEBUG 0
@ -2003,42 +2008,82 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
// NV3062
case NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN:
{
m_context_dma_img_dst = ARGS(0);
if (count == 1)
{
m_context_dma_img_dst = ARGS(0);
}
else
{
LOG_ERROR(RSX, "NV3062_SET_CONTEXT_DMA_IMAGE__DESTIN: unknown arg count (%d)", count);
}
break;
}
case NV3062_SET_OFFSET_DESTIN:
{
m_dst_offset = ARGS(0);
if (count == 1)
{
m_dst_offset = ARGS(0);
}
else
{
LOG_ERROR(RSX, "NV3062_SET_OFFSET_DESTIN: unknown arg count (%d)", count);
}
break;
}
case NV3062_SET_COLOR_FORMAT:
{
m_color_format = ARGS(0);
m_color_format_src_pitch = ARGS(1);
m_color_format_dst_pitch = ARGS(1) >> 16;
if (count == 2 || count == 4)
{
m_color_format = ARGS(0);
m_color_format_src_pitch = ARGS(1);
m_color_format_dst_pitch = ARGS(1) >> 16;
if (count == 4)
{
if (ARGS(2))
{
LOG_ERROR(RSX, "NV3062_SET_COLOR_FORMAT: unknown arg2 value (0x%x)", ARGS(2));
}
m_dst_offset = ARGS(3);
}
}
else
{
LOG_ERROR(RSX, "NV3062_SET_COLOR_FORMAT: unknown arg count (%d)", count);
}
break;
}
// NV309E
case NV309E_SET_CONTEXT_DMA_IMAGE:
{
if (u32 value = ARGS(0))
if (count == 1)
{
LOG_WARNING(RSX, "TODO: NV309E_SET_CONTEXT_DMA_IMAGE: 0x%x", value);
m_context_dma_img_src = ARGS(0);
}
else
{
LOG_ERROR(RSX, "NV309E_SET_CONTEXT_DMA_IMAGE: unknown arg count (%d)", count);
}
break;
}
case NV309E_SET_FORMAT:
{
const u8 height = ARGS(0) >> 24;
const u8 width = ARGS(0) >> 16;
const u8 format = ARGS(0);
const u32 offset = ARGS(1);
LOG_WARNING(RSX, "TODO: NV309E_SET_FORMAT: Format:0x%x, Width:%d, Height:%d, Offset:0x%x", format, width, height, offset);
if (count == 2)
{
m_swizzle_format = ARGS(0);
m_swizzle_width = ARGS(0) >> 16;
m_swizzle_height = ARGS(0) >> 24;
m_swizzle_offset = ARGS(1);
}
else
{
LOG_ERROR(RSX, "NV309E_SET_FORMAT: unknown arg count (%d)", count);
}
break;
}
@ -2086,7 +2131,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
if (count >= 5)
{
LOG_WARNING(RSX, "NV308A_COLOR: count = %d", count);
LOG_ERROR(RSX, "NV308A_COLOR: unknown arg count (%d)", count);
}
m_fragment_constants.push_back(c);
@ -2098,69 +2143,180 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
// NV3089
case NV3089_SET_CONTEXT_DMA_IMAGE:
{
m_context_dma_img_src = ARGS(0);
if (count == 1)
{
m_context_dma_img_src = ARGS(0);
}
else
{
LOG_ERROR(RSX, "NV3089_SET_CONTEXT_DMA_IMAGE: unknown arg count (%d)", count);
}
break;
}
case NV3089_SET_CONTEXT_SURFACE:
{
if (ARGS(0) != CELL_GCM_CONTEXT_SURFACE2D)
if (count == 1)
{
LOG_ERROR(RSX, "NV3089_SET_CONTEXT_SURFACE: Unsupported surface (0x%x)", ARGS(0));
m_context_surface = ARGS(0);
if (m_context_surface != CELL_GCM_CONTEXT_SURFACE2D && m_context_surface != CELL_GCM_CONTEXT_SWIZZLE2D)
{
LOG_ERROR(RSX, "NV3089_SET_CONTEXT_SURFACE: unknown surface (0x%x)", ARGS(0));
}
}
else
{
LOG_ERROR(RSX, "NV3089_SET_CONTEXT_SURFACE: unknown arg count (%d)", count);
}
break;
}
case NV3089_IMAGE_IN_SIZE:
{
u16 width = ARGS(0);
u16 height = ARGS(0) >> 16;
const u16 width = ARGS(0);
const u16 height = ARGS(0) >> 16;
const u16 pitch = ARGS(1);
u16 pitch = ARGS(1);
u8 origin = ARGS(1) >> 16;
u8 inter = ARGS(1) >> 24;
const u8 origin = ARGS(1) >> 16;
if (origin != 2 /* CELL_GCM_TRANSFER_ORIGIN_CORNER */)
{
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", origin);
}
u32 offset = ARGS(2);
const u8 inter = ARGS(1) >> 24;
if (inter != 0 /* CELL_GCM_TRANSFER_INTERPOLATOR_ZOH */ && inter != 1 /* CELL_GCM_TRANSFER_INTERPOLATOR_FOH */)
{
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", inter);
}
u16 u = ARGS(3);
u16 v = ARGS(3) >> 16;
const u32 offset = ARGS(2);
const u16 u = ARGS(3); // inX (currently ignored)
const u16 v = ARGS(3) >> 16; // inY (currently ignored)
u8* pixels_src = vm::get_ptr<u8>(GetAddress(offset, m_context_dma_img_src - 0xfeed0000));
u8* pixels_dst = vm::get_ptr<u8>(GetAddress(m_dst_offset, m_context_dma_img_dst - 0xfeed0000));
LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: width=%d, height=%d, pitch=%d, origin=%d, inter=%d, offset=0x%x, u=%d, v=%d", width, height, pitch, origin, inter, offset, u, v);
LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: m_dst_offset=0x%x, m_color: conv_in_h=0x%x, format_src_pitch=0x%x, conv_in_x=0x%x, conv_in_y=0x%x, conv_out_x=0x%x, conv_out_y=0x%x",
m_dst_offset, m_color_conv_in_h, m_color_format_src_pitch, m_color_conv_in_x, m_color_conv_in_y, m_color_conv_out_x, m_color_conv_out_y);
for (u16 y=0; y<m_color_conv_in_h; ++y)
if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D)
{
for (u16 x=0; x<m_color_format_src_pitch/4/*m_color_conv_in_w*/; ++x)
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: Swizzle2D not implemented");
}
else if (m_context_surface != CELL_GCM_CONTEXT_SURFACE2D)
{
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", m_context_surface);
}
if (m_color_format != 4 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 */ && m_color_format != 10 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 */)
{
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_color_format (%d)", m_color_format);
}
const u32 in_bpp = m_color_format == 4 ? 2 : 4; // bytes per pixel
const u32 out_bpp = m_color_conv_fmt == 7 ? 2 : 4;
const s32 out_w = (s32)(u64(width) * (1 << 20) / m_color_conv_dsdx);
const s32 out_h = (s32)(u64(height) * (1 << 20) / m_color_conv_dtdy);
LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: w=%d, h=%d, pitch=%d, offset=0x%x, inX=%f, inY=%f, scaleX=%f, scaleY=%f",
width, height, pitch, offset, double(u) / 16, double(v) / 16, double(1 << 20) / (m_color_conv_dsdx), double(1 << 20) / (m_color_conv_dtdy));
std::unique_ptr<u8[]> temp;
if (in_bpp != out_bpp && width != out_w && height != out_h)
{
// resize/convert if necessary
temp.reset(new u8[out_bpp * out_w * out_h]);
AVPixelFormat in_format = m_color_format == 4 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_BGRA; // ???
AVPixelFormat out_format = m_color_conv_fmt == 7 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_BGRA; // ???
std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(width, height, in_format, out_w, out_h, out_format, inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext);
int in_line = in_bpp * width;
u8* out_ptr = temp.get();
int out_line = out_bpp * out_w;
sws_scale(sws.get(), &pixels_src, &in_line, 0, height, &out_ptr, &out_line);
pixels_src = temp.get(); // use resized image as a source
}
if (m_color_conv_out_w != m_color_conv_clip_w || m_color_conv_out_w != out_w ||
m_color_conv_out_h != m_color_conv_clip_h || m_color_conv_out_h != out_h ||
m_color_conv_out_x || m_color_conv_out_y || m_color_conv_clip_x || m_color_conv_clip_y)
{
// clip if necessary
for (s32 y = m_color_conv_clip_y, dst_y = m_color_conv_out_y; y < out_h; y++, dst_y++)
{
const u32 src_offset = (m_color_conv_in_y + y) * m_color_format_src_pitch + (m_color_conv_in_x + x) * 4;
const u32 dst_offset = (m_color_conv_out_y + y) * m_color_format_dst_pitch + (m_color_conv_out_x + x) * 4;
//(u32&)pixels_dst[dst_offset] = (u32&)pixels_src[src_offset];
if (dst_y >= 0 && dst_y < m_color_conv_out_h)
{
// destination line
u8* dst_line = pixels_dst + dst_y * out_bpp * m_color_conv_out_w + std::min<s32>(std::max<s32>(m_color_conv_out_x, 0), m_color_conv_out_w);
size_t dst_max = std::min<s32>(std::max<s32>((s32)m_color_conv_out_w - m_color_conv_out_x, 0), m_color_conv_out_w) * out_bpp;
if (y >= 0 && y < std::min<s32>(m_color_conv_clip_h, out_h))
{
// source line
u8* src_line = pixels_src + y * out_bpp * out_w + std::min<s32>(std::max<s32>(m_color_conv_clip_x, 0), m_color_conv_clip_w);
size_t src_max = std::min<s32>(std::max<s32>((s32)m_color_conv_clip_w - m_color_conv_clip_x, 0), m_color_conv_clip_w) * out_bpp;
std::pair<u8*, size_t>
z0 = { src_line + 0, std::min<size_t>(dst_max, std::max<s64>(0, m_color_conv_clip_x)) },
d0 = { src_line + z0.second, std::min<size_t>(dst_max - z0.second, src_max) },
z1 = { src_line + d0.second, dst_max - z0.second - d0.second };
memset(z0.first, 0, z0.second);
memcpy(d0.first, src_line, d0.second);
memset(z1.first, 0, z1.second);
}
else
{
memset(dst_line, 0, dst_max);
}
}
}
}
else
{
memcpy(pixels_dst, pixels_src, out_w * out_h * out_bpp);
}
break;
}
case NV3089_SET_COLOR_CONVERSION:
{
m_color_conv = ARGS(0);
if (m_color_conv != 1 /* CELL_GCM_TRANSFER_CONVERSION_TRUNCATE */)
{
LOG_ERROR(RSX, "NV3089_SET_COLOR_CONVERSION: unknown color conv (%d)", m_color_conv);
}
m_color_conv_fmt = ARGS(1);
if (m_color_conv_fmt != 3 /* CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 */ && m_color_conv_fmt != 7 /* CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 */)
{
LOG_ERROR(RSX, "NV3089_SET_COLOR_CONVERSION: unknown format (%d)", m_color_conv_fmt);
}
m_color_conv_op = ARGS(2);
m_color_conv_in_x = ARGS(3);
m_color_conv_in_y = ARGS(3) >> 16;
m_color_conv_in_w = ARGS(4);
m_color_conv_in_h = ARGS(4) >> 16;
if (m_color_conv_op != 3 /* CELL_GCM_TRANSFER_OPERATION_SRCCOPY */)
{
LOG_ERROR(RSX, "NV3089_SET_COLOR_CONVERSION: unknown color conv op (%d)", m_color_conv_op);
}
m_color_conv_clip_x = ARGS(3);
m_color_conv_clip_y = ARGS(3) >> 16;
m_color_conv_clip_w = ARGS(4);
m_color_conv_clip_h = ARGS(4) >> 16;
m_color_conv_out_x = ARGS(5);
m_color_conv_out_y = ARGS(5) >> 16;
m_color_conv_out_w = ARGS(6);
m_color_conv_out_h = ARGS(6) >> 16;
m_color_conv_dsdx = ARGS(7);
m_color_conv_dtdy = ARGS(8);
LOG_WARNING(RSX, "TODO: NV3089_SET_COLOR_CONVERSION");
break;
}

View File

@ -330,16 +330,16 @@ public:
u32 m_color_conv;
u32 m_color_conv_fmt;
u32 m_color_conv_op;
u16 m_color_conv_in_x;
u16 m_color_conv_in_y;
u16 m_color_conv_in_w;
u16 m_color_conv_in_h;
u16 m_color_conv_out_x;
u16 m_color_conv_out_y;
s16 m_color_conv_clip_x;
s16 m_color_conv_clip_y;
u16 m_color_conv_clip_w;
u16 m_color_conv_clip_h;
s16 m_color_conv_out_x;
s16 m_color_conv_out_y;
u16 m_color_conv_out_w;
u16 m_color_conv_out_h;
u32 m_color_conv_dsdx;
u32 m_color_conv_dtdy;
s32 m_color_conv_dsdx;
s32 m_color_conv_dtdy;
// Semaphore
bool m_set_semaphore_offset;
@ -398,12 +398,19 @@ public:
u32 m_context_dma_color_d;
bool m_set_context_dma_z;
u32 m_context_dma_z;
u32 m_context_surface;
u32 m_context_dma_img_src;
u32 m_context_dma_img_dst;
u32 m_context_dma_buffer_in_src;
u32 m_context_dma_buffer_in_dst;
u32 m_dst_offset;
// Swizzle2D?
u16 m_swizzle_format;
u8 m_swizzle_width;
u8 m_swizzle_height;
u32 m_swizzle_offset;
// Cull face
bool m_set_cull_face;
u32 m_cull_face;

View File

@ -136,7 +136,7 @@ const char *getModuleName(int id) {
}
}
return 0;
return "UNKNOWN MODULE";
}
int cellSysmoduleInitialize()
@ -159,11 +159,12 @@ int cellSysmoduleSetMemcontainer(u32 ct_id)
int cellSysmoduleLoadModule(u16 id)
{
cellSysmodule->Warning("cellSysmoduleLoadModule(id=0x%04x: %s)", id, getModuleName(id));
if (id == 0xf054)
{
cellSysmodule->Todo("cellSysmoduleLoadModule: CELL_SYSMODULE_LIBATRAC3MULTI");
}
cellSysmodule->Warning("cellSysmoduleLoadModule(%s)", getModuleName(id));
if (Module* m = Emu.GetModuleManager().GetModuleById(id))
{
@ -180,7 +181,8 @@ int cellSysmoduleLoadModule(u16 id)
int cellSysmoduleUnloadModule(u16 id)
{
cellSysmodule->Warning("cellSysmoduleUnloadModule(%s)", getModuleName(id));
cellSysmodule->Warning("cellSysmoduleUnloadModule(id=0x%04x: %s)", id, getModuleName(id));
Module* m = Emu.GetModuleManager().GetModuleById(id);
if(!m)
@ -199,7 +201,8 @@ int cellSysmoduleUnloadModule(u16 id)
int cellSysmoduleIsLoaded(u16 id)
{
cellSysmodule->Warning("cellSysmoduleIsLoaded(%s)", getModuleName(id));
cellSysmodule->Warning("cellSysmoduleIsLoaded(id=0x%04x: %s)", id, getModuleName(id));
Module* m = Emu.GetModuleManager().GetModuleById(id);
if(!m)

View File

@ -132,7 +132,7 @@ int cellVpostExec(u32 handle, vm::ptr<const u8> inPicBuff, vm::ptr<const CellVpo
//u64 stamp1 = get_system_time();
SwsContext* sws = sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
std::unique_ptr<SwsContext, void(*)(SwsContext*)> sws(sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL), sws_freeContext);
//u64 stamp2 = get_system_time();
@ -141,11 +141,7 @@ int cellVpostExec(u32 handle, vm::ptr<const u8> inPicBuff, vm::ptr<const CellVpo
u8* out_data[4] = { outPicBuff.get_ptr(), NULL, NULL, NULL };
int out_line[4] = { static_cast<int>(ow*4), 0, 0, 0 };
sws_scale(sws, in_data, in_line, 0, h, out_data, out_line);
//u64 stamp3 = get_system_time();
sws_freeContext(sws);
sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line);
//ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)",
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);

View File

@ -69,6 +69,13 @@ struct sceNpTrophyInternal
sceNpTrophyInternal sceNpTrophyInstance;
static sceNpTrophyInternalContext& getContext(u32 context) {
// The invalid context is 0, so remap contexts 1... to indices 0...
if (context == 0)
throw "getContext: context == 0";
return sceNpTrophyInstance.contexts[context - 1];
}
// Functions
int sceNpTrophyInit(u32 pool_addr, u32 poolSize, u32 containerId, u64 options)
{
@ -114,6 +121,7 @@ int sceNpTrophyCreateContext(vm::ptr<u32> context, vm::ptr<SceNpCommunicationId>
ctxt.trp_stream.reset(stream);
ctxt.trp_name = entry->name;
stream = nullptr;
*context = sceNpTrophyInstance.contexts.size(); // contexts start from 1
return CELL_OK;
}
}
@ -124,7 +132,7 @@ int sceNpTrophyCreateContext(vm::ptr<u32> context, vm::ptr<SceNpCommunicationId>
int sceNpTrophyCreateHandle(vm::ptr<u32> handle)
{
sceNpTrophy->Warning("sceNpTrophyCreateHandle(handle_addr=0x%x)", handle.addr());
sceNpTrophy->Todo("sceNpTrophyCreateHandle(handle_addr=0x%x)", handle.addr());
if (!sceNpTrophyInstance.m_bInitialized)
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
@ -144,11 +152,13 @@ int sceNpTrophyRegisterContext(u32 context, u32 handle, vm::ptr<SceNpTrophyStatu
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
if (options & (~(u64)1))
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED;
if (context >= sceNpTrophyInstance.contexts.size())
if (context == 0 || context > sceNpTrophyInstance.contexts.size()) {
sceNpTrophy->Warning("sceNpTrophyRegisterContext: invalid context (%d)", context);
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
}
// TODO: There are other possible errors
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
sceNpTrophyInternalContext& ctxt = getContext(context);
if (!ctxt.trp_stream)
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
@ -219,11 +229,13 @@ int sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr<u64> reqspa
if (!sceNpTrophyInstance.m_bInitialized)
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
if (context >= sceNpTrophyInstance.contexts.size())
if (context == 0 || context > sceNpTrophyInstance.contexts.size()) {
sceNpTrophy->Warning("sceNpTrophyGetRequiredDiskSpace: invalid context (%d)", context);
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
}
// TODO: There are other possible errors
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
const sceNpTrophyInternalContext& ctxt = getContext(context);
if (!ctxt.trp_stream)
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
@ -260,7 +272,7 @@ int sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptr<SceNpTrophyGameDetai
std::string path;
rXmlDocument doc;
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
const sceNpTrophyInternalContext& ctxt = getContext(context);
Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt.trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user
doc.Load(path);
@ -316,7 +328,7 @@ int sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::ptr<u32>
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
// TODO: There are other possible errors
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
sceNpTrophyInternalContext& ctxt = getContext(context);
if (trophyId >= (s32)ctxt.tropusr->GetTrophiesCount())
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
if (ctxt.tropusr->GetTrophyUnlockState(trophyId))
@ -351,15 +363,20 @@ int sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr<SceNpTrophy
if (!sceNpTrophyInstance.m_bInitialized)
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
if (context == 0 || context > sceNpTrophyInstance.contexts.size()) {
sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: invalid context (%d)", context);
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
}
// TODO: There are other possible errors
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
*count = ctxt.tropusr->GetTrophiesCount();
if (*count > 128)
const sceNpTrophyInternalContext& ctxt = getContext(context);
u32 count_ = ctxt.tropusr->GetTrophiesCount();
*count = count_;
if (count_ > 128)
sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected!");
// Pack up to 128 bools in u32 flag_bits[4]
for (u32 id=0; id<*count; id++)
for (u32 id = 0; id < count_; id++)
{
if (ctxt.tropusr->GetTrophyUnlockState(id))
flags->flag_bits[id/32] |= 1<<(id%32);
@ -387,7 +404,7 @@ int sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceN
std::string path;
rXmlDocument doc;
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
const sceNpTrophyInternalContext& ctxt = getContext(context);
Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt.trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user
doc.Load(path);

View File

@ -395,7 +395,7 @@ s32 cellFsFsync(u32 fd)
s32 cellFsRmdir(vm::ptr<const char> path)
{
sys_fs->Warning("cellFsRmdir(path=0x%x)", path.get_ptr());
sys_fs->Warning("cellFsRmdir(path=0x%x)", path);
std::string _path = path.get_ptr();

View File

@ -349,6 +349,8 @@ void Emulator::Resume()
GetCallbackManager().RunPauseCallbacks(false);
}
extern std::map<u32, std::string> g_armv7_dump;
void Emulator::Stop()
{
if(IsStopped()) return;
@ -365,6 +367,14 @@ void Emulator::Stop()
finalize_psv_modules();
clear_all_psv_objects();
for (auto& v : g_armv7_dump)
{
LOG_NOTICE(ARMv7, v.second);
}
g_armv7_dump.clear();
m_rsx_callback = 0;
// TODO: check finalization order

View File

@ -401,8 +401,8 @@ namespace loader
armv7_decoder_initialize(code_start, code_end);
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 0;
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0;
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 256 * 1024;
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 160;
armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
break;

View File

@ -57,7 +57,9 @@
<ClCompile Include="Emu\ARMv7\ARMv7DisAsm.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Interpreter.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Thread.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\psv_cond.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\psv_event_flag.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\psv_mutex.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\psv_sema.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAppMgr.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAppUtil.cpp" />
@ -335,7 +337,9 @@
<ClInclude Include="Emu\ARMv7\ARMv7Interpreter.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Opcodes.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Thread.h" />
<ClInclude Include="Emu\ARMv7\Modules\psv_cond.h" />
<ClInclude Include="Emu\ARMv7\Modules\psv_event_flag.h" />
<ClInclude Include="Emu\ARMv7\Modules\psv_mutex.h" />
<ClInclude Include="Emu\ARMv7\Modules\psv_sema.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAppUtil.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceGxm.h" />

View File

@ -583,7 +583,7 @@
</ClCompile>
<ClCompile Include="Emu\RSX\RSXDMA.cpp">
<Filter>Emu\GPU\RSX</Filter>
</ClCompile>
</ClCompile>
<ClCompile Include="Emu\RSX\RSXTexture.cpp">
<Filter>Emu\GPU\RSX</Filter>
</ClCompile>
@ -851,6 +851,12 @@
<ClCompile Include="Emu\ARMv7\Modules\sceSha.cpp">
<Filter>Emu\CPU\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\psv_mutex.cpp">
<Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\psv_cond.cpp">
<Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -1353,7 +1359,7 @@
</ClInclude>
<ClInclude Include="Emu\RSX\RSXDMA.h">
<Filter>Emu\GPU\RSX</Filter>
</ClInclude>
</ClInclude>
<ClInclude Include="Emu\RSX\RSXFragmentProgram.h">
<Filter>Emu\GPU\RSX</Filter>
</ClInclude>
@ -1513,5 +1519,11 @@
<ClInclude Include="Emu\ARMv7\Modules\sceNpCommon.h">
<Filter>Emu\CPU\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\psv_mutex.h">
<Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\psv_cond.h">
<Filter>Emu\CPU\ARMv7\Objects</Filter>
</ClInclude>
</ItemGroup>
</Project>