Proper way to emulate DMA transfers.

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Proper way to emulate DMA transfers.
by on (#189239)
Hi all, I am currently writing an SNES emulator, and have been implementing the CPU so far. I have implemented about 120 opcodes and have gotten it to be able to execute some code in Super Mario World ROM. For debugging, I have it output some disassembly. I have gotten to the point where the SMW rom executes what looks to be a DMA transfer... I have never written an emulator for a game console before and was wondering if anyone here could point me in the right direction on how DMA transfer will work in an emulated sense.

My assumption is that CPU loop stops and we actually modify the array that represents RAM directly and move the PC value the number of bytes that were read? (In a sense, this would behave like an interrupt, right?)

The piece of disassembly I have encountered is along the lines of:

Code:
LDA $9277, X


At $9277, I see there are bytes $42 and $26 loaded. Which prompts a series of consecutive bytes to follow:

Code:
7C 92 00 F0 A0 04 F0 80 05 00


I actually am using a disassembly for reference and it looks to be referring to this piece of code here:

Site for reference:
http://caffie.net:31415/root/smw-irq/bl ... ank_00.asm

Image

Any thoughts?

Thanks!
Re: Proper way to emulate DMA transfers.
by on (#189267)
documentation

HDMA is DMA that automatically runs in HBLANK when enabled.
Re: Proper way to emulate DMA transfers.
by on (#189272)
I thought it was called HDMA because it ran in horizontal blanking, not vertical blanking.
Re: Proper way to emulate DMA transfers.
by on (#189275)
...fixed.
Re: Proper way to emulate DMA transfers.
by on (#189278)
creaothceann wrote:
documentation

HDMA is DMA that automatically runs in HBLANK when enabled.


So basically, I would watch for a flag in HBLANK or some sort and then proceed with emulating the transfers from there?

In my mind:
1. CPU execution stops due to HBLANK.
2. Handle the HDMA transfer. => From here, the PC is incremented to transfer the appropriate data.
3. Proceed with CPU execution again?

Thanks.
Re: Proper way to emulate DMA transfers.
by on (#189280)
PC? As in the program counter? No, that shouldn't be touched at all, it transfers data from whatever HDMA tables are pointed to in the HDMA registers.
Re: Proper way to emulate DMA transfers.
by on (#189283)
Nicole wrote:
PC? As in the program counter? No, that shouldn't be touched at all, it transfers data from whatever HDMA tables are pointed to in the HDMA registers.


Ah, ok. I guess my main and probably very stupid question is... How would we move past the following bytes in the emulator:

If the PC (program counter) if left off around here:
Code:
7C 92 00 F0 A0 04 F0 80 05 00


Those would be interpreted as opcodes and operands -- but it looks like from the assembly reference, it looks to just be raw data.
Re: Proper way to emulate DMA transfers.
by on (#189286)
The PC is never there in the first place, it doesn't need to move past them.
Re: Proper way to emulate DMA transfers.
by on (#189293)
Did you already emulate the RTS opcode, or at least understand what RTS is supposed to do?
Re: Proper way to emulate DMA transfers.
by on (#189294)
Nicole wrote:
The PC is never there in the first place, it doesn't need to move past them.


Ah I realize this now after tracing this... So basically it's something like this for this snippet of code:

Code:
setup_window_HDMA:
   LDX.b #$04                            ;$009250   \ Index for DMA set up
.loop                                  ;                \ Upload to $4374 to $4370
   LDA.w window_HDMA_settings,X      ;$009252     |
   STA.w $4370,X                            ;$009255     |
   DEX                                       ;$009258     |
   BPL .loop                                    ;$009259    /
   LDA.b #$00                            ;$00925B    \ HDMA Data bank $00
   STA.w $4377                            ;$00925D    /


....

window_HDMA_settings:                 
   db $41,$26                                               ;$009277
   dl window_HDMA_data

window_HDMA_data:
   db $F0                                                      ;$00927C
   dw $04A0
   db $F0
   dw $0580
   db $00


X = $04

LDA $9277, X => LDA $927C, Then A = $00
STA $4370, X => STA $4374, Then $00 gets stored in $4370
DEX => X = 3

Repeat until X is negative

And we will have:

Code:
$4370 -> $41
$4371 -> $26
$4372 -> $7C
$4373 -> $92
$4374 -> $00


Apologies for being so newbie. Still trying to learn assembly, hehe.
Re: Proper way to emulate DMA transfers.
by on (#189295)
nocash wrote:
Did you already emulate the RTS opcode, or at least understand what RTS is supposed to do?


Yes -- i realized now that it was my misunderstanding in the assembly code that caused me to trace it the incorrect way initially. But correct me if I am wrong:

RTS will basically:

- Pull the PC values from the stack.
-> increments the PC by 1 to point to the next instruction of where the jump occurred.