LADX: Fix getting old items over and over again in Bizhawk (#2011)

There was a bug that randomly after opening and closing the menu, some players on Bizhawk would get old items again. Tracking this down took multiple hours over the course of several weeks. The root cause turned out to be reading from the System Bus domain while an DMA copy was happening. Doing so is undefined behavior on GBC (though I'm sure some game relies on it). On Gambatte, you end up reading some garbage byte no matter what the read is (unsure what the providence of the byte is - some garbage, some register, the actual DMA data, who knows?). Normally, this isn't an issue, as Bizhawk callbacks only happen during vblank/halt, which is generally a state where we have valid WRAM to read from. However - a setting is being passed around the community for Bizhawk that changes the frame counter to go from "only when Vblank happens" to "whenever some number of audio samples have happened" which causes the bizhawk callbacks to happen....nearly whenever. Including during a DMA. You can tell this is happening if you print the `PC` register when reading memory - if it matches `FFXX` then you are executing in a routine in HRAM and likely doing a DMA.

Additionally, the check items counter specifically is in WRAM Bank 1 which could be swapped out of - will have to keep an eye on this - generally LADX lives in Bank 1, but there are a few things that use the other banks (swap space for some objects??). This could be a problem on any platform - if we get more reports of bad items gets, that's probably why.

Also, fixes some logging that was never getting reenabled.
This commit is contained in:
zig-for 2023-07-27 07:08:14 -07:00 committed by GitHub
parent 2333ddeaf7
commit 3bf86cd8f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 11 additions and 5 deletions

View File

@ -347,12 +347,13 @@ class LinksAwakeningClient():
f"Core type should be '{GAME_BOY}', found {core_type} instead - wrong type of ROM?")
await asyncio.sleep(1.0)
continue
self.stop_bizhawk_spam = False
logger.info(f"Connected to Retroarch {version.decode('ascii')} running {rom_name.decode('ascii')}")
return
except (BlockingIOError, TimeoutError, ConnectionResetError):
await asyncio.sleep(1.0)
pass
self.stop_bizhawk_spam = False
async def reset_auth(self):
auth = binascii.hexlify(await self.gameboy.async_read_memory(0x0134, 12)).decode()
self.auth = auth

View File

@ -43,13 +43,13 @@
local socket = require("socket")
local udp = socket.socket.udp()
udp = socket.socket.udp()
require('common')
udp:setsockname('127.0.0.1', 55355)
udp:settimeout(0)
while true do
function on_vblank()
-- Attempt to lessen the CPU load by only polling the UDP socket every x frames.
-- x = 10 is entirely arbitrary, very little thought went into it.
-- We could try to make use of client.get_approx_framerate() here, but the values returned
@ -112,6 +112,7 @@ while true do
for _, v in ipairs(mem) do
hex_string = hex_string .. string.format("%02X ", v)
end
hex_string = hex_string:sub(1, -2) -- Hang head in shame, remove last " "
local reply = string.format("%s %02x %s\n", command, address, hex_string)
udp:sendto(reply, msg_or_ip, port_or_nil)
@ -135,6 +136,10 @@ while true do
udp:sendto(reply, msg_or_ip, port_or_nil)
end
end
emu.frameadvance()
end
event.onmemoryexecute(on_vblank, 0x40, "ap_connector_vblank")
while true do
emu.yield()
end