It is currently Mon Sep 24, 2018 1:21 pm

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 103 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next
Author Message
PostPosted: Wed Apr 25, 2018 2:17 pm 
Offline

Joined: Fri Mar 01, 2013 4:46 am
Posts: 301
I'm not sure. I'm just doing the test right at the very beginning of the NMI. It's the only code I have running, then I end with an RTI.


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 2:45 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 963
You have to write two bytes minimum to OAM or CGRAM before it shows up in the actual memory. There's a word buffer.


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 2:56 pm 
Offline

Joined: Fri Mar 01, 2013 4:46 am
Posts: 301
So if X,Y are 16 bits, and I want the order of bytes stored to oam are 88,FF, I'd do LDY #$FF88 STA $2104

Am I understanding that correctly?


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 3:20 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20572
Location: NE Indiana, USA (NTSC)
For OAM, both the even byte and the odd byte have to be stored to the same address, one after the other.


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 3:31 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 963
In other words, you can't use 16-bit writes, because then the top byte will go to $2105. Writing $FF88 to $2104 as a 16-bit value would set all four BG layers to 16x16 tile size, set the BG3 priority bit, and put the PPU in Mode 7, and OAM would still be blank.

More importantly, did you mean STY and not STA?


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 4:37 pm 
Offline

Joined: Fri Mar 01, 2013 4:46 am
Posts: 301
93143 wrote:
More importantly, did you mean STY and not STA?


Yes, STY, sorry I had a typo.

And I got the oam to write without dma, the info on the write register being a word helped!


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 5:15 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3607
Location: Mountain View, CA
infidelity wrote:
And I got the oam to write without dma, the info on the write register being a word helped!

From my previous post:
koitsu wrote:
$2104 is write-only an 8-bit double-write register (i.e. it's like $2122 but for OAM).

FeelsBadMan. By "8-bit double-write", that means the MMIO register itself is a single address (ex. $2104), not a pair of addresses (ex. $2104 + $2105), and that it requires you to write twice to it (low byte first, then high byte). It's just like MMIO register $2122 in this respect. A "full 16-bit address" would be like $2116 and $2117 (for PPU RAM access), where you can do rep #$10 ldx #$1234 stx $2116 to write $34 to $2116 and $12 to $2117.

The SNES has a few "inconsistencies" like this (some MMIOs are 8-bit and double-write, others are two MMIO registers in sequence to make life easier when using 16-bit registers), so you really have to read the documentation slowly/clearly. This is one reason why I really don't like the Super Famicom Development Wiki's format of MMIO register descriptions:

Code:
2104  wb++--
        dddddddd

2116  wl++?-
2117  wh++?-
        aaaaaaaa aaaaaaaa

2122  ww+++-
        -bbbbbgg gggrrrrr

Cryptic shit. Sorry, but my SNES docs were much more clear:

Code:
|rwd2?|Address|Title & Explanation                                           |
||||||-----------------------------------------------------------------------|
||||||                                                                       |
||||||__  ?: Don't know what the statistics on this register are             |
|||||____ 2: 2 byte (1 word) length register                                 |
||||_____ d: Double-byte write required when writing to this register        |
|||______ w: Writable register                                               |
||_______ r: Readable register                                               |

|----------------------------------------------------------------------------|
|rwd2?|Address|Title & Explanation                                           |
|----------------------------------------------------------------------------|
...
| wd  |$2104  |OAM data register [OAMDATA]                                   |
|     |       |???????? ????????                                             |
...
| w 2 |$2116  |Video port address [VMADDL/VMADDH]                            |
|     |       |???????? ????????                                             |
...
| wd  |$2122  |Colour data register [CGDATA]                                 |
|     |       |xxxxxxxx              x: Value of colour.                     |

This all should help explain why bits 4 and 2-0 of $43x0 are so incredibly important. And you'll find other docs online that document these wrong as well (such as saying %010 is the same as %000 -- no!). Hell, even I got mine wrong back in the 90s. Sticking to general DMA:

Code:
| w   |$43x0  |DMA Control register [DMAPX]                                  |
|     |       |vh0cbaaa              v: 0 = CPU memory -> PPU.               |
|     |       |                         1 = PPU -> CPU memory.               |
|     |       |                      h: For HDMA only:                       |
|     |       |                         0 = Absolute addressing.             |
|     |       |                         1 = Indirect addressing.             |
|     |       |                      c: 0 = Auto address inc/decrement.      |
|     |       |                         1 = Fixed address (for VRAM, etc.).  |
|     |       |                      b: 0 = Automatic increment.             |
|     |       |                         1 = Automatic decrement.             |
|     |       |                      a: Transfer type:
|     |       |                         000 = 1 address write twice: LH.     |
|     |       |                         001 = 2 addresses: LH.               |
|     |       |                         010 = 1 address write once.          |
|     |       |                         011 = 2 addresses write twice: LLHH  |
|     |       |                         100 = 4 addresses: LHLH              |

Here's another one, more clear than mine, but still wrong (%010 is not the same as %000!)
Code:
$43x0: AB0CDEEE    DMA Setup Register [DMAPx]
         A -- Transfer Direction (0==CPU -> PPU, 1==PPU -> CPU)
         B -- HDMA Addressing Mode (0==Absolute, 1==Indirect)
         C -- CPU addr Auto inc/dec selection (0==Increment, 1==Decrement)
         D -- CPU addr Auto inc/dec enable (0==Enable, 1==Disable (fixed))
         E -- DMA Transfer Word Select
            For DMA: (B0-B3 are the source data bytes, $21XX is PPU destination)
               000 == Write 1 byte, B0->$21xx
               001 == Write 2 bytes, B0->$21xx B1->$21XX+1
               010 == Identical to 000
               011 == Write 4 bytes, B0->$21XX B1->$21XX B2->$21XX+1 B3->$21XX+1
               100 == Write 4 bytes, B0->$21XX B1->$21XX+1 B2->$21XX+2 B3->$21XX+3

What it should have said:
Code:
               010 == Write 2 bytes, B0->$21xx B0->$21xx (i.e. same byte, written twice)


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 8:48 pm 
Offline

Joined: Sat Apr 25, 2015 1:47 pm
Posts: 420
Location: FL
koitsu wrote:
(i.e. same byte, written twice)


Are you sure about this part? My understanding (based on higan) is that the A-bus address is always updated after every byte written regardless of transfer type.

(Which, given that regular DMA size is measured in bytes and not "transfer units", means that it would be equivalent to %000 for regular DMA, but not HDMA)


Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 10:45 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3607
Location: Mountain View, CA
Revenant wrote:
koitsu wrote:
(i.e. same byte, written twice)


Are you sure about this part? My understanding (based on higan) is that the A-bus address is always updated after every byte written regardless of transfer type.

(Which, given that regular DMA size is measured in bytes and not "transfer units", means that it would be equivalent to %000 for regular DMA, but not HDMA)

Honestly, I'm not sure. Quoting official documentation:

(2018/08/29 Edit: attachments removed.)

The description for %010 means one of two things:

a) Write a single byte to the destination address two times (ex. B0->$21xx B0->$21xx)
b) Write a single byte to the destination address and destination address+1 (ex. B0->$21xx B0->$21xx+1)

From the diagrams we can tell:

* There is a difference between %000 and %010 ("1-ADDRESS" vs. "1-ADDRESS (WRITE TWICE)")
* The same description is used for HDMA (but with additional specification of L,L for low byte, low byte)
* The description for general DMA %010 is a little vague, but HDMA helps gives us a slightly better idea.

Conclusion: if the %010 description meant (b), then it would have been listed as "2-ADDRESS" (since that is certainly the terminology used to refer to writing to multiple (sequential) destination addresses).

I have several revisions of manuals (not just the popular one that circulates), across ~3 years, and they all denote %010 the above way.

Going back to "Grog's Guide to DMA and HDMA" as a comparison:

Code:
$43x0: AB0CDEEE    DMA Setup Register [DMAPx]
         A -- Transfer Direction (0==CPU -> PPU, 1==PPU -> CPU)
         B -- HDMA Addressing Mode (0==Absolute, 1==Indirect)
         C -- CPU addr Auto inc/dec selection (0==Increment, 1==Decrement)
         D -- CPU addr Auto inc/dec enable (0==Enable, 1==Disable (fixed))
         E -- DMA Transfer Word Select
            For DMA: (B0-B3 are the source data bytes, $21XX is PPU destination)
               000 == Write 1 byte, B0->$21xx
               001 == Write 2 bytes, B0->$21xx B1->$21XX+1
               010 == Identical to 000
               011 == Write 4 bytes, B0->$21XX B1->$21XX B2->$21XX+1 B3->$21XX+1
               100 == Write 4 bytes, B0->$21XX B1->$21XX+1 B2->$21XX+2 B3->$21XX+3

            For HDMA: (B0-B3 are the source data bytes, $21XX is PPU destination)
               000 == Write 1 byte, B0->$21xx
               001 == Write 2 bytes, B0->$21XX, B1->$21XX+1
               010 == Write 2 bytes, B0->$21XX, B1->$21XX
               011 == Write 4 bytes, B0->$21XX, B1->$21XX B2->$21XX+1 B3->$21XX+1
               100 == Write 4 bytes, B0->$21XX, B1->$21XX+1, B2->$21XX+2, B3->$21XX+3

The description of %010 here claims %010 is the same as %000, yet HDMA's %010 writes two (different) bytes to the same destination ("1-ADDRESS")... except the official documentation clearly says L,L not L,H. That would mean the same source byte.

Super Famicom Development Wiki says this -- and documents even more modes that aren't in the official documentation:

Code:
43x0 rwb++++
        da-ifttt
        d        = Transfer Direction.^
         a       = HDMA Addressing Mode.^^
           i     = DMA Address Increment.^^^
            f    = DMA Fixed Transfer.^^^^

        ttt  = Transfer Mode.
            000 => 1 register write once             (1 byte:  p               )
            001 => 2 registers write once            (2 bytes: p, p+1          )
            010 => 1 register write twice            (2 bytes: p, p            )
            011 => 2 registers write twice each      (4 bytes: p, p,   p+1, p+1)
            100 => 4 registers write once            (4 bytes: p, p+1, p+2, p+3)
            101 => 2 registers write twice alternate (4 bytes: p, p+1, p,   p+1)
            110 => 1 register write twice            (2 bytes: p, p            )
            111 => 2 registers write twice each      (4 bytes: p, p,   p+1, p+1)

p in this context is the first individual byte read from the source. So, B0->$21xx B0->$21xx. This could also (to me) be represented as what Nintendo said: "1-ADDRESS (WRITE TWICE) L,L".

I don't know of any games which use %010 off the top of my head (do I look like I sit around disassembling every commercial game and analysing their DMA params? Haha :-) ), but it's safe to say we can't trust emulator source code, and everyone's documentation is either inconsistent or wrong (including my own).

Possible to test on hardware? Absolutely! Should it be tested on hardware? Absolutely!


Last edited by koitsu on Wed Aug 29, 2018 6:46 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Wed Apr 25, 2018 10:51 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7548
Location: Seattle
I used HDMA mode 2 in my PPU bus activity program to adjust the vertical scrolling for the offset-per-tile layer.


Top
 Profile  
 
PostPosted: Thu Apr 26, 2018 6:02 am 
Offline

Joined: Fri Mar 01, 2013 4:46 am
Posts: 301
I'll have to recheck my routine for $2104, I'm doing a double write, but it's storing at 2 addresses in oam, but I'm able to load a table for the values I want. There's a lot for me to digest and understand correctly, a bit overwhelmed a points, but as long as I get the results I'm trying to accomplish, I'll know I'm on the right track and continously study what's going on, that is giving me my desired results.

I have another question regarding "WAI"

Is that 1 byte opcode the same as what the NES uses for cpu cycles (LDA $2002, DEX, BPL back to DEX)? I want to know examples of how to use WAI properly.


Top
 Profile  
 
PostPosted: Thu Apr 26, 2018 6:09 am 
Offline

Joined: Sat Apr 25, 2015 1:47 pm
Posts: 420
Location: FL
koitsu wrote:
I don't know of any games which use %010 off the top of my head (do I look like I sit around disassembling every commercial game and analysing their DMA params? Haha :-) ), but it's safe to say we can't trust emulator source code, and everyone's documentation is either inconsistent or wrong (including my own).

Possible to test on hardware? Absolutely! Should it be tested on hardware? Absolutely!

I don't know why I somehow failed to remember this in my last post (other than it being somewhat late at night), but the last demo I wrote/released uses %010 for CGRAM color gradients. Presumably, so does every other game that uses HDMA to perform color gradient effects. So yes, it writes two different bytes.

My interpretation of the official documentation's "1-ADDRESS (WRITE TWICE)" is that it's only supposed to describe which type of register it's designed to write to. It clearly also states that it "transfers" two bytes, not just performs two writes. (Likewise, "L" and "H" are clearly referring to register addresses, not source bytes.)


Top
 Profile  
 
PostPosted: Thu Apr 26, 2018 12:40 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3607
Location: Mountain View, CA
infidelity wrote:
I have another question regarding "WAI"

Is that 1 byte opcode the same as what the NES uses for cpu cycles (LDA $2002, DEX, BPL back to DEX)? I want to know examples of how to use WAI properly.

With NMI-on-VBlank enabled, you can use wai in your main loop to effectively wait for VBlank to finish (e.g. wai / lda #1 would sit and wait for NMI to occur, then after rti in your NMI routine, the next instruction run would be lda #1). Technically it waits for any interrupt (NMI, IRQ, ABORT, or RESET (not that the latter matters)). It's quicker, easier, faster (cycle-wise) and more precise (timing-wise) than polling $4210 and watching bit 7 (akin to the above loop on the NES) but it depends on what your needs are.

If you don't have a 65816 instruction manual by now, then get it. Pages 192-202 (Chapter 13) and page 420 (opcode description) are useful.


Top
 Profile  
 
PostPosted: Thu Apr 26, 2018 1:20 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3607
Location: Mountain View, CA
Revenant wrote:
I don't know why I somehow failed to remember this in my last post (other than it being somewhat late at night), but the last demo I wrote/released uses %010 for CGRAM color gradients. Presumably, so does every other game that uses HDMA to perform color gradient effects. So yes, it writes two different bytes.

Respectfully, this description is no better than any of the existing documentation. :\ Which is it?

a) B0->$21xx B0->$21xx (e.g. byte 0 of source written to $21xx, followed by byte 0 of source written to $21xx)
b) B0->$21xx B1->$21xx (e.g. byte 0 of source written to $21xx, followed by byte 1 of source written to $21xx)

If you're using it for CGRAM data (ex. writes to $2122) then it's almost certainly (b), which means that yes, the very last paragraph of my previous post is incorrect.

Regardless, %010 is not the same as %000 (re: Grog's guide). Meanwhile, the Super Famicom Development Wiki doesn't bother to explain what p is, when if (b) is true, then p refers to the destination address only -- and that the source address is effectively always incrementing by 1 (which would correlate with what you said earlier, re: A-bus address always incrementing). It's like whoever wrote this was trying to be terse through implication (and it's described differently in two different parts of the site -- here we are again with an example of why wikis are not inherently better for documentation).

Overall, I actually prefer the nomenclature from Grog's guide since it makes it clearer what source data is going to what destination. This thread is a good example of why denoting both is important. Without both, the programmer doesn't know how to format the data that's used as the source.

Revenant wrote:
My interpretation of the official documentation's "1-ADDRESS (WRITE TWICE)" is that it's only supposed to describe which type of register it's designed to write to. It clearly also states that it "transfers" two bytes, not just performs two writes. (Likewise, "L" and "H" are clearly referring to register addresses, not source bytes.)

It's subjective. Two writes to a single MMIO register still technically is "transferring" two bytes of data. What matter is *which* two bytes it's transferring (from the source). Case in point: %001 is described "2 BYTE", "2-ADDRESS (VRAM etc.) L,H" -- two different source bytes are transferred, to two different destination addresses (i.e. B0->$21xx, B1->$21xx+1).

Nintendo's documentation has always been unclear/vague in this regard, but what we have in the community is still not crystal clear to programmers. I mean we can sit here and debate what's what 'til the cows come home, but this thread acts as solid proof that it's not clear to programmers. And without clear/concise examples that can be referenced in the existing documentation, the situation doesn't improve. (To this, please do not tell me "Well it's a wiki, go fix it yourself")


Top
 Profile  
 
PostPosted: Thu Apr 26, 2018 2:59 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 963
Revenant wrote:
the last demo I wrote/released uses %010 for CGRAM color gradients. Presumably, so does every other game that uses HDMA to perform color gradient effects.

I use %x11, so that I can set both the address and the colour with one channel. This method wastes a write because the address gets hit twice, but unfortunately (p, p+1, p+1) is not an available HDMA pattern.

Sadly, (p, p, p, p) isn't available either, so if you want to do >8 consecutive colours you have to use regular DMA in an IRQ...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 103 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 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