ARMv7: argc, argv setting, LDRSB_IMM, bugfixes

This commit is contained in:
Nekotekina 2015-02-01 16:52:34 +03:00
parent 8a945a1a52
commit e5dd03dbcb
14 changed files with 184 additions and 98 deletions

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include <unordered_map> #include <unordered_map>
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "ARMv7Thread.h" #include "ARMv7Thread.h"
#include "ARMv7Interpreter.h" #include "ARMv7Interpreter.h"
#include "ARMv7Opcodes.h" #include "ARMv7Opcodes.h"
@ -1262,7 +1263,7 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
addr += 16; 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) u32 ARMv7Decoder::DecodeMemory(const u32 address)

View file

@ -191,7 +191,7 @@ namespace ARMv7_instrs
template<typename T> T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) template<typename T> 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; T result = x + y;
carry_out = ((x & y) | ((x ^ y) & ~result)) & sign_mask; 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)) 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); 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: case T3:
{ {
cond = context.ITSTATE.advance();
n = (code.data & 0xf0000) >> 16; n = (code.data & 0xf0000) >> 16;
m = (code.data & 0xf); m = (code.data & 0xf);
shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n); 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)) if (ConditionPassed(context, cond))
{ {
const u32 m_value = context.read_gpr(m);
const u32 n_value = context.read_gpr(n);
bool carry, overflow; bool carry, overflow;
const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, true); const u32 shifted = Shift(m_value, shift_t, shift_n, true);
const u32 res = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow); const u32 res = AddWithCarry(n_value, ~shifted, true, carry, overflow);
context.APSR.N = res >> 31; context.APSR.N = res >> 31;
context.APSR.Z = res == 0; context.APSR.Z = res == 0;
context.APSR.C = carry; context.APSR.C = carry;
context.APSR.V = overflow; 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) 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) 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__; case A1: throw __FUNCTION__;
default: 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) void ARMv7_instrs::LDRSB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)

View file

@ -120,10 +120,19 @@ void ARMv7Thread::InitRegs()
void ARMv7Thread::InitStack() void ARMv7Thread::InitStack()
{ {
if(!m_stack_addr) if (!m_stack_addr)
{ {
m_stack_size = 0x10000; assert(m_stack_size);
m_stack_addr = (u32)Memory.Alloc(0x10000, 1); 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; 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); 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; argc = 0;
} }
cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
{
assert(argc == 0);
if (!values.size())
{
return *this;
}
std::vector<char> 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<ARMv7Thread*>(thread)->context.GPR[0] = argc;
static_cast<ARMv7Thread*>(thread)->context.GPR[1] = argv;
return *this;
}

View file

@ -1,29 +1,19 @@
#pragma once #pragma once
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
#include "ARMv7Context.h" #include "ARMv7Context.h"
class ARMv7Thread : public CPUThread class ARMv7Thread : public CPUThread
{ {
public: public:
ARMv7Context context; ARMv7Context context;
//u32 m_arg;
//u8 m_last_instr_size;
//const char* m_last_instr_name;
ARMv7Thread(); ARMv7Thread();
~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: public:
virtual void InitRegs(); virtual void InitRegs();
virtual void InitStack(); virtual void InitStack();
virtual void CloseStack();
u32 GetStackArg(u32 pos); u32 GetStackArg(u32 pos);
void FastCall(u32 addr); void FastCall(u32 addr);
void FastStop(); void FastStop();
@ -42,48 +32,16 @@ protected:
virtual void DoCode(); virtual void DoCode();
}; };
class arm7_thread : cpu_thread
class armv7_thread : cpu_thread
{ {
static const u32 stack_align = 0x10; u32 argv;
vm::ptr<u64> argv;
u32 argc; u32 argc;
vm::ptr<u64> envp;
public: 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<std::string> values) override cpu_thread& args(std::initializer_list<std::string> values) override;
{
if (!values.size())
return *this;
//assert(argc == 0); cpu_thread& run() override;
//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<char>(arg_addr), arg.c_str());
//argv[argc++] = arg_addr;
}
return *this;
}
cpu_thread& run() override
{
thread->Run();
//static_cast<ARMv7Thread*>(thread)->GPR[0] = argc;
//static_cast<ARMv7Thread*>(thread)->GPR[1] = argv.addr();
//static_cast<ARMv7Thread*>(thread)->GPR[2] = envp.addr();
return *this;
}
}; };

View file

@ -64,17 +64,6 @@ void CPUThread::Reset()
DoReset(); 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) void CPUThread::SetId(const u32 id)
{ {
m_id = id; m_id = id;

View file

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
enum CPUThreadType :unsigned char enum CPUThreadType : unsigned char
{ {
CPU_THREAD_PPU, CPU_THREAD_PPU,
CPU_THREAD_SPU, CPU_THREAD_SPU,
@ -46,10 +45,10 @@ protected:
bool m_trace_call_stack; bool m_trace_call_stack;
public: public:
virtual void InitRegs()=0; virtual void InitRegs() = 0;
virtual void InitStack()=0; virtual void InitStack() = 0;
virtual void CloseStack(); virtual void CloseStack() = 0;
u32 GetStackAddr() const { return m_stack_addr; } u32 GetStackAddr() const { return m_stack_addr; }
u32 GetStackSize() const { return m_stack_size; } u32 GetStackSize() const { return m_stack_size; }

View file

@ -25,18 +25,3 @@ PPCThread::~PPCThread()
void PPCThread::DoReset() 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);
*/
}

View file

@ -4,9 +4,6 @@
class PPCThread : public CPUThread class PPCThread : public CPUThread
{ {
public: public:
virtual void InitRegs()=0;
virtual void InitStack();
virtual std::string GetThreadName() const virtual std::string GetThreadName() const
{ {
return fmt::format("%s[0x%08x]", GetFName(), PC); return fmt::format("%s[0x%08x]", GetFName(), PC);

View file

@ -80,6 +80,24 @@ void PPUThread::InitRegs()
TB = 0; 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() void PPUThread::DoRun()
{ {
switch(Ini.CPUDecoderMode.GetValue()) switch(Ini.CPUDecoderMode.GetValue())

View file

@ -799,8 +799,10 @@ public:
} }
public: public:
virtual void InitRegs(); virtual void InitRegs() override;
virtual void Task(); virtual void InitStack() override;
virtual void CloseStack() override;
virtual void Task() override;
u64 GetStackArg(s32 i); u64 GetStackArg(s32 i);
u64 FastCall2(u32 addr, u32 rtoc); u64 FastCall2(u32 addr, u32 rtoc);
void FastStop(); void FastStop();

View file

@ -103,6 +103,17 @@ void SPUThread::InitRegs()
R_ADDR = 0; 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() void SPUThread::DoRun()
{ {
switch(Ini.SPUDecoderMode.GetValue()) switch(Ini.SPUDecoderMode.GetValue())

View file

@ -568,6 +568,8 @@ public:
public: public:
virtual void InitRegs(); virtual void InitRegs();
virtual void InitStack();
virtual void CloseStack();
virtual void Task(); virtual void Task();
void FastCall(u32 ls_addr); void FastCall(u32 ls_addr);
void FastStop(); void FastStop();

View file

@ -2,6 +2,7 @@
#include "Memory.h" #include "Memory.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"
namespace vm namespace vm
{ {
@ -167,13 +168,14 @@ namespace vm
u32 stack_push(CPUThread& CPU, u32 size, u32 align_v, u32& old_pos) u32 stack_push(CPUThread& CPU, u32 size, u32 align_v, u32& old_pos)
{ {
assert(align_v);
switch (CPU.GetType()) switch (CPU.GetType())
{ {
case CPU_THREAD_PPU: case CPU_THREAD_PPU:
{ {
PPUThread& PPU = static_cast<PPUThread&>(CPU); PPUThread& PPU = static_cast<PPUThread&>(CPU);
assert(align_v);
old_pos = (u32)PPU.GPR[1]; old_pos = (u32)PPU.GPR[1];
PPU.GPR[1] -= align(size, 8); // room minimal possible size PPU.GPR[1] -= align(size, 8); // room minimal possible size
PPU.GPR[1] &= ~(align_v - 1); // fix stack alignment PPU.GPR[1] &= ~(align_v - 1); // fix stack alignment
@ -199,8 +201,22 @@ namespace vm
case CPU_THREAD_ARMv7: case CPU_THREAD_ARMv7:
{ {
assert(!"stack_push(): ARMv7 not supported"); ARMv7Context& context = static_cast<ARMv7Thread&>(CPU).context;
return 0;
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: default:

View file

@ -323,7 +323,7 @@ namespace loader
armv7_init_tls(); armv7_init_tls();
armv7_decoder_initialize(code_start, code_end); 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; 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; 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;