Files
tatu/sim/verilator/memory.cpp
2026-06-26 08:20:25 +00:00

112 lines
3.0 KiB
C++

#include "memory.h"
#include <cstring>
#include <cstdio>
#include <elf.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
Memory::Memory() : base_addr(MEM_BASE), entry_point(MEM_BASE) {
mem.resize(MEM_SIZE, 0);
}
uint64_t Memory::to_offset(uint64_t addr) {
if (addr < base_addr || addr >= base_addr + MEM_SIZE) {
fprintf(stderr, "Memory access out of bounds: 0x%lx\n", addr);
return 0;
}
return addr - base_addr;
}
uint8_t Memory::read8(uint64_t addr) {
return mem[to_offset(addr)];
}
uint16_t Memory::read16(uint64_t addr) {
uint64_t off = to_offset(addr);
return mem[off] | (mem[off + 1] << 8);
}
uint32_t Memory::read32(uint64_t addr) {
uint64_t off = to_offset(addr);
return mem[off] | (mem[off + 1] << 8) | (mem[off + 2] << 16) | (mem[off + 3] << 24);
}
uint64_t Memory::read64(uint64_t addr) {
uint64_t off = to_offset(addr);
uint64_t lo = read32(addr);
uint64_t hi = read32(addr + 4);
return lo | (hi << 32);
}
void Memory::write8(uint64_t addr, uint8_t data) {
mem[to_offset(addr)] = data;
}
void Memory::write16(uint64_t addr, uint16_t data) {
uint64_t off = to_offset(addr);
mem[off] = data & 0xFF;
mem[off + 1] = (data >> 8) & 0xFF;
}
void Memory::write32(uint64_t addr, uint32_t data) {
uint64_t off = to_offset(addr);
mem[off] = data & 0xFF;
mem[off + 1] = (data >> 8) & 0xFF;
mem[off + 2] = (data >> 16) & 0xFF;
mem[off + 3] = (data >> 24) & 0xFF;
}
void Memory::write64(uint64_t addr, uint64_t data) {
write32(addr, data & 0xFFFFFFFF);
write32(addr + 4, (data >> 32) & 0xFFFFFFFF);
}
bool Memory::load_elf(const std::string& filename) {
int fd = open(filename.c_str(), O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open ELF file: %s\n", filename.c_str());
return false;
}
Elf64_Ehdr ehdr;
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
fprintf(stderr, "Failed to read ELF header\n");
close(fd);
return false;
}
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
fprintf(stderr, "Not a valid ELF file\n");
close(fd);
return false;
}
entry_point = ehdr.e_entry;
// Load program headers
for (int i = 0; i < ehdr.e_phnum; i++) {
Elf64_Phdr phdr;
lseek(fd, ehdr.e_phoff + i * sizeof(phdr), SEEK_SET);
if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
fprintf(stderr, "Failed to read program header %d\n", i);
continue;
}
if (phdr.p_type == PT_LOAD) {
uint64_t offset = to_offset(phdr.p_paddr);
lseek(fd, phdr.p_offset, SEEK_SET);
if (read(fd, &mem[offset], phdr.p_filesz) != (ssize_t)phdr.p_filesz) {
fprintf(stderr, "Failed to load segment %d\n", i);
close(fd);
return false;
}
printf("Loaded segment: paddr=0x%lx size=%lu\n", phdr.p_paddr, phdr.p_filesz);
}
}
close(fd);
printf("ELF loaded: entry=0x%lx\n", entry_point);
return true;
}