mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 09:48:37 +12:00
Merge remote-tracking branch 'upstream/master' into spurs_taskset
This commit is contained in:
commit
853234f7d7
47 changed files with 3235 additions and 801 deletions
|
@ -109,7 +109,15 @@ struct FileListener : LogListener
|
||||||
if (mPrependChannelName)
|
if (mPrependChannelName)
|
||||||
{
|
{
|
||||||
text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
|
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);
|
mFile.Write(text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co
|
||||||
pos += to.length();
|
pos += to.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return src;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move this wx Stuff somewhere else
|
//TODO: move this wx Stuff somewhere else
|
||||||
|
@ -339,3 +339,34 @@ std::string fmt::tolower(std::string source)
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
@ -177,6 +177,8 @@ namespace fmt
|
||||||
std::string to_udec(u64 value);
|
std::string to_udec(u64 value);
|
||||||
std::string to_sdec(s64 value);
|
std::string to_sdec(s64 value);
|
||||||
|
|
||||||
|
std::string toupper(std::string source);
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
size_t get_fmt_start(const char* fmt, size_t len);
|
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));
|
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')
|
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
|
||||||
{
|
{
|
||||||
return to_udec(arg);
|
return to_udec(arg);
|
||||||
|
@ -218,6 +224,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
|
||||||
{
|
{
|
||||||
return to_udec(arg);
|
return to_udec(arg);
|
||||||
|
@ -238,6 +248,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
|
||||||
{
|
{
|
||||||
return to_udec(arg);
|
return to_udec(arg);
|
||||||
|
@ -258,6 +272,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex(arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd' || fmt[len - 1] == 'u')
|
||||||
{
|
{
|
||||||
return to_udec(arg);
|
return to_udec(arg);
|
||||||
|
@ -278,6 +296,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u8)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd')
|
||||||
{
|
{
|
||||||
return to_sdec(arg);
|
return to_sdec(arg);
|
||||||
|
@ -298,6 +320,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u16)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd')
|
||||||
{
|
{
|
||||||
return to_sdec(arg);
|
return to_sdec(arg);
|
||||||
|
@ -318,6 +344,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u32)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd')
|
||||||
{
|
{
|
||||||
return to_sdec(arg);
|
return to_sdec(arg);
|
||||||
|
@ -338,6 +368,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u64)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'd')
|
||||||
{
|
{
|
||||||
return to_sdec(arg);
|
return to_sdec(arg);
|
||||||
|
@ -358,6 +392,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u32&)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'f')
|
||||||
{
|
{
|
||||||
return std::to_string(arg);
|
return std::to_string(arg);
|
||||||
|
@ -378,6 +416,10 @@ namespace fmt
|
||||||
{
|
{
|
||||||
return to_hex((u64&)arg, get_fmt_precision(fmt, len));
|
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')
|
else if (fmt[len - 1] == 'f')
|
||||||
{
|
{
|
||||||
return std::to_string(arg);
|
return std::to_string(arg);
|
||||||
|
@ -394,7 +436,7 @@ namespace fmt
|
||||||
{
|
{
|
||||||
static std::string text(const char* fmt, size_t len, bool arg)
|
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));
|
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::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 merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator);
|
||||||
std::string tolower(std::string source);
|
std::string tolower(std::string source);
|
||||||
|
std::string toupper(std::string source);
|
||||||
|
std::string escape(std::string source);
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,9 +213,10 @@ static const reg_table_t reg_table[17] =
|
||||||
|
|
||||||
#endif
|
#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
|
// one x64 instruction is manually decoded and interpreted
|
||||||
x64_op_t op;
|
x64_op_t op;
|
||||||
|
@ -277,6 +278,12 @@ bool handle_access_violation(const u32 addr, x64_context* context)
|
||||||
return true;
|
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
|
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory
|
||||||
return false;
|
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)
|
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;
|
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||||
|
|
||||||
if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64)
|
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);
|
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
|
#else
|
||||||
|
|
||||||
void signal_handler(int sig, siginfo_t* info, void* uct)
|
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 ((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
|
return; // proceed execution
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this may be wrong
|
// 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
|
// else some fatal error
|
||||||
|
@ -352,6 +370,11 @@ void SetCurrentNamedThread(NamedThreadBase* value)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old_value)
|
||||||
|
{
|
||||||
|
vm::reservation_free();
|
||||||
|
}
|
||||||
|
|
||||||
if (value && value->m_tls_assigned.exchange(true))
|
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());
|
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
|
#ifdef _WIN32
|
||||||
auto old_se_translator = _set_se_translator(_se_translator);
|
auto old_se_translator = _set_se_translator(_se_translator);
|
||||||
|
if (!exception_handler)
|
||||||
|
{
|
||||||
|
LOG_ERROR(GENERAL, "exception_handler not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (sigaction_result == -1) assert(!"sigaction() failed");
|
if (sigaction_result == -1)
|
||||||
|
{
|
||||||
|
printf("sigaction() failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SetCurrentNamedThread(this);
|
SetCurrentNamedThread(this);
|
||||||
|
@ -560,8 +592,6 @@ void thread_t::start(std::function<void()> func)
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto old_se_translator = _set_se_translator(_se_translator);
|
auto old_se_translator = _set_se_translator(_se_translator);
|
||||||
#else
|
|
||||||
if (sigaction_result == -1) assert(!"sigaction() failed");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NamedThreadBase info(name);
|
NamedThreadBase info(name);
|
||||||
|
|
|
@ -120,7 +120,7 @@ set_source_files_properties(${RPCS3_SRC_DIR}/Emu/Cell/PPULLVMRecompiler.cpp PROP
|
||||||
add_executable(rpcs3 ${RPCS3_SRC})
|
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
|
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")
|
set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h")
|
||||||
cotire(rpcs3)
|
cotire(rpcs3)
|
||||||
|
|
|
@ -10,17 +10,15 @@ enum ARMv7InstructionSet
|
||||||
ThumbEE
|
ThumbEE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum armv7_debug_flags : u32
|
||||||
|
{
|
||||||
|
DF_DISASM = 1 << 0,
|
||||||
|
DF_PRINT = 1 << 1,
|
||||||
|
DF_NO_EXE = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct ARMv7Context
|
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
|
union
|
||||||
{
|
{
|
||||||
u32 GPR[15];
|
u32 GPR[15];
|
||||||
|
@ -116,9 +114,6 @@ struct ARMv7Context
|
||||||
|
|
||||||
u32 TLS;
|
u32 TLS;
|
||||||
|
|
||||||
u32 R_ADDR;
|
|
||||||
u64 R_DATA;
|
|
||||||
|
|
||||||
struct perf_counter
|
struct perf_counter
|
||||||
{
|
{
|
||||||
u32 event;
|
u32 event;
|
||||||
|
@ -127,6 +122,18 @@ struct ARMv7Context
|
||||||
|
|
||||||
std::array<perf_counter, 6> counters;
|
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)
|
void write_gpr(u32 n, u32 value)
|
||||||
{
|
{
|
||||||
assert(n < 16);
|
assert(n < 16);
|
||||||
|
|
|
@ -30,137 +30,147 @@ struct ARMv7_opcode_t
|
||||||
|
|
||||||
const ARMv7_opcode_t ARMv7_opcode_table[] =
|
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(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_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4040, T1, ADC_REG),
|
ARMv7_OP2(0xffc0, 0x4140, T1, ADC_REG, nullptr),
|
||||||
ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG),
|
ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG, nullptr),
|
||||||
ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG),
|
ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR),
|
ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR),
|
||||||
|
|
||||||
ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM),
|
ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM, nullptr),
|
||||||
ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM),
|
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(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(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM, SKIP_IF( (BF(16, 19) & 13) == 13 )),
|
||||||
ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM),
|
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_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(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, 0x0010, 0x0080, 0x0000, A1, ADD_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR),
|
ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR),
|
||||||
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI),
|
ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI, nullptr),
|
||||||
ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI),
|
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(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_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_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_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0xa000, T1, ADR),
|
ARMv7_OP2(0xf800, 0xa000, T1, ADR, nullptr),
|
||||||
ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR),
|
ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR, nullptr),
|
||||||
ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR),
|
ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR, nullptr),
|
||||||
ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR),
|
ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR),
|
||||||
ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, 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_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG),
|
ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG, nullptr),
|
||||||
ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG),
|
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, 0x0010, 0x0000, 0x0000, A1, AND_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR),
|
ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM),
|
ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM, nullptr),
|
||||||
ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM),
|
ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM, nullptr),
|
||||||
ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM),
|
ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG),
|
ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG, nullptr),
|
||||||
ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG),
|
ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG, nullptr),
|
||||||
ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG),
|
ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG),
|
||||||
|
|
||||||
ARMv7_OP2(0xf000, 0xd000, T1, B),
|
ARMv7_OP2(0xf000, 0xd000, T1, B, SKIP_IF( BF(9, 11) == 0x7 )),
|
||||||
ARMv7_OP2(0xf800, 0xe000, T2, B),
|
ARMv7_OP2(0xf800, 0xe000, T2, B, nullptr),
|
||||||
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B),
|
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B, SKIP_IF( BF(23, 25) == 0x7 )),
|
||||||
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B),
|
ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B, nullptr),
|
||||||
ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B),
|
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(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(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_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG),
|
ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG, nullptr),
|
||||||
ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG),
|
ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG, nullptr),
|
||||||
ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG),
|
ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR),
|
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(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_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL),
|
||||||
ARMv7_OP2(0xff80, 0x4780, T1, BLX),
|
ARMv7_OP2(0xff80, 0x4780, T1, BLX, nullptr),
|
||||||
ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX),
|
ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX, nullptr),
|
||||||
ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX),
|
ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX),
|
||||||
ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, 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_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(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_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG),
|
ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG, nullptr),
|
||||||
ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG),
|
ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG, nullptr),
|
||||||
ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG),
|
ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG),
|
||||||
ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR),
|
ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM),
|
ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM, nullptr),
|
||||||
ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM),
|
ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM, nullptr),
|
||||||
ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM),
|
ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG),
|
ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG, nullptr),
|
||||||
ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG),
|
ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG, nullptr),
|
||||||
ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG),
|
ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG, nullptr),
|
||||||
ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG),
|
ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG),
|
||||||
ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR),
|
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_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG),
|
ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG, nullptr),
|
||||||
ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG),
|
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, 0x0010, 0x0020, 0x0000, A1, EOR_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR),
|
ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR),
|
||||||
|
|
||||||
ARMv7_OP2(0xff00, 0xbf00, T1, IT, SKIP_IF( BF(0, 3) == 0 )),
|
ARMv7_OP2(0xff00, 0xbf00, T1, IT, SKIP_IF( BF(0, 3) == 0 )),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0xc800, T1, LDM),
|
ARMv7_OP2(0xf800, 0xc800, T1, LDM, nullptr),
|
||||||
ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM),
|
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, 0x0890, 0x0000, A1, LDM),
|
||||||
ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA),
|
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, 0x0910, 0x0000, A1, LDMDB),
|
||||||
ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB),
|
ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM),
|
ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM, nullptr),
|
||||||
ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM),
|
ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM, nullptr),
|
||||||
ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM),
|
ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM, SKIP_IF( BF(16, 19) == 15 )),
|
||||||
ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM),
|
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_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM),
|
||||||
ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT),
|
ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT, nullptr),
|
||||||
ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT),
|
ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT, nullptr),
|
||||||
ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT),
|
ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT),
|
||||||
ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG),
|
ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG, nullptr),
|
||||||
ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG),
|
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_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG),
|
||||||
|
|
||||||
ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM),
|
ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM),
|
||||||
ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM),
|
ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM),
|
||||||
ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, 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(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM),
|
||||||
ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM),
|
ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM),
|
||||||
ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG),
|
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, 0x0010, 0x0180, 0x0000, A1, ORR_REG),
|
||||||
ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR),
|
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
|
struct ARMv7_op2_table_t
|
||||||
{
|
{
|
||||||
const ARMv7_opcode_t* data[0x10000];
|
const ARMv7_opcode_t* data[0x10000];
|
||||||
|
u32 null_ops;
|
||||||
|
|
||||||
ARMv7_op2_table_t()
|
ARMv7_op2_table_t()
|
||||||
{
|
{
|
||||||
|
@ -1123,6 +1134,8 @@ struct ARMv7_op2_table_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
null_ops = 0x10000;
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x10000; i++)
|
for (u32 i = 0; i < 0x10000; i++)
|
||||||
{
|
{
|
||||||
data[i] = nullptr;
|
data[i] = nullptr;
|
||||||
|
@ -1132,6 +1145,7 @@ struct ARMv7_op2_table_t
|
||||||
if (((i << 16) & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(i)))
|
if (((i << 16) & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(i)))
|
||||||
{
|
{
|
||||||
data[i] = opcode;
|
data[i] = opcode;
|
||||||
|
null_ops--;
|
||||||
break;
|
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)
|
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
|
// 2. If some instruction is not recognized, print the error
|
||||||
// 3. Possibly print disasm
|
// 3. Possibly print disasm
|
||||||
|
|
||||||
g_opct.clear();
|
//g_opct.clear();
|
||||||
|
//g_opct.reserve(end_addr - addr);
|
||||||
|
|
||||||
while (addr < end_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 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 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:
|
// possibly a call to imported function:
|
||||||
if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090)
|
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;
|
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)
|
u32 ARMv7Decoder::DecodeMemory(const u32 address)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,12 +18,11 @@ enum ARMv7_encoding
|
||||||
|
|
||||||
enum SRType : u32
|
enum SRType : u32
|
||||||
{
|
{
|
||||||
SRType_None,
|
|
||||||
SRType_LSL,
|
SRType_LSL,
|
||||||
SRType_LSR,
|
SRType_LSR,
|
||||||
SRType_ASR,
|
SRType_ASR,
|
||||||
SRType_ROR,
|
SRType_ROR,
|
||||||
SRType_RRX
|
SRType_RRX,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace ARMv7_instrs
|
namespace ARMv7_instrs
|
||||||
|
@ -79,6 +78,10 @@ namespace ARMv7_instrs
|
||||||
void CMP_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
|
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 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_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
|
||||||
void EOR_REG(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);
|
void EOR_RSR(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type);
|
||||||
|
|
|
@ -18,7 +18,7 @@ void ARMv7Context::write_pc(u32 value)
|
||||||
|
|
||||||
u32 ARMv7Context::read_pc()
|
u32 ARMv7Context::read_pc()
|
||||||
{
|
{
|
||||||
return thread.PC;
|
return ISET == ARM ? thread.PC + 8 : thread.PC + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ARMv7Context::get_stack_arg(u32 pos)
|
u32 ARMv7Context::get_stack_arg(u32 pos)
|
||||||
|
@ -118,7 +118,7 @@ void ARMv7Thread::InitRegs()
|
||||||
context.ITSTATE.IT = 0;
|
context.ITSTATE.IT = 0;
|
||||||
context.SP = m_stack_addr + m_stack_size;
|
context.SP = m_stack_addr + m_stack_size;
|
||||||
context.TLS = armv7_get_tls(GetId());
|
context.TLS = armv7_get_tls(GetId());
|
||||||
context.R_ADDR = 0;
|
context.debug |= DF_DISASM | DF_PRINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv7Thread::InitStack()
|
void ARMv7Thread::InitStack()
|
||||||
|
@ -230,14 +230,14 @@ void ARMv7Thread::FastStop()
|
||||||
m_status = Stopped;
|
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 = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
|
||||||
|
|
||||||
thread->SetName(name);
|
thread->SetName(name);
|
||||||
thread->SetEntry(entry);
|
thread->SetEntry(entry);
|
||||||
thread->SetStackSize(stack_size ? stack_size : Emu.GetInfo().GetProcParam().primary_stacksize);
|
thread->SetStackSize(stack_size);
|
||||||
thread->SetPrio(prio ? prio : Emu.GetInfo().GetProcParam().primary_prio);
|
thread->SetPrio(prio);
|
||||||
|
|
||||||
argc = 0;
|
argc = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class armv7_thread : cpu_thread
|
||||||
u32 argc;
|
u32 argc;
|
||||||
|
|
||||||
public:
|
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;
|
cpu_thread& args(std::initializer_list<std::string> values) override;
|
||||||
|
|
||||||
|
|
13
rpcs3/Emu/ARMv7/Modules/psv_cond.cpp
Normal file
13
rpcs3/Emu/ARMv7/Modules/psv_cond.cpp
Normal 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);
|
||||||
|
}
|
24
rpcs3/Emu/ARMv7/Modules/psv_cond.h
Normal file
24
rpcs3/Emu/ARMv7/Modules/psv_cond.h
Normal 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;
|
|
@ -16,6 +16,9 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
psv_event_flag_t(const char* name, u32 attr, u32 pattern);
|
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;
|
extern psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> g_psv_ef_list;
|
||||||
|
|
13
rpcs3/Emu/ARMv7/Modules/psv_mutex.cpp
Normal file
13
rpcs3/Emu/ARMv7/Modules/psv_mutex.cpp
Normal 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);
|
||||||
|
}
|
24
rpcs3/Emu/ARMv7/Modules/psv_mutex.h
Normal file
24
rpcs3/Emu/ARMv7/Modules/psv_mutex.h
Normal 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;
|
|
@ -17,6 +17,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value);
|
psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value);
|
||||||
|
void on_init(s32 id) {}
|
||||||
|
void on_stop() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "sceLibKernel.h"
|
#include "sceLibKernel.h"
|
||||||
#include "psv_sema.h"
|
#include "psv_sema.h"
|
||||||
#include "psv_event_flag.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; }
|
#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)
|
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)
|
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)
|
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)
|
s32 sceKernelDeleteCond(s32 condId)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Utilities/Log.h"
|
#include "Utilities/Log.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/ARMv7/PSVFuncList.h"
|
#include "Emu/ARMv7/PSVFuncList.h"
|
||||||
|
#include "Emu/ARMv7/ARMv7Thread.h"
|
||||||
#include "Emu/ARMv7/ARMv7Callback.h"
|
#include "Emu/ARMv7/ARMv7Callback.h"
|
||||||
|
|
||||||
extern psv_log_base sceLibc;
|
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::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
|
namespace sce_libc_func
|
||||||
{
|
{
|
||||||
void __cxa_atexit(vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> arg, vm::psv::ptr<void> dso)
|
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...
|
void printf(ARMv7Context& context, vm::psv::ptr<const char> fmt) // va_args...
|
||||||
{
|
{
|
||||||
sceLibc.Warning("printf(fmt=0x%x)", fmt);
|
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...
|
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.Warning("sprintf(str=0x%x, fmt=0x%x)", str, fmt);
|
||||||
|
sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr());
|
||||||
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
|
|
||||||
|
|
||||||
const std::string& result = armv7_fmt(context, fmt, 2, 0, 0);
|
const std::string& result = armv7_fmt(context, fmt, 2, 0, 0);
|
||||||
|
sceLibc.Log("*** -> '%s'", result);
|
||||||
sceLibc.Notice("*** res -> '%s'", result);
|
|
||||||
|
|
||||||
::memcpy(str.get_ptr(), result.c_str(), result.size() + 1);
|
::memcpy(str.get_ptr(), result.c_str(), result.size() + 1);
|
||||||
}
|
}
|
||||||
|
@ -158,11 +236,12 @@ namespace sce_libc_func
|
||||||
::memset(dst.get_ptr(), value, size);
|
::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_ERROR(TTY, "%s : %s\n", func.get_ptr(), text.get_ptr());
|
||||||
|
LOG_NOTICE(ARMv7, context.thread.RegsToString());
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,11 @@ s32 scePerfArmPmonSelectEvent(ARMv7Context& context, s32 threadId, u32 counter,
|
||||||
|
|
||||||
case SCE_PERF_ARM_PMON_BRANCH_MISPREDICT:
|
case SCE_PERF_ARM_PMON_BRANCH_MISPREDICT:
|
||||||
case SCE_PERF_ARM_PMON_DCACHE_MISS:
|
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:
|
case SCE_PERF_ARM_PMON_UNALIGNED:
|
||||||
{
|
{
|
||||||
value = 1; // these events will probably never be implemented
|
value = 1; // these events will probably never be implemented
|
||||||
|
|
|
@ -6,21 +6,21 @@ extern psv_log_base sceSysmodule;
|
||||||
|
|
||||||
s32 sceSysmoduleLoadModule(u16 id)
|
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
|
return SCE_OK; // loading succeeded
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceSysmoduleUnloadModule(u16 id)
|
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
|
return SCE_OK; // unloading succeeded
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceSysmoduleIsLoaded(u16 id)
|
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
|
return SCE_OK; // module is loaded
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ void add_psv_func(psv_func& data)
|
||||||
g_psv_func_list.push_back(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)
|
for (auto& f : g_psv_func_list)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ psv_func* get_psv_func_by_nid(u32 nid)
|
||||||
return nullptr;
|
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();
|
auto res = func - g_psv_func_list.data();
|
||||||
|
|
||||||
|
@ -32,14 +32,21 @@ u32 get_psv_func_index(psv_func* func)
|
||||||
return (u32)res;
|
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());
|
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;
|
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;
|
context.thread.m_last_syscall = old_last_syscall;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +181,7 @@ void initialize_psv_modules()
|
||||||
// setup special functions (without NIDs)
|
// setup special functions (without NIDs)
|
||||||
psv_func unimplemented;
|
psv_func unimplemented;
|
||||||
unimplemented.nid = 0;
|
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)
|
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);
|
context.thread.m_last_syscall = vm::psv::read32(context.thread.PC + 4);
|
||||||
|
@ -184,7 +191,7 @@ void initialize_psv_modules()
|
||||||
|
|
||||||
psv_func hle_return;
|
psv_func hle_return;
|
||||||
hle_return.nid = 1;
|
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)
|
hle_return.func.reset(new psv_func_detail::func_binder<void, ARMv7Context&>([](ARMv7Context& context)
|
||||||
{
|
{
|
||||||
context.thread.FastStop();
|
context.thread.FastStop();
|
||||||
|
|
|
@ -492,9 +492,11 @@ template<typename RT, typename... T> void reg_psv_func(u32 nid, psv_log_base* mo
|
||||||
add_psv_func(f);
|
add_psv_func(f);
|
||||||
}
|
}
|
||||||
// Find registered HLE function by its ID
|
// 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
|
// 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
|
// Execute registered HLE function by its index
|
||||||
void execute_psv_func_by_index(ARMv7Context& context, u32 index);
|
void execute_psv_func_by_index(ARMv7Context& context, u32 index);
|
||||||
// Register all HLE functions
|
// Register all HLE functions
|
||||||
|
|
|
@ -5,12 +5,18 @@
|
||||||
#include "Modules/sceLibKernel.h"
|
#include "Modules/sceLibKernel.h"
|
||||||
#include "Modules/psv_sema.h"
|
#include "Modules/psv_sema.h"
|
||||||
#include "Modules/psv_event_flag.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_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_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()
|
void clear_all_psv_objects()
|
||||||
{
|
{
|
||||||
g_psv_sema_list.clear();
|
g_psv_sema_list.clear();
|
||||||
g_psv_ef_list.clear();
|
g_psv_ef_list.clear();
|
||||||
|
g_psv_mutex_list.clear();
|
||||||
|
g_psv_cond_list.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,18 @@ template<typename T, u32 type>
|
||||||
class psv_object_list_t // Class for managing object data
|
class psv_object_list_t // Class for managing object data
|
||||||
{
|
{
|
||||||
std::array<std::shared_ptr<T>, 0x8000> m_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
|
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:
|
public:
|
||||||
static const u32 uid_class = type;
|
static const u32 uid_class = type;
|
||||||
|
|
||||||
|
@ -60,18 +70,18 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
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
|
// find an empty position and copy the pointer
|
||||||
//std::shared_ptr<T> old_ptr = nullptr;
|
if (!m_data[j])
|
||||||
//if (std::atomic_compare_exchange_strong(&value, &old_ptr, data))
|
|
||||||
if (!value)
|
|
||||||
{
|
{
|
||||||
value = data;
|
m_data[j] = data;
|
||||||
|
m_hint = j + 1; // guess next position
|
||||||
psv_uid_t id = psv_uid_t::make(1); // odd number
|
psv_uid_t id = psv_uid_t::make(1); // odd number
|
||||||
id.type = uid_class; // set type
|
id.type = uid_class; // set type
|
||||||
id.number = &value - m_data.data(); // set position
|
id.number = j; // set position
|
||||||
return id.uid;
|
data->on_init(id.uid); // save UID
|
||||||
|
return id.uid; // return UID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +96,14 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const u32 pos = psv_uid_t::make(uid).number;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
std::shared_ptr<T> old_ptr = nullptr;
|
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 old_ptr;
|
||||||
//return std::atomic_exchange<std::shared_ptr<T>>(&m_data[psv_uid_t::make(uid).number], nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all objects
|
// remove all objects
|
||||||
|
@ -99,10 +111,17 @@ public:
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
CPUThread& AddThread(CPUThreadType type);
|
CPUThread& AddThread(CPUThreadType type);
|
||||||
void RemoveThread(const u32 id);
|
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);
|
s32 GetThreadNumById(CPUThreadType type, u32 id);
|
||||||
std::shared_ptr<CPUThread> GetThread(u32 id);
|
std::shared_ptr<CPUThread> GetThread(u32 id);
|
||||||
std::shared_ptr<CPUThread> GetThread(u32 id, CPUThreadType type);
|
std::shared_ptr<CPUThread> GetThread(u32 id, CPUThreadType type);
|
||||||
|
|
|
@ -2500,39 +2500,16 @@ private:
|
||||||
}
|
}
|
||||||
void MFOCRF(u32 a, u32 rd, u32 crm)
|
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;
|
CPU.GPR[rd] = CPU.CR.CR;
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
void LWARX(u32 rd, u32 ra, u32 rb)
|
void LWARX(u32 rd, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
const u32 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);
|
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)
|
void LDX(u32 rd, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -2682,9 +2659,12 @@ private:
|
||||||
}
|
}
|
||||||
void LDARX(u32 rd, u32 ra, u32 rb)
|
void LDARX(u32 rd, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
const u64 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);
|
be_t<u64> value;
|
||||||
|
vm::reservation_acquire(&value, vm::cast(addr), sizeof(value));
|
||||||
|
|
||||||
|
CPU.GPR[rd] = value;
|
||||||
}
|
}
|
||||||
void DCBF(u32 ra, u32 rb)
|
void DCBF(u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -2800,15 +2780,8 @@ private:
|
||||||
{
|
{
|
||||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||||
|
|
||||||
if (CPU.R_ADDR == addr)
|
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)));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
void STWX(u32 rs, u32 ra, u32 rb)
|
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];
|
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
||||||
|
|
||||||
if (CPU.R_ADDR == addr)
|
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)));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
void STBX(u32 rs, u32 ra, u32 rb)
|
void STBX(u32 rs, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -2945,9 +2911,7 @@ private:
|
||||||
}
|
}
|
||||||
void ECIWX(u32 rd, u32 ra, u32 rb)
|
void ECIWX(u32 rd, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
//HACK!
|
throw __FUNCTION__;
|
||||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
|
||||||
CPU.GPR[rd] = vm::read32(vm::cast(addr));
|
|
||||||
}
|
}
|
||||||
void LHZUX(u32 rd, u32 ra, u32 rb)
|
void LHZUX(u32 rd, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -3020,9 +2984,7 @@ private:
|
||||||
}
|
}
|
||||||
void ECOWX(u32 rs, u32 ra, u32 rb)
|
void ECOWX(u32 rs, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
//HACK!
|
throw __FUNCTION__;
|
||||||
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
|
|
||||||
vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]);
|
|
||||||
}
|
}
|
||||||
void STHUX(u32 rs, u32 ra, u32 rb)
|
void STHUX(u32 rs, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2463,25 +2463,27 @@ void Compiler::MFOCRF(u32 a, u32 rd, u32 crm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::LWARX(u32 rd, u32 ra, u32 rb) {
|
void Compiler::LWARX(u32 rd, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
if (ra) {
|
|
||||||
auto ra_i64 = GetGpr(ra);
|
//auto addr_i64 = GetGpr(rb);
|
||||||
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
//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_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_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);
|
//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_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_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_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_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);
|
//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_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());
|
//resv_val_i64 = m_ir_builder->CreateZExt(resv_val_i32, m_ir_builder->getInt64Ty());
|
||||||
SetGpr(rd, resv_val_i64);
|
//SetGpr(rd, resv_val_i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::LDX(u32 rd, u32 ra, u32 rb) {
|
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) {
|
void Compiler::LDARX(u32 rd, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
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 addr_i64 = GetGpr(rb);
|
||||||
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
//if (ra) {
|
||||||
m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
|
// 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_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
|
||||||
auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
|
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||||
auto resv_val_i64_ptr = m_ir_builder->CreateBitCast(resv_val_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
//m_ir_builder->CreateAlignedStore(addr_i64, resv_addr_i64_ptr, 8);
|
||||||
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);
|
//auto resv_val_i64 = ReadMemory(addr_i64, 64, 8, false);
|
||||||
SetGpr(rd, resv_val_i64);
|
//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) {
|
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) {
|
void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
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 addr_i64 = GetGpr(rb);
|
||||||
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
//if (ra) {
|
||||||
auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
|
// auto ra_i64 = GetGpr(ra);
|
||||||
auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
|
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
||||||
|
//}
|
||||||
|
|
||||||
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
|
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
|
||||||
auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
|
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||||
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
|
//auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
|
||||||
m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
|
//auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
|
||||||
|
|
||||||
m_ir_builder->SetInsertPoint(then_bb);
|
//auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
|
||||||
auto rs_i32 = GetGpr(rs, 32);
|
//auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
|
||||||
rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32);
|
//auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
|
||||||
resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
//m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
|
||||||
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 res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
|
//m_ir_builder->SetInsertPoint(then_bb);
|
||||||
auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
|
//auto rs_i32 = GetGpr(rs, 32);
|
||||||
auto cr_i32 = GetCr();
|
//rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i32->getType()), rs_i32);
|
||||||
cr_i32 = SetBit(cr_i32, 2, success_i1);
|
//resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||||
SetCr(cr_i32);
|
//auto resv_addr_val_i32_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt32Ty()->getPointerTo());
|
||||||
m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
|
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
|
||||||
m_ir_builder->CreateBr(merge_bb);
|
//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);
|
//auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i32_ptr, resv_val_i32, rs_i32, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
|
||||||
cr_i32 = GetCr();
|
//auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
|
||||||
cr_i32 = ClrBit(cr_i32, 2);
|
//auto cr_i32 = GetCr();
|
||||||
SetCr(cr_i32);
|
//cr_i32 = SetBit(cr_i32, 2, success_i1);
|
||||||
m_ir_builder->CreateBr(merge_bb);
|
//SetCr(cr_i32);
|
||||||
m_ir_builder->SetInsertPoint(merge_bb);
|
//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) {
|
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) {
|
void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
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 addr_i64 = GetGpr(rb);
|
||||||
auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
//if (ra) {
|
||||||
auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
|
// auto ra_i64 = GetGpr(ra);
|
||||||
auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
|
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
||||||
|
//}
|
||||||
|
|
||||||
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
|
//auto resv_addr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_ADDR));
|
||||||
auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
|
//auto resv_addr_i64_ptr = m_ir_builder->CreateBitCast(resv_addr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||||
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
|
//auto resv_addr_i64 = (Value *)m_ir_builder->CreateAlignedLoad(resv_addr_i64_ptr, 8);
|
||||||
m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
|
//auto cmp_i1 = m_ir_builder->CreateICmpEQ(addr_i64, resv_addr_i64);
|
||||||
|
|
||||||
m_ir_builder->SetInsertPoint(then_bb);
|
//auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then");
|
||||||
auto rs_i64 = GetGpr(rs, 64);
|
//auto else_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "else");
|
||||||
rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64);
|
//auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge");
|
||||||
resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
//m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb);
|
||||||
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 res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
|
//m_ir_builder->SetInsertPoint(then_bb);
|
||||||
auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
|
//auto rs_i64 = GetGpr(rs, 64);
|
||||||
auto cr_i32 = GetCr();
|
//rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, rs_i64->getType()), rs_i64);
|
||||||
cr_i32 = SetBit(cr_i32, 2, success_i1);
|
//resv_addr_i64 = m_ir_builder->CreateAdd(resv_addr_i64, m_ir_builder->getInt64((u64)vm::get_ptr<u8>(0)));
|
||||||
SetCr(cr_i32);
|
//auto resv_addr_val_i64_ptr = m_ir_builder->CreateIntToPtr(resv_addr_i64, m_ir_builder->getInt64Ty()->getPointerTo());
|
||||||
m_ir_builder->CreateAlignedStore(m_ir_builder->getInt64(0), resv_addr_i64_ptr, 8);
|
//auto resv_val_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, R_VALUE));
|
||||||
m_ir_builder->CreateBr(merge_bb);
|
//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);
|
//auto res_s = m_ir_builder->CreateAtomicCmpXchg(resv_addr_val_i64_ptr, resv_val_i64, rs_i64, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic);
|
||||||
cr_i32 = GetCr();
|
//auto success_i1 = m_ir_builder->CreateExtractValue(res_s, {1});
|
||||||
cr_i32 = ClrBit(cr_i32, 2);
|
//auto cr_i32 = GetCr();
|
||||||
SetCr(cr_i32);
|
//cr_i32 = SetBit(cr_i32, 2, success_i1);
|
||||||
m_ir_builder->CreateBr(merge_bb);
|
//SetCr(cr_i32);
|
||||||
m_ir_builder->SetInsertPoint(merge_bb);
|
//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) {
|
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) {
|
void Compiler::ECIWX(u32 rd, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
if (ra) {
|
//auto addr_i64 = GetGpr(rb);
|
||||||
auto ra_i64 = GetGpr(ra);
|
//if (ra) {
|
||||||
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
// auto ra_i64 = GetGpr(ra);
|
||||||
}
|
// addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
||||||
|
//}
|
||||||
|
|
||||||
auto mem_i32 = ReadMemory(addr_i64, 32);
|
//auto mem_i32 = ReadMemory(addr_i64, 32);
|
||||||
auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty());
|
//auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty());
|
||||||
SetGpr(rd, mem_i64);
|
//SetGpr(rd, mem_i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::LHZUX(u32 rd, u32 ra, u32 rb) {
|
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) {
|
void Compiler::ECOWX(u32 rs, u32 ra, u32 rb) {
|
||||||
auto addr_i64 = GetGpr(rb);
|
throw __FUNCTION__;
|
||||||
if (ra) {
|
//auto addr_i64 = GetGpr(rb);
|
||||||
auto ra_i64 = GetGpr(ra);
|
//if (ra) {
|
||||||
addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64);
|
// 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) {
|
void Compiler::STHUX(u32 rs, u32 ra, u32 rb) {
|
||||||
|
|
|
@ -59,10 +59,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
|
||||||
/// Time base register
|
/// Time base register
|
||||||
u64 TB;
|
u64 TB;
|
||||||
|
|
||||||
/// Reservations
|
|
||||||
u64 R_ADDR;
|
|
||||||
u64 R_VALUE;
|
|
||||||
|
|
||||||
/// Memory block
|
/// Memory block
|
||||||
u32 address;
|
u32 address;
|
||||||
u64 mem_block[64];
|
u64 mem_block[64];
|
||||||
|
@ -86,9 +82,6 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
|
||||||
CTR = ppu.CTR;
|
CTR = ppu.CTR;
|
||||||
TB = ppu.TB;
|
TB = ppu.TB;
|
||||||
|
|
||||||
R_ADDR = ppu.R_ADDR;
|
|
||||||
R_VALUE = ppu.R_VALUE;
|
|
||||||
|
|
||||||
address = addr;
|
address = addr;
|
||||||
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
|
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
|
||||||
mem_block[i] = vm::read64(address + (i * 8));
|
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.CTR = CTR;
|
||||||
ppu.TB = TB;
|
ppu.TB = TB;
|
||||||
|
|
||||||
ppu.R_ADDR = R_ADDR;
|
|
||||||
ppu.R_VALUE = R_VALUE;
|
|
||||||
|
|
||||||
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
|
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
|
||||||
vm::write64(address + (i * 8), mem_block[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();
|
LR = rng();
|
||||||
CTR = rng();
|
CTR = rng();
|
||||||
TB = rng();
|
TB = rng();
|
||||||
R_ADDR = rng();
|
|
||||||
R_VALUE = rng();
|
|
||||||
|
|
||||||
address = addr;
|
address = addr;
|
||||||
for (int i = 0; i < (sizeof(mem_block) / 8); i++) {
|
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.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));
|
// 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("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) {
|
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]);
|
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[14] = 10;
|
||||||
input.GPR[21] = 15;
|
input.GPR[21] = 15;
|
||||||
input.GPR[23] = 0x10000;
|
input.GPR[23] = 0x10000;
|
||||||
input.R_ADDR = 0x10000;
|
|
||||||
input.R_VALUE = 0x1122334455667788;
|
|
||||||
input.mem_block[0] = 0x8877665544332211;
|
input.mem_block[0] = 0x8877665544332211;
|
||||||
|
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LBZ, 0, input, 5, 0, 0x10000);
|
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(LHZU, 0, input, 5, 14, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 0, input, 5, 0, 23);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 0, input, 5, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHZX, 1, input, 5, 14, 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, 0, input, 5, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECIWX, 1, input, 5, 14, 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(LHZUX, 0, input, 5, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 0, input, 5, 0, 0x100F0);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 0, input, 5, 0, 0x100F0);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LHA, 1, input, 5, 14, 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, 0, input, 5, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LFDX, 1, input, 5, 14, 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(LFDUX, 0, input, 5, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LWARX, 0, input, 5, 0, 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(LWARX, 1, input, 5, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LDARX, 0, input, 5, 0, 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(LDARX, 1, input, 5, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 0, input, 5, 23, 0);
|
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, 1, input, 5, 23, 2);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(LSWI, 2, input, 5, 23, 7);
|
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, 0, input, 3, 0, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STB, 1, input, 3, 14, 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(STBU, 0, input, 3, 14, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDCX_, 0, input, 3, 0, 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(STDCX_, 1, input, 3, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBX, 0, input, 3, 0, 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(STBX, 1, input, 3, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STBUX, 0, 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(STHU, 0, input, 3, 14, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 0, input, 3, 0, 23);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 0, input, 3, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHX, 1, input, 3, 14, 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, 0, input, 3, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(ECOWX, 1, input, 3, 14, 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(STHUX, 0, input, 3, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STHBRX, 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);
|
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(STDU, 0, input, 3, 14, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 0, input, 3, 0, 23);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 0, input, 3, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STDX, 1, input, 3, 14, 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_, 0, input, 3, 0, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWCX_, 1, input, 3, 14, 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(STDUX, 0, input, 3, 14, 23);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 0, input, 3, 0, 0x10000);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 0, input, 3, 0, 0x10000);
|
||||||
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 1, input, 3, 14, 0x10000);
|
VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFS, 1, input, 3, 14, 0x10000);
|
||||||
|
|
|
@ -536,11 +536,6 @@ public:
|
||||||
//TBR : Time-Base Registers
|
//TBR : Time-Base Registers
|
||||||
u64 TB; //TBR 0x10C - 0x10D
|
u64 TB; //TBR 0x10C - 0x10D
|
||||||
|
|
||||||
u64 cycle;
|
|
||||||
|
|
||||||
u64 R_ADDR; // reservation address
|
|
||||||
u64 R_VALUE; // reservation value (BE)
|
|
||||||
|
|
||||||
u32 owned_mutexes;
|
u32 owned_mutexes;
|
||||||
std::function<void(PPUThread& CPU)> custom_task;
|
std::function<void(PPUThread& CPU)> custom_task;
|
||||||
|
|
||||||
|
|
|
@ -99,8 +99,6 @@ void SPUThread::InitRegs()
|
||||||
|
|
||||||
m_event_mask = 0;
|
m_event_mask = 0;
|
||||||
m_events = 0;
|
m_events = 0;
|
||||||
|
|
||||||
R_ADDR = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPUThread::InitStack()
|
void SPUThread::InitStack()
|
||||||
|
@ -437,103 +435,48 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||||
|
|
||||||
if (op == MFC_GETLLAR_CMD) // get reservation
|
if (op == MFC_GETLLAR_CMD) // get reservation
|
||||||
{
|
{
|
||||||
if (R_ADDR)
|
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
{
|
|
||||||
m_events |= SPU_EVENT_LR;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_ADDR = ea;
|
vm::reservation_acquire(vm::get_ptr(ls_offset + lsa), ea, 128, [this]()
|
||||||
for (u32 i = 0; i < 16; i++)
|
|
||||||
{
|
{
|
||||||
R_DATA[i] = vm::get_ptr<u64>((u32)R_ADDR)[i];
|
//std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(tid);
|
||||||
vm::get_ptr<u64>(ls_offset + lsa)[i] = R_DATA[i];
|
|
||||||
}
|
//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);
|
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
|
||||||
}
|
}
|
||||||
else if (op == MFC_PUTLLC_CMD) // store conditional
|
else if (op == MFC_PUTLLC_CMD) // store conditional
|
||||||
{
|
{
|
||||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
|
if (vm::reservation_update(ea, vm::get_ptr(ls_offset + lsa), 128))
|
||||||
|
|
||||||
if (R_ADDR == ea)
|
|
||||||
{
|
{
|
||||||
u32 changed = 0, mask = 0;
|
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
|
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)
|
if (op == MFC_PUTLLUC_CMD)
|
||||||
{
|
{
|
||||||
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
|
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
|
||||||
}
|
}
|
||||||
R_ADDR = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -548,19 +491,6 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
|
||||||
bool SPUThread::CheckEvents()
|
bool SPUThread::CheckEvents()
|
||||||
{
|
{
|
||||||
// checks events:
|
// 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;
|
return (m_events & m_event_mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,9 +295,6 @@ public:
|
||||||
u32 SRR0;
|
u32 SRR0;
|
||||||
SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
|
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
|
std::shared_ptr<EventPort> SPUPs[64]; // SPU Thread Event Ports
|
||||||
EventManager SPUQs; // SPU Queue Mapping
|
EventManager SPUQs; // SPU Queue Mapping
|
||||||
std::shared_ptr<SpuGroupInfo> group; // associated SPU Thread Group (null for raw spu)
|
std::shared_ptr<SpuGroupInfo> group; // associated SPU Thread Group (null for raw spu)
|
||||||
|
|
|
@ -102,20 +102,17 @@ void MemoryBase::Init(MemoryType type)
|
||||||
memset(m_pages, 0, sizeof(m_pages));
|
memset(m_pages, 0, sizeof(m_pages));
|
||||||
memset(RawSPUMem, 0, sizeof(RawSPUMem));
|
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
|
#ifdef _WIN32
|
||||||
if (!vm::g_base_addr)
|
if (!vm::g_base_addr || !vm::g_priv_addr)
|
||||||
#else
|
#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
|
#endif
|
||||||
{
|
{
|
||||||
LOG_ERROR(MEMORY, "Initializing memory failed");
|
LOG_ERROR(MEMORY, "Initializing memory failed");
|
||||||
assert(0);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_NOTICE(MEMORY, "Initializing memory: base_addr = 0x%llx", (u64)vm::g_base_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -207,7 +204,7 @@ bool MemoryBase::Map(const u64 addr, const u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBlocks.push_back((new MemoryBlock())->SetRange(addr, size));
|
MemoryBlocks.push_back((new MemoryBlock())->SetRange(addr, size));
|
||||||
|
|
||||||
LOG_WARNING(MEMORY, "Memory mapped at 0x%llx: size=0x%x", addr, size);
|
LOG_WARNING(MEMORY, "Memory mapped at 0x%llx: size=0x%x", addr, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -231,20 +228,14 @@ bool MemoryBase::Unmap(const u64 addr)
|
||||||
MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
|
MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
|
||||||
: MemInfo(_addr, PAGE_4K(_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
|
#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
|
#else
|
||||||
if (::mprotect(real_addr, size, PROT_READ | PROT_WRITE))
|
if (mprotect(real_addr, size, PROT_READ | PROT_WRITE) || mprotect(priv_addr, size, PROT_READ | PROT_WRITE))
|
||||||
{
|
|
||||||
mem = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mem = real_addr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (mem != real_addr)
|
|
||||||
{
|
{
|
||||||
LOG_ERROR(MEMORY, "Memory allocation failed (addr=0x%llx, size=0x%x)", addr, size);
|
LOG_ERROR(MEMORY, "Memory allocation failed (addr=0x%llx, size=0x%x)", addr, size);
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
|
@ -252,7 +243,9 @@ MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Memory.RegisterPages(_addr, PAGE_4K(_size));
|
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);
|
Memory.UnregisterPages(addr, size);
|
||||||
#ifdef _WIN32
|
#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
|
#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
|
#endif
|
||||||
{
|
{
|
||||||
LOG_ERROR(MEMORY, "Memory deallocation failed (addr=0x%llx, size=0x%x)", addr, size);
|
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);
|
LOG_ERROR(MEMORY, "DynamicMemoryBlockBase::AllocAlign(size=0x%x, align=0x%x): memory block not initialized", size, align);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = PAGE_4K(size);
|
size = PAGE_4K(size);
|
||||||
u32 exsize;
|
u32 exsize;
|
||||||
|
|
||||||
|
@ -715,4 +710,4 @@ bool VirtualMemoryBlock::Unreserve(u32 size)
|
||||||
u32 VirtualMemoryBlock::GetReservedAmount()
|
u32 VirtualMemoryBlock::GetReservedAmount()
|
||||||
{
|
{
|
||||||
return m_reserve_size;
|
return m_reserve_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,6 @@ public:
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* const GetBaseAddr()
|
|
||||||
{
|
|
||||||
return vm::g_base_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterPages(u64 addr, u32 size);
|
void RegisterPages(u64 addr, u32 size);
|
||||||
|
|
||||||
void UnregisterPages(u64 addr, u32 size);
|
void UnregisterPages(u64 addr, u32 size);
|
||||||
|
|
|
@ -1,24 +1,339 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "Utilities/Log.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
#include "Emu/System.h"
|
||||||
#include "Emu/CPU/CPUThread.h"
|
#include "Emu/CPU/CPUThread.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "Emu/ARMv7/ARMv7Thread.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
|
namespace vm
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
HANDLE g_memory_handle;
|
||||||
void* const g_base_addr = VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS);
|
#endif
|
||||||
#else
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
|
void* g_priv_addr;
|
||||||
#ifndef MAP_ANONYMOUS
|
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void* const g_base_addr = mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
void* initialize()
|
||||||
#endif
|
{
|
||||||
|
#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)
|
bool check_addr(u32 addr)
|
||||||
{
|
{
|
||||||
|
@ -62,8 +377,12 @@ namespace vm
|
||||||
{
|
{
|
||||||
return res;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,4 +582,4 @@ namespace vm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,24 @@ namespace vm
|
||||||
static void set_stack_size(u32 size) {}
|
static void set_stack_size(u32 size) {}
|
||||||
static void initialize_stack() {}
|
static void initialize_stack() {}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern HANDLE g_memory_handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void* g_priv_addr;
|
||||||
extern void* const g_base_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 map(u32 addr, u32 size, u32 flags);
|
||||||
bool unmap(u32 addr, u32 size = 0, u32 flags = 0);
|
bool unmap(u32 addr, u32 size = 0, u32 flags = 0);
|
||||||
u32 alloc(u32 size, memory_location location = user_space);
|
u32 alloc(u32 size, memory_location location = user_space);
|
||||||
|
@ -40,6 +57,18 @@ namespace vm
|
||||||
return *get_ptr<T>(addr);
|
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);
|
u32 get_addr(const void* real_pointer);
|
||||||
|
|
||||||
__noinline void error(const u64 addr, const char* func);
|
__noinline void error(const u64 addr, const char* func);
|
||||||
|
|
|
@ -213,6 +213,11 @@ namespace vm
|
||||||
{
|
{
|
||||||
return vm::get_ptr<T>(vm::cast(m_addr));
|
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)
|
static const _ptr_base make(const AT& addr)
|
||||||
{
|
{
|
||||||
|
@ -243,6 +248,11 @@ namespace vm
|
||||||
return vm::get_ptr<void>(vm::cast(m_addr));
|
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
|
explicit operator void*() const
|
||||||
{
|
{
|
||||||
return get_ptr();
|
return get_ptr();
|
||||||
|
@ -301,6 +311,11 @@ namespace vm
|
||||||
return vm::get_ptr<const void>(vm::cast(m_addr));
|
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
|
explicit operator const void*() const
|
||||||
{
|
{
|
||||||
return get_ptr();
|
return get_ptr();
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
#include "Emu/SysCalls/CB_FUNC.h"
|
#include "Emu/SysCalls/CB_FUNC.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_time.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 ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].value())
|
||||||
#define CMD_DEBUG 0
|
#define CMD_DEBUG 0
|
||||||
|
|
||||||
|
@ -2003,42 +2008,82 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
|
||||||
// NV3062
|
// NV3062
|
||||||
case NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV3062_SET_OFFSET_DESTIN:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV3062_SET_COLOR_FORMAT:
|
case NV3062_SET_COLOR_FORMAT:
|
||||||
{
|
{
|
||||||
m_color_format = ARGS(0);
|
if (count == 2 || count == 4)
|
||||||
m_color_format_src_pitch = ARGS(1);
|
{
|
||||||
m_color_format_dst_pitch = ARGS(1) >> 16;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NV309E
|
// NV309E
|
||||||
case NV309E_SET_CONTEXT_DMA_IMAGE:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV309E_SET_FORMAT:
|
case NV309E_SET_FORMAT:
|
||||||
{
|
{
|
||||||
const u8 height = ARGS(0) >> 24;
|
if (count == 2)
|
||||||
const u8 width = ARGS(0) >> 16;
|
{
|
||||||
const u8 format = ARGS(0);
|
m_swizzle_format = ARGS(0);
|
||||||
const u32 offset = ARGS(1);
|
m_swizzle_width = ARGS(0) >> 16;
|
||||||
|
m_swizzle_height = ARGS(0) >> 24;
|
||||||
LOG_WARNING(RSX, "TODO: NV309E_SET_FORMAT: Format:0x%x, Width:%d, Height:%d, Offset:0x%x", format, width, height, offset);
|
m_swizzle_offset = ARGS(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR(RSX, "NV309E_SET_FORMAT: unknown arg count (%d)", count);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2086,7 +2131,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const
|
||||||
|
|
||||||
if (count >= 5)
|
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);
|
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
|
// NV3089
|
||||||
case NV3089_SET_CONTEXT_DMA_IMAGE:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV3089_SET_CONTEXT_SURFACE:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV3089_IMAGE_IN_SIZE:
|
case NV3089_IMAGE_IN_SIZE:
|
||||||
{
|
{
|
||||||
u16 width = ARGS(0);
|
const u16 width = ARGS(0);
|
||||||
u16 height = ARGS(0) >> 16;
|
const u16 height = ARGS(0) >> 16;
|
||||||
|
const u16 pitch = ARGS(1);
|
||||||
|
|
||||||
u16 pitch = ARGS(1);
|
const u8 origin = ARGS(1) >> 16;
|
||||||
u8 origin = ARGS(1) >> 16;
|
if (origin != 2 /* CELL_GCM_TRANSFER_ORIGIN_CORNER */)
|
||||||
u8 inter = ARGS(1) >> 24;
|
{
|
||||||
|
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);
|
const u32 offset = ARGS(2);
|
||||||
u16 v = ARGS(3) >> 16;
|
|
||||||
|
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_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));
|
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);
|
if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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;
|
if (dst_y >= 0 && dst_y < m_color_conv_out_h)
|
||||||
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];
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NV3089_SET_COLOR_CONVERSION:
|
case NV3089_SET_COLOR_CONVERSION:
|
||||||
{
|
{
|
||||||
m_color_conv = ARGS(0);
|
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);
|
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_op = ARGS(2);
|
||||||
m_color_conv_in_x = ARGS(3);
|
if (m_color_conv_op != 3 /* CELL_GCM_TRANSFER_OPERATION_SRCCOPY */)
|
||||||
m_color_conv_in_y = ARGS(3) >> 16;
|
{
|
||||||
m_color_conv_in_w = ARGS(4);
|
LOG_ERROR(RSX, "NV3089_SET_COLOR_CONVERSION: unknown color conv op (%d)", m_color_conv_op);
|
||||||
m_color_conv_in_h = ARGS(4) >> 16;
|
}
|
||||||
|
|
||||||
|
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_x = ARGS(5);
|
||||||
m_color_conv_out_y = ARGS(5) >> 16;
|
m_color_conv_out_y = ARGS(5) >> 16;
|
||||||
m_color_conv_out_w = ARGS(6);
|
m_color_conv_out_w = ARGS(6);
|
||||||
m_color_conv_out_h = ARGS(6) >> 16;
|
m_color_conv_out_h = ARGS(6) >> 16;
|
||||||
m_color_conv_dsdx = ARGS(7);
|
m_color_conv_dsdx = ARGS(7);
|
||||||
m_color_conv_dtdy = ARGS(8);
|
m_color_conv_dtdy = ARGS(8);
|
||||||
|
|
||||||
LOG_WARNING(RSX, "TODO: NV3089_SET_COLOR_CONVERSION");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,16 +330,16 @@ public:
|
||||||
u32 m_color_conv;
|
u32 m_color_conv;
|
||||||
u32 m_color_conv_fmt;
|
u32 m_color_conv_fmt;
|
||||||
u32 m_color_conv_op;
|
u32 m_color_conv_op;
|
||||||
u16 m_color_conv_in_x;
|
s16 m_color_conv_clip_x;
|
||||||
u16 m_color_conv_in_y;
|
s16 m_color_conv_clip_y;
|
||||||
u16 m_color_conv_in_w;
|
u16 m_color_conv_clip_w;
|
||||||
u16 m_color_conv_in_h;
|
u16 m_color_conv_clip_h;
|
||||||
u16 m_color_conv_out_x;
|
s16 m_color_conv_out_x;
|
||||||
u16 m_color_conv_out_y;
|
s16 m_color_conv_out_y;
|
||||||
u16 m_color_conv_out_w;
|
u16 m_color_conv_out_w;
|
||||||
u16 m_color_conv_out_h;
|
u16 m_color_conv_out_h;
|
||||||
u32 m_color_conv_dsdx;
|
s32 m_color_conv_dsdx;
|
||||||
u32 m_color_conv_dtdy;
|
s32 m_color_conv_dtdy;
|
||||||
|
|
||||||
// Semaphore
|
// Semaphore
|
||||||
bool m_set_semaphore_offset;
|
bool m_set_semaphore_offset;
|
||||||
|
@ -398,12 +398,19 @@ public:
|
||||||
u32 m_context_dma_color_d;
|
u32 m_context_dma_color_d;
|
||||||
bool m_set_context_dma_z;
|
bool m_set_context_dma_z;
|
||||||
u32 m_context_dma_z;
|
u32 m_context_dma_z;
|
||||||
|
u32 m_context_surface;
|
||||||
u32 m_context_dma_img_src;
|
u32 m_context_dma_img_src;
|
||||||
u32 m_context_dma_img_dst;
|
u32 m_context_dma_img_dst;
|
||||||
u32 m_context_dma_buffer_in_src;
|
u32 m_context_dma_buffer_in_src;
|
||||||
u32 m_context_dma_buffer_in_dst;
|
u32 m_context_dma_buffer_in_dst;
|
||||||
u32 m_dst_offset;
|
u32 m_dst_offset;
|
||||||
|
|
||||||
|
// Swizzle2D?
|
||||||
|
u16 m_swizzle_format;
|
||||||
|
u8 m_swizzle_width;
|
||||||
|
u8 m_swizzle_height;
|
||||||
|
u32 m_swizzle_offset;
|
||||||
|
|
||||||
// Cull face
|
// Cull face
|
||||||
bool m_set_cull_face;
|
bool m_set_cull_face;
|
||||||
u32 m_cull_face;
|
u32 m_cull_face;
|
||||||
|
|
|
@ -136,7 +136,7 @@ const char *getModuleName(int id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return "UNKNOWN MODULE";
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellSysmoduleInitialize()
|
int cellSysmoduleInitialize()
|
||||||
|
@ -159,11 +159,12 @@ int cellSysmoduleSetMemcontainer(u32 ct_id)
|
||||||
|
|
||||||
int cellSysmoduleLoadModule(u16 id)
|
int cellSysmoduleLoadModule(u16 id)
|
||||||
{
|
{
|
||||||
|
cellSysmodule->Warning("cellSysmoduleLoadModule(id=0x%04x: %s)", id, getModuleName(id));
|
||||||
|
|
||||||
if (id == 0xf054)
|
if (id == 0xf054)
|
||||||
{
|
{
|
||||||
cellSysmodule->Todo("cellSysmoduleLoadModule: CELL_SYSMODULE_LIBATRAC3MULTI");
|
cellSysmodule->Todo("cellSysmoduleLoadModule: CELL_SYSMODULE_LIBATRAC3MULTI");
|
||||||
}
|
}
|
||||||
cellSysmodule->Warning("cellSysmoduleLoadModule(%s)", getModuleName(id));
|
|
||||||
|
|
||||||
if (Module* m = Emu.GetModuleManager().GetModuleById(id))
|
if (Module* m = Emu.GetModuleManager().GetModuleById(id))
|
||||||
{
|
{
|
||||||
|
@ -180,7 +181,8 @@ int cellSysmoduleLoadModule(u16 id)
|
||||||
|
|
||||||
int cellSysmoduleUnloadModule(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);
|
Module* m = Emu.GetModuleManager().GetModuleById(id);
|
||||||
|
|
||||||
if(!m)
|
if(!m)
|
||||||
|
@ -199,7 +201,8 @@ int cellSysmoduleUnloadModule(u16 id)
|
||||||
|
|
||||||
int cellSysmoduleIsLoaded(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);
|
Module* m = Emu.GetModuleManager().GetModuleById(id);
|
||||||
|
|
||||||
if(!m)
|
if(!m)
|
||||||
|
|
|
@ -132,7 +132,7 @@ int cellVpostExec(u32 handle, vm::ptr<const u8> inPicBuff, vm::ptr<const CellVpo
|
||||||
|
|
||||||
//u64 stamp1 = get_system_time();
|
//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();
|
//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 };
|
u8* out_data[4] = { outPicBuff.get_ptr(), NULL, NULL, NULL };
|
||||||
int out_line[4] = { static_cast<int>(ow*4), 0, 0, 0 };
|
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);
|
sws_scale(sws.get(), in_data, in_line, 0, h, out_data, out_line);
|
||||||
|
|
||||||
//u64 stamp3 = get_system_time();
|
|
||||||
|
|
||||||
sws_freeContext(sws);
|
|
||||||
|
|
||||||
//ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)",
|
//ConLog.Write("cellVpostExec() perf (access=%d, getContext=%d, scale=%d, finalize=%d)",
|
||||||
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
|
//stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
|
||||||
|
|
|
@ -69,6 +69,13 @@ struct sceNpTrophyInternal
|
||||||
|
|
||||||
sceNpTrophyInternal sceNpTrophyInstance;
|
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
|
// Functions
|
||||||
int sceNpTrophyInit(u32 pool_addr, u32 poolSize, u32 containerId, u64 options)
|
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_stream.reset(stream);
|
||||||
ctxt.trp_name = entry->name;
|
ctxt.trp_name = entry->name;
|
||||||
stream = nullptr;
|
stream = nullptr;
|
||||||
|
*context = sceNpTrophyInstance.contexts.size(); // contexts start from 1
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +132,7 @@ int sceNpTrophyCreateContext(vm::ptr<u32> context, vm::ptr<SceNpCommunicationId>
|
||||||
|
|
||||||
int sceNpTrophyCreateHandle(vm::ptr<u32> handle)
|
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)
|
if (!sceNpTrophyInstance.m_bInitialized)
|
||||||
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
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;
|
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
||||||
if (options & (~(u64)1))
|
if (options & (~(u64)1))
|
||||||
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED;
|
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;
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
||||||
|
}
|
||||||
// TODO: There are other possible errors
|
// TODO: There are other possible errors
|
||||||
|
|
||||||
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
|
sceNpTrophyInternalContext& ctxt = getContext(context);
|
||||||
if (!ctxt.trp_stream)
|
if (!ctxt.trp_stream)
|
||||||
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
|
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)
|
if (!sceNpTrophyInstance.m_bInitialized)
|
||||||
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
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;
|
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT;
|
||||||
|
}
|
||||||
// TODO: There are other possible errors
|
// TODO: There are other possible errors
|
||||||
|
|
||||||
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
|
const sceNpTrophyInternalContext& ctxt = getContext(context);
|
||||||
if (!ctxt.trp_stream)
|
if (!ctxt.trp_stream)
|
||||||
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
|
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;
|
std::string path;
|
||||||
rXmlDocument doc;
|
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
|
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);
|
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;
|
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
||||||
// TODO: There are other possible errors
|
// TODO: There are other possible errors
|
||||||
|
|
||||||
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
|
sceNpTrophyInternalContext& ctxt = getContext(context);
|
||||||
if (trophyId >= (s32)ctxt.tropusr->GetTrophiesCount())
|
if (trophyId >= (s32)ctxt.tropusr->GetTrophiesCount())
|
||||||
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
|
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID;
|
||||||
if (ctxt.tropusr->GetTrophyUnlockState(trophyId))
|
if (ctxt.tropusr->GetTrophyUnlockState(trophyId))
|
||||||
|
@ -351,15 +363,20 @@ int sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr<SceNpTrophy
|
||||||
|
|
||||||
if (!sceNpTrophyInstance.m_bInitialized)
|
if (!sceNpTrophyInstance.m_bInitialized)
|
||||||
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
|
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
|
// TODO: There are other possible errors
|
||||||
|
|
||||||
sceNpTrophyInternalContext& ctxt = sceNpTrophyInstance.contexts[context];
|
const sceNpTrophyInternalContext& ctxt = getContext(context);
|
||||||
*count = ctxt.tropusr->GetTrophiesCount();
|
u32 count_ = ctxt.tropusr->GetTrophiesCount();
|
||||||
if (*count > 128)
|
*count = count_;
|
||||||
|
if (count_ > 128)
|
||||||
sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected!");
|
sceNpTrophy->Warning("sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected!");
|
||||||
|
|
||||||
// Pack up to 128 bools in u32 flag_bits[4]
|
// 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))
|
if (ctxt.tropusr->GetTrophyUnlockState(id))
|
||||||
flags->flag_bits[id/32] |= 1<<(id%32);
|
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;
|
std::string path;
|
||||||
rXmlDocument doc;
|
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
|
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);
|
doc.Load(path);
|
||||||
|
|
||||||
|
|
|
@ -395,7 +395,7 @@ s32 cellFsFsync(u32 fd)
|
||||||
|
|
||||||
s32 cellFsRmdir(vm::ptr<const char> path)
|
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();
|
std::string _path = path.get_ptr();
|
||||||
|
|
||||||
|
|
|
@ -349,6 +349,8 @@ void Emulator::Resume()
|
||||||
GetCallbackManager().RunPauseCallbacks(false);
|
GetCallbackManager().RunPauseCallbacks(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern std::map<u32, std::string> g_armv7_dump;
|
||||||
|
|
||||||
void Emulator::Stop()
|
void Emulator::Stop()
|
||||||
{
|
{
|
||||||
if(IsStopped()) return;
|
if(IsStopped()) return;
|
||||||
|
@ -365,6 +367,14 @@ void Emulator::Stop()
|
||||||
|
|
||||||
finalize_psv_modules();
|
finalize_psv_modules();
|
||||||
clear_all_psv_objects();
|
clear_all_psv_objects();
|
||||||
|
|
||||||
|
for (auto& v : g_armv7_dump)
|
||||||
|
{
|
||||||
|
LOG_NOTICE(ARMv7, v.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_armv7_dump.clear();
|
||||||
|
|
||||||
m_rsx_callback = 0;
|
m_rsx_callback = 0;
|
||||||
|
|
||||||
// TODO: check finalization order
|
// TODO: check finalization order
|
||||||
|
|
|
@ -401,8 +401,8 @@ namespace loader
|
||||||
armv7_decoder_initialize(code_start, code_end);
|
armv7_decoder_initialize(code_start, code_end);
|
||||||
|
|
||||||
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
|
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 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 256 * 1024;
|
||||||
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0;
|
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 160;
|
||||||
|
|
||||||
armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
|
armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -57,7 +57,9 @@
|
||||||
<ClCompile Include="Emu\ARMv7\ARMv7DisAsm.cpp" />
|
<ClCompile Include="Emu\ARMv7\ARMv7DisAsm.cpp" />
|
||||||
<ClCompile Include="Emu\ARMv7\ARMv7Interpreter.cpp" />
|
<ClCompile Include="Emu\ARMv7\ARMv7Interpreter.cpp" />
|
||||||
<ClCompile Include="Emu\ARMv7\ARMv7Thread.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_event_flag.cpp" />
|
||||||
|
<ClCompile Include="Emu\ARMv7\Modules\psv_mutex.cpp" />
|
||||||
<ClCompile Include="Emu\ARMv7\Modules\psv_sema.cpp" />
|
<ClCompile Include="Emu\ARMv7\Modules\psv_sema.cpp" />
|
||||||
<ClCompile Include="Emu\ARMv7\Modules\sceAppMgr.cpp" />
|
<ClCompile Include="Emu\ARMv7\Modules\sceAppMgr.cpp" />
|
||||||
<ClCompile Include="Emu\ARMv7\Modules\sceAppUtil.cpp" />
|
<ClCompile Include="Emu\ARMv7\Modules\sceAppUtil.cpp" />
|
||||||
|
@ -335,7 +337,9 @@
|
||||||
<ClInclude Include="Emu\ARMv7\ARMv7Interpreter.h" />
|
<ClInclude Include="Emu\ARMv7\ARMv7Interpreter.h" />
|
||||||
<ClInclude Include="Emu\ARMv7\ARMv7Opcodes.h" />
|
<ClInclude Include="Emu\ARMv7\ARMv7Opcodes.h" />
|
||||||
<ClInclude Include="Emu\ARMv7\ARMv7Thread.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_event_flag.h" />
|
||||||
|
<ClInclude Include="Emu\ARMv7\Modules\psv_mutex.h" />
|
||||||
<ClInclude Include="Emu\ARMv7\Modules\psv_sema.h" />
|
<ClInclude Include="Emu\ARMv7\Modules\psv_sema.h" />
|
||||||
<ClInclude Include="Emu\ARMv7\Modules\sceAppUtil.h" />
|
<ClInclude Include="Emu\ARMv7\Modules\sceAppUtil.h" />
|
||||||
<ClInclude Include="Emu\ARMv7\Modules\sceGxm.h" />
|
<ClInclude Include="Emu\ARMv7\Modules\sceGxm.h" />
|
||||||
|
|
|
@ -583,7 +583,7 @@
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\RSX\RSXDMA.cpp">
|
<ClCompile Include="Emu\RSX\RSXDMA.cpp">
|
||||||
<Filter>Emu\GPU\RSX</Filter>
|
<Filter>Emu\GPU\RSX</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\RSX\RSXTexture.cpp">
|
<ClCompile Include="Emu\RSX\RSXTexture.cpp">
|
||||||
<Filter>Emu\GPU\RSX</Filter>
|
<Filter>Emu\GPU\RSX</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -851,6 +851,12 @@
|
||||||
<ClCompile Include="Emu\ARMv7\Modules\sceSha.cpp">
|
<ClCompile Include="Emu\ARMv7\Modules\sceSha.cpp">
|
||||||
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
||||||
</ClCompile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Crypto\aes.h">
|
<ClInclude Include="Crypto\aes.h">
|
||||||
|
@ -1353,7 +1359,7 @@
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\RSX\RSXDMA.h">
|
<ClInclude Include="Emu\RSX\RSXDMA.h">
|
||||||
<Filter>Emu\GPU\RSX</Filter>
|
<Filter>Emu\GPU\RSX</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\RSX\RSXFragmentProgram.h">
|
<ClInclude Include="Emu\RSX\RSXFragmentProgram.h">
|
||||||
<Filter>Emu\GPU\RSX</Filter>
|
<Filter>Emu\GPU\RSX</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1513,5 +1519,11 @@
|
||||||
<ClInclude Include="Emu\ARMv7\Modules\sceNpCommon.h">
|
<ClInclude Include="Emu\ARMv7\Modules\sceNpCommon.h">
|
||||||
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
||||||
</ClInclude>
|
</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>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue