DMA to WRAM on FC Twin

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
DMA to WRAM on FC Twin
by on (#47623)
I have some DMA code that appears to run correctly on a real SNES and the RetroDuo, but not the FC Twin.

I am using channel 1 (0-7) to do graphics updates during vblank. That part is working fine on all systems.

I am using channel 0 to do data transfer from ROM to WRAM, not necessarily in vblank. This is the part that doesn't work on the FC Twin. Putting WAI before the DMA code doesn't help, and neither does forcing vblank using $2100 before the DMA. My code seems pretty basic:

Code:
 
  (16 bit X/Y, 8 bit A)
  ldx destLo
  stx $2181
  lda #$00
  sta $2183  ;;load the WRAM dest address
 
  lda #$08
  sta $4300   ;;no source increment
 
  lda #$80
  sta $4301   ;;dest = wram, $2180
 
  lda sourcelow
  sta $4302
  lda sourcehigh
  sta $4303
  lda sourcebank
  sta $4304
 
  ldx sourceBytes16
  stx $4305   ;;size in bytes

  lda #$01
  sta $420B   ;Initiate transfer using channel 0


Any more ideas?

by on (#47633)
I'm a little confused by what it is you're trying to do here. :-)

My first question is: why are you using $2180 and $2181? WRAM is memory mapped to $0000-1FFF in banks $00-3F and $80-BF, as well as bank $7E (I think).

Next, you're claiming you're copying part of the ROM space to WRAM directly (e.g. A-bus --> B-bus, where A-bus == ROM/CPU and B-bus == $2180), but I see you're setting D3 of $4300 to 1, which stops the A-bus address from incrementing when reading from the source.

This would cause the DMA transfer to essentially copy a single byte of data in ROM to $2180, for a total of sourceBytes16 times. You also have the code comment "no source increment", which implies that's what you want.

This means your DMA transfer is being used solely to clear WRAM by using a DMA transfer, copying a single byte from sourcebank/sourcehigh/sourcelow into $2180 over and over. You can accomplish the exact same using a simple loop.

Otherwise, if you're trying to copy a "chunk" of existing memory (ROM or otherwise) into WRAM, you should set D3 of $4300 to 0 and D4 of $4300 to 0, to ensure that the A-bus address is incremented.

Another workaround for copying data using DMA is to use the MVN opcode. The SFC's DMA gives you a lot more control than MVN, but for copying memory around, MVN can get the job done. Or just go with a custom loop... :-)

by on (#47637)
koitsu wrote:
My first question is: why are you using $2180 and $2181? WRAM is memory mapped to $0000-1FFF in banks $00-3F and $80-BF, as well as bank $7E (I think).

Because the DMA dest can only access the $21xx range on the A bus, when the source is the B bus. But somehow I think you already knew that :)

koitsu wrote:
Next, you're claiming you're copying part of the ROM space to WRAM directly (e.g. A-bus --> B-bus, where A-bus == ROM/CPU and B-bus == $2180), but I see you're setting D3 of $4300 to 1, which stops the A-bus address from incrementing when reading from the source.

Think of it as memory mapped IO, not an actual ROM chip. I will test it but I doubt the non incrementing source is the problem anyways.

Of course there are other (slower) ways of doing it, but that wasn't the question. Code like the starter kit uses it to clear WRAM, but that is likely before the PPU is enabled. I don't want to say it is just clone incompatibility since the SNES clones seem to be very good.

by on (#47641)
I'm pretty sure anomie's doc mentionned trying to DMA to WRAM by $2180 won't work (so I don't even understand why can $2180 be usefull, why won't you adress WRAM directly ?). I could be wrong tough. Check anomie's docs on DMA.

by on (#47643)
koitsu wrote:
Another workaround for copying data using DMA is to use the MVN opcode. The SFC's DMA gives you a lot more control than MVN, but for copying memory around, MVN can get the job done. Or just go with a custom loop... :-)

But isn't that slow? From my Apple IIGS days, I seem to remember MVN taking 7 cycles per byte and requiring self-modifying code to set the source and destination banks. On the GBA at least, the fastest memcpy() from ROM to WRAM is DMA; the LDMIA/STMIA loop comes in a close second and has better IRQ latency.

by on (#47645)
Bregalad wrote:
I'm pretty sure anomie's doc mentionned trying to DMA to WRAM by $2180 won't work

Anomie's docs say you can't DMA between WRAM and $2180, because the WRAM can't respond to both buses at once. Between ROM and $2180 is no problem, and works on the real SNES.

by on (#47652)
Oh thanks for correcting me.

by on (#47655)
tepples wrote:
koitsu wrote:
Another workaround for copying data using DMA is to use the MVN opcode. The SFC's DMA gives you a lot more control than MVN, but for copying memory around, MVN can get the job done. Or just go with a custom loop... :-)

But isn't that slow? From my Apple IIGS days, I seem to remember MVN taking 7 cycles per byte and requiring self-modifying code to set the source and destination banks. On the GBA at least, the fastest memcpy() from ROM to WRAM is DMA; the LDMIA/STMIA loop comes in a close second and has better IRQ latency.


You remember correctly -- MVN/MVP are indeed slow. My point was to offer an alternative if needed. Plus, given that I wasn't sure what bunnyboy was trying to do (re: is this code intended to just init WRAM, or is it actually wanting to copy ROM contents into WRAM?), it's a legitimate alternative to said problem. That said, it's almost always faster to do things in an actual loop vs. using MVN/MVP, but again, depends on what the code was trying to do.

I'll read the rest of the thread after I've slept. :)

by on (#47669)
Slight bit of additional info: it looks like the DMA is happening but the bytes are shifted to the left, like the first byte was skipped. Next to check if its actually copying the right amount, or the address is wrong, etc...

by on (#47681)
F YOU FC Twin!

Turns out there is frequently a sysclk glitch at the beginning of DMA. This is no problem when reading from ROM, because the value doesn't change. When reading from IO the glitch triggers and extra read, shifting everything over. Now to figure out how to detect that clone and switch to a fixed loop...

Image

by on (#47682)
Hmmm... What could cause a glitch? Did the SPC700 fetch a sample at that exact moment? ;-)

You could try to do an I/O from a known data source and if it screws up, it's a clone.

by on (#47688)
tepples wrote:
Hmmm... What could cause a glitch? Did the SPC700 fetch a sample at that exact moment? ;-)

You could try to do an I/O from a known data source and if it screws up, it's a clone.


Don't have any audio running so I hope its not the same DPCM bug :)

Can't just check for alignment wrong because it doesn't happen every time. Would have to do something like run it 10-20x and see if any fail.

by on (#47692)
You're not doing any HDMA transfers anywhere in your program are you?

by on (#47695)
Nope no HDMA, IRQs also off, turning NMI off or making it happen before the DMA doesn't make a diff either. I can test doing the DMA before any of the screen is turned on but I am skeptical that will make a difference. Wonder if its something with the clock alignment.

by on (#47709)
bunnyboy wrote:
Nope no HDMA, IRQs also off, turning NMI off or making it happen before the DMA doesn't make a diff either. I can test doing the DMA before any of the screen is turned on but I am skeptical that will make a difference. Wonder if its something with the clock alignment.


The reason I ask about HDMA is that there's a documented bug in the SFC (and possibly the Twin, or maybe they have to emulate it!) which happens where an HDMA transfer starts shortly before a DMA transfer finishes. I can outline the bug if people need details, but it sounds unrelated to this problem.

I guess you've found a nice quirk in the FC Twin... :)

by on (#47793)
Your example code is fine, and there's no need to be in vblank or force blank to transfer from ROM to WRAM. Looks like you found a hardware bug. One of the reasons I refuse to buy one of these clone systems. I'd rather use an emulator at that point.

Quote:
Between ROM and $2180 is no problem, and works on the real SNES.


For others here, think of it like this: each "chip" (we're simplifying a bit here) only has one address and one data bus. You can't have it point to two different addresses (source and dest) at the same exact time. This applies the same way for the cartridge connector: so ROM <> save RAM will not work.

Quote:
The reason I ask about HDMA is that there's a documented bug in the SFC (and possibly the Twin, or maybe they have to emulate it!)


The glitch only occurs on revision 1 CPUs. And I'd be really surprised if they figured out how to reproduce it. The effect is seriously insane to witness. The entire system state goes straight to hell. While you'd think it was just corrupting the program counter (or the next opcode fetched after it), the destruction of absolutely everything is so extreme that it seems highly unlikely a bad execution path (invariably leading to a BRK loop or similar) could do so much damage.

I really want to emulate this effect, but I would need someone with hardware tools to see what's happening at the circuit level to get it right.

by on (#47803)
byuu wrote:
Your example code is fine, and there's no need to be in vblank or force blank to transfer from ROM to WRAM. Looks like you found a hardware bug. One of the reasons I refuse to buy one of these clone systems. I'd rather use an emulator at that point.

Quote:
Between ROM and $2180 is no problem, and works on the real SNES.


For others here, think of it like this: each "chip" (we're simplifying a bit here) only has one address and one data bus. You can't have it point to two different addresses (source and dest) at the same exact time. This applies the same way for the cartridge connector: so ROM <> save RAM will not work.


I thought bunnyboy was transferring between ROM and WRAM ("work RAM"), not ROM and SRAM (battery-backed, mode 20 = banks $70-77, offsets $0000-7FFF; mode 21 = banks $30-3F, offsets $6000-8000)?

byuu wrote:
The glitch only occurs on revision 1 CPUs.


I didn't bother to state this because I was under the impression there was only one revision which made it out into the market. Yes/no?

by on (#47817)
koitsu wrote:
byuu wrote:
The glitch only occurs on revision 1 CPUs.


I didn't bother to state this because I was under the impression there was only one revision which made it out into the market. Yes/no?


Only very early NTSC models have a rev. 1 CPU (i. e., only pre-1991 Super Famicoms, AFAIK). All later models have rev. 2 CPUs.

by on (#47819)
I seem to remember Super Street Fighter II for Super NES not running on the earliest consoles, and Nintendo having to issue replacements. Can anyone else dig up info on this?

by on (#47838)
Quote:
I thought bunnyboy was transferring between ROM and WRAM ("work RAM")


He was, and I said that transfer was fine. I used ROM<>SRAM as an example for others to understand what types of transfers are invalid without having to list each and every one.

Amazing as it is, some games rely on this behavior. Krusty's Super Fun House performs illegal DMA transfers that, if allowed, would corrupt the in-game palette.

Quote:
I didn't bother to state this because I was under the impression there was only one revision which made it out into the market. Yes/no?


Revision 1 is very rare. Usually if you have an oxidized case (eg it is yellow), you have a rev. 1. Otherwise it's probably a rev. 2. I have not seen a CPU revision of 3 yet, but it may exist in the mini-SNES.

There are real differences other than the DMA crashing glitch. They changed the way DRAM refresh and HDMA init timing works as well. Then there are also different S-PPU1, S-PPU2, S-SMP (mini-SNES lacks timer glitch) and S-DSP revisions.

One wonders why they felt the need to keep changing shit (supplier issues?), but I digress. It gives emulators a tiny bit of leeway to act differently, if real hardware does as well.

Quote:
I seem to remember Super Street Fighter II for Super NES not running on the earliest consoles, and Nintendo having to issue replacements. Can anyone else dig up info on this?


That would be very interesting if true. I always assumed developers were forced to test their games on all current versions of hardware, and if anything, only newer revisions would break older games.

by on (#47872)
Thanks for the clarification, byuu! Nice to see someone kept up on what happened with the SFC/SNES over time. Always learning something around here... :-)

by on (#47907)
byuu wrote:
Usually if you have an oxidized case (eg it is yellow), you have a rev. 1. Otherwise it's probably a rev. 2.


No. The materials used in the process of SNES casing construction don't correlate with CPU revisions.

As I said, there are probably only Japanese SFC systems with rev. 1 CPUs. If there are series of US and/or PAL SNES systems at all that have a rev. 1 CPU, they are very rare and CANNOT be identified from their exterior appearance, but possibly from their serial number.

by on (#47962)
orwannon wrote:
No. The materials used in the process of SNES casing construction don't correlate with CPU revisions.


I did say usually, not always. It was my impression they fixed the oxidation shortly after introducing the rev. 2 CPU. Guess that's wrong, do you have more info on that?

Interesting that there aren't (m)any in the US. Only have Japanese ones myself, a 1/1/1 and 2/1/3. The US design sucked.

by on (#47969)
bunnyboy, is this your way of dropping a hint that you are developing a "Super PowerPak" for the SNES?

by on (#48036)
I dont think theres any doubt he's developing one at least. (I mean he's said he would like to a couple of times iirc) The question is how far he is along (if he's even started or sees a future in the project) and if this is related. ;-)

by on (#48043)
Oh no! I'm going to have to beat you to it ;)