Как получить ППУ память от FCEUX в Lua?
Я не уверен, что это подходящее сообщество для этого, но решил, что я попробую.
FCEUX - это удивительный эмулятор для NES, который богат функциями отладки. Он также предлагает пользователям возможность запускать сценарии Lua, которые имеют доступ к различным функциям эмулятора. Тем не менее, я не могу понять, как получить доступ к памяти PPU NES. Он предлагает прямой доступ к памяти ЦП и данным ПЗУ, но, похоже, не имеет прямого доступа к памяти ППУ. Поскольку NES использует ввод-вывод с отображением в памяти, теоретически возможно получить данные из специальных адресов памяти ЦП, но это кажется громоздким, а также может помешать эмуляции.
Кто-нибудь знает способ программного извлечения памяти PPU через Lua API FCEUX? Если нет, кто-нибудь знает об эмуляторе, который имеет API для программного извлечения памяти PPU?
3 ответа
После осознания того, что "Ой, подождите, я программист, а FCEUX с открытым исходным кодом! Так что, может быть, мне стоит потратить время на просмотр их источника / хранилища, чтобы посмотреть, смогу ли я ответить на вопрос сам!", Я нашел ответ, который я искал:
Таким образом, может показаться, что на момент написания этой статьи доступ к памяти PPU через Lua невозможен в текущей версии выпуска ( 2.2.3, выпущенной 28 июля 2016 года), но, вероятно, будет доступен в будущем выпуске.
Кроме того, после проверки Nestopia и Jnes (двух других, казалось бы, самых популярных эмуляторов NES), кажется, что эти эмуляторы не предлагают такой функциональности. Относительно того, существуют ли какие-либо другие эмуляторы, которые предлагают эту функцию, все еще остается открытым вопрос, поскольку в настоящее время существует множество других эмуляторов для проверки.
Вот что я использую:
function memory.readbyteppu(a)
memory.writebyte(0x2001,0x00) -- Turn off rendering
memory.readbyte(0x2002) -- PPUSTATUS (reset address latch)
memory.writebyte(0x2006,math.floor(a/0x100)) -- PPUADDR high byte
memory.writebyte(0x2006,a % 0x100) -- PPUADDR low byte
if a < 0x3f00 then
dummy=memory.readbyte(0x2007) -- PPUDATA (discard contents of internal buffer if not reading palette area)
end
ret=memory.readbyte(0x2007) -- PPUDATA
memory.writebyte(0x2001,0x1e) -- Turn on rendering
return ret
end
function memory.readbytesppu(a,l)
memory.writebyte(0x2001,0x00) -- Turn off rendering
local ret
local i
ret=""
for i=0,l-1 do
memory.readbyte(0x2002) -- PPUSTATUS (reset address latch)
memory.writebyte(0x2006,math.floor((a+i)/0x100)) -- PPUADDR high byte
memory.writebyte(0x2006,(a+i) % 0x100) -- PPUADDR low byte
if (a+i) < 0x3f00 then
dummy=memory.readbyte(0x2007) -- PPUDATA (discard contents of internal buffer if not reading palette area)
end
ret=ret..string.char(memory.readbyte(0x2007)) -- PPUDATA
end
memory.writebyte(0x2001,0x1e) -- Turn on rendering
return ret
end
function memory.writebyteppu(a,v)
memory.writebyte(0x2001,0x00) -- Turn off rendering
memory.readbyte(0x2002) -- PPUSTATUS (reset address latch)
memory.writebyte(0x2006,math.floor(a/0x100)) -- PPUADDR high byte
memory.writebyte(0x2006,a % 0x100) -- PPUADDR low byte
memory.writebyte(0x2007,v) -- PPUDATA
memory.writebyte(0x2001,0x1e) -- Turn on rendering
end
function memory.writebytesppu(a,str)
memory.writebyte(0x2001,0x00) -- Turn off rendering
local i
for i = 0, #str-1 do
memory.readbyte(0x2002) -- PPUSTATUS (reset address latch)
memory.writebyte(0x2006,math.floor((a+i)/0x100)) -- PPUADDR high byte
memory.writebyte(0x2006,(a+i) % 0x100) -- PPUADDR low byte
memory.writebyte(0x2007,string.byte(str,i+1)) -- PPUDATA
end
memory.writebyte(0x2001,0x1e) -- Turn on rendering
end
В 2.2.3 он не работает на старом ядре PPU, но на 2.2.2 работает. Работает с новым ядром ППУ на обеих версиях.
Начиная с FCEUX 2.3.0, вы можете использовать
ppu.readbyte(int address)
а также
ppu.readbyterange(int address, int length)
. Впрочем, для записи байтов по-прежнему ничего.
Чтобы добавить к ответу SpiderDave, вам может повезти больше, если вы назовете его
writebyteppu
взломать
registerexec
обратный вызов по адресу сразу после того, как игра закончила писать графику для кадра.
-- For Rockman 2. Directly after all graphics update routines finish.
memory.registerexec(0xD031, function()
local paletteBase = 0x3F00
-- Make all BG colors pink
for i = 0x00, 0x0F do
memory.writebyteppu(paletteBase + i, 0x35)
end
end)