diff --git a/include/core/memorymanip.hpp b/include/core/memorymanip.hpp index 617db347..003c8d7b 100644 --- a/include/core/memorymanip.hpp +++ b/include/core/memorymanip.hpp @@ -1,50 +1,13 @@ #ifndef _memorymanip__hpp__included__ #define _memorymanip__hpp__included__ +#include "interface/core.hpp" #include #include #include #include #include -/** - * \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 get_regions() throw(std::bad_alloc); +std::vector get_regions() throw(std::bad_alloc); /** * \brief Read byte from memory @@ -72,7 +35,7 @@ std::vector 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 get_candidates() throw(std::bad_alloc); + std::list get_candidates() throw(std::bad_alloc); private: std::vector previous_content; std::vector still_in; - uint32_t candidates; + uint64_t candidates; }; #endif diff --git a/include/interface/core.hpp b/include/interface/core.hpp index bc129b91..02e3b92a 100644 --- a/include/interface/core.hpp +++ b/include/interface/core.hpp @@ -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& content) = 0; virtual void copy_from_core(std::vector& 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 diff --git a/src/core/memorymanip.cpp b/src/core/memorymanip.cpp index c5eefe03..9fbdca10 100644 --- a/src/core/memorymanip.cpp +++ b/src/core/memorymanip.cpp @@ -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 @@ -12,334 +13,174 @@ #include #include #include -/* -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 -#include -#include -#include -#include -#include -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 memory_regions; - uint32_t linear_ram_size = 0; + std::vector 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 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) + template T endian_convert(T x) throw(); + + template<> uint8_t endian_convert(uint8_t x) throw() { - return create_region(name, base, memory.data(), memory.size(), readonly, native_endian); + return x; } - uint16_t native_littleendian_convert(uint16_t x) throw() + template<> uint16_t endian_convert(uint16_t x) throw() { - if(!system_little_endian) - return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); - else - return x; + return (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); } - uint32_t native_littleendian_convert(uint32_t x) throw() + 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; + return (((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | + ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000)); } - 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; + 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)); + } + + template<> int8_t endian_convert(int8_t x) throw() { return endian_convert(static_cast(x)); } + template<> int16_t endian_convert(int16_t x) throw() { return endian_convert(static_cast(x)); } + template<> int32_t endian_convert(int32_t x) throw() { return endian_convert(static_cast(x)); } + template<> int64_t endian_convert(int64_t x) throw() { return endian_convert(static_cast(x)); } + + template 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(&value), sizeof(T)); + if(!laddr.native_endian) + value = endian_convert(value); + return value; + } + + //Byte write to address (false if failed). + template 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(&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(SNES::necdsp.dataRAM), 4096, false, - true); - create_region("DSPPROM", 0xF0000000, reinterpret_cast(SNES::necdsp.programROM), 65536, true, - true); - create_region("DSPDROM", 0xF0010000, reinterpret_cast(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(&x) == 2); + emucore_refresh_cart(); + copy_regions_from_core(); } -std::vector get_regions() throw(std::bad_alloc) +std::vector get_regions() throw(std::bad_alloc) { - std::vector 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 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(laddr.memory[laddr.rel_addr++])); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(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(laddr.memory[laddr.rel_addr++])); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 8); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 16); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(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(laddr.memory[laddr.rel_addr++])); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 8); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 16); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 24); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 32); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 40); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(laddr.memory[laddr.rel_addr++]) << 48); - if(laddr.rel_addr < laddr.memory_size) - value |= (static_cast(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(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(data); - laddr.memory[laddr.rel_addr++] = static_cast(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(data); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 8); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 16); - laddr.memory[laddr.rel_addr++] = static_cast(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(data); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 8); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 16); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 24); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 32); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 40); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 48); - laddr.memory[laddr.rel_addr++] = static_cast(data >> 56); - return true; -} +uint8_t memory_read_byte(uint64_t addr) throw() { return memory_read(addr); } +uint16_t memory_read_word(uint64_t addr) throw() { return memory_read(addr); } +uint32_t memory_read_dword(uint64_t addr) throw() { return memory_read(addr); } +uint64_t memory_read_qword(uint64_t addr) throw() { return memory_read(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(&previous_content[addr]), t.mem_size); + addr += t.mem_size; } candidates = linearram; } @@ -594,20 +435,16 @@ 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(oldv); - v2 = *reinterpret_cast(newv); - } else - for(size_t i = 0; i < sizeof(value_type); i++) { - v1 |= static_cast(oldv[i]) << (8 * i); - v2 |= static_cast(newv[i]) << (8 * i); - } + value_type v1 = *reinterpret_cast(oldv); + value_type v2 = *reinterpret_cast(newv); + if(!nativeendian) { + v1 = endian_convert(v1); + v2 = endian_convert(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 void memorysearch::search(const T& obj) throw() { search_value_helper 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(BUFFER_HIWATER_MARK), t.mem_size - (i - base)) - + bufferfill; + t.vma->copy_from_core(i - base + bufferfill, reinterpret_cast(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(&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()); } 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 memorysearch::get_candidates() throw(std::bad_alloc) +std::list 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 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 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(firstword); + address = parse_value(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 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 + "
\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 diff --git a/src/core/misc.cpp b/src/core/misc.cpp index 124df591..1be96566 100644 --- a/src/core/misc.cpp +++ b/src/core/misc.cpp @@ -141,11 +141,18 @@ struct loaded_rom load_rom_from_commandline(std::vector cmdline) th void dump_region_map() throw(std::bad_alloc) { - std::vector regions = get_regions(); + std::vector 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; } } diff --git a/src/interface/bsnes.cpp b/src/interface/bsnes.cpp index 9fad0613..1d7357f7 100644 --- a/src/interface/bsnes.cpp +++ b/src/interface/bsnes.cpp @@ -1,5 +1,7 @@ #include "core/bsnes.hpp" +#include #include "interface/core.hpp" +#include "library/minmax.hpp" #include /** @@ -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 sram_slots; + std::vector 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 new_sram_slots; + std::vector 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(SNES::necdsp.dataRAM), 0x00023000, 4096, + vma_structure::E_HOST, false)); + new_vma_slots.push_back(new bsnes_vma_slot("DSPPROM", + reinterpret_cast(SNES::necdsp.programROM), 0xF0000000, 65536, + vma_structure::E_HOST, true)); + new_vma_slots.push_back(new bsnes_vma_slot("DSPDROMM", + reinterpret_cast(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; } diff --git a/src/interface/core.cpp b/src/interface/core.cpp new file mode 100644 index 00000000..f014246c --- /dev/null +++ b/src/interface/core.cpp @@ -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() +{ +} diff --git a/src/lua/memory.cpp b/src/lua/memory.cpp index 6406b67f..25984b14 100644 --- a/src/lua/memory.cpp +++ b/src/lua/memory.cpp @@ -4,27 +4,27 @@ namespace { - template + template 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(LS, 1, fname.c_str()); + uint64_t addr = get_numeric_argument(LS, 1, fname.c_str()); lua_pushnumber(LS, static_cast(rfun(addr))); return 1; } }; - template + template 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(LS, 1, fname.c_str()); + uint64_t addr = get_numeric_argument(LS, 1, fname.c_str()); T value = get_numeric_argument(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& regions, size_t idx) + int handle_push_vma(lua_State* LS, std::vector& 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 regions = get_regions(); - uint32_t num = get_numeric_argument(LS, 1, fname.c_str()); + std::vector regions = get_regions(); + size_t num = get_numeric_argument(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 regions = get_regions(); - uint32_t addr = get_numeric_argument(LS, 1, fname.c_str()); + std::vector regions = get_regions(); + uint64_t addr = get_numeric_argument(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); }); diff --git a/src/platform/wxwidgets/memorysearch.cpp b/src/platform/wxwidgets/memorysearch.cpp index de5ca159..eb0ec7c9 100644 --- a/src/platform/wxwidgets/memorysearch.cpp +++ b/src/platform/wxwidgets/memorysearch.cpp @@ -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 addrs = msearch->get_candidates(); + std::list addrs = msearch->get_candidates(); for(auto i : addrs) { std::ostringstream row; row << hexformat_address(i) << " ";