Split VMA handling

Move VMA handling from memorymanip.cpp to bsnes.cpp
This commit is contained in:
Ilari Liusvaara 2012-03-16 12:44:00 +02:00
parent e42ce000cb
commit a59650b11d
8 changed files with 382 additions and 386 deletions

View file

@ -1,50 +1,13 @@
#ifndef _memorymanip__hpp__included__
#define _memorymanip__hpp__included__
#include "interface/core.hpp"
#include <string>
#include <list>
#include <vector>
#include <cstdint>
#include <stdexcept>
/**
* \brief Information about region of memory
*
* This structure contains information about memory region.
*/
struct memory_region
{
/**
* \brief Name of region.
*
* This is name of region, mainly for debugging and showing to the user.
*/
std::string region_name;
/**
* \brief Base address of region.
*/
uint32_t baseaddr;
/**
* \brief Size of region in bytes.
*/
uint32_t size;
/**
* \brief Last valid address in this region.
*/
uint32_t lastaddr;
/**
* \brief True for ROM, false for RAM.
*/
bool readonly;
/**
* \brief Endianess of the region.
*
* If true, region uses host endian.
* If false, region uses SNES (big) endian.
*/
bool native_endian;
};
/**
* \brief Refresh cart memory mappings
*
@ -62,7 +25,7 @@ void refresh_cart_mappings() throw(std::bad_alloc);
* \return All regions
* \throws std::bad_alloc Not enough memory.
*/
std::vector<struct memory_region> get_regions() throw(std::bad_alloc);
std::vector<vma_structure*> get_regions() throw(std::bad_alloc);
/**
* \brief Read byte from memory
@ -72,7 +35,7 @@ std::vector<struct memory_region> get_regions() throw(std::bad_alloc);
* \param addr The address to read.
* \return The byte read.
*/
uint8_t memory_read_byte(uint32_t addr) throw();
uint8_t memory_read_byte(uint64_t addr) throw();
/**
* \brief Read word from memory
@ -82,7 +45,7 @@ uint8_t memory_read_byte(uint32_t addr) throw();
* \param addr The address to read.
* \return The word read.
*/
uint16_t memory_read_word(uint32_t addr) throw();
uint16_t memory_read_word(uint64_t addr) throw();
/**
* \brief Read dword from memory
@ -92,7 +55,7 @@ uint16_t memory_read_word(uint32_t addr) throw();
* \param addr The address to read.
* \return The dword read.
*/
uint32_t memory_read_dword(uint32_t addr) throw();
uint32_t memory_read_dword(uint64_t addr) throw();
/**
* \brief Read qword from memory
@ -102,7 +65,7 @@ uint32_t memory_read_dword(uint32_t addr) throw();
* \param addr The address to read.
* \return The qword read.
*/
uint64_t memory_read_qword(uint32_t addr) throw();
uint64_t memory_read_qword(uint64_t addr) throw();
/**
* \brief Write byte to memory
@ -113,7 +76,7 @@ uint64_t memory_read_qword(uint32_t addr) throw();
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_byte(uint32_t addr, uint8_t data) throw();
bool memory_write_byte(uint64_t addr, uint8_t data) throw();
/**
* \brief Write word to memory
@ -124,7 +87,7 @@ bool memory_write_byte(uint32_t addr, uint8_t data) throw();
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_word(uint32_t addr, uint16_t data) throw();
bool memory_write_word(uint64_t addr, uint16_t data) throw();
/**
* \brief Write dword to memory
@ -135,7 +98,7 @@ bool memory_write_word(uint32_t addr, uint16_t data) throw();
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_dword(uint32_t addr, uint32_t data) throw();
bool memory_write_dword(uint64_t addr, uint32_t data) throw();
/**
* \brief Write qword to memory
@ -146,7 +109,7 @@ bool memory_write_dword(uint32_t addr, uint32_t data) throw();
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_qword(uint32_t addr, uint64_t data) throw();
bool memory_write_qword(uint64_t addr, uint64_t data) throw();
/**
* \brief Memory search context
@ -412,7 +375,7 @@ public:
*
* \return The number of candidates
*/
uint32_t get_candidate_count() throw();
uint64_t get_candidate_count() throw();
/**
* \brief Get List of all candidate addresses
@ -422,11 +385,11 @@ public:
* \return Candidate address list
* \throws std::bad_alloc Not enough memory.
*/
std::list<uint32_t> get_candidates() throw(std::bad_alloc);
std::list<uint64_t> get_candidates() throw(std::bad_alloc);
private:
std::vector<uint8_t> previous_content;
std::vector<uint64_t> still_in;
uint32_t candidates;
uint64_t candidates;
};
#endif

View file

@ -12,14 +12,43 @@ void emucore_basic_init();
struct sram_slot_structure
{
virtual ~sram_slot_structure();
virtual std::string get_name() = 0;
virtual void copy_to_core(const std::vector<char>& content) = 0;
virtual void copy_from_core(std::vector<char>& content) = 0;
virtual size_t get_size() = 0; //0 if variable size.
};
struct vma_structure
{
enum endian
{
E_LITTLE = -1,
E_HOST = 0,
E_BIG = 1
};
vma_structure(const std::string& _name, uint64_t _base, uint64_t _size, endian _rendian, bool _readonly);
virtual ~vma_structure();
std::string get_name() { return name; }
uint64_t get_base() { return base; }
uint64_t get_size() { return size; }
bool is_readonly() { return readonly; }
endian get_endian() { return rendian; }
virtual void copy_from_core(uint64_t start, char* buffer, uint64_t size) = 0;
virtual void copy_to_core(uint64_t start, const char* buffer, uint64_t size) = 0;
protected:
std::string name;
uint64_t base;
uint64_t size;
bool readonly;
endian rendian;
};
size_t emucore_sram_slots();
struct sram_slot_structure* emucore_sram_slot(size_t index);
size_t emucore_vma_slots();
struct vma_structure* emucore_vma_slot(size_t index);
void emucore_refresh_cart();
#endif

View file

@ -5,6 +5,7 @@
#include "core/memorymanip.hpp"
#include "core/misc.hpp"
#include "core/rom.hpp"
#include "interface/core.hpp"
#include "library/string.hpp"
#include <iostream>
@ -12,334 +13,174 @@
#include <sstream>
#include <iomanip>
#include <cstdint>
/*
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
#include <nall/platform.hpp>
#include <nall/endian.hpp>
#include <nall/varint.hpp>
#include <nall/bit.hpp>
#include <nall/serializer.hpp>
#include <nall/property.hpp>
using namespace nall;
using namespace SNES;
*/
namespace
{
struct translated_address
{
uint32_t rel_addr;
uint32_t raw_addr;
uint8_t* memory;
uint32_t memory_size;
bool not_writable;
bool native_endian;
uint64_t rel_addr; //Address relative to start of VMA.
uint64_t raw_addr; //Raw address.
uint64_t mem_size; //Memory size.
vma_structure* vma; //VMA referred to.
bool read_only; //RO flag.
bool native_endian; //Is in native endian.
};
struct region
{
std::string name;
uint32_t base;
uint32_t size;
uint8_t* memory;
bool not_writable;
bool native_endian;
};
std::vector<region> memory_regions;
uint32_t linear_ram_size = 0;
std::vector<vma_structure*> memory_regions;
uint64_t linear_ram_size = 0;
bool system_little_endian = true;
struct translated_address translate_address(uint32_t rawaddr) throw()
struct translated_address translate_address(uint64_t rawaddr) throw()
{
struct translated_address t;
t.rel_addr = 0;
t.raw_addr = 0;
t.memory = NULL;
t.memory_size = 0;
t.not_writable = true;
t.mem_size = 0;
t.vma = NULL;
t.read_only = true;
t.native_endian = true;
for(auto i : memory_regions) {
if(i.base > rawaddr || i.base + i.size <= rawaddr)
if(i->get_base() > rawaddr || i->get_base() + i->get_size() <= rawaddr)
continue;
t.rel_addr = rawaddr - i.base;
t.rel_addr = rawaddr - i->get_base();
t.raw_addr = rawaddr;
t.memory = i.memory;
t.memory_size = i.size;
t.not_writable = i.not_writable;
t.native_endian = i.native_endian;
t.vma = i;
t.mem_size = i->get_size();
t.read_only = i->is_readonly();
t.native_endian = (!system_little_endian && i->get_endian() == vma_structure::E_BIG) ||
(system_little_endian && i->get_endian() == vma_structure::E_LITTLE) ||
i->get_endian() == vma_structure::E_HOST;
break;
}
return t;
}
struct translated_address translate_address_linear_ram(uint32_t ramlinaddr) throw()
struct translated_address translate_address_linear_ram(uint64_t ramlinaddr) throw()
{
struct translated_address t;
t.rel_addr = 0;
t.raw_addr = 0;
t.memory = NULL;
t.memory_size = 0;
t.not_writable = true;
t.mem_size = 0;
t.vma = NULL;
t.read_only = true;
t.native_endian = true;
for(auto i : memory_regions) {
if(i.not_writable)
if(i->is_readonly())
continue;
if(ramlinaddr >= i.size) {
ramlinaddr -= i.size;
if(ramlinaddr >= i->get_size()) {
ramlinaddr -= i->get_size();
continue;
}
t.rel_addr = ramlinaddr;
t.raw_addr = i.base + ramlinaddr;
t.memory = i.memory;
t.memory_size = i.size;
t.not_writable = i.not_writable;
t.native_endian = i.native_endian;
t.raw_addr = i->get_base() + ramlinaddr;
t.vma = i;
t.mem_size = i->get_size();
t.read_only = i->is_readonly();
t.native_endian = (!system_little_endian && i->get_endian() == vma_structure::E_BIG) ||
(system_little_endian && i->get_endian() == vma_structure::E_LITTLE) ||
i->get_endian() == vma_structure::E_HOST;
break;
}
return t;
}
uint32_t get_linear_ram_size() throw()
uint64_t get_linear_ram_size() throw()
{
return linear_ram_size;
}
uint32_t create_region(const std::string& name, uint32_t base, uint8_t* memory, uint32_t size, bool readonly,
bool native_endian = false) throw(std::bad_alloc)
void copy_regions_from_core()
{
if(size == 0)
return base;
struct region r;
r.name = name;
r.base = base;
r.memory = memory;
r.size = size;
r.not_writable = readonly;
r.native_endian = native_endian;
if(!readonly)
linear_ram_size += size;
memory_regions.push_back(r);
return base + size;
uint64_t new_linsize = 0;
std::vector<vma_structure*> new_memory_regions;
for(size_t i = 0; i < emucore_vma_slots(); i++) {
vma_structure* j = emucore_vma_slot(i);
new_memory_regions.push_back(j);
if(!j->is_readonly())
new_linsize += j->get_size();
}
std::swap(memory_regions, new_memory_regions);
linear_ram_size = new_linsize;
}
uint32_t create_region(const std::string& name, uint32_t base, SNES::MappedRAM& memory, bool readonly,
bool native_endian = false) throw(std::bad_alloc)
{
return create_region(name, base, memory.data(), memory.size(), readonly, native_endian);
}
template<typename T> T endian_convert(T x) throw();
uint16_t native_littleendian_convert(uint16_t x) throw()
template<> uint8_t endian_convert(uint8_t x) throw()
{
if(!system_little_endian)
return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
else
return x;
}
uint32_t native_littleendian_convert(uint32_t x) throw()
template<> uint16_t endian_convert(uint16_t x) throw()
{
return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00));
}
template<> uint32_t endian_convert(uint32_t x) throw()
{
if(!system_little_endian)
return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) |
((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000));
else
return x;
}
uint64_t native_littleendian_convert(uint64_t x) throw()
template<> uint64_t endian_convert(uint64_t x) throw()
{
if(!system_little_endian)
return (((x >> 56) & 0xFF) | ((x >> 40) & 0xFF00) |
((x >> 24) & 0xFF0000) | ((x >> 8) & 0xFF000000) |
((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) |
((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL));
else
return x;
}
template<> int8_t endian_convert(int8_t x) throw() { return endian_convert(static_cast<uint8_t>(x)); }
template<> int16_t endian_convert(int16_t x) throw() { return endian_convert(static_cast<uint16_t>(x)); }
template<> int32_t endian_convert(int32_t x) throw() { return endian_convert(static_cast<uint32_t>(x)); }
template<> int64_t endian_convert(int64_t x) throw() { return endian_convert(static_cast<uint64_t>(x)); }
template<typename T> T memory_read(uint64_t addr) throw()
{
struct translated_address laddr = translate_address(addr);
T value = 0;
laddr.vma->copy_from_core(laddr.rel_addr, reinterpret_cast<char*>(&value), sizeof(T));
if(!laddr.native_endian)
value = endian_convert(value);
return value;
}
//Byte write to address (false if failed).
template<typename T> bool memory_write(uint64_t addr, T data) throw()
{
struct translated_address laddr = translate_address(addr);
if(laddr.rel_addr > laddr.mem_size - sizeof(T) || laddr.read_only)
return false;
if(!laddr.native_endian)
data = endian_convert(data);
laddr.vma->copy_to_core(laddr.rel_addr, reinterpret_cast<char*>(&data), sizeof(T));
return true;
}
}
void refresh_cart_mappings() throw(std::bad_alloc)
{
linear_ram_size = 0;
memory_regions.clear();
if(get_current_rom_info().first == ROMTYPE_NONE)
return;
create_region("WRAM", 0x007E0000, SNES::cpu.wram, 131072, false);
create_region("APURAM", 0x00000000, SNES::smp.apuram, 65536, false);
create_region("VRAM", 0x00010000, SNES::ppu.vram, 65536, false);
create_region("OAM", 0x00020000, SNES::ppu.oam, 544, false);
create_region("CGRAM", 0x00021000, SNES::ppu.cgram, 512, false);
if(SNES::cartridge.has_srtc()) create_region("RTC", 0x00022000, SNES::srtc.rtc, 20, false);
if(SNES::cartridge.has_spc7110rtc()) create_region("RTC", 0x00022000, SNES::spc7110.rtc, 20, false);
if(SNES::cartridge.has_necdsp()) {
create_region("DSPRAM", 0x00023000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM), 4096, false,
true);
create_region("DSPPROM", 0xF0000000, reinterpret_cast<uint8_t*>(SNES::necdsp.programROM), 65536, true,
true);
create_region("DSPDROM", 0xF0010000, reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM), 4096, true,
true);
}
create_region("SRAM", 0x10000000, SNES::cartridge.ram, false);
create_region("ROM", 0x80000000, SNES::cartridge.rom, true);
switch(get_current_rom_info().first) {
case ROMTYPE_BSX:
case ROMTYPE_BSXSLOTTED:
create_region("BSXFLASH", 0x90000000, SNES::bsxflash.memory, true);
create_region("BSX_RAM", 0x20000000, SNES::bsxcartridge.sram, false);
create_region("BSX_PRAM", 0x30000000, SNES::bsxcartridge.psram, false);
break;
case ROMTYPE_SUFAMITURBO:
create_region("SLOTA_ROM", 0x90000000, SNES::sufamiturbo.slotA.rom, true);
create_region("SLOTB_ROM", 0xA0000000, SNES::sufamiturbo.slotB.rom, true);
create_region("SLOTA_RAM", 0x20000000, SNES::sufamiturbo.slotA.ram, false);
create_region("SLOTB_RAM", 0x30000000, SNES::sufamiturbo.slotB.ram, false);
break;
case ROMTYPE_SGB:
create_region("GBROM", 0x90000000, GameBoy::cartridge.romdata, GameBoy::cartridge.romsize, true);
create_region("GBRAM", 0x20000000, GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize, false);
break;
case ROMTYPE_SNES:
case ROMTYPE_NONE:
break;
};
uint16_t x = 258;
system_little_endian = (*reinterpret_cast<char*>(&x) == 2);
emucore_refresh_cart();
copy_regions_from_core();
}
std::vector<struct memory_region> get_regions() throw(std::bad_alloc)
std::vector<vma_structure*> get_regions() throw(std::bad_alloc)
{
std::vector<struct memory_region> out;
for(auto i : memory_regions) {
struct memory_region r;
r.region_name = i.name;
r.baseaddr = i.base;
r.size = i.size;
r.lastaddr = i.base + i.size - 1;
r.readonly = i.not_writable;
r.native_endian = i.native_endian;
out.push_back(r);
}
std::vector<vma_structure*> out;
for(auto i : memory_regions)
out.push_back(i);
return out;
}
uint8_t memory_read_byte(uint32_t addr) throw()
{
struct translated_address laddr = translate_address(addr);
uint8_t value = 0;
if(laddr.rel_addr < laddr.memory_size)
value |= laddr.memory[laddr.rel_addr++];
return value;
}
uint16_t memory_read_word(uint32_t addr) throw()
{
struct translated_address laddr = translate_address(addr);
uint16_t value = 0;
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]));
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint16_t>(laddr.memory[laddr.rel_addr++]) << 8);
if(laddr.native_endian)
value = native_littleendian_convert(value);
return value;
}
uint32_t memory_read_dword(uint32_t addr) throw()
{
struct translated_address laddr = translate_address(addr);
uint32_t value = 0;
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]));
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 8);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 16);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint32_t>(laddr.memory[laddr.rel_addr++]) << 24);
if(laddr.native_endian)
value = native_littleendian_convert(value);
return value;
}
uint64_t memory_read_qword(uint32_t addr) throw()
{
struct translated_address laddr = translate_address(addr);
uint64_t value = 0;
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]));
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 8);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 16);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 24);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 32);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 40);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 48);
if(laddr.rel_addr < laddr.memory_size)
value |= (static_cast<uint64_t>(laddr.memory[laddr.rel_addr++]) << 56);
if(laddr.native_endian)
value = native_littleendian_convert(value);
return value;
}
//Byte write to address (false if failed).
bool memory_write_byte(uint32_t addr, uint8_t data) throw()
{
struct translated_address laddr = translate_address(addr);
if(laddr.rel_addr >= laddr.memory_size || laddr.not_writable)
return false;
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
return true;
}
bool memory_write_word(uint32_t addr, uint16_t data) throw()
{
struct translated_address laddr = translate_address(addr);
if(laddr.native_endian)
data = native_littleendian_convert(data);
if(laddr.rel_addr >= laddr.memory_size - 1 || laddr.not_writable)
return false;
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
return true;
}
bool memory_write_dword(uint32_t addr, uint32_t data) throw()
{
struct translated_address laddr = translate_address(addr);
if(laddr.native_endian)
data = native_littleendian_convert(data);
if(laddr.rel_addr >= laddr.memory_size - 3 || laddr.not_writable)
return false;
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
return true;
}
bool memory_write_qword(uint32_t addr, uint64_t data) throw()
{
struct translated_address laddr = translate_address(addr);
if(laddr.native_endian)
data = native_littleendian_convert(data);
if(laddr.rel_addr >= laddr.memory_size - 7 || laddr.not_writable)
return false;
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 8);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 16);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 24);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 32);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 40);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 48);
laddr.memory[laddr.rel_addr++] = static_cast<uint8_t>(data >> 56);
return true;
}
uint8_t memory_read_byte(uint64_t addr) throw() { return memory_read<uint8_t>(addr); }
uint16_t memory_read_word(uint64_t addr) throw() { return memory_read<uint16_t>(addr); }
uint32_t memory_read_dword(uint64_t addr) throw() { return memory_read<uint32_t>(addr); }
uint64_t memory_read_qword(uint64_t addr) throw() { return memory_read<uint64_t>(addr); }
bool memory_write_byte(uint64_t addr, uint8_t data) throw() { return memory_write(addr, data); }
bool memory_write_word(uint64_t addr, uint16_t data) throw() { return memory_write(addr, data); }
bool memory_write_dword(uint64_t addr, uint32_t data) throw() { return memory_write(addr, data); }
bool memory_write_qword(uint64_t addr, uint64_t data) throw() { return memory_write(addr, data); }
memorysearch::memorysearch() throw(std::bad_alloc)
{
@ -348,18 +189,18 @@ memorysearch::memorysearch() throw(std::bad_alloc)
void memorysearch::reset() throw(std::bad_alloc)
{
uint32_t linearram = get_linear_ram_size();
uint64_t linearram = get_linear_ram_size();
previous_content.resize(linearram);
still_in.resize((linearram + 63) / 64);
for(uint32_t i = 0; i < linearram / 64; i++)
for(uint64_t i = 0; i < linearram / 64; i++)
still_in[i] = 0xFFFFFFFFFFFFFFFFULL;
if(linearram % 64)
still_in[linearram / 64] = (1ULL << (linearram % 64)) - 1;
uint32_t addr = 0;
uint64_t addr = 0;
while(addr < linearram) {
struct translated_address t = translate_address_linear_ram(addr);
memcpy(&previous_content[addr], t.memory, t.memory_size);
addr += t.memory_size;
t.vma->copy_from_core(0, reinterpret_cast<char*>(&previous_content[addr]), t.mem_size);
addr += t.mem_size;
}
candidates = linearram;
}
@ -594,19 +435,15 @@ struct search_value_helper
*
* This function is search()-compatible condition function calling the underlying condition.
*/
bool operator()(const uint8_t* newv, const uint8_t* oldv, uint32_t left, bool nativeendian) const throw()
bool operator()(const uint8_t* newv, const uint8_t* oldv, uint64_t left, bool nativeendian) const throw()
{
if(left < sizeof(value_type))
return false;
value_type v1 = 0;
value_type v2 = 0;
if(nativeendian) {
v1 = *reinterpret_cast<const value_type*>(oldv);
v2 = *reinterpret_cast<const value_type*>(newv);
} else
for(size_t i = 0; i < sizeof(value_type); i++) {
v1 |= static_cast<value_type>(oldv[i]) << (8 * i);
v2 |= static_cast<value_type>(newv[i]) << (8 * i);
value_type v1 = *reinterpret_cast<const value_type*>(oldv);
value_type v2 = *reinterpret_cast<const value_type*>(newv);
if(!nativeendian) {
v1 = endian_convert<value_type>(v1);
v2 = endian_convert<value_type>(v2);
}
return val(v1, v2);
}
@ -617,42 +454,70 @@ struct search_value_helper
const T& val;
};
#define BUFFER_LOWATER_MARK 16
#define BUFFER_HIWATER_MARK 4096
template<class T> void memorysearch::search(const T& obj) throw()
{
search_value_helper<T> helper(obj);
struct translated_address t = translate_address_linear_ram(0);
uint32_t switch_at = t.memory_size;
uint32_t base = 0;
uint32_t size = previous_content.size();
for(uint32_t i = 0; i < size; i++) {
uint64_t switch_at = t.mem_size;
uint64_t base = 0;
uint64_t size = previous_content.size();
uint8_t buffer[BUFFER_HIWATER_MARK];
size_t bufferfill = 0;
size_t bufferused = 0;
for(uint64_t i = 0; i < size; i++) {
if(still_in[i / 64] == 0) {
uint64_t old_i = i;
i = (i + 64) >> 6 << 6;
size_t delta_i = i - old_i;
bufferused += delta_i;
if(bufferused > bufferfill)
bufferused = bufferfill = 0;
i--;
continue;
}
//t.memory_size == 0 can happen if cart changes.
while(i >= switch_at && t.memory_size > 0) {
//t.mem_size == 0 can happen if cart changes.
while(i >= switch_at && t.mem_size > 0) {
t = translate_address_linear_ram(switch_at);
base = switch_at;
switch_at += t.memory_size;
switch_at += t.mem_size;
bufferfill = 0;
bufferused = 0;
}
if(t.memory_size == 0 || !helper(t.memory + i - base, &previous_content[i],
t.memory_size - (i - base), t.native_endian)) {
if(bufferfill - bufferused < BUFFER_LOWATER_MARK && i - bufferused + bufferfill < switch_at) {
//Right now the buffer covers the region from [i - bufferused, i - bufferused + bufferfill).
if(bufferused < bufferfill)
memmove(buffer, buffer + bufferused, bufferfill - bufferused);
bufferfill -= bufferused;
bufferused = 0;
//Right now the buffer covers the region from [i, i + bufferfill).
size_t csize = min(static_cast<uint64_t>(BUFFER_HIWATER_MARK), t.mem_size - (i - base)) -
bufferfill;
t.vma->copy_from_core(i - base + bufferfill, reinterpret_cast<char*>(buffer + bufferfill),
csize);
bufferfill += csize;
}
if(t.mem_size == 0 || !helper(buffer + bufferused, &previous_content[i], t.mem_size - (i - base),
t.native_endian)) {
if((still_in[i / 64] >> (i % 64)) & 1) {
still_in[i / 64] &= ~(1ULL << (i % 64));
candidates--;
}
}
if(t.mem_size > 0)
bufferused++;
}
t = translate_address_linear_ram(0);
base = 0;
size = previous_content.size();
while(base < size) {
size_t m = t.memory_size;
size_t m = t.mem_size;
if(m > (size - base))
m = size - base;
memcpy(&previous_content[base], t.memory, m);
base += t.memory_size;
t.vma->copy_from_core(0, reinterpret_cast<char*>(&previous_content[base]), m);
base += t.mem_size;
t = translate_address_linear_ram(base);
}
}
@ -715,36 +580,35 @@ void memorysearch::qword_ugt() throw() { search(search_gt<uint64_t>()); }
void memorysearch::update() throw() { search(search_update()); }
uint32_t memorysearch::get_candidate_count() throw()
uint64_t memorysearch::get_candidate_count() throw()
{
return candidates;
}
std::list<uint32_t> memorysearch::get_candidates() throw(std::bad_alloc)
std::list<uint64_t> memorysearch::get_candidates() throw(std::bad_alloc)
{
struct translated_address t = translate_address_linear_ram(0);
uint32_t switch_at = t.memory_size;
uint32_t base = 0;
uint32_t rbase = t.raw_addr;
uint32_t size = previous_content.size();
std::list<uint32_t> out;
uint64_t switch_at = t.mem_size;
uint64_t base = 0;
uint64_t rbase = t.raw_addr;
uint64_t size = previous_content.size();
std::list<uint64_t> out;
for(uint32_t i = 0; i < size; i++) {
for(uint64_t i = 0; i < size; i++) {
if(still_in[i / 64] == 0) {
i = (i + 64) >> 6 << 6;
i--;
continue;
}
while(i >= switch_at && t.memory_size > 0) {
while(i >= switch_at && t.mem_size > 0) {
t = translate_address_linear_ram(switch_at);
base = switch_at;
rbase = t.raw_addr - t.rel_addr;
switch_at += t.memory_size;
switch_at += t.mem_size;
}
if((still_in[i / 64] >> (i % 64)) & 1)
out.push_back(i - base + rbase);
}
std::cout << "out=" << out.size() << " candidates=" << candidates << std::endl;
return out;
}
@ -799,13 +663,13 @@ namespace
has_value = (secondword != "");
try {
if(t = regex("0x(.+)", firstword)) {
if(t[1].length() > 8)
if(t[1].length() > 16)
throw 42;
address = 0;
for(unsigned i = 0; i < t[1].length(); i++)
address = 16 * address + hex(t[1][i]);
} else {
address = parse_value<uint32_t>(firstword);
address = parse_value<uint64_t>(firstword);
}
address_bad = false;
} catch(...) {
@ -830,7 +694,7 @@ namespace
virtual void invoke2() throw(std::bad_alloc, std::runtime_error) = 0;
std::string firstword;
std::string secondword;
uint32_t address;
uint64_t address;
uint64_t value;
bool has_tail;
bool address_bad;
@ -843,7 +707,7 @@ namespace
class read_command : public memorymanip_command
{
public:
read_command(const std::string& cmd, ret (*_rfn)(uint32_t addr)) throw(std::bad_alloc)
read_command(const std::string& cmd, ret (*_rfn)(uint64_t addr)) throw(std::bad_alloc)
: memorymanip_command(cmd)
{
rfn = _rfn;
@ -867,14 +731,14 @@ namespace
"Reads data from memory.\n";
}
ret (*rfn)(uint32_t addr);
ret (*rfn)(uint64_t addr);
};
template<typename arg, int64_t low, uint64_t high>
class write_command : public memorymanip_command
{
public:
write_command(const std::string& cmd, bool (*_wfn)(uint32_t addr, arg a)) throw(std::bad_alloc)
write_command(const std::string& cmd, bool (*_wfn)(uint64_t addr, arg a)) throw(std::bad_alloc)
: memorymanip_command(cmd)
{
wfn = _wfn;
@ -895,7 +759,7 @@ namespace
return "Syntax: " + _command + " <address> <value>\n"
"Writes data to memory.\n";
}
bool (*wfn)(uint32_t addr, arg a);
bool (*wfn)(uint64_t addr, arg a);
};
class memorysearch_command : public memorymanip_command
@ -1026,7 +890,7 @@ namespace
auto c = isrch->get_candidates();
for(auto ci : c) {
std::ostringstream x;
x << "0x" << std::hex << std::setw(8) << std::setfill('0') << ci;
x << "0x" << std::hex << std::setw(16) << std::setfill('0') << ci;
messages << x.str() << std::endl;
}
} else

View file

@ -141,11 +141,18 @@ struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) th
void dump_region_map() throw(std::bad_alloc)
{
std::vector<struct memory_region> regions = get_regions();
std::vector<vma_structure*> regions = get_regions();
for(auto i : regions) {
char buf[256];
sprintf(buf, "Region: %08X-%08X %08X %s%c %s", i.baseaddr, i.lastaddr, i.size,
i.readonly ? "R-" : "RW", i.native_endian ? 'N' : 'L', i.region_name.c_str());
char echar;
if(i->get_endian() == vma_structure::E_LITTLE)
echar = 'L';
if(i->get_endian() == vma_structure::E_BIG)
echar = 'B';
if(i->get_endian() == vma_structure::E_HOST)
echar = 'N';
sprintf(buf, "Region: %016X-%016X %016X %s%c %s", i->get_base(), i->get_base() + i->get_size() - 1,
i->get_size(), i->is_readonly() ? "R-" : "RW", echar, i->get_name().c_str());
messages << buf << std::endl;
}
}

View file

@ -1,5 +1,7 @@
#include "core/bsnes.hpp"
#include <gameboy/gameboy.hpp>
#include "interface/core.hpp"
#include "library/minmax.hpp"
#include <sstream>
/**
@ -114,7 +116,42 @@ namespace
}
};
struct bsnes_vma_slot : public vma_structure
{
bsnes_vma_slot(const std::string& _name, unsigned char* _memory, uint64_t _base, uint64_t _size,
endian _rendian, bool _readonly)
: vma_structure(_name, _base, _size, _rendian, _readonly)
{
memory = _memory;
}
void copy_from_core(uint64_t start, char* buffer, uint64_t _size)
{
uint64_t inrange = _size;
if(start >= size)
inrange = 0;
inrange = min(inrange, size - start);
if(inrange)
memcpy(buffer, memory + start, inrange);
if(inrange < _size)
memset(buffer + inrange, 0, _size - inrange);
}
void copy_to_core(uint64_t start, const char* buffer, uint64_t _size)
{
uint64_t inrange = _size;
if(start >= size)
inrange = 0;
inrange = min(inrange, size - start);
if(inrange && !readonly)
memcpy(memory + start, buffer, inrange);
}
private:
unsigned char* memory;
};
std::vector<bsnes_sram_slot*> sram_slots;
std::vector<bsnes_vma_slot*> vma_slots;
}
size_t emucore_sram_slots()
@ -129,9 +166,22 @@ struct sram_slot_structure* emucore_sram_slot(size_t index)
return sram_slots[index];
}
size_t emucore_vma_slots()
{
return vma_slots.size();
}
struct vma_structure* emucore_vma_slot(size_t index)
{
if(index >= vma_slots.size())
return NULL;
return vma_slots[index];
}
void emucore_refresh_cart()
{
std::vector<bsnes_sram_slot*> new_sram_slots;
std::vector<bsnes_vma_slot*> new_vma_slots;
size_t slots = SNES::cartridge.nvram.size();
new_sram_slots.resize(slots);
for(size_t i = 0; i < slots; i++)
@ -142,13 +192,78 @@ void emucore_refresh_cart()
SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
new_sram_slots[i] = new bsnes_sram_slot(s.id, s.slot, s.data, s.size);
}
new_vma_slots.push_back(new bsnes_vma_slot("WRAM", SNES::cpu.wram, 0x007E0000, 131072,
vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("APURAM", SNES::smp.apuram, 0x00000000, 65536,
vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("VRAM", SNES::ppu.vram, 0x00010000, 65536,
vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("OAM", SNES::ppu.oam, 0x00020000, 544,
vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("CGRAM", SNES::ppu.cgram, 0x00021000, 512,
vma_structure::E_LITTLE, false));
if(SNES::cartridge.ram.size() > 0)
new_vma_slots.push_back(new bsnes_vma_slot("SRAM", SNES::cartridge.ram.data(), 0x10000000,
SNES::cartridge.ram.size(), vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("ROM", SNES::cartridge.rom.data(), 0x80000000,
SNES::cartridge.rom.size(), vma_structure::E_LITTLE, true));
if(SNES::cartridge.has_srtc())
new_vma_slots.push_back(new bsnes_vma_slot("RTC", SNES::srtc.rtc, 0x00022000, 20,
vma_structure::E_LITTLE, false));
if(SNES::cartridge.has_spc7110rtc())
new_vma_slots.push_back(new bsnes_vma_slot("RTC", SNES::spc7110.rtc, 0x00022000, 20,
vma_structure::E_LITTLE, false));
if(SNES::cartridge.has_necdsp()) {
new_vma_slots.push_back(new bsnes_vma_slot("DSPRAM",
reinterpret_cast<uint8_t*>(SNES::necdsp.dataRAM), 0x00023000, 4096,
vma_structure::E_HOST, false));
new_vma_slots.push_back(new bsnes_vma_slot("DSPPROM",
reinterpret_cast<uint8_t*>(SNES::necdsp.programROM), 0xF0000000, 65536,
vma_structure::E_HOST, true));
new_vma_slots.push_back(new bsnes_vma_slot("DSPDROMM",
reinterpret_cast<uint8_t*>(SNES::necdsp.dataROM), 0xF0010000, 4096,
vma_structure::E_HOST, true));
}
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::Bsx ||
SNES::cartridge.mode() == SNES::Cartridge::Mode::BsxSlotted) {
new_vma_slots.push_back(new bsnes_vma_slot("BSXFLASH",
SNES::bsxflash.memory.data(), 0x90000000, SNES::bsxflash.memory.size(),
vma_structure::E_LITTLE, true));
new_vma_slots.push_back(new bsnes_vma_slot("BSX_RAM",
SNES::bsxcartridge.sram.data(), 0x20000000, SNES::bsxcartridge.sram.size(),
vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("BSX_PRAM",
SNES::bsxcartridge.psram.data(), 0x30000000, SNES::bsxcartridge.psram.size(),
vma_structure::E_LITTLE, false));
}
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SufamiTurbo) {
new_vma_slots.push_back(new bsnes_vma_slot("SLOTA_ROM", SNES::sufamiturbo.slotA.rom.data(),
0x90000000, SNES::sufamiturbo.slotA.rom.size(), vma_structure::E_LITTLE, true));
new_vma_slots.push_back(new bsnes_vma_slot("SLOTB_ROM", SNES::sufamiturbo.slotB.rom.data(),
0xA0000000, SNES::sufamiturbo.slotB.rom.size(), vma_structure::E_LITTLE, true));
new_vma_slots.push_back(new bsnes_vma_slot("SLOTA_RAM", SNES::sufamiturbo.slotA.ram.data(),
0x20000000, SNES::sufamiturbo.slotA.ram.size(), vma_structure::E_LITTLE, false));
new_vma_slots.push_back(new bsnes_vma_slot("SLOTB_RAM", SNES::sufamiturbo.slotB.ram.data(),
0x30000000, SNES::sufamiturbo.slotB.ram.size(), vma_structure::E_LITTLE, false));
}
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
new_vma_slots.push_back(new bsnes_vma_slot("GBROM", GameBoy::cartridge.romdata,
0x90000000, GameBoy::cartridge.romsize, vma_structure::E_LITTLE, true));
new_vma_slots.push_back(new bsnes_vma_slot("GBRAM", GameBoy::cartridge.ramdata,
0x20000000, GameBoy::cartridge.ramsize, vma_structure::E_LITTLE, false));
}
} catch(...) {
for(auto i : new_sram_slots)
delete i;
for(auto i : new_vma_slots)
delete i;
throw;
}
std::swap(sram_slots, new_sram_slots);
std::swap(vma_slots, new_vma_slots);
for(auto i : new_sram_slots)
delete i;
for(auto i : new_vma_slots)
delete i;
}

18
src/interface/core.cpp Normal file
View file

@ -0,0 +1,18 @@
#include "interface/core.hpp"
sram_slot_structure::~sram_slot_structure()
{
}
vma_structure::vma_structure(const std::string& _name, uint64_t _base, uint64_t _size, endian _rendian, bool _readonly)
{
name = _name;
base = _base;
size = _size;
rendian = _rendian;
readonly = _readonly;
}
vma_structure::~vma_structure()
{
}

View file

@ -4,27 +4,27 @@
namespace
{
template<typename T, typename U, U (*rfun)(uint32_t addr)>
template<typename T, typename U, U (*rfun)(uint64_t addr)>
class lua_read_memory : public lua_function
{
public:
lua_read_memory(const std::string& name) : lua_function(name) {}
int invoke(lua_State* LS)
{
uint32_t addr = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
uint64_t addr = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
lua_pushnumber(LS, static_cast<T>(rfun(addr)));
return 1;
}
};
template<typename T, bool (*wfun)(uint32_t addr, T value)>
template<typename T, bool (*wfun)(uint64_t addr, T value)>
class lua_write_memory : public lua_function
{
public:
lua_write_memory(const std::string& name) : lua_function(name) {}
int invoke(lua_State* LS)
{
uint32_t addr = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
uint64_t addr = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
T value = get_numeric_argument<T>(LS, 2, fname.c_str());
wfun(addr, value);
return 0;
@ -36,47 +36,47 @@ namespace
return 1;
});
int handle_push_vma(lua_State* LS, std::vector<memory_region>& regions, size_t idx)
int handle_push_vma(lua_State* LS, std::vector<vma_structure*>& regions, size_t idx)
{
if(idx >= regions.size()) {
lua_pushnil(LS);
return 1;
}
memory_region& r = regions[idx];
vma_structure* r = regions[idx];
lua_newtable(LS);
lua_pushstring(LS, "region_name");
lua_pushlstring(LS, r.region_name.c_str(), r.region_name.size());
lua_pushlstring(LS, r->get_name().c_str(), r->get_name().size());
lua_settable(LS, -3);
lua_pushstring(LS, "baseaddr");
lua_pushnumber(LS, r.baseaddr);
lua_pushnumber(LS, r->get_base());
lua_settable(LS, -3);
lua_pushstring(LS, "size");
lua_pushnumber(LS, r.size);
lua_pushnumber(LS, r->get_size());
lua_settable(LS, -3);
lua_pushstring(LS, "lastaddr");
lua_pushnumber(LS, r.lastaddr);
lua_pushnumber(LS, r->get_base() + r->get_size() - 1);
lua_settable(LS, -3);
lua_pushstring(LS, "readonly");
lua_pushboolean(LS, r.readonly);
lua_pushboolean(LS, r->is_readonly());
lua_settable(LS, -3);
lua_pushstring(LS, "native_endian");
lua_pushboolean(LS, r.native_endian);
lua_pushstring(LS, "endian");
lua_pushinteger(LS, r->get_endian());
lua_settable(LS, -3);
return 1;
}
function_ptr_luafun readvma("memory.read_vma", [](lua_State* LS, const std::string& fname) -> int {
std::vector<memory_region> regions = get_regions();
uint32_t num = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
std::vector<vma_structure*> regions = get_regions();
size_t num = get_numeric_argument<size_t>(LS, 1, fname.c_str());
return handle_push_vma(LS, regions, num);
});
function_ptr_luafun findvma("memory.find_vma", [](lua_State* LS, const std::string& fname) -> int {
std::vector<memory_region> regions = get_regions();
uint32_t addr = get_numeric_argument<uint32_t>(LS, 1, fname.c_str());
std::vector<vma_structure*> regions = get_regions();
uint64_t addr = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
size_t i;
for(i = 0; i < regions.size(); i++)
if(addr >= regions[i].baseaddr && addr <= regions[i].lastaddr)
if(addr >= regions[i]->get_base() && addr < regions[i]->get_base() + regions[i]->get_size())
break;
return handle_push_vma(LS, regions, i);
});

View file

@ -70,10 +70,10 @@ namespace
&memorysearch::qword_une, &memorysearch::qword_uge, &memorysearch::qword_ugt, &memorysearch::update }
};
std::string hexformat_address(uint32_t addr)
std::string hexformat_address(uint64_t addr)
{
std::ostringstream x;
x << std::setfill('0') << std::setw(8) << std::hex << addr;
x << std::setfill('0') << std::setw(16) << std::hex << addr;
return x.str();
}
@ -246,7 +246,7 @@ void wxwindow_memorysearch::update()
runemufn([msearch, &ret, &addr_count, typecode, hexmode]() {
addr_count = msearch->get_candidate_count();
if(addr_count <= CANDIDATE_LIMIT) {
std::list<uint32_t> addrs = msearch->get_candidates();
std::list<uint64_t> addrs = msearch->get_candidates();
for(auto i : addrs) {
std::ostringstream row;
row << hexformat_address(i) << " ";