It is currently Wed Oct 17, 2018 8:02 pm

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 11:54 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2760
Something that has always bothered me is how many registers you need to write to in order to get DMA to working.

Not only do you have to touch $4300-$4306 and $420b, but if you need to touch other registers depending on what you're trying to do:

$2115 to $2117 for VRAM
$2102 and $2103 for OAM
$2121 for CGRAM
$2181 to $2183 for WRAM

I remember somebody saying "but you only need to make a routine that writes to these registers ONCE" but how do I make a routine that writes to a bunch of registers without having to pass a ton of variables, which would require as much code as I would need to write to said registers in the first place?

I know there are some commonly used arrangements such as:

-Writing bytes to $2104
-Writing bytes to $2122
-Writing bytes to $2180
-Writing words to $2118, incrementing by 1 when $2119 is written
-Writing bytes to $2118, incrementing by 1 when $2118 is written
-Writing bytes to $2119, incrementing by 1 when $2119 is written
-Writing words to $2118, incrementing by 32 when $2119 is written

Actually there are a TON of commonly used arrangements, and even more potentially useful arrangements, but I know for fact that most combinations don't make any sense, so there must be a way of pre-baking in patterns that make sense.

There's also a dilema of immediate parameters vs variable parameters. Immediate parameters you can store in an array, but variable parameters you have to either hardcode or use some kind of parameter passing method.


Top
 Profile  
 
 Post subject: Re: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 12:07 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3634
Location: Mountain View, CA
Most people made macros to do this. There wasn't (and isn't) a fear of "passing a ton of {variables,arguments}". It's inherent to programming.

In commercial games I've seen source code for, most use a combination of macros for some DMA routines, while others are actually jsl-able based on what's passed on the stack, or referenced directly by a small set of variables in DP/RAM that are dedicated solely for this purpose. SNES has a tolerably large amount of RAM, so this isn't very wasteful.

The advice "but you only need to make a routine that writes to these registers ONCE" is almost certainly referring to the fact that you can write a general-purpose routine that handles $4300-4306 + $420b for you, while the rest is up to you.

Some games I believe have some DMA that's done inside of NMI, where some of the "source" values come from DP/RAM variables, while others are hard-coded (e.g. your graphics transfer routine uses a static length of data so you don't need to tweak the DMA length register every time; palette update DMA, etc.) based on a global variable that controls whether or not the DMA should be done (so that it isn't being done every single frame). But that's more about "saving time" (cycle-wise) than "how many registers I have to write to".

if the concern is truly how many registers you need to write to (read: the quantity of), then I don't think anything can be done about that. You're going to have to write to said registers to accomplish DMA in the fashion you want regardless. It's how the system was designed. How can this be fought aside from inventing a time machine and going back in time to Nintendo Co. Ltd and demanding they design the system differently? Hmm, feeling of deja vu...


Top
 Profile  
 
 Post subject: Re: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 12:20 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6887
Location: Canada
Macros are indeed a great way to eliminate subroutine argument boilerplate. In ca65:

Code:
.macro FUNC a0, a1, a2, a3
   lda #a0
   sta arg0
   ldy #a1
   ldx #a2
   lda #a3
   jsr func
.endmacro

; calling becomes one line in your code
FUNC 1, 2, 3, 4


And if you later decide that you're calling this function so much that it would be good to optimize the calls for size instead of speed you can modify the function and macro without having to change any of the other calling code:

Code:
.macro FUNC a0, a1, a2, a3
   jsr func
   .byte a0, a1, a2, a3
.endmacro


In this case, the start of func should now add +4 to the return value on the stack, and load the 4 variables from where the original return address pointed. Adds some cycles of overhead but it reduces the argument part of each call to just the direct bytes.

One thing that's hard to deal with in macros is immediate values vs. arguments that should come from memory locations, current registers, etc. So you can't treat it like a C function where any result goes into an argument, but you can make variations of the macro to take different argument types if you need that.


Top
 Profile  
 
 Post subject: Re: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 12:55 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20662
Location: NE Indiana, USA (NTSC)
Fortunately, the 65816 has just enough registers to pass all arguments of a DMA copy. From my first attempt at programming the Super NES:
Code:
;;
; Copies data to the S-PPU using DMA channel 0.
; @param X source address
; @param DBR source bank
; @param Y number of bytes to copy
; @param A 15-8: destination PPU register; 7-0: DMA mode
.proc ppu_copy
  php
  setaxy16
  sta $804300
  stx $804302
  sty $804305
  seta8
  phb
  pla
  sta $804304
  lda #%00000001
  sta $80420B
  plp
  rtl
.endproc

The use of the mirror in $800000 forces the write to go to a bank with MMIO even if DBR is in $40-$7F or $C0-$FF.


Top
 Profile  
 
 Post subject: Re: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 1:12 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2760
That gives me an idea:

How about:
X = VRAM address
Y = length
A = source address
DP = source bank

Code:
stx $2116
ldx #$1801
stx $4300
sta $4302
sep #$20
tdc
sta $4304
sty $4305
lda #$80
sta $2115
lda #$01
sta $420b


Top
 Profile  
 
 Post subject: Re: Abstracting DMA code
PostPosted: Tue Sep 04, 2018 1:57 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3634
Location: Mountain View, CA
Yup, seen games that do it that way too. Just make sure that if it's a subroutine you push/pop 16-bit A/X/Y and P if appropriate.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: Jarhmander and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group