new to snes environment, have some questions.
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
-
- Posts: 490
- Joined: Fri Mar 01, 2013 4:46 am
Re: new to snes environment, have some questions.
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.
Re: new to snes environment, have some questions.
You have to write two bytes minimum to OAM or CGRAM before it shows up in the actual memory. There's a word buffer.
-
- Posts: 490
- Joined: Fri Mar 01, 2013 4:46 am
Re: new to snes environment, have some questions.
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?
Am I understanding that correctly?
Re: new to snes environment, have some questions.
For OAM, both the even byte and the odd byte have to be stored to the same address, one after the other.
Re: new to snes environment, have some questions.
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?
More importantly, did you mean STY and not STA?
-
- Posts: 490
- Joined: Fri Mar 01, 2013 4:46 am
Re: new to snes environment, have some questions.
Yes, STY, sorry I had a typo.93143 wrote:More importantly, did you mean STY and not STA?
And I got the oam to write without dma, the info on the write register being a word helped!
Re: new to snes environment, have some questions.
From my previous post:infidelity wrote:And I got the oam to write without dma, the info on the write register being a word helped!
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.koitsu wrote: $2104 is write-only an 8-bit double-write register (i.e. it's like $2122 but for OAM).
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
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. |
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 |
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
Code: Select all
010 == Write 2 bytes, B0->$21xx B0->$21xx (i.e. same byte, written twice)
Re: new to snes environment, have some questions.
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.koitsu wrote:(i.e. same byte, written twice)
(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)
Re: new to snes environment, have some questions.
Honestly, I'm not sure. Quoting official documentation:Revenant wrote: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.koitsu wrote:(i.e. same byte, written twice)
(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)
(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
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)
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.
Re: new to snes environment, have some questions.
I used HDMA mode 2 in my PPU bus activity program to adjust the vertical scrolling for the offset-per-tile layer.
-
- Posts: 490
- Joined: Fri Mar 01, 2013 4:46 am
Re: new to snes environment, have some questions.
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.
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.
Re: new to snes environment, have some questions.
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.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!
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.)
Re: new to snes environment, have some questions.
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.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.
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.
Re: new to snes environment, have some questions.
Respectfully, this description is no better than any of the existing documentation. :\ Which is it?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.
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.
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).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.)
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")
Re: new to snes environment, have some questions.
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.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.
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...