+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  420B wont transfer
Pages: [1] 2
Author Topic: 420B wont transfer  (Read 1198 times)
aspire
Guest
« on: April 21, 2007, 09:43:34 pm »

I am working on a game (SNES) which has 4 tilemap routines that I need to overwrite and DMA my own data. I have completed this for three of the routines however, the last one for some reason wont transfer on 420b. My DMA routine is inside the VSYNC interupt itself - In the routines I am overwriting, I just set a flag and wait for dma (ROM->VRAM). I did a trace and reviewed it line by line but everything looks legit and the DMA data in RAM is definately there. Any idea what might be going on? Could another register be interfering? Anything else I could be missing?

« Last Edit: April 21, 2007, 09:59:59 pm by aspire »
Nightcrawler
Guest
« Reply #1 on: April 21, 2007, 10:03:21 pm »

I assume you're referencing register $420b in the SNES? You might want to be more descriptive when asking for help.

I'm also assuming you mean your DMA routine is inside the NMI routine?

How can you just set a flag and wait for DMA? DMA pauses CPU execution and executes practically immediately after being enabled on $420b.

If you are 'waiting' for DMA, you are probably using it incorrectly as that's not really possible.

As for potential problems:

1. Depending on how long the original game's NMI routine is and where your code was added, your added code may not always execute within the vblank period in which case, your transfer may not occur.

2. Make sure that channel is not in use by the game. It's easy to think a channel is not in use and later find it is under certain circumstances.

There's obviously something different occurring on the fourth transfer that doesn't happen on the other three. You'll need to find out what that is. You can use the debugging version of BSNES which will show the results of DMA realtime when viewing VRAM. You can step through and see if it indeed worked immediate after that instruction. If it didn't, something is wrong with your DMA code or the game messed with some of the DMA register settings.
aspire
Guest
« Reply #2 on: April 21, 2007, 10:14:02 pm »

Yes, I stuck the DMA routine in the NMI itself - which when called, checks a flag (VAR_VSYNCFLAG) and if set, DMA's the data. 

In the tilemap routine I overwrote, I set the flag and wait as follows.

SEP #$20
LDA #$80
STA VAR_VSYNCFLAG       ; set vsync flag and wait for DMA
WAIT:
LDA VAR_VSYNCFLAG
BNE WAIT
REP #$20

This gets called just fine for the last routine, but after $420b nothing shows up in VRAM.

Per your suggestion, I will try the debug version of BSNES.
Nightcrawler
Guest
« Reply #3 on: April 22, 2007, 01:03:30 pm »

What is VAR_VSYNCFLAG? That's what I don't get.

Is that code separated? Your NMI code shouldn't be waiting for anything. Perhaps I misunderstand what you're doing.

If you're setting a flag in the normal game code and then NMI will DMA if it's set that's another thing. If that's what you're doing, then that's ok.

There's really not a lot that can go wrong here. I will wait and see what you come up with after looking at the debugger. If your DMA code is write and the registers are set correctly, DMA WILL fire on $420b enable. It has to.
aspire
Guest
« Reply #4 on: April 23, 2007, 09:53:23 am »

Quote from: Nightcrawler on April 22, 2007, 01:03:30 pm
What is VAR_VSYNCFLAG? That's what I don't get.

Is that code separated? Your NMI code shouldn't be waiting for anything. Perhaps I misunderstand what you're doing.

If you're setting a flag in the normal game code and then NMI will DMA if it's set that's another thing. If that's what you're doing, then that's ok.

There's really not a lot that can go wrong here. I will wait and see what you come up with after looking at the debugger. If your DMA code is write and the registers are set correctly, DMA WILL fire on $420b enable. It has to.

Yes, your assessment is correct. Im setting a flag in normal game code and then the NMI will DMA.  However, we can ignore that for the moment, because its still not working even if I DMA directly without the NMI.

Here is my  DMA JSL code:
LDA #$1801
STA $4300               ""; configure for $2118 vram
LDA #$5600
STA $2116               ""; write to VRAM
LDA #$AE00
STA $4302               ""; Read from ROM
LDA #$0200               
STA $4305               ""; number of bytes to copy
SEP #$20                ; 8 bit stuff
LDA #$80
STA $2115
LDA #$8B                ; Read source bank
STA $4304
LDA #$01
STA $420b               ""; start DMA
REP #$20
RTL

I am calling this JSL in three other routines and it works fine. However, the last routine I need to overwrite still refuses to transfer on $420b, nothing shows up in VRAM.  Verified with BSNES and Geiger's debugger and zsnes save state.

Totally stumped. It's like the ability to DMA has been turned off somehow.
« Last Edit: April 23, 2007, 10:39:50 am by aspire »
Disch
Guest
« Reply #5 on: April 23, 2007, 10:48:39 am »

Nothing appears to be wrong with your DMA code.

Considering this works 3 out of 4 places -- I'm inclined to think you might be mistaking that last area for something other than it really is -- and perhaps your DMA routine isn't being called because the original routine isn't being run when you are thinking it is.

I would try to verify that your DMA routine is even being called.

The only other thing I can think of, is maybe the DMA is working, but then the game is overwriting VRAM again a little bit further in the code.  Perhaps you might want to check that out as well.
aspire
Guest
« Reply #6 on: April 23, 2007, 11:00:22 am »

Quote from: Disch on April 23, 2007, 10:48:39 am
Nothing appears to be wrong with your DMA code.

Considering this works 3 out of 4 places -- I'm inclined to think you might be mistaking that last area for something other than it really is -- and perhaps your DMA routine isn't being called because the original routine isn't being run when you are thinking it is.

I would try to verify that your DMA routine is even being called.

The only other thing I can think of, is maybe the DMA is working, but then the game is overwriting VRAM again a little bit further in the code.  Perhaps you might want to check that out as well.

I used both Geiger's Debugger and BSNES, set a breakpoint and it snaps when the routine is hit...

I then stepped through until $420b

$B0/84A1 A9 01 18    LDA #$1801              A:A2FB X:A2FB Y:0008 P:eNvmxdizc
$B0/84A4 8D 00 43    STA $4300  [$7E:4300]   A:1801 X:A2FB Y:0008 P:envmxdizc
$B0/84A7 A9 00 56    LDA #$5600              A:1801 X:A2FB Y:0008 P:envmxdizc
$B0/84AA 8D 16 21    STA $2116  [$7E:2116]   A:5600 X:A2FB Y:0008 P:envmxdizc
$B0/84AD A9 00 AE    LDA #$AE00              A:5600 X:A2FB Y:0008 P:envmxdizc
$B0/84B0 8D 02 43    STA $4302  [$7E:4302]   A:AE00 X:A2FB Y:0008 P:eNvmxdizc
$B0/84B3 A9 00 0A    LDA #$0A00              A:AE00 X:A2FB Y:0008 P:eNvmxdizc
$B0/84B6 8D 35 43    STA $4305  [$7E:4305]   A:0A00 X:A2FB Y:0008 P:envmxdizc
$B0/84B9 E2 20       SEP #$20                A:0A00 X:A2FB Y:0008 P:envmxdizc
$B0/84BB A9 80       LDA #$80                A:0A00 X:A2FB Y:0008 P:envMxdizc
$B0/84BD 8D 15 21    STA $2115  [$7E:2115]   A:0A80 X:A2FB Y:0008 P:eNvMxdizc
$B0/84C0 A9 8B       LDA #$8B                A:0A80 X:A2FB Y:0008 P:eNvMxdizc
$B0/84C2 8D 04 43    STA $4304  [$7E:4304]   A:0A8B X:A2FB Y:0008 P:eNvMxdizc
$B0/84C5 A9 01       LDA #$01                A:0A8B X:A2FB Y:0008 P:eNvMxdizc
$B0/84C7 8D 0B 42    STA $420B  [$7E:420B]   A:0A01 X:A2FB Y:0008 P:envMxdizc
$B0/84CA C2 20       REP #$20                A:0A01 X:A2FB Y:0008 P:envMxdizc

Nothing shows up in VRAM at this point. Sad
Nightcrawler
Guest
« Reply #7 on: April 23, 2007, 12:07:28 pm »

Ok.. so we know:

1. Your DMA code is correct.
2. It actually is being executed when expected.
3. The game doesn't interfere with the register settings.
4. DMA must execute as per hardware design.

Therefore.. I can think of a few more things...

1. Does the code still fail on an older version of ZSNES? I only ask because this will eliminate all possibilities of trying to send data to VRAM while not under vblank. Being that the other three circumstances work, this probably is not the case, but I like to be sure. If it worked with ZSNES for some odd reason, that would be the avenue to peruse. The DMA may fire, but the data does not actually get to VRAM.

2.   Not to insult your intelligence, but are you sure you're looking in VRAM and at the right VRAM address for the results? In BSNES you also have to refresh the contents with the update button to see the current values as I don't think it's updated on the fly by default like Geiger's.
If you write to location $5600 as set via $2216, you're actually writing to effective location $AC00 which is where you'll need to look if you want to view VRAM contents. VRAM is only addressable to $7fff via $2116. It's because there are two VRAM chips that you can get an effective VRAM range of 0-ffff.

3. A savestate is not too useful if the condition Disch mentioned exists. If the game overwrote VRAM again soon after your DMA, the savestate would show that data and visually it would appear as if your transfer never happened.

Aside from those three things, I can't think of much else that could possibly be happening. DMA is executing. It's just either not going where you think it's going, or it is trying to go there, but can't get there. And check and double check your source data is where it should be. It's quite easy to bang your head over an issue and then find out, you had moved some data around, or were dyslexic when putting down the source address.
aspire
Guest
« Reply #8 on: April 23, 2007, 12:14:24 pm »

Finally fixed! After talking to Disnesquick, he pointed out what the problem is...

" Yes it's as I suspected. The databank is screwed up. If you look at tge positions actually being written then you'll see they are 7E:430B and the like rather than 00:430B which is what you actually need. What you're doing here is just writing to RAM rather than the DMA registers! Just do a LDA #$00 PHA PLB at the start of the routine to write to the correct bank (the registers) and that should fix your problems. Remember to restore the bank at the end (wrap PHB PHP and PLP PLB around the whole routine to avoid corruption of calling code)."

I wont forget this next time. What a chore!

Thanks for helping me with this.
Disch
Guest
« Reply #9 on: April 23, 2007, 01:14:59 pm »

aha!

That hadn't even crossed my mind.

Glad to hear you got it working  :thumbsup:
byuu
Guest
« Reply #10 on: April 23, 2007, 04:36:27 pm »

A shame you posted the tracelog in Geiger's format. Mine would have shown the DBR register, as well as the H/V registers to verify you had enough vblank time for the complete transfer. But you were still able to get it fixed, so congratulations on that.
Nightcrawler
Guest
« Reply #11 on: April 24, 2007, 07:53:18 am »

+1 for Disnesquick! Smart cookie. I didn't even think about that. Hopefully that'll stick in my head if I ever make the same mistake in the future. That's definitely one of those annoying problems that could cause some head banging.
MathOnNapkins
Guest
« Reply #12 on: May 27, 2007, 02:36:41 am »

As inelegant as Geiger's Debugger output is, you could have caught it from his original log.

$B0/84C7 8D 0B 42    STA $420B  [$7E:420B]   A:0A01 X:A2FB Y:0008 P:envMxdizc

Also, you can enable vcount and hcount in the debugger, as well as DBR and stack pointer. You just need to uncheck "squelch". The real problem was that no one was thinking about the data bank register :/. Just want to get all the info out there. Geiger's Debugger is a flawed tool but I use it every day and I know what it can do. As a tip to anyone trying to track DMA, set a write breakpoint on $00420B. DMA logging on its own goes so fast in real time that it's pretty useless.

Though I should try BSNES out again, I haven't used it since... version .15 I think.
Nightcrawler
Guest
« Reply #13 on: May 28, 2007, 09:20:12 am »

Quote from: MathOnNapkins on May 27, 2007, 02:36:41 am
As inelegant as Geiger's Debugger output is, you could have caught it from his original log.

$B0/84C7 8D 0B 42    STA $420B  [$7E:420B]   A:0A01 X:A2FB Y:0008 P:envMxdizc

Also, you can enable vcount and hcount in the debugger, as well as DBR and stack pointer. You just need to uncheck "squelch". The real problem was that no one was thinking about the data bank register :/. Just want to get all the info out there. Geiger's Debugger is a flawed tool but I use it every day and I know what it can do. As a tip to anyone trying to track DMA, set a write breakpoint on $00420B. DMA logging on its own goes so fast in real time that it's pretty useless.

Though I should try BSNES out again, I haven't used it since... version .15 I think.

Yes, that was indeed the problem. I thought that was obvious. The information was available, nobody thought about it. Sometimes it doesn't matter like for instance writing to the lower 128K of RAM. You can do that in a LoROM setup from most banks. It's not hard to overlook the data bank register even if you full well know the rules and how it works. I know for fact that every person who responded in this topic knows how DMA works and understands why it didn't work in this case. It just wasn't caught. No need to give us all an undecided face.  Undecided\

You can be decided. :laugh:
MathOnNapkins
Guest
« Reply #14 on: May 28, 2007, 01:09:48 pm »

That wasn't really my point. My point was to inform people that GSD has all the information people need in the tracelog if you set it up properly. (hell, even the default setup is usually enough, as it is in this case)
« Last Edit: May 28, 2007, 01:24:25 pm by MathOnNapkins »
Pages: [1] 2  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC