-
Notifications
You must be signed in to change notification settings - Fork 385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory hook improvements #3821
base: master
Are you sure you want to change the base?
Memory hook improvements #3821
Conversation
- related to issue TASEmulators#3813 - update signatures, send returned value from bus read as data to read callback
- related to issue TASEmulators#3813 - update signatures, create new value variable in each of the memory read core functions, pass it to the callback and return it instead of the inline calculations. Also, pass val to write and exec callbacks in IDebuggable since they all use the same mem_cb signature and it would break otherwise. I want to update write and exec callbacks in next commit though to ensure nothing unexpected happens.
- related to issue TASEmulators#3813
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good from what I can see without actually testing them.
Something important to keep in mind is that there's a trade-off to these changes, and that is that a |
That's actually a valid point, and it reinforces the point that there IS a "before" and "after" state when it comes to reading values, and the decision on where the callback is called has an actual impact on how that callback can be used.
@YoshiRulz I do believe the "before" part for the callback is correct and matches expectations, we just need to decide what to do with the
|
I don't understand your question.
...seems pretty clear to me. Are you saying we should make that even clearer, maybe "
In our discussions on Discord re: possible implementations, this never came up. Freezing needs to remain functional—and I believe if you've broken it for Lua then it must also be broken for cheats. |
Both, probably. First of all yes, Making it clearer in the docs what's important would help here. |
I think there's a misunderstanding: freezing still works as usual and hasn't been affected in any way. What I meant with the wording "stronger freezing" is that when you freeze a memory address using cheats (traditional way), you are not actually freezing the memory address in the strict sense of the word, or at least not the way I'd expect. Whenever a frame advances, if the game's code updates the memory address, it will be updated. Say for example that you freeze Also, the way I see it, there are 3 key moments to have in mind:
The moment the bus is read is for BSNES when this line My point being that as I mentioned in the issue comments, while I agree with Morilli that the decision on where the callback is called has an actual impact on how that callback can be used, I still don't think there is really a "before" and an "after" state. The value still hasn't been sent when the callback is run, in fact, one possible way to go around this is to call I do believe Also, speaking of which. This detail slipped my mind earlier, but for the existing implementations, like here: BizHawk/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs Lines 1077 to 1084 in b98942d
(As a positive of this implementation, you can know how many bytes are actually being read by the game (so val will be 1 byte if just 1 byte is being read, 2 bytes if 2 bytes are being read, etc.). This has been very useful to me for reverse engineering.) |
This discussion is continuing on Discord, but I want to apologise for my earlier assertion that you'd broken freezing. Freezing is, of course, already "broken" in that sense, and has been forever since it's implemented as pokes. BizHawk/src/BizHawk.Client.Common/tools/Cheat.cs Lines 168 to 176 in bb0d8f2
(This method is called twice in StepRunLoop_Core , both before and after FrameAdvance .)
|
Please rebase. Since GPGX got a big update, it may not be trivial to recreate those changes, in which case you can drop them and we'll leave the linked issue open to track that. Or maybe it was magically fixed in the update? (GPGX also now includes a stronger version of freezing, if you were interested in that.) |
Definitely interested, thanks for letting me know. Will check the changes and see if I can recreate what I did in this PR (if still necessary). |
Maybe things changed in this last month, but still, to make the PR discussion easy to track, I'd like to include what we recently talked on Discord, namely that after bringing in the changes from gpgx upstream, it was in fact sort of "magically fixed", because now the order is the same as it is in this PR (first read the value, then call the callback). The problem is the same as before and that is that this way, deep freezing is not possible using |
While we were working on deep freeze for gpgx I pondered a few approaches. The current one is simply freezing individual bytes by restoring their values after every write. We discussed changing the value to be written right before it's written, also from inside the write callback. The problem with changing it while inside the write callback is different widths of written values. If in a given scenario we only need to freeze 1 byte because we know the game uses that address that way, we won't be able to easily overwrite it because callbacks can access that address using a different width, and we don't want to freeze adjacent addresses, so we'll only need to change a part of the bigger value that goes to that one byte address. Or we may be freezing a 32-bit value, but the game may be writing to it using smaller sizes. And overwriting it right after it's written while inside the write callback, changes the order of things, which may be problematic due to inconsistency. |
For BSNES core, signatures were updated and data value was passed to the read callback after reading from the bus. For genplus-gx, since all callbacks (read/write/exec) use the same signature from
mem_cb
, I had to pass the value to all three of them. And since this could potentially cause some unwanted behavior, I also updated the values passed to the write and exec callbacks inside the core (I divided each update in a separate commit so it's easier to follow and understand).Check if completed:
resolves #3813