diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp index fac6873a33..ce2dbb6914 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include #include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" #include "ARMv7Thread.h" #include "ARMv7Interpreter.h" #include "ARMv7Opcodes.h" @@ -1262,7 +1263,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump) addr += 16; } - LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", g_opct.size()); + LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", (u64)g_opct.size()); } u32 ARMv7Decoder::DecodeMemory(const u32 address) diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index 6ea768832b..c204351616 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -191,7 +191,7 @@ namespace ARMv7_instrs template T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) { - const T sign_mask = (T)1 << (sizeof(T) - 1); + const T sign_mask = (T)1 << (sizeof(T) * 8 - 1); T result = x + y; carry_out = ((x & y) | ((x ^ y) & ~result)) & sign_mask; @@ -823,6 +823,7 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en if (ConditionPassed(context, cond)) { + //LOG_NOTICE(ARMv7, "Branch to 0x%x (cond=0x%x)", context.thread.PC + jump, cond); context.thread.SetBranch(context.thread.PC + jump); } } @@ -1174,6 +1175,7 @@ void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const AR } case T3: { + cond = context.ITSTATE.advance(); n = (code.data & 0xf0000) >> 16; m = (code.data & 0xf); shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); @@ -1187,13 +1189,17 @@ void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const AR if (ConditionPassed(context, cond)) { + const u32 m_value = context.read_gpr(m); + const u32 n_value = context.read_gpr(n); bool carry, overflow; - const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, true); - const u32 res = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow); + const u32 shifted = Shift(m_value, shift_t, shift_n, true); + const u32 res = AddWithCarry(n_value, ~shifted, true, carry, overflow); context.APSR.N = res >> 31; context.APSR.Z = res == 0; context.APSR.C = carry; context.APSR.V = overflow; + + //LOG_NOTICE(ARMv7, "CMP: r%d=0x%08x <> r%d=0x%08x, shifted=0x%08x, res=0x%08x", n, n_value, m, m_value, shifted, res); } } @@ -1619,11 +1625,60 @@ void ARMv7_instrs::LDRH_REG(ARMv7Context& context, const ARMv7Code code, const A void ARMv7_instrs::LDRSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) { + u32 cond, t, n, imm32; + bool index, add, wback; + switch (type) { + case T1: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xfff); + index = true; + add = true; + wback = false; + + reject(t == 15, "PLI"); + reject(n == 15, "LDRSB (literal)"); + reject(t == 13, "UNPREDICTABLE"); + break; + } + case T2: + { + cond = context.ITSTATE.advance(); + t = (code.data & 0xf000) >> 12; + n = (code.data & 0xf0000) >> 16; + imm32 = (code.data & 0xff); + index = (code.data & 0x400); + add = (code.data & 0x200); + wback = (code.data & 0x100); + + reject(t == 15 && index && !add && !wback, "PLI"); + reject(n == 15, "LDRSB (literal)"); + reject(index && add && !wback, "LDRSBT"); + reject(!index && !wback, "UNDEFINED"); + reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE"); + break; + } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } + + if (ConditionPassed(context, cond)) + { + const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : context.read_gpr(n); + const s8 value = vm::psv::read8(addr); + + context.write_gpr(t, value); // sign-extend + + if (wback) + { + context.write_gpr(n, offset_addr); + } + } } void ARMv7_instrs::LDRSB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 1a968dd858..f58acfd0d3 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -120,10 +120,19 @@ void ARMv7Thread::InitRegs() void ARMv7Thread::InitStack() { - if(!m_stack_addr) + if (!m_stack_addr) { - m_stack_size = 0x10000; - m_stack_addr = (u32)Memory.Alloc(0x10000, 1); + assert(m_stack_size); + m_stack_addr = vm::cast(Memory.Alloc(m_stack_size, 4096)); + } +} + +void ARMv7Thread::CloseStack() +{ + if (m_stack_addr) + { + Memory.Free(m_stack_addr); + m_stack_addr = 0; } } @@ -218,7 +227,7 @@ void ARMv7Thread::FastStop() m_status = Stopped; } -arm7_thread::arm7_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, u32 prio) { thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); @@ -229,3 +238,47 @@ arm7_thread::arm7_thread(u32 entry, const std::string& name, u32 stack_size, u32 argc = 0; } + +cpu_thread& armv7_thread::args(std::initializer_list values) +{ + assert(argc == 0); + + if (!values.size()) + { + return *this; + } + + std::vector argv_data; + u32 argv_size = 0; + + for (auto& arg : values) + { + const u32 arg_size = vm::cast(arg.size(), "arg.size()"); // get arg size + + for (char c : arg) + { + argv_data.push_back(c); // append characters + } + + argv_data.push_back('\0'); // append null terminator + + argv_size += arg_size + 1; + argc++; + } + + argv = vm::cast(Memory.PSV.RAM.AllocAlign(argv_size, 4096)); // allocate arg list + memcpy(vm::get_ptr(argv), argv_data.data(), argv_size); // copy arg list + + return *this; +} + +cpu_thread& armv7_thread::run() +{ + thread->Run(); + + // set arguments + static_cast(thread)->context.GPR[0] = argc; + static_cast(thread)->context.GPR[1] = argv; + + return *this; +} diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index c806f4b6c4..a8a0f75311 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -1,29 +1,19 @@ #pragma once #include "Emu/CPU/CPUThread.h" -#include "Emu/Memory/Memory.h" #include "ARMv7Context.h" class ARMv7Thread : public CPUThread { public: ARMv7Context context; - //u32 m_arg; - //u8 m_last_instr_size; - //const char* m_last_instr_name; ARMv7Thread(); ~ARMv7Thread(); - //void update_code(const u32 address) - //{ - // code.code0 = vm::psv::read16(address & ~1); - // code.code1 = vm::psv::read16(address + 2 & ~1); - // m_arg = address & 0x1 ? code.code1 << 16 | code.code0 : code.data; - //} - public: virtual void InitRegs(); virtual void InitStack(); + virtual void CloseStack(); u32 GetStackArg(u32 pos); void FastCall(u32 addr); void FastStop(); @@ -42,48 +32,16 @@ protected: virtual void DoCode(); }; -class arm7_thread : cpu_thread + +class armv7_thread : cpu_thread { - static const u32 stack_align = 0x10; - vm::ptr argv; + u32 argv; u32 argc; - vm::ptr envp; public: - arm7_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 = 0, u32 prio = 0); - cpu_thread& args(std::initializer_list values) override - { - if (!values.size()) - return *this; + cpu_thread& args(std::initializer_list values) override; - //assert(argc == 0); - - //envp.set(vm::alloc((u32)sizeof(envp), stack_align, vm::main)); - //*envp = 0; - //argv.set(vm::alloc(u32(sizeof(argv)* values.size()), stack_align, vm::main)); - - for (auto &arg : values) - { - //u32 arg_size = align(u32(arg.size() + 1), stack_align); - //u32 arg_addr = vm::alloc(arg_size, stack_align, vm::main); - - //std::strcpy(vm::get_ptr(arg_addr), arg.c_str()); - - //argv[argc++] = arg_addr; - } - - return *this; - } - - cpu_thread& run() override - { - thread->Run(); - - //static_cast(thread)->GPR[0] = argc; - //static_cast(thread)->GPR[1] = argv.addr(); - //static_cast(thread)->GPR[2] = envp.addr(); - - return *this; - } + cpu_thread& run() override; }; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index a69ec8338a..b2224af9c0 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -64,17 +64,6 @@ void CPUThread::Reset() DoReset(); } -void CPUThread::CloseStack() -{ - if(m_stack_addr) - { - Memory.StackMem.Free(m_stack_addr); - m_stack_addr = 0; - } - - m_stack_size = 0; -} - void CPUThread::SetId(const u32 id) { m_id = id; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index dd79700c65..35010483cc 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -1,8 +1,7 @@ #pragma once - #include "Utilities/Thread.h" -enum CPUThreadType :unsigned char +enum CPUThreadType : unsigned char { CPU_THREAD_PPU, CPU_THREAD_SPU, @@ -46,10 +45,10 @@ protected: bool m_trace_call_stack; public: - virtual void InitRegs()=0; + virtual void InitRegs() = 0; - virtual void InitStack()=0; - virtual void CloseStack(); + virtual void InitStack() = 0; + virtual void CloseStack() = 0; u32 GetStackAddr() const { return m_stack_addr; } u32 GetStackSize() const { return m_stack_size; } @@ -271,4 +270,4 @@ public: { return thread->GetId(); } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Cell/PPCThread.cpp b/rpcs3/Emu/Cell/PPCThread.cpp index 4248fd58a8..4d77900d90 100644 --- a/rpcs3/Emu/Cell/PPCThread.cpp +++ b/rpcs3/Emu/Cell/PPCThread.cpp @@ -25,18 +25,3 @@ PPCThread::~PPCThread() void PPCThread::DoReset() { } - -void PPCThread::InitStack() -{ - if(m_stack_addr) return; - if(m_stack_size == 0) m_stack_size = 0x10000; - m_stack_addr = (u32)Memory.StackMem.AllocAlign(m_stack_size, 0x100); - /* - m_stack_point += m_stack_size - 0x10; - m_stack_point &= -0x10; - vm::write64(m_stack_point, 0); - m_stack_point -= 0x60; - vm::write64(m_stack_point, m_stack_point + 0x60); - */ -} - diff --git a/rpcs3/Emu/Cell/PPCThread.h b/rpcs3/Emu/Cell/PPCThread.h index 99471f7a80..2c3fa5c05b 100644 --- a/rpcs3/Emu/Cell/PPCThread.h +++ b/rpcs3/Emu/Cell/PPCThread.h @@ -4,9 +4,6 @@ class PPCThread : public CPUThread { public: - virtual void InitRegs()=0; - virtual void InitStack(); - virtual std::string GetThreadName() const { return fmt::format("%s[0x%08x]", GetFName(), PC); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e064a54feb..e6d229583a 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -80,6 +80,24 @@ void PPUThread::InitRegs() TB = 0; } +void PPUThread::InitStack() +{ + if (!m_stack_addr) + { + assert(m_stack_size); + m_stack_addr = vm::cast(Memory.StackMem.AllocAlign(m_stack_size, 4096)); + } +} + +void PPUThread::CloseStack() +{ + if (m_stack_addr) + { + Memory.StackMem.Free(m_stack_addr); + m_stack_addr = 0; + } +} + void PPUThread::DoRun() { switch(Ini.CPUDecoderMode.GetValue()) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 51722f1645..820b244c2b 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -799,8 +799,10 @@ public: } public: - virtual void InitRegs(); - virtual void Task(); + virtual void InitRegs() override; + virtual void InitStack() override; + virtual void CloseStack() override; + virtual void Task() override; u64 GetStackArg(s32 i); u64 FastCall2(u32 addr, u32 rtoc); void FastStop(); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 1c861da43c..f5faf9fff1 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -103,6 +103,17 @@ void SPUThread::InitRegs() R_ADDR = 0; } +void SPUThread::InitStack() +{ + m_stack_size = 0x1000; // this value is wrong + m_stack_addr = m_offset + 0x40000 - m_stack_size; // stack is the part of SPU Local Storage +} + +void SPUThread::CloseStack() +{ + // nothing to do here +} + void SPUThread::DoRun() { switch(Ini.SPUDecoderMode.GetValue()) diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 50d70b1c7f..c2e2cc2f03 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -568,6 +568,8 @@ public: public: virtual void InitRegs(); + virtual void InitStack(); + virtual void CloseStack(); virtual void Task(); void FastCall(u32 ls_addr); void FastStop(); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 2c23ecdb66..69e42e62cb 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -2,6 +2,7 @@ #include "Memory.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/ARMv7/ARMv7Thread.h" namespace vm { @@ -167,13 +168,14 @@ namespace vm u32 stack_push(CPUThread& CPU, u32 size, u32 align_v, u32& old_pos) { + assert(align_v); + switch (CPU.GetType()) { case CPU_THREAD_PPU: { PPUThread& PPU = static_cast(CPU); - assert(align_v); old_pos = (u32)PPU.GPR[1]; PPU.GPR[1] -= align(size, 8); // room minimal possible size PPU.GPR[1] &= ~(align_v - 1); // fix stack alignment @@ -199,8 +201,22 @@ namespace vm case CPU_THREAD_ARMv7: { - assert(!"stack_push(): ARMv7 not supported"); - return 0; + ARMv7Context& context = static_cast(CPU).context; + + old_pos = context.SP; + context.SP -= align(size, 4); // room minimal possible size + context.SP &= ~(align_v - 1); // fix stack alignment + + if (context.SP < CPU.GetStackAddr()) + { + // stack overflow + context.SP = old_pos; + return 0; + } + else + { + return context.SP; + } } default: diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 9c7f19d0c2..c622308f3d 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -323,7 +323,7 @@ namespace loader armv7_init_tls(); armv7_decoder_initialize(code_start, code_end); - arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); + armv7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath(), "-emu" }).run(); break; } case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break;