65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
Today's question comes about from a detail in a video from the excellent Youtube channel Retro Game Mechanics Explained about an advanced Super Mario World speedrun technique that leverages arbitrary code execution. The video goes into great detail about how this technique works, but the question I'm interested in today comes from a detail about 34:25 into the video, timestamped below.
https://youtu.be/cPdlFUfENok?t=2065
This section of the video explains an example of a code path that does *not* produce an advantage in the game, but instead jumps to a part of the memory that's open bus. In the end, $4C is read, and because of bus capacitance, executed. This executes $4C $4C $4C, or jmp $4C4C. ($5C in the video is a typo.) Since $4C4C in itself is open bus, this creates a self-sustaining endless loop.
This explanation doesn't sit right with me since open bus tends to decay over time. If this truly just an open bus behavior, the endless loop might keep going for a few tens of microseconds, but the bus capacitance is likely to decay to either 0 or 1 instead of whatever was on the bus previously.
And if this is related to an MDR (memory data register) then the MDR, being essentially just a buffer for the data bus, should refresh by fetching the current value from the bus (which is decaying) instead of somehow knowing the address in question is open bus and not updating the MDR in that case.
I reached out to IsoFrieze, and he's been running a few tests to narrow down the possibilities.
- Maybe his flash cartridge has level shifters with bus hold functionality, like 74ALVCBH164245. (Nope, it has plain 74ALVC164245's and the behavior also reproduces on an original game cartridge.)
- He set up a test where the SA1 (a cartridge coprocessor with its own CPU) interrupts the main CPU after multiple seconds and then inspects what value (return address) was pushed to the stack. This test shows the same $4C4C, indicating the CPU was indeed still stuck in an endless loop at this point.
- Other tricks (as explained in the video) involve executing instructions which do not get stuck in an endless loop, which seems to work as theorized.
So, I'm at a loss as to what might actually be going on here. In my opinion, some mechanism has to be either holding or refreshing the data bus to prevent it from decaying. But what mechanism might that be? One candidate might be DRAM refresh, but I'm unsure how DRAM refresh might put a value on the data bus that was last read from ROM and not RAM.
Maybe there's something special about the 4xxx area above the IO registers which probably decodes to internal open bus, instead of being open bus due to being a window into a HiROM mirror of the LoROM area. (If LoROM even has such mirrors...)
Any thoughts of anything I might have missed would be helpful.
https://youtu.be/cPdlFUfENok?t=2065
This section of the video explains an example of a code path that does *not* produce an advantage in the game, but instead jumps to a part of the memory that's open bus. In the end, $4C is read, and because of bus capacitance, executed. This executes $4C $4C $4C, or jmp $4C4C. ($5C in the video is a typo.) Since $4C4C in itself is open bus, this creates a self-sustaining endless loop.
This explanation doesn't sit right with me since open bus tends to decay over time. If this truly just an open bus behavior, the endless loop might keep going for a few tens of microseconds, but the bus capacitance is likely to decay to either 0 or 1 instead of whatever was on the bus previously.
And if this is related to an MDR (memory data register) then the MDR, being essentially just a buffer for the data bus, should refresh by fetching the current value from the bus (which is decaying) instead of somehow knowing the address in question is open bus and not updating the MDR in that case.
I reached out to IsoFrieze, and he's been running a few tests to narrow down the possibilities.
- Maybe his flash cartridge has level shifters with bus hold functionality, like 74ALVCBH164245. (Nope, it has plain 74ALVC164245's and the behavior also reproduces on an original game cartridge.)
- He set up a test where the SA1 (a cartridge coprocessor with its own CPU) interrupts the main CPU after multiple seconds and then inspects what value (return address) was pushed to the stack. This test shows the same $4C4C, indicating the CPU was indeed still stuck in an endless loop at this point.
- Other tricks (as explained in the video) involve executing instructions which do not get stuck in an endless loop, which seems to work as theorized.
So, I'm at a loss as to what might actually be going on here. In my opinion, some mechanism has to be either holding or refreshing the data bus to prevent it from decaying. But what mechanism might that be? One candidate might be DRAM refresh, but I'm unsure how DRAM refresh might put a value on the data bus that was last read from ROM and not RAM.
Maybe there's something special about the 4xxx area above the IO registers which probably decodes to internal open bus, instead of being open bus due to being a window into a HiROM mirror of the LoROM area. (If LoROM even has such mirrors...)
Any thoughts of anything I might have missed would be helpful.
- Individualised
- Posts: 310
- Joined: Mon Sep 05, 2022 6:46 am
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
I saw this video and thought something was off about how open bus was being explained, I always thought that open bus values aren't always guaranteed and can exhibit behaviour based on analogue effects, but thought maybe it worked differently on the SNES. Very interested to see this be looked in to.
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
The explanation I'd previously seen is from Anomie and claims this: "The theory is that the S-CPU chip has something called a "Memory Data Register" or MDR, which stores the value for every read/write. When you attempt to read from unmapped memory, no new value is supplied for this register and so you read the same old value over and over." (https://wiki.superfamicom.org/open-bus)
However, I find this extremely unlikely because it suggests the CPU would be able to tell whether the value on the bus is driven or not, which I don't believe. I chatted with people about this on the NESdev Discord server and the best guess is that a component in the system has a buskeeper that is maintaining the current bus value by weakly driving it.
However, I find this extremely unlikely because it suggests the CPU would be able to tell whether the value on the bus is driven or not, which I don't believe. I chatted with people about this on the NESdev Discord server and the best guess is that a component in the system has a buskeeper that is maintaining the current bus value by weakly driving it.
- Jarhmander
- Formerly ~J-@D!~
- Posts: 569
- Joined: Sun Mar 12, 2006 12:36 am
- Location: Rive nord de Montréal
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
This is highly unlikely to be a bus holder doing this effect. It's almost certainly the bus capacitance holding (temporarily) the last value that was present on the bus.
((λ (x) (x x)) (λ (x) (x x)))
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
That's what I thought too, but when I had another round of contemplation and reading the docs, I realized that it might be doing something different in the 4000-5FFF internal CPU MMIO region. It may not be whether the data lines are driven that's detected, but rather if it's true thatFiskbit wrote: ↑Tue Mar 21, 2023 5:42 pm The explanation I'd previously seen is from Anomie and claims this: "The theory is that the S-CPU chip has something called a "Memory Data Register" or MDR, which stores the value for every read/write. When you attempt to read from unmapped memory, no new value is supplied for this register and so you read the same old value over and over." (https://wiki.superfamicom.org/open-bus)
However, I find this extremely unlikely because it suggests the CPU would be able to tell whether the value on the bus is driven or not, which I don't believe. I chatted with people about this on the NESdev Discord server and the best guess is that a component in the system has a buskeeper that is maintaining the current bus value by weakly driving it.
1) the address is in the 4000-5FFF region.
2) the adress is unmapped.
Both those are digital signals that should be easily available in the S-CPU, and could be used to inhibit updates to the MDR. Then again, when I discussed this with kevtris, he claimed there was nothing special about 4000-5FFF region.
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
For the $4000-5FFF region to be special in this way, I think the CPU would have to cut off its access to the external data bus when reading it in much the same way the NES CPU does when it reads from $4015. This means the CPU would be unable to read from external devices at all in this range, so they wouldn't just be unmapped, but unmappable.
What makes this unlikely? The problem here with the standard open bus behavior where capacitance holds a charge is that the value experimentally does not decay, so if the value is indeed coming from the bus as seems most likely, then something must be maintaining or resetting that charge. [Edit: lidnariq's findings below contradict these other results, so unless it varies by cartridge or console chipset, it sounds like this is probably standard open bus behavior.]Jarhmander wrote: ↑Tue Mar 21, 2023 9:00 pm This is highly unlikely to be a bus holder doing this effect. It's almost certainly the bus capacitance holding (temporarily) the last value that was present on the bus.
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
2 theories
1.) it just so happens that the last byte put on the bus by the DRAM refresh is $4C which is the only way to explain that the value holds for more than a line.
or
2.) there is an internal latch or something that holds the value, and it is not touched by DRAM refresh and hence the value is stored on an internal static bus.
1.) it just so happens that the last byte put on the bus by the DRAM refresh is $4C which is the only way to explain that the value holds for more than a line.
or
2.) there is an internal latch or something that holds the value, and it is not touched by DRAM refresh and hence the value is stored on an internal static bus.
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
Does DRAM refresh use the data bus? The WRAM chip has a REFRESH input and I would guess the CPU sets that briefly and doesn't touch the data bus, so refresh wouldn't affect open bus.
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
no, I'm being stupid. it would use the Address bus. or well half of it. Although it might have an internal counter which may or may not be put onto a bus somewhere. Not sure anybody has really looked into the DRAM Refresh mechanism. Maybe Grog did, I will have to see if I can dig out his doc somewhere..
Anomie doc does point out that all the chips seem to have a MBR with values being held and bits being held across accesses to just them and holds values with other accesses elsewhere. I.e access PPU, then WRAM then PPU open bus and you get the PPU value not the WRAM value. If you do an open bus read, than nothing will have a Chip select generated which means the MBR probably wouldn't have its latch enabled either. hence it won't refresh its value, hence the value is held?
Anomie doc does point out that all the chips seem to have a MBR with values being held and bits being held across accesses to just them and holds values with other accesses elsewhere. I.e access PPU, then WRAM then PPU open bus and you get the PPU value not the WRAM value. If you do an open bus read, than nothing will have a Chip select generated which means the MBR probably wouldn't have its latch enabled either. hence it won't refresh its value, hence the value is held?
-
- Posts: 611
- Joined: Mon Jan 23, 2006 7:47 am
- Location: Germany
- Contact:
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
As far as I can tell at least some of the registers in the original NMOS 6502 were not static (so there was a minimum frequency that was enough to refresh them), but the CMOS version (65c02) was already fully static.
So it seems that by the time the 65c816 was released, the MDR was a register made from flip-flops (or latches?), i.e. fast and static (no capacitors, no refresh needed), not DRAM cells or just wires holding their last value in the CPU or on the PCB.
It might be possible that the values in the MDR can be influenced by strong electrical interference in the environment, since (like any wire) the PCB traces also act like antennas.
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
I just set about making a very simple test on my 1-1-1 SNES (i.e. 3chip) and I can say that there is absolutely nothing resembling an MDR.
There is only normal open bus, and it decays fairly quickly (roughly 2 vsyncs)
My test setup is a plain 1-1-1 SNES, a cart with only a SST39SF040 and CIC on it, and a logic analyzer for the purposes of recording this result.
My code is attached. My logic analyzer dump is attached. After initializing everything and starting a GPDMA to clear PPU RAM (hence 25ms of all zeroes on the data and address buses) it loads the operands of the jmp $4C4C, and $4C stays on the data bus on my SNES for 24-25ms. After that, the value decays and it starts doing random crap. In the logic analyzer trace, I run the test twice by resetting in the middle. The timing is almost identical the second time.
The value decays regardless of whether I am doing this test with a logic analyzer : if I remove it and use an oscilloscope to check the contents of the data bus after a second or two, the data bus is not a stable $4c but is some different crash loop. The FX2LP is known to have weak pullup resistors on its lines (undocumented in the datasheet), but if there were actually a logic device holding the current bus contents, it wouldn't care about these weak pullups. Weak pullups can only possibly matter if it's only bus capacitance.
So even if there are specific circumstances in which it appears to persist for "seconds", such as mentioned in the initial post testing with an SA-1 - at the very least it's not part of the hardware present in a 1-1-1 SNES with a 1A0N-class board and a generic chunk of flash.
There is only normal open bus, and it decays fairly quickly (roughly 2 vsyncs)
My test setup is a plain 1-1-1 SNES, a cart with only a SST39SF040 and CIC on it, and a logic analyzer for the purposes of recording this result.
My code is attached. My logic analyzer dump is attached. After initializing everything and starting a GPDMA to clear PPU RAM (hence 25ms of all zeroes on the data and address buses) it loads the operands of the jmp $4C4C, and $4C stays on the data bus on my SNES for 24-25ms. After that, the value decays and it starts doing random crap. In the logic analyzer trace, I run the test twice by resetting in the middle. The timing is almost identical the second time.
The value decays regardless of whether I am doing this test with a logic analyzer : if I remove it and use an oscilloscope to check the contents of the data bus after a second or two, the data bus is not a stable $4c but is some different crash loop. The FX2LP is known to have weak pullup resistors on its lines (undocumented in the datasheet), but if there were actually a logic device holding the current bus contents, it wouldn't care about these weak pullups. Weak pullups can only possibly matter if it's only bus capacitance.
So even if there are specific circumstances in which it appears to persist for "seconds", such as mentioned in the initial post testing with an SA-1 - at the very least it's not part of the hardware present in a 1-1-1 SNES with a 1A0N-class board and a generic chunk of flash.
- Attachments
-
- snes-has-no-mdr-just-normal-floating-open-bus.sr.zip
- (397.56 KiB) Downloaded 16 times
-
- pinkeeper.zip
- (11.81 KiB) Downloaded 17 times
Re: 65816/SNES open bus/MDR mystery, (re: the latest RGMEx video)
Even 2 vsyncs seems suspiciously long tbh. Back of the envelope calculation: If we take 2 vsyncs to be 30 ms and use this is an RC time constant and assume (the resistive part of) the bus impedance is 1 Mohm (probably on the high side) we get that the total bus capacitance is 30 nF. I don't know what to expect, really, but that seems like it would certainly take the edge off of all digital signals to say the least. However, the fact that you're observing it decay at all points toward bus capacitance as the answer for your tests.
To be clear btw, Iso's test was doing using SA-1 as emulated by SD2SNES. The point of using the SA1 was to be able to interrupt the S-CPU after a long time, without affecting the main buses in the meantime.lidnariq wrote: ↑Wed Mar 22, 2023 6:21 pmSo even if there are specific circumstances in which it appears to persist for "seconds", such as mentioned in the initial post testing with an SA-1 - at the very least it's not part of the hardware present in a 1-1-1 SNES with a 1A0N-class board and a generic chunk of flash.