Post subject: Global.CheatList.Pulse() called twice. Is it necessary?
Joined: 5/4/2016
Posts: 67
I'm well aware cheat support in Bizhawk is shoddy at best, but I recently came across an oddness in the implementation that seemed like it was introducing overhead which I couldn't quite see a reason for. Within the main emulation step loop, Global.CheatList.Pulse() is called twice. Before the frame advance and After the frame advance This seems to me like it's introducing unnecessary overhead, but I may be missing the reasoning for it being called twice under all circumstances. Obviously, it needs to apply before frame 0. That means you need to set the value before the first frame advance. You then need to constantly set the value before the next frame advance as well. Applying twice solves this problem. You set the value before the first frame advance, step, then write the value back. Anything that needs to check the value after the step still gets the correct value as it was written back. At that point though, applying pre-step seems pointless outside of the very first step. I personally can't come up with any cases where the value would have changed between frame end and the start of the next frame (outside of a lua script overwriting the value in either the frameend or the next framestart event). Framestart is currently called after the initial cheat pulse anyways so that can already overwrite the value. I get the reasoning for having the tools update before and after every step, but why pulse cheats twice (outside of the first step)? Am I missing something, is it done that way for consistency sake (since everything else is called before and after a step), or is it just an issue in the implementation?
Alyosha
He/Him
Editor, Expert player (3536)
Joined: 11/30/2014
Posts: 2733
Location: US
This is a weakness of the current implementation of the cheat system. Currently, a cheat doesn't actually freeze an address in writable memory. Instead, it just pokes it at the start of a frame. This address can still change over the course of a frame though. So, in order for things like RAM watch to make sense, you have to reset it to the desired value after the frame as well. And you can't simply make all pokes permanent. You may want a one time poke in hex editor for example. This situation is evident in the core side as well, where pokes generally just end up as one time writes. Theoretically, you can pass a variable along with a poke to tell a core whether its a freeze (cheat) or just a one time poke. In fact, as a proof of concept I just did so on my personal build for NESHawk. Then the value truly is frozen, and there would be no need for a second call. This is a tractable problem for in house cores. But, for anything non-native, it's basically hopeless. Rewriting the desired value is the only way to do it. EDIT: I should also note that the implementation I did for NESHawk is only applicable to the system bus. Fairly substantial restructuring would be required for it to be more generally applicable to other memory domains.
Joined: 5/4/2016
Posts: 67
Well my point is: Frame 0 Original value - 00 Poke - FF Advance - 00 Poke - FF Frame 1 Current value (since it was poked at the end of the last frame) - FF Advance - 00 Poke - FF Repeat. I don't see why it's needed to poke before any frame except the very first frame. In all other cases, the poke from the end of the previous frame would still persist, would it not? The only exception I can see is if a lua script goes and writes over the value after the previous step but before the next step and that seems like a user issue
Alyosha
He/Him
Editor, Expert player (3536)
Joined: 11/30/2014
Posts: 2733
Location: US
Loading a state where the cheat isn't set yet? Then you'd frame advance without the cheat taking effect. (It's the poke afterwards that shouldn't need to be called.)
Joined: 5/4/2016
Posts: 67
Well my point was for the very first frame you'd do the double poke but for any future frames you wouldn't. I'd assume you'd want post-frame poke for tool purposes, not pre-frame?
Alyosha
He/Him
Editor, Expert player (3536)
Joined: 11/30/2014
Posts: 2733
Location: US
I’m not seeing how that would work. Any frame can be the first one. The system doesn’t track which cheats are new and need to be applied for the first time.
Joined: 5/4/2016
Posts: 67
Alyosha wrote:
I’m not seeing how that would work. Any frame can be the first one. The system doesn’t track which cheats are new and need to be applied for the first time.
Yep that's where my issue is. I'm thinking in the context of my use case where you're always applying cheats at the same time you load a state and was completely ignoring the fact that applying them on the fly would cause it to fall apart.
adelikat
He/Him
Emulator Coder, Site Developer, Site Owner, Expert player (3600)
Joined: 11/3/2004
Posts: 4739
Location: Tennessee
Also, as far as a performance hit, is basically nothing, unless you had all the ram tools open at once, but then you already have a much more huge hit anyway
It's hard to look this good. My TAS projects