News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: N64 DMA specifics  (Read 3188 times)

tmk

  • Newbie
  • *
  • Posts: 2
    • View Profile
N64 DMA specifics
« on: May 21, 2014, 05:46:40 pm »
I'm trying to make an ASM hack for the N64 that involves DMA. I just recently learned about DMA and so I'm just messing around and trying to get the hang of it. Unfortunately some very basic code that involves 2 almost-consecutive DMAs doesn't work, and crashes the emulator I'm using (Nemu). I've been unable to find a good tutorial online that fixes my problem so I hope somebody here has the expertise.

My code is for Super Smash 64, what I'm trying to do specifically isn't really relevant as I'm just testing stuff right now.

Here is my code:

JUMP OUT:
34C98 J 0x803A0000 
34C9C NOP 

NEW CODE: 
3A0000 LUI k1,0x1022 
4 ORI k1,k1,0xDDCC 
8 BNE t6,k1,0x803A003C 
C NOP 
10 ORI k1,r0,0x03FF 
4 SW k1,0x000C(t0) 
8 NOP 
C SW k1,0x0010(t0) 
20 LW k1,0x0010(t0) 
4 BNE k1,r0,-1 
8 NOP 
C LUI k1,0x8004 
30 ORI k1,k1,0x3974 
4 SW k1,0x0000(t0) 
8 LUI k1,0x1022 
C ORI k1,k1,0xDF48 
40 SW k1,0x0004(t0) 
4 ORI t9,r0,0x0007 
8 J 0x80034CB8 
C SW t9,0x000C(t0) 

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: N64 DMA specifics
« Reply #1 on: May 23, 2014, 02:00:50 pm »
I'm just going to assume that T0 points to the PI registers (A4600000), but that really is something you should have specified (or at least region+version).  I'm also assuming you've already dealt with the cache and the error lies here as opposed to the code you're returning to.

I expect the reason the code fails in the second DMA is that you set the PI Status value so the loop will never occur.  The PI interrupt is triggered by a write to either PI read length or PI write length.  PI Status will be nonzero if the PI can not receive a new transfer request or it broke.  You must wait for the value to clear or run the risk of bad things happening.

Several other problems here though that would prevent running on console:
  • Target rdram addresses are hardware addresses, so they don't use the 80-.  On hardware that wouldn't work, since the 80- specifies you're using a cached mirror.  The same applies to A0-, or any TLB mapped address.  Only use hardware addresses with the PI.
  • Don't use K1.  Any code using standard libraries presumes K* are unsafe.  The exception handler uses them without storing the previous values, so unless you disable exceptions don't ever use them outside of the exception handler.
  • Don't save a value into PI Status (line 1C) especially before you read it.  To be honest, I think it's read-only on console.  Never, never write to this register.
[li]This:
[/li][/list]
Code: [Select]
BNE T6,K1,803A003Cis executing this:
Code: [Select]
ORI K1,K1,DF48 
SW K1,0004 (T0) 
ORI T9,R0,0007 
J 80034CB8 
SW T9,000C (T0)
    That means you didn't set an rdram address, so whatever value was there is rolled over.  It also means your ROM address will be 1022DFCC, which is the previous value of K1 OR 0xDF48.  You still execute the DMA, but it effectively corrupts whatever was at the previous address.[/li]

One thing you'll probably find listed wrong in docs is that ROM and rdram addresses must be HW (16bit) aligned, not word aligned.  Lengths should be mutliples of 2 (counting zero, so -1 of what you want).

tmk

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: N64 DMA specifics
« Reply #2 on: May 23, 2014, 04:52:33 pm »
Zoinkity, you are literally my favorite person right now. I've spent days trying to figure this out and finally I've got the info I need. Turns out the problem, after all, was my failure to use the hardware rdram address. This was very subtle and since the CPU always uses 80 I didn't pick up on it.

About the other things in your reply:

-BNE T6,K1,803A003C should be BNE T6,K1,803A0048 and that was the code I used in the emulator. My mistake.

-t0 does point to the PI registers, you're correct. I really should have specified that. Also this is US version of SSB64.

-On some hacking guides I've read, they recommend using K1, even going so far to suggest using it the most because the main game code doesn't mess with it. I see your point, but I'm wondering if it is okay to use in a situation where no exceptions/interrupts are expected. Obviously this isn't one of those situations though.

-Good to know that addresses need to only be HW aligned.

Again, this was immensely helpful to me. I've spent months learning about how the N64 and this game operate and I'm very close to making the codes I want. This DMA bs was a major roadblock.

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: N64 DMA specifics
« Reply #3 on: May 25, 2014, 08:57:26 am »
All registers are safe when interrupts and exceptions are disabled.  Thinking on the situation more, since you borrowed your p->PI regs they probably already disabled interrupts.  If you don't disable interrupts though the exception handler can clobber those values.

In case you need it, I have filelists for all the files in every known version of Smash Brothers.  The decompressor is hit-and-miss about whose system it works on, but at the least filelists help.
http://www.mediafire.com/?zije4b8bbc15wvb

The ones you want are:
SMASH BROTHERS-NALE.txt
SMASH BROTHERS-NALJ.txt
SMASH BROTHERS-NALP.txt
SMASH BROTHERS-NALU.txt
-for US, japanese, PAL, and Australia, respectively.

Decompression method for those VPK files can be found in module_vpk.  It works, but I'm awful at programming anything.