mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 06:05:40 +12:00
Finish ELF loading, running actual code now
This commit is contained in:
parent
51689af51f
commit
275c6dfd0c
7 changed files with 135 additions and 59 deletions
|
@ -8,21 +8,18 @@
|
|||
class MyEnvironment final : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
u64 ticks_left = 0;
|
||||
std::array<u8, 2048> memory{};
|
||||
Memory& mem;
|
||||
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
if (vaddr >= memory.size()) {
|
||||
return 0;
|
||||
}
|
||||
return memory[vaddr];
|
||||
return mem.read8(vaddr);
|
||||
}
|
||||
|
||||
u16 MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
return mem.read16(vaddr);
|
||||
}
|
||||
|
||||
u32 MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
return mem.read32(vaddr);
|
||||
}
|
||||
|
||||
u64 MemoryRead64(u32 vaddr) override {
|
||||
|
@ -30,20 +27,15 @@ public:
|
|||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
if (vaddr >= memory.size()) {
|
||||
return;
|
||||
}
|
||||
memory[vaddr] = value;
|
||||
mem.write8(vaddr, value);
|
||||
}
|
||||
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override {
|
||||
MemoryWrite8(vaddr, u8(value));
|
||||
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||
mem.write16(vaddr, value);
|
||||
}
|
||||
|
||||
void MemoryWrite32(u32 vaddr, u32 value) override {
|
||||
MemoryWrite16(vaddr, u16(value));
|
||||
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||
mem.write32(vaddr, value);
|
||||
}
|
||||
|
||||
void MemoryWrite64(u32 vaddr, u64 value) override {
|
||||
|
@ -75,6 +67,8 @@ public:
|
|||
u64 GetTicksRemaining() override {
|
||||
return ticks_left;
|
||||
}
|
||||
|
||||
MyEnvironment(Memory& mem) : mem(mem) {}
|
||||
};
|
||||
|
||||
class CPU {
|
||||
|
@ -105,4 +99,10 @@ public:
|
|||
u32 getCPSR() {
|
||||
return jit.Cpsr();
|
||||
}
|
||||
|
||||
void runFrame() {
|
||||
env.ticks_left = 268111856 / 60;
|
||||
const auto exitReason = jit.Run();
|
||||
Helpers::panic("Exit reason: %d", (u32)exitReason);
|
||||
}
|
||||
};
|
|
@ -4,6 +4,18 @@
|
|||
#include <vector>
|
||||
#include "helpers.hpp"
|
||||
|
||||
namespace VirtualAddrs {
|
||||
enum : u32 {
|
||||
ExecutableStart = 0x00100000,
|
||||
MaxExeSize = 0x03F00000,
|
||||
ExecutableEnd = 0x00100000 + 0x03F00000,
|
||||
|
||||
// Stack for main ARM11 thread.
|
||||
// Typically 0x4000 bytes
|
||||
StackTop = 0x10000000
|
||||
};
|
||||
}
|
||||
|
||||
class Memory {
|
||||
u8* fcram;
|
||||
|
||||
|
@ -12,11 +24,19 @@ class Memory {
|
|||
static constexpr u32 pageShift = 12;
|
||||
static constexpr u32 pageSize = 1 << pageShift;
|
||||
static constexpr u32 pageMask = pageSize - 1;
|
||||
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
|
||||
|
||||
public:
|
||||
Memory();
|
||||
void* getReadPointer(u32 address);
|
||||
void* getWritePointer(u32 address);
|
||||
|
||||
std::optional<u32> loadELF(std::filesystem::path& path);
|
||||
|
||||
u8 read8(u32 vaddr);
|
||||
u16 read16(u32 vaddr);
|
||||
u32 read32(u32 vaddr);
|
||||
|
||||
void write8(u32 vaddr, u8 value);
|
||||
void write16(u32 vaddr, u16 value);
|
||||
void write32(u32 vaddr, u32 value);
|
||||
};
|
|
@ -1,35 +1,15 @@
|
|||
#ifdef CPU_DYNARMIC
|
||||
#include "cpu_dynarmic.hpp"
|
||||
|
||||
CPU::CPU(Memory& mem) : mem(mem) {
|
||||
// Execute at least 1 instruction.
|
||||
// (Note: More than one instruction may be executed.)
|
||||
env.ticks_left = 10;
|
||||
|
||||
// Write some code to memory.
|
||||
env.MemoryWrite16(0, 0x0088); // lsls r0, r1, #2
|
||||
env.MemoryWrite16(2, 0x3045); // adds r0, #69
|
||||
env.MemoryWrite16(4, 0x3845); // subs r0, #69
|
||||
env.MemoryWrite16(6, 0xE7FE); // b +#0 (infinite loop)
|
||||
|
||||
// Setup registers.
|
||||
auto& regs = jit.Regs();
|
||||
regs[0] = 1;
|
||||
regs[1] = 2;
|
||||
regs[15] = 0; // PC = 0
|
||||
setCPSR(0x00000030); // Thumb mode
|
||||
|
||||
// Execute!
|
||||
jit.Run();
|
||||
|
||||
// Here we would expect cpu.Regs()[0] == 77
|
||||
printf("R0: %u\n", jit.Regs()[0]);
|
||||
}
|
||||
CPU::CPU(Memory& mem) : mem(mem), env(mem) {}
|
||||
|
||||
void CPU::reset() {
|
||||
jit.Regs().fill(0);
|
||||
// ARM mode, all flags disabled, interrupts and aborts all enabled, user mode
|
||||
setCPSR(0x00000010);
|
||||
|
||||
jit.Reset();
|
||||
jit.ClearCache();
|
||||
jit.Regs().fill(0);
|
||||
}
|
||||
|
||||
#endif // CPU_DYNARMIC
|
|
@ -1,4 +1,6 @@
|
|||
#include "memory.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include "elfio/elfio.hpp"
|
||||
|
||||
using namespace ELFIO;
|
||||
|
@ -10,14 +12,35 @@ std::optional<u32> Memory::loadELF(std::filesystem::path& path) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto seg_num = reader.segments.size();
|
||||
printf("Number of segments: %d\n", seg_num);
|
||||
for (int i = 0; i < seg_num; ++i) {
|
||||
const auto pseg = reader.segments[i];
|
||||
std::cout << " [" << i << "] 0x" << std::hex << pseg->get_flags()
|
||||
<< "\t0x" << pseg->get_virtual_address() << "\t0x"
|
||||
<< pseg->get_file_size() << "\t0x" << pseg->get_memory_size()
|
||||
<< std::endl;
|
||||
auto segNum = reader.segments.size();
|
||||
printf("Number of segments: %d\n", segNum);
|
||||
for (int i = 0; i < segNum; ++i) {
|
||||
const auto seg = reader.segments[i];
|
||||
const auto flags = seg->get_flags();
|
||||
const u32 vaddr = static_cast<u32>(seg->get_virtual_address()); // Vaddr the segment is loaded in
|
||||
u32 fileSize = static_cast<u32>(seg->get_file_size()); // Size of segment in file
|
||||
u32 memorySize = static_cast<u32>(seg->get_memory_size()); // Size of segment in memory
|
||||
u8* data = (u8*)seg->get_data();
|
||||
|
||||
// Get read/write/execute permissions for segment
|
||||
const bool r = (flags & 0b100) != 0;
|
||||
const bool w = (flags & 0b010) != 0;
|
||||
const bool x = (flags & 0b001) != 0;
|
||||
|
||||
printf(" # Perms Vaddr File Size Mem Size\n");
|
||||
printf("[%d] (%c%c%c)\t%08X\t%08X\t%08X\n", i, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', vaddr, fileSize, memorySize);
|
||||
|
||||
// Assert that the segment will be loaded in the executable region. If it isn't then panic.
|
||||
// The executable region starts at 0x00100000 and has a maximum size of 0x03F00000
|
||||
u64 endAddress = (u64)vaddr + (u64)fileSize;
|
||||
const bool isGood = vaddr >= VirtualAddrs::ExecutableStart && endAddress < VirtualAddrs::ExecutableEnd;
|
||||
if (!isGood) {
|
||||
Helpers::panic("ELF is loaded at invalid place");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
u32 fcramAddr = vaddr - VirtualAddrs::ExecutableStart;
|
||||
std::memcpy(&fcram[fcramAddr], data, fileSize);
|
||||
}
|
||||
|
||||
return static_cast<u32>(reader.get_entry());
|
||||
|
|
|
@ -2,11 +2,66 @@
|
|||
|
||||
Memory::Memory() {
|
||||
fcram = new uint8_t[128_MB]();
|
||||
readTable.resize(totalPageCount, 0);
|
||||
writeTable.resize(totalPageCount, 0);
|
||||
|
||||
// Map 63MB of FCRAM in the executable section as read/write
|
||||
// TODO: This should probably be read-only, but making it r/w shouldn't hurt?
|
||||
// Because if that were the case then writes would cause data aborts, so games wouldn't write to read-only memory
|
||||
u32 executablePageCount = VirtualAddrs::MaxExeSize / pageSize;
|
||||
u32 page = VirtualAddrs::ExecutableStart / pageSize;
|
||||
for (u32 i = 0; i < executablePageCount; i++) {
|
||||
const auto pointer = (uintptr_t)&fcram[i * pageSize];
|
||||
readTable[page] = pointer;
|
||||
writeTable[page++] = pointer;
|
||||
}
|
||||
}
|
||||
|
||||
u8 Memory::read8(u32 vaddr) {
|
||||
Helpers::panic("Unimplemented 8-bit read, addr: %08X", vaddr);
|
||||
}
|
||||
|
||||
u16 Memory::read16(u32 vaddr) {
|
||||
Helpers::panic("Unimplemented 16-bit read, addr: %08X", vaddr);
|
||||
}
|
||||
|
||||
u32 Memory::read32(u32 vaddr) {
|
||||
const u32 page = vaddr >> pageShift;
|
||||
const u32 offset = vaddr & pageMask;
|
||||
|
||||
uintptr_t pointer = readTable[page];
|
||||
if (pointer != 0) [[likely]] {
|
||||
printf("Read %08X from %08X\n", *(u32*)(pointer + offset), vaddr);
|
||||
return *(u32*)(pointer + offset);
|
||||
} else {
|
||||
Helpers::panic("Unimplemented 32-bit read, addr: %08X", vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::write8(u32 vaddr, u8 value) {
|
||||
Helpers::panic("Unimplemented 8-bit write, addr: %08X, val: %02X", vaddr, value);
|
||||
}
|
||||
|
||||
void Memory::write16(u32 vaddr, u16 value) {
|
||||
Helpers::panic("Unimplemented 16-bit write, addr: %08X, val: %04X", vaddr, value);
|
||||
}
|
||||
|
||||
void Memory::write32(u32 vaddr, u32 value) {
|
||||
const u32 page = vaddr >> pageShift;
|
||||
const u32 offset = vaddr & pageMask;
|
||||
|
||||
uintptr_t pointer = writeTable[page];
|
||||
if (pointer != 0) [[likely]] {
|
||||
printf("Wrote %08X to %08X\n", value, vaddr);
|
||||
*(u32*)(pointer + offset) = value;
|
||||
} else {
|
||||
Helpers::panic("Unimplemented 32-bit write, addr: %08X, val: %08X", vaddr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void* Memory::getReadPointer(u32 address) {
|
||||
const auto page = address >> pageShift;
|
||||
const auto offset = address & pageMask;
|
||||
const u32 page = address >> pageShift;
|
||||
const u32 offset = address & pageMask;
|
||||
|
||||
uintptr_t pointer = readTable[page];
|
||||
if (pointer == 0) return nullptr;
|
||||
|
@ -14,8 +69,8 @@ void* Memory::getReadPointer(u32 address) {
|
|||
}
|
||||
|
||||
void* Memory::getWritePointer(u32 address) {
|
||||
const auto page = address >> pageShift;
|
||||
const auto offset = address & pageMask;
|
||||
const u32 page = address >> pageShift;
|
||||
const u32 offset = address & pageMask;
|
||||
|
||||
uintptr_t pointer = writeTable[page];
|
||||
if (pointer == 0) return nullptr;
|
||||
|
|
|
@ -30,10 +30,7 @@ void Emulator::run() {
|
|||
}
|
||||
|
||||
void Emulator::runFrame() {
|
||||
constexpr u32 freq = 268 * 1024 * 1024;
|
||||
for (u32 i = 0; i < freq; i += 2) {
|
||||
step();
|
||||
}
|
||||
cpu.runFrame();
|
||||
}
|
||||
|
||||
bool Emulator::loadELF(std::filesystem::path& path) {
|
||||
|
@ -41,5 +38,6 @@ bool Emulator::loadELF(std::filesystem::path& path) {
|
|||
if (!entrypoint.has_value())
|
||||
return false;
|
||||
|
||||
Helpers::panic("Entrypoint: %08X\n", entrypoint.value());
|
||||
cpu.setReg(15, entrypoint.value()); // Set initial PC
|
||||
return true;
|
||||
}
|
|
@ -8,7 +8,7 @@ int main (int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
auto elfPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "simple_tri.elf");
|
||||
if (emu.loadELF(elfPath)) {
|
||||
if (!emu.loadELF(elfPath)) {
|
||||
Helpers::panic("Failed to load ELF file: %s", elfPath.c_str());
|
||||
}
|
||||
emu.run();
|
||||
|
|
Loading…
Add table
Reference in a new issue