overhaul memory, manage open bus, pal timing, v_pos, h_pos, cartridges, dma channels
This commit is contained in:
@@ -14,6 +14,215 @@ namespace app {
|
||||
namespace emu {
|
||||
namespace memory {
|
||||
|
||||
void MemoryImpl::Initialize(const std::vector<uint8_t>& romData, bool verbose) {
|
||||
verbose_ = verbose;
|
||||
|
||||
auto location = 0x7FC0; // GetHeaderOffset();
|
||||
romSize = 0x400 << romData[location + 0x17];
|
||||
sramSize = 0x400 << romData[location + 0x18];
|
||||
rom_.resize(romSize);
|
||||
|
||||
// Copy memory into rom_
|
||||
std::copy(romData.begin() + kROMStart, romData.begin() + kROMStart + kROMSize,
|
||||
rom_.begin());
|
||||
|
||||
memory_.resize(0x1000000); // 16 MB
|
||||
|
||||
const size_t ROM_CHUNK_SIZE = 0x8000; // 32 KB
|
||||
|
||||
// Clear memory
|
||||
std::fill(memory_.begin(), memory_.end(), 0);
|
||||
|
||||
// Load ROM data into memory based on LoROM mapping
|
||||
size_t romSize = romData.size();
|
||||
size_t romAddress = 0;
|
||||
for (size_t bank = 0x00; bank <= 0x3F; ++bank) {
|
||||
for (size_t offset = 0x8000; offset <= 0xFFFF; offset += ROM_CHUNK_SIZE) {
|
||||
if (romAddress < romSize) {
|
||||
std::copy(romData.begin() + romAddress,
|
||||
romData.begin() + romAddress + ROM_CHUNK_SIZE,
|
||||
memory_.begin() + (bank << 16) + offset);
|
||||
romAddress += ROM_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy data into rom_ vector
|
||||
rom_.resize(kROMSize);
|
||||
std::copy(memory_.begin() + kROMStart, memory_.begin() + kROMStart + kROMSize,
|
||||
rom_.begin());
|
||||
|
||||
// Copy data into ram_ vector
|
||||
ram_.resize(kRAMSize);
|
||||
std::copy(memory_.begin() + kRAMStart, memory_.begin() + kRAMStart + kRAMSize,
|
||||
ram_.begin());
|
||||
}
|
||||
|
||||
memory::RomInfo MemoryImpl::ReadRomHeader() {
|
||||
memory::RomInfo romInfo;
|
||||
|
||||
uint32_t offset = GetHeaderOffset();
|
||||
|
||||
// Read cartridge title
|
||||
char title[22];
|
||||
for (int i = 0; i < 21; ++i) {
|
||||
title[i] = ReadByte(offset + i);
|
||||
}
|
||||
title[21] = '\0'; // Null-terminate the string
|
||||
romInfo.title = std::string(title);
|
||||
|
||||
// Read ROM speed and memory map mode
|
||||
uint8_t romSpeedAndMapMode = ReadByte(offset + 0x15);
|
||||
romInfo.romSpeed = (memory::RomSpeed)(romSpeedAndMapMode & 0x07);
|
||||
romInfo.bankSize = (memory::BankSize)((romSpeedAndMapMode >> 5) & 0x01);
|
||||
|
||||
// Read ROM type
|
||||
romInfo.romType = (memory::RomType)ReadByte(offset + 0x16);
|
||||
|
||||
// Read ROM size
|
||||
romInfo.romSize = (memory::RomSize)ReadByte(offset + 0x17);
|
||||
|
||||
// Read RAM size
|
||||
romInfo.sramSize = (memory::SramSize)ReadByte(offset + 0x18);
|
||||
|
||||
// Read country code
|
||||
romInfo.countryCode = (memory::CountryCode)ReadByte(offset + 0x19);
|
||||
|
||||
// Read license
|
||||
romInfo.license = (memory::License)ReadByte(offset + 0x1A);
|
||||
|
||||
// Read ROM version
|
||||
romInfo.version = ReadByte(offset + 0x1B);
|
||||
|
||||
// Read checksum complement
|
||||
romInfo.checksumComplement = ReadWord(offset + 0x1E);
|
||||
|
||||
// Read checksum
|
||||
romInfo.checksum = ReadWord(offset + 0x1C);
|
||||
|
||||
// Read NMI VBL vector
|
||||
romInfo.nmiVblVector = ReadWord(offset + 0x3E);
|
||||
|
||||
// Read reset vector
|
||||
romInfo.resetVector = ReadWord(offset + 0x3C);
|
||||
|
||||
return romInfo;
|
||||
}
|
||||
|
||||
uint8_t MemoryImpl::cart_read(uint8_t bank, uint16_t adr) {
|
||||
switch (type_) {
|
||||
case 0:
|
||||
return open_bus_;
|
||||
case 1:
|
||||
return cart_readLorom(bank, adr);
|
||||
case 2:
|
||||
return cart_readHirom(bank, adr);
|
||||
case 3:
|
||||
return cart_readExHirom(bank, adr);
|
||||
}
|
||||
return open_bus_;
|
||||
}
|
||||
|
||||
void MemoryImpl::cart_write(uint8_t bank, uint16_t adr, uint8_t val) {
|
||||
switch (type_) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
cart_writeLorom(bank, adr, val);
|
||||
break;
|
||||
case 2:
|
||||
cart_writeHirom(bank, adr, val);
|
||||
break;
|
||||
case 3:
|
||||
cart_writeHirom(bank, adr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MemoryImpl::cart_readLorom(uint8_t bank, uint16_t adr) {
|
||||
if (((bank >= 0x70 && bank < 0x7e) || bank >= 0xf0) && adr < 0x8000 &&
|
||||
sramSize > 0) {
|
||||
// banks 70-7e and f0-ff, adr 0000-7fff
|
||||
return ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)];
|
||||
}
|
||||
bank &= 0x7f;
|
||||
if (adr >= 0x8000 || bank >= 0x40) {
|
||||
// adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
|
||||
return rom_[((bank << 15) | (adr & 0x7fff)) & (romSize - 1)];
|
||||
}
|
||||
return open_bus_;
|
||||
}
|
||||
|
||||
void MemoryImpl::cart_writeLorom(uint8_t bank, uint16_t adr, uint8_t val) {
|
||||
if (((bank >= 0x70 && bank < 0x7e) || bank > 0xf0) && adr < 0x8000 &&
|
||||
sramSize > 0) {
|
||||
// banks 70-7e and f0-ff, adr 0000-7fff
|
||||
ram_[(((bank & 0xf) << 15) | adr) & (sramSize - 1)] = val;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MemoryImpl::cart_readHirom(uint8_t bank, uint16_t adr) {
|
||||
bank &= 0x7f;
|
||||
if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) {
|
||||
// banks 00-3f and 80-bf, adr 6000-7fff
|
||||
return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)];
|
||||
}
|
||||
if (adr >= 0x8000 || bank >= 0x40) {
|
||||
// adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
|
||||
return rom_[(((bank & 0x3f) << 16) | adr) & (romSize - 1)];
|
||||
}
|
||||
return open_bus_;
|
||||
}
|
||||
|
||||
uint8_t MemoryImpl::cart_readExHirom(uint8_t bank, uint16_t adr) {
|
||||
if ((bank & 0x7f) < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) {
|
||||
// banks 00-3f and 80-bf, adr 6000-7fff
|
||||
return ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)];
|
||||
}
|
||||
bool secondHalf = bank < 0x80;
|
||||
bank &= 0x7f;
|
||||
if (adr >= 0x8000 || bank >= 0x40) {
|
||||
// adr 8000-ffff in all banks or all addresses in banks 40-7f and c0-ff
|
||||
return rom_[(((bank & 0x3f) << 16) | (secondHalf ? 0x400000 : 0) | adr) &
|
||||
(romSize - 1)];
|
||||
}
|
||||
return open_bus_;
|
||||
}
|
||||
|
||||
void MemoryImpl::cart_writeHirom(uint8_t bank, uint16_t adr, uint8_t val) {
|
||||
bank &= 0x7f;
|
||||
if (bank < 0x40 && adr >= 0x6000 && adr < 0x8000 && sramSize > 0) {
|
||||
// banks 00-3f and 80-bf, adr 6000-7fff
|
||||
ram_[(((bank & 0x3f) << 13) | (adr & 0x1fff)) & (sramSize - 1)] = val;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t MemoryImpl::GetMappedAddress(uint32_t address) const {
|
||||
uint8_t bank = address >> 16;
|
||||
uint32_t offset = address & 0xFFFF;
|
||||
|
||||
if (bank <= 0x3F) {
|
||||
if (address <= 0x1FFF) {
|
||||
return (0x7E << 16) + offset; // Shadow RAM
|
||||
} else if (address <= 0x5FFF) {
|
||||
return (bank << 16) + (offset - 0x2000) + 0x2000; // Hardware Registers
|
||||
} else if (address <= 0x7FFF) {
|
||||
return offset - 0x6000 + 0x6000; // Expansion RAM
|
||||
} else {
|
||||
// Return lorom mapping
|
||||
return (bank << 16) + (offset - 0x8000) + 0x8000; // ROM
|
||||
}
|
||||
} else if (bank == 0x7D) {
|
||||
return offset + 0x7D0000; // SRAM
|
||||
} else if (bank == 0x7E || bank == 0x7F) {
|
||||
return offset + 0x7E0000; // System RAM
|
||||
} else if (bank >= 0x80) {
|
||||
// Handle HiROM and mirrored areas
|
||||
}
|
||||
|
||||
return address; // Return the original address if no mapping is defined
|
||||
}
|
||||
|
||||
void DrawSnesMemoryMapping(const MemoryImpl& memory) {
|
||||
// Using those as a base value to create width/height that are factor of the
|
||||
// size of our font
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#define MEM_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app/emu/debug/log.h"
|
||||
#include "app/emu/memory/dma_channel.h"
|
||||
|
||||
// LoROM (Mode 20):
|
||||
|
||||
@@ -91,20 +93,16 @@ class RomInfo {
|
||||
uint16_t resetVector;
|
||||
};
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() = default;
|
||||
virtual void Notify(uint32_t address, uint16_t data) = 0;
|
||||
};
|
||||
typedef struct CpuCallbacks {
|
||||
std::function<uint8_t(uint32_t)> read_byte;
|
||||
std::function<void(uint32_t, uint8_t)> write_byte;
|
||||
std::function<void(bool waiting)> idle;
|
||||
} CpuCallbacks;
|
||||
|
||||
constexpr uint32_t kROMStart = 0x008000;
|
||||
constexpr uint32_t kROMSize = 0x200000;
|
||||
constexpr uint32_t kRAMStart = 0x7E0000;
|
||||
constexpr uint32_t kRAMSize = 0x20000;
|
||||
constexpr uint32_t kVRAMStart = 0x210000;
|
||||
constexpr uint32_t kVRAMSize = 0x10000;
|
||||
constexpr uint32_t kOAMStart = 0x218000;
|
||||
constexpr uint32_t kOAMSize = 0x220;
|
||||
|
||||
/**
|
||||
* @brief Memory interface
|
||||
@@ -136,139 +134,86 @@ class Memory {
|
||||
|
||||
virtual uint8_t operator[](int i) const = 0;
|
||||
virtual uint8_t at(int i) const = 0;
|
||||
};
|
||||
|
||||
enum class MemoryMapping { SNES_LOROM = 0, PC_ADDRESS = 1 };
|
||||
virtual uint8_t open_bus() const = 0;
|
||||
virtual void set_open_bus(uint8_t value) = 0;
|
||||
|
||||
virtual bool hdma_init_requested() const = 0;
|
||||
virtual bool hdma_run_requested() const = 0;
|
||||
virtual void init_hdma_request() = 0;
|
||||
virtual void run_hdma_request() = 0;
|
||||
virtual void set_hdma_run_requested(bool value) = 0;
|
||||
virtual void set_hdma_init_requested(bool value) = 0;
|
||||
virtual void set_pal_timing(bool value) = 0;
|
||||
virtual void set_h_pos(uint16_t value) = 0;
|
||||
virtual void set_v_pos(uint16_t value) = 0;
|
||||
|
||||
// get h_pos and v_pos
|
||||
virtual auto h_pos() const -> uint16_t = 0;
|
||||
virtual auto v_pos() const -> uint16_t = 0;
|
||||
// get pal timing
|
||||
virtual auto pal_timing() const -> bool = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class MemoryImpl
|
||||
* @brief Implementation of the Memory interface for emulating memory in a SNES
|
||||
* system.
|
||||
*
|
||||
* The MemoryImpl class provides methods for initializing and accessing memory
|
||||
* in a SNES system. It implements the Memory interface and inherits from the
|
||||
* Loggable class.
|
||||
*
|
||||
* The class supports different memory mappings, including LoROM and PC_ADDRESS
|
||||
* mappings. It provides methods for reading and writing bytes, words, and longs
|
||||
* from/to memory. It also supports stack operations for pushing and popping
|
||||
* values.
|
||||
*
|
||||
* The class maintains separate vectors for ROM, RAM, VRAM, and OAM memory
|
||||
* regions. It provides methods for accessing these memory regions and
|
||||
* retrieving their sizes.
|
||||
*
|
||||
* The class also allows adding observers to be notified when memory is read or
|
||||
* written.
|
||||
*
|
||||
* @note This class assumes a 16-bit address space.
|
||||
*/
|
||||
class MemoryImpl : public Memory, public Loggable {
|
||||
public:
|
||||
void Initialize(const std::vector<uint8_t>& romData, bool verbose = false,
|
||||
MemoryMapping mapping = MemoryMapping::SNES_LOROM) {
|
||||
verbose_ = verbose;
|
||||
mapping_ = mapping;
|
||||
if (mapping == MemoryMapping::PC_ADDRESS) {
|
||||
memory_.resize(romData.size());
|
||||
std::copy(romData.begin(), romData.end(), memory_.begin());
|
||||
return;
|
||||
uint32_t romSize;
|
||||
uint32_t sramSize;
|
||||
void Initialize(const std::vector<uint8_t>& romData, bool verbose = false);
|
||||
|
||||
uint16_t GetHeaderOffset() {
|
||||
uint8_t mapMode = rom_[(0x00 << 16) + 0xFFD5];
|
||||
uint16_t offset;
|
||||
|
||||
switch (mapMode & 0x07) {
|
||||
case 0: // LoROM
|
||||
offset = 0x7FC0;
|
||||
break;
|
||||
case 1: // HiROM
|
||||
offset = 0xFFC0;
|
||||
break;
|
||||
case 5: // ExHiROM
|
||||
offset = 0x40;
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
"Unable to locate supported ROM mapping mode in the provided ROM "
|
||||
"file. Please try another ROM file.");
|
||||
}
|
||||
|
||||
memory_.resize(0x1000000); // 16 MB
|
||||
|
||||
const size_t ROM_CHUNK_SIZE = 0x8000; // 32 KB
|
||||
const size_t SRAM_SIZE = 0x10000; // 64 KB
|
||||
const size_t SYSTEM_RAM_SIZE = 0x20000; // 128 KB
|
||||
const size_t EXPANSION_RAM_SIZE = 0x2000; // 8 KB
|
||||
const size_t HARDWARE_REGISTERS_SIZE = 0x4000; // 16 KB
|
||||
|
||||
// Clear memory
|
||||
std::fill(memory_.begin(), memory_.end(), 0);
|
||||
|
||||
// Load ROM data into memory based on LoROM mapping
|
||||
size_t romSize = romData.size();
|
||||
size_t romAddress = 0;
|
||||
for (size_t bank = 0x00; bank <= 0x3F; ++bank) {
|
||||
for (size_t offset = 0x8000; offset <= 0xFFFF; offset += ROM_CHUNK_SIZE) {
|
||||
if (romAddress < romSize) {
|
||||
std::copy(romData.begin() + romAddress,
|
||||
romData.begin() + romAddress + ROM_CHUNK_SIZE,
|
||||
memory_.begin() + (bank << 16) + offset);
|
||||
romAddress += ROM_CHUNK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize SRAM at banks 0x7D and 0xFD
|
||||
std::fill(memory_.begin() + (0x7D << 16), memory_.begin() + (0x7E << 16),
|
||||
0);
|
||||
std::fill(memory_.begin() + (0xFD << 16), memory_.begin() + (0xFE << 16),
|
||||
0);
|
||||
|
||||
// Initialize System RAM at banks 0x7E and 0x7F
|
||||
std::fill(memory_.begin() + (0x7E << 16),
|
||||
memory_.begin() + (0x7E << 16) + SYSTEM_RAM_SIZE, 0);
|
||||
|
||||
// Initialize Shadow RAM at banks 0x00-0x3F and 0x80-0xBF
|
||||
for (size_t bank = 0x00; bank <= 0xBF; bank += 0x80) {
|
||||
std::fill(memory_.begin() + (bank << 16),
|
||||
memory_.begin() + (bank << 16) + 0x2000, 0);
|
||||
}
|
||||
|
||||
// Initialize Hardware Registers at banks 0x00-0x3F and 0x80-0xBF
|
||||
for (size_t bank = 0x00; bank <= 0xBF; bank += 0x80) {
|
||||
std::fill(
|
||||
memory_.begin() + (bank << 16) + 0x2000,
|
||||
memory_.begin() + (bank << 16) + 0x2000 + HARDWARE_REGISTERS_SIZE, 0);
|
||||
}
|
||||
|
||||
// Initialize Expansion RAM at banks 0x00-0x3F and 0x80-0xBF
|
||||
for (size_t bank = 0x00; bank <= 0xBF; bank += 0x80) {
|
||||
std::fill(memory_.begin() + (bank << 16) + 0x6000,
|
||||
memory_.begin() + (bank << 16) + 0x6000 + EXPANSION_RAM_SIZE,
|
||||
0);
|
||||
}
|
||||
|
||||
// Initialize Reset and NMI Vectors at bank 0xFF
|
||||
std::fill(memory_.begin() + (0xFF << 16) + 0xFF00,
|
||||
memory_.begin() + (0xFF << 16) + 0xFFFF + 1, 0);
|
||||
|
||||
// Copy data into rom_ vector
|
||||
rom_.resize(kROMSize);
|
||||
std::copy(memory_.begin() + kROMStart,
|
||||
memory_.begin() + kROMStart + kROMSize, rom_.begin());
|
||||
|
||||
// Copy data into ram_ vector
|
||||
ram_.resize(kRAMSize);
|
||||
std::copy(memory_.begin() + kRAMStart,
|
||||
memory_.begin() + kRAMStart + kRAMSize, ram_.begin());
|
||||
|
||||
// Copy data into vram_ vector
|
||||
vram_.resize(kVRAMSize);
|
||||
std::copy(memory_.begin() + kVRAMStart,
|
||||
memory_.begin() + kVRAMStart + kVRAMSize, vram_.begin());
|
||||
|
||||
// Copy data into oam_ vector
|
||||
oam_.resize(kOAMSize);
|
||||
std::copy(memory_.begin() + kOAMStart,
|
||||
memory_.begin() + kOAMStart + kOAMSize, oam_.begin());
|
||||
return offset;
|
||||
}
|
||||
|
||||
memory::RomInfo ReadRomHeader();
|
||||
|
||||
uint8_t cart_read(uint8_t bank, uint16_t adr);
|
||||
void cart_write(uint8_t bank, uint16_t adr, uint8_t val);
|
||||
|
||||
uint8_t cart_readLorom(uint8_t bank, uint16_t adr);
|
||||
void cart_writeLorom(uint8_t bank, uint16_t adr, uint8_t val);
|
||||
|
||||
uint8_t cart_readHirom(uint8_t bank, uint16_t adr);
|
||||
uint8_t cart_readExHirom(uint8_t bank, uint16_t adr);
|
||||
|
||||
void cart_writeHirom(uint8_t bank, uint16_t adr, uint8_t val);
|
||||
|
||||
uint8_t ReadByte(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return memory_.at(mapped_address);
|
||||
}
|
||||
uint16_t ReadWord(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return static_cast<uint16_t>(memory_.at(mapped_address)) |
|
||||
(static_cast<uint16_t>(memory_.at(mapped_address + 1)) << 8);
|
||||
}
|
||||
uint32_t ReadWordLong(uint32_t address) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return static_cast<uint32_t>(memory_.at(mapped_address)) |
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 1)) << 8) |
|
||||
(static_cast<uint32_t>(memory_.at(mapped_address + 2)) << 16);
|
||||
@@ -276,7 +221,6 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
std::vector<uint8_t> ReadByteVector(uint32_t address,
|
||||
uint16_t length) const override {
|
||||
uint32_t mapped_address = GetMappedAddress(address);
|
||||
NotifyObservers(mapped_address, /*data=*/0);
|
||||
return std::vector<uint8_t>(memory_.begin() + mapped_address,
|
||||
memory_.begin() + mapped_address + length);
|
||||
}
|
||||
@@ -343,8 +287,6 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
(static_cast<uint32_t>(mid) << 8) | low;
|
||||
}
|
||||
|
||||
void AddObserver(Observer* observer) { observers_.push_back(observer); }
|
||||
|
||||
// Stack Pointer access.
|
||||
uint16_t SP() const override { return SP_; }
|
||||
void SetSP(uint16_t value) override { SP_ = value; }
|
||||
@@ -363,61 +305,69 @@ class MemoryImpl : public Memory, public Loggable {
|
||||
auto begin() const { return memory_.begin(); }
|
||||
auto end() const { return memory_.end(); }
|
||||
auto data() const { return memory_.data(); }
|
||||
void set_open_bus(uint8_t value) override { open_bus_ = value; }
|
||||
auto open_bus() const -> uint8_t override { return open_bus_; }
|
||||
auto hdma_init_requested() const -> bool override {
|
||||
return hdma_init_requested_;
|
||||
}
|
||||
auto hdma_run_requested() const -> bool override {
|
||||
return hdma_run_requested_;
|
||||
}
|
||||
void init_hdma_request() override { hdma_init_requested_ = true; }
|
||||
void run_hdma_request() override { hdma_run_requested_ = true; }
|
||||
void set_hdma_run_requested(bool value) override {
|
||||
hdma_run_requested_ = value;
|
||||
}
|
||||
void set_hdma_init_requested(bool value) override {
|
||||
hdma_init_requested_ = value;
|
||||
}
|
||||
void set_pal_timing(bool value) override { pal_timing_ = value; }
|
||||
void set_h_pos(uint16_t value) override { h_pos_ = value; }
|
||||
void set_v_pos(uint16_t value) override { v_pos_ = value; }
|
||||
auto h_pos() const -> uint16_t override { return h_pos_; }
|
||||
auto v_pos() const -> uint16_t override { return v_pos_; }
|
||||
auto pal_timing() const -> bool override { return pal_timing_; }
|
||||
|
||||
auto dma_state() -> uint8_t& { return dma_state_; }
|
||||
void set_dma_state(uint8_t value) { dma_state_ = value; }
|
||||
auto dma_channels() -> DmaChannel* { return channel; }
|
||||
|
||||
// Define memory regions
|
||||
std::vector<uint8_t> rom_;
|
||||
std::vector<uint8_t> ram_;
|
||||
std::vector<uint8_t> vram_;
|
||||
std::vector<uint8_t> oam_;
|
||||
|
||||
private:
|
||||
uint32_t GetMappedAddress(uint32_t address) const {
|
||||
uint8_t bank = address >> 16;
|
||||
uint32_t offset = address & 0xFFFF;
|
||||
|
||||
if (mapping_ == MemoryMapping::PC_ADDRESS) {
|
||||
return address;
|
||||
}
|
||||
|
||||
if (bank <= 0x3F) {
|
||||
if (address <= 0x1FFF) {
|
||||
return (0x7E << 16) + offset; // Shadow RAM
|
||||
} else if (address <= 0x5FFF) {
|
||||
return (bank << 16) + (offset - 0x2000) + 0x2000; // Hardware Registers
|
||||
} else if (address <= 0x7FFF) {
|
||||
return offset - 0x6000 + 0x6000; // Expansion RAM
|
||||
} else {
|
||||
// Return lorom mapping
|
||||
return (bank << 16) + (offset - 0x8000) + 0x8000; // ROM
|
||||
}
|
||||
} else if (bank == 0x7D) {
|
||||
return offset + 0x7D0000; // SRAM
|
||||
} else if (bank == 0x7E || bank == 0x7F) {
|
||||
return offset + 0x7E0000; // System RAM
|
||||
} else if (bank >= 0x80) {
|
||||
// Handle HiROM and mirrored areas
|
||||
}
|
||||
|
||||
return address; // Return the original address if no mapping is defined
|
||||
}
|
||||
|
||||
void NotifyObservers(uint32_t address, uint16_t data) const {
|
||||
for (auto observer : observers_) {
|
||||
observer->Notify(address, data);
|
||||
}
|
||||
}
|
||||
uint32_t GetMappedAddress(uint32_t address) const;
|
||||
|
||||
bool verbose_ = false;
|
||||
|
||||
std::vector<Observer*> observers_;
|
||||
// DMA requests
|
||||
bool hdma_run_requested_ = false;
|
||||
bool hdma_init_requested_ = false;
|
||||
|
||||
// Memory (64KB)
|
||||
std::vector<uint8_t> memory_;
|
||||
bool pal_timing_ = false;
|
||||
|
||||
// Frame timing
|
||||
uint16_t h_pos_ = 0;
|
||||
uint16_t v_pos_ = 0;
|
||||
|
||||
// Dma State
|
||||
uint8_t dma_state_ = 0;
|
||||
|
||||
// Dma Channels
|
||||
DmaChannel channel[8];
|
||||
|
||||
// Open bus
|
||||
uint8_t open_bus_ = 0;
|
||||
|
||||
// Stack Pointer
|
||||
uint16_t SP_ = 0x01FF;
|
||||
|
||||
MemoryMapping mapping_ = MemoryMapping::SNES_LOROM;
|
||||
// Cart Type
|
||||
uint8_t type_;
|
||||
|
||||
// Memory (64KB)
|
||||
std::vector<uint8_t> memory_;
|
||||
};
|
||||
|
||||
void DrawSnesMemoryMapping(const MemoryImpl& memory);
|
||||
|
||||
@@ -72,6 +72,21 @@ class MockMemory : public Memory {
|
||||
MOCK_CONST_METHOD1(at, uint8_t(int i));
|
||||
uint8_t operator[](int i) const override { return memory_[i]; }
|
||||
|
||||
MOCK_METHOD0(init_hdma_request, void());
|
||||
MOCK_METHOD0(run_hdma_request, void());
|
||||
MOCK_METHOD1(set_hdma_run_requested, void(bool value));
|
||||
MOCK_METHOD1(set_hdma_init_requested, void(bool value));
|
||||
MOCK_CONST_METHOD0(hdma_init_requested, bool());
|
||||
MOCK_CONST_METHOD0(hdma_run_requested, bool());
|
||||
MOCK_METHOD1(set_pal_timing, void(bool value));
|
||||
MOCK_CONST_METHOD0(pal_timing, bool());
|
||||
MOCK_CONST_METHOD0(h_pos, uint16_t());
|
||||
MOCK_CONST_METHOD0(v_pos, uint16_t());
|
||||
MOCK_METHOD1(set_h_pos, void(uint16_t value));
|
||||
MOCK_METHOD1(set_v_pos, void(uint16_t value));
|
||||
MOCK_METHOD1(set_open_bus, void(uint8_t value));
|
||||
MOCK_CONST_METHOD0(open_bus, uint8_t());
|
||||
|
||||
void SetMemoryContents(const std::vector<uint8_t>& data) {
|
||||
if (data.size() > memory_.size()) {
|
||||
memory_.resize(data.size());
|
||||
|
||||
Reference in New Issue
Block a user