2

我不确定这是否是合适的社区,但我想我会试一试。

FCEUX是 NES 的一个了不起的模拟器,它具有丰富的调试工具功能。它还为用户提供了运行 Lua 脚本的能力,这些脚本可以访问各种仿真器功能。但是,我似乎无法弄清楚如何访问 NES 的PPU 内存。它提供对CPU 内存和 ROM 数据的直接访问,但似乎无法直接访问 PPU 内存。由于 NES 使用内存映射 I/O,理论上可以从特殊的 CPU 内存地址获取数据,但这似乎很麻烦,而且可能会干扰仿真。

有谁知道通过 FCEUX 的 Lua API 以编程方式提取 PPU 内存的方法?如果没有,是否有人知道具有以编程方式提取 PPU 内存的 API 的模拟器?

4

3 回答 3

4

这是我使用的:

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 中可以。适用于两个版本的新 ppu 核心。

于 2017-04-19T03:21:34.593 回答
1

在意识到“哦,等等,我是一名程序员,FCEUX 是开源的!所以也许我应该花时间看看他们的源代码/存储库,看看我是否可以自己回答这个问题!”,我发现我正在寻找的答案:

2016 年 12 月 22 日提交 [r3327]:添加 ppu lua 库,目前只有 readbyte 和 readbyterange

因此,在撰写本文时,在当前版本(2016 年 7 月 28 日发布的2.2.3 )中似乎无法通过 Lua 访问 PPU 内存,但可能会在未来的版本中提供。

此外,在查看NestopiaJnes(其他两个看似最流行的 NES 模拟器)之后,似乎这些模拟器不提供此类功能。至于是否有任何其他模拟器提供此功能仍然是一个悬而未决的问题,因为目前存在许多其他模拟器需要检查。

于 2017-01-31T12:17:18.790 回答
1

FCEUX 2.3.0 开始,您可以使用ppu.readbyte(int address)ppu.readbyterange(int address, int length). 但是,仍然没有写入字节。

要添加到 SpiderDave 的答案,如果您在游戏完成为框架编写图形之后writebyteppu从一个地址的回调中调用他的 hack ,您可能会有更好的运气。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)
于 2021-07-04T07:43:19.197 回答