Эмулировать отображение памяти игровой консоли, доступ к различным местам на основе предоставленного адреса

Я реализую эмулятор для старой игровой консоли, в основном для учебных целей.

Эта консоль отображает ромы и многое другое в регионы своего адресного пространства. Определенные местоположения также отражаются, так что несколько адресов могут соответствовать одному физическому местоположению. Я хотел бы подражать этому, но я не уверен, что было бы хорошим подходом для этого (и также не знаю, как называется этот процесс, отсюда и этот несколько общий вопрос).

Одна вещь, которая работает, это простая неупорядоченная карта. Содержат ли они абсолютные адреса и соответствующие указатели на мои структуры данных. Таким образом, я могу легко отобразить все, что мне нужно, в адресное пространство системы. Проблема с этим подходом заключается в том, что, очевидно, это боров памяти. Даже с небольшими ромами я получаю около десяти миллионов записей благодаря вышеупомянутому зеркалированию. Конечно, это не может быть самым сложным делом?

Буду признателен за любую оказанную помощь.

Редактировать:

Чтобы предоставить некоторые детали относительно того, как именно я делаю это:

Рассматриваемая система — это, конечно, SNES. С помощью эта вики в качестве основного ресурса я реализовал то, что упомянул выше:

  • Создать std::unordered_map<uint32,uint8_t*> mMemoryMap;
  • Проверьте, является ли ром LoRom или HiRom
  • За каждый байт в роме
    • Вычислите адрес, по которому он должен быть отображен, и поместите в карту и адрес, и указатель на указанный байт.
    • Если раздел нужно отразить в другом месте, повторите выше
  • Это будет применяться ко всему, что мне нужно сделать доступным, например, к видео- или системной памяти.

Если я теперь хочу получить доступ к чему-либо в адресном пространстве, я могу просто использовать адрес, который система будет использовать внутри.

4

Решение

Я предполагаю, что для смежных адресов физические местоположения также являются смежными, в определенных блоках памяти или «кусках». То есть, если адрес 0x0000 отображается на 0xFF00, то 0x0004 отображается на 0xFF04.

введите описание изображения здесь

Если они так работают, то вы можете составить список, содержащий информацию об этих чанках. Сказать:

struct Chunk
{
int addressStart, memoryStart, size;
}

Чанки могут быть упорядочены по адресу addressStart, поэтому вы можете найти правильный чанк, который вам понадобится для любого адреса. Это требует от вас повторения списка, но если у вас есть только несколько кусков, это может быть приемлемым.

1

Другие решения

Вместо того, чтобы использовать простые карты (которые даже с диапазонами могут увеличиться до больших размеров), вы можете вместо этого использовать более интеллектуальную карту.

Например, если консоль сопоставляет 0x10XXXX через 0x1FXXXX все к тому же 0x20XXXX Вы можете спроектировать структуру, которая содержит это повторение (начало 0x100000 конец 0x1FFFFF повторение 0x010000 хотя вы можете использовать битовую маску, а не повторять).

1

В настоящее время я нахожусь в той же лодке, что и вы, и выполняю эмулятор NES в учебных целях. Полная карта памяти объявляется как массив указателей на байты. Каждый указатель может указывать на другой массив, что позволяет мне иметь указатели на те же данные в случае зеркального отображения.

byte *memoryMap[cpuMemSize];

Я перебираю адреса, которые повторяются, и отображаю их, чтобы они указывали на байты в следующем массиве. Массив оперативной памяти — это память, которая отображается 4 раза по карте памяти процессора.

byte ram[ramSize];

Следующий код проходит через массив RAM и сопоставляет его с картой памяти CPU 4 раза.

// map RAM 4 times to emulate mirroring
mem_address memAddr = 0;
for (int x = 0; x < 4; ++x)
{
for (mem_address ramAddr = 0; ramAddr < ramSize; ++ramAddr.value)
{
memoryMap[memAddr.value++] = &ram[ramAddr.value];
}
}

Затем вы можете записать значение в 256-й байт, используя что-то вроде этого, что, конечно, будет распространено на другие части карты памяти, поскольку они указывают на один и тот же байт в памяти:

*memoryMap[0x00ff] = 10;

Я на самом деле не проверял это и хочу провести дополнительное тестирование в отношении использования кэша процессора и производительности. Я явно искал другие способы сделать это, когда наткнулся на ваш вопрос и решил, что я положу свои (непроверенные) два цента. Надеюсь, это имеет смысл.

0
По вопросам рекламы [email protected]