new to snes environment, have some questions.

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
infidelity
Posts: 490
Joined: Fri Mar 01, 2013 4:46 am

Re: new to snes environment, have some questions.

Post by infidelity »

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.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: new to snes environment, have some questions.

Post by 93143 »

You have to write two bytes minimum to OAM or CGRAM before it shows up in the actual memory. There's a word buffer.
infidelity
Posts: 490
Joined: Fri Mar 01, 2013 4:46 am

Re: new to snes environment, have some questions.

Post by infidelity »

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?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: new to snes environment, have some questions.

Post by tepples »

For OAM, both the even byte and the odd byte have to be stored to the same address, one after the other.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: new to snes environment, have some questions.

Post by 93143 »

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?
infidelity
Posts: 490
Joined: Fri Mar 01, 2013 4:46 am

Re: new to snes environment, have some questions.

Post by infidelity »

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!
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: new to snes environment, have some questions.

Post by koitsu »

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: Select all

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: Select all

|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: Select all

| 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: Select all

$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: Select all

               010 == Write 2 bytes, B0->$21xx B0->$21xx (i.e. same byte, written twice)
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: new to snes environment, have some questions.

Post by Revenant »

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)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: new to snes environment, have some questions.

Post by koitsu »

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: Select all

$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: Select all

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.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: new to snes environment, have some questions.

Post by lidnariq »

I used HDMA mode 2 in my PPU bus activity program to adjust the vertical scrolling for the offset-per-tile layer.
infidelity
Posts: 490
Joined: Fri Mar 01, 2013 4:46 am

Re: new to snes environment, have some questions.

Post by infidelity »

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.
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: new to snes environment, have some questions.

Post by Revenant »

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.)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: new to snes environment, have some questions.

Post by koitsu »

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.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: new to snes environment, have some questions.

Post by koitsu »

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")
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: new to snes environment, have some questions.

Post by 93143 »

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...
Post Reply