It is currently Mon Oct 23, 2017 1:15 am

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Dec 10, 2016 5:36 pm 
Offline
User avatar

Joined: Sat Jun 27, 2009 11:05 pm
Posts: 712
Location: New Mexico, USA
Regarding the following from Anomie's regs.txt (same info exists in fullsnes.txt):
Code:
210f  ww+++- BG2HOFS - BG2 Horizontal Scroll
2110  ww+++- BG2VOFS - BG2 Vertical Scroll
2111  ww+++- BG3HOFS - BG3 Horizontal Scroll
2112  ww+++- BG3VOFS - BG3 Vertical Scroll
2113  ww+++- BG4HOFS - BG4 Horizontal Scroll
2114  ww+++- BG4VOFS - BG4 Vertical Scroll
        ------xx xxxxxxxx

        Note that these are "write twice" registers, first the low byte is
        written then the high. Current theory is that writes to the register
        work like this:
          BGnHOFS = (Current<<8) | (Prev&~7) | ((Reg>>8)&7);
          Prev = Current;
            or
          BGnVOFS = (Current<<8) | Prev;
          Prev = Current;
1) Can anyone explain to me that insane horizontal offset assignment? Why does it do this?? The vertical offset assignment makes perfect sense to me but what's up with the horizontal?

2) Assuming that 'Reg' refers to the current BGnHOFS register value that is being written to (although this isn't stated anywhere), the '((Reg>>8)&7)' part doesn't make any sense. The registers are only 10-bit. So if you right-shift by 8 then you only have 2 bits left. So doing a mask of the lower 3 bits (i.e. '&7') doesn't make any sense. Are you just supposed to set the upper bit to 0?

Some notes:
- 'Current' is the 8-bit value that's being written *right now* to the PPU by the CPU.
- 'Prev' is an 8-bit latch value storing the last 8-bit value written to any of these registers.
- Assuming that 'Reg' is the current value stored in the 10-bit BGnHOFS register. Not sure why he doesn't just use BGnHOFS instead of creating a new undefined term of 'Reg'.....??

Thanks!


Last edited by jwdonal on Sat Dec 10, 2016 11:36 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 6:01 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
nocash's documentation explains this a little better: http://problemkaputt.de/fullsnes.htm

Code:
210Dh - BG1HOFS - BG1 Horizontal Scroll (X) (W) and M7HOFS
210Eh - BG1VOFS - BG1 Vertical Scroll (Y) (W) and M7VOFS
210Fh - BG2HOFS - BG2 Horizontal Scroll (X) (W)
2110h - BG2VOFS - BG2 Vertical Scroll (Y) (W)
2111h - BG3HOFS - BG3 Horizontal Scroll (X) (W)
2112h - BG3VOFS - BG3 Vertical Scroll (Y) (W)
2113h - BG4HOFS - BG4 Horizontal Scroll (X) (W)
2114h - BG4VOFS - BG4 Vertical Scroll (Y) (W)
  1st Write: Lower 8bit  ;\1st/2nd write mechanism uses "BG_old"
  2nd Write: Upper 2bit  ;/
Note: Port 210Dh/210Eh are also used as M7HOFS/M7VOFS, these registers have a similar purpose, but internally they are separate registers: Writing to 210Dh does BOTH update M7HOFS (via M7_old mechanism), and also updates BG1HOFS (via BG_old mechanism). In the same fashion, 210Eh updates both M7VOFS and BG1VOFS.
          BGnHOFS = (Current<<8) | (Prev&~7) | ((Reg>>8)&7);
          Prev = Current;
            or
          BGnVOFS = (Current<<8) | Prev;
          Prev = Current;

In other words: the behaviour of $210d and $210e is multi-purpose depending on if you're in modes 0-6 or mode 7. For modes 0-6, they're 10-bit (range 0-1023) as described (I'm avoiding modes 5 and 6 :-) ). For mode 7, it's more complicated (see "SNES PPU Rotating/Scaling" right beneath that).

Do you need me to post pages from the official documentation that depict these registers' use on the actual screen? They're not particularly useful, but it is covered.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 6:07 pm 
Offline
User avatar

Joined: Sat Jun 27, 2009 11:05 pm
Posts: 712
Location: New Mexico, USA
Yep, got it. So just keeping the discussion specific to registers $210F-$2114 I believe both of my original questions are still valid. Those registers are physically only 10-bit according to both docs. And I still don't understand why that assignment is so weird. There must be a reason behind it...well, we are talking SNES, so I suppose that's not necessarily true. But I don't even see how that assignment pattern is even supposed to work properly.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 6:30 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Okay, so this is more about 1) a complaint about the syntax of the documentation (the fields in question aren't described anywhere), and 2) why does the PPU internally operate that way (re: all the bitshifts and AND'd with a bitwise NOT of 7 (so %1000)). Yeah?


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 7:01 pm 
Offline
User avatar

Joined: Sat Jun 27, 2009 11:05 pm
Posts: 712
Location: New Mexico, USA
Yes that's it.

Although I wouldn't really say "complaint" about the syntax. It could be that the syntax is actually better than how I would describe it but I'm just not understanding something properly...?

To put question 1 more simply, why isn't the horizontal offset assignment just the exact same as the vertical offset assignment? Why do they even need to be different at all? It must be something to do with the graphics rendering that I either don't understand or haven't learned/seen yet.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 7:16 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
I'm under the impression the "crazy formulas" shown only pertain to mode 7. But I can't be sure because of how the documentation is formatted.

If they apply universally to all modes, then my theory would be that the whole current vs. prev vs. written value (presumably Reg) thing is probably an effect of the PPU having some kind of latch buffering going on. Warning: I'm talking out my ass here a bit -- and as such I hope byuu or Revenant or lidnariq appear and correct me, honestly! -- but the NES PPU is very much like this. In fact, it's one of the things (once understood) that "revolutionised" NES emulation. There's a reason there's an enormous doc about it maintained by many of us.

I will say it's strange that the formula is (current*256) | (previous & %11111000) | ((regvalue/256) & %00000111). I'm kinda curious what those "magic 4 bits" are about.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 7:19 pm 
Offline
User avatar

Joined: Sat Jun 27, 2009 11:05 pm
Posts: 712
Location: New Mexico, USA
koitsu wrote:
"magic 4 bits"
Did you mean magic *3* bits? My total guess is that they have something to do with the fine horizontal scroll.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 7:31 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6297
Location: Seattle
I'm definitely out of my depth, much as I appreciate koitsu's flattery ;)
All I can really say is that bsnes-plus HEAD includes the following
Code:
//BG2HOFS
void PPU::mmio_w210f(uint8 data) {
  bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7);
  regs.bgofs_latchdata = data;
}

This looks like it means you'll get odd (and unhelpful) behavior if you interleave writes to different registers.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 7:57 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
The reason is due to internal latching. The low three bits of the horizontal offset are special and used for internal tile rendering/fetching. You can think of them as actually separate registers internally. Or not, I'm not your father :P

This matters. Try running Theme Park, it'll screw up if you don't do the horizontal scroll latching correctly. Stuff like this, it's best to just grit your teeth and implement it as we've described it :/

It's screwy, yes, but it's not nearly as bad as the NES' loopy_t/v stuff.


Top
 Profile  
 
PostPosted: Sat Dec 10, 2016 8:54 pm 
Offline

Joined: Sat Apr 25, 2015 1:47 pm
Posts: 329
Location: FL
lidnariq wrote:
I'm definitely out of my depth, much as I appreciate koitsu's flattery ;)

Me too, to be honest :P I tend to just defer to the bsnes/higan source code for stuff like this, since I don't have a huge amount of hands-on experience with the weird quirks of the SNES PPU.


Top
 Profile  
 
PostPosted: Sun Dec 11, 2016 12:47 am 
Offline
User avatar

Joined: Sat Jun 27, 2009 11:05 pm
Posts: 712
Location: New Mexico, USA
I appreciate all the replies but I don't think either of my questions has actually been answered. Well, maybe a little...
byuu wrote:
The reason is due to internal latching. The low three bits of the horizontal offset are special and used for internal tile rendering/fetching.
I suppose this is an answer to question 1 but it's very vague. Any more details? The low 3 bits are definitely used for fine horizontal scrolling but I don't see how that relates to "internal latching". I'm trying to understand the purpose of the strange assignment pattern.

I wrote out a few examples by hand and it seems that the weird assignment behavior only makes a difference if you write to a BGnHOFS register only once instead of the required 2 times. If you always write to the register twice for both low and high bytes I don't believe there is any way that the final register value could contain anything other than what the user wrote. Am I wrong about that? Or is the weird assignment pattern only important for when/if a game writes to the BGnHOFS register once instead of twice?

For my second question I still don't see how this part of the assignment '((Reg>>8)&7)' makes any sense for a 10-bit register. It would make a lot more sense if it was '((Reg>>8)&3)'. Are you just always supposed to set the upper of the three bits to 0 since it's only a 10-bit register? I don't see higan source doing that though...

Additionally, Anomie's regs.txt states that the offset registers $210D-$2114 can only be written during F/V/H-blank (as denoted by the "ww+++-"). Is that actually true? Looking at higan source I don't see anything preventing them from being written whenever you want. Also, unless I made a silly goof, I just tried to set the registers to a non-zero value outside of F/H/V-blank and it worked just fine. I can see why you _shouldn't_ write to those registers outside of F/H/V-blank, but it does seem to be physically possible.


Top
 Profile  
 
PostPosted: Sun Dec 11, 2016 1:16 am 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 788
jwdonal wrote:
Additionally, Anomie's regs.txt states that the offset registers $210D-$2114 can only be written during F/V/H-blank (as denoted by the "ww+++-"). Is that actually true? Looking at higan source I don't see anything preventing them from being written whenever you want. Also, unless I made a silly goof, I just tried to set the registers to a non-zero value outside of F/H/V-blank and it worked just fine. I can see why you _shouldn't_ write to those registers outside of F/H/V-blank, but it does seem to be physically possible.

Anomie is conservative that way; as I heard it he doesn't declare something writable if he isn't sure.

You can indeed write to the scroll registers in the middle of active display. The PPU won't notice right away, but after a couple of slivers (in my experience) the new values will take effect. Air Strike Patrol does this, as does my shmup port.

You can change a number of things mid-scanline. Changing the VRAM locations of OBJ data via OBSEL works cleanly during active display, and won't produce any visible changes until the next line (HBlank seems to be a better time to change the size bits, if you must mess with them mid-frame). Changing BGMODE mid-line produces garbage in the BG layers for a short period, but ultimately works in all cases tried so far (that I'm aware of); just don't change to Mode 7 from something else mid-line as the init won't have been done and the results will not be as expected...


Last edited by 93143 on Sun Dec 11, 2016 3:18 am, edited 3 times in total.

Top
 Profile  
 
PostPosted: Sun Dec 11, 2016 1:18 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6297
Location: Seattle
Best guesses:
Quote:
Can anyone explain to me that insane horizontal offset assignment? Why does it do this??
The fine X scroll probably does something similar to how the NES PPU's fine X scroll is implemented using one output of a multiplexer. It may well be in an entirely different section of the IC, and it might have been easier to route the existing upper byte of the X scroll value instead of the FIFO.

Quote:
The registers are only 10-bit. So if you right-shift by 8 then you only have 2 bits left. So doing a mask of the lower 3 bits (i.e. '&7') doesn't make any sense. Are you just supposed to set the upper bit to 0?
By elimination, the X scroll registers have to be at least 11-bit, because when it's moved over into the fine X scroll the &4s bit isn't 0.

Quote:
only makes a difference if you write to a BGnHOFS register only once instead of the required 2 times. If you always write to the register twice for both low and high bytes I don't believe there is any way that the final register value could contain anything other than what the user wrote. Am I wrong about that? Or is the weird assignment pattern only important for when/if a game writes to the BGnHOFS register once instead of twice?
They're only the same if your write pattern is BGxHOFS BGxHOFS BGxVOFS BGxVOFS. If you were tempted to do something like BGxHOFS BGxVOFS BGxHOFS BGxVOFS you'd get something uphelpful.

OTOH, if I'm reading this right, you could also do something daft like BG4VOFS BG1VOFS BG4VOFS BG2VOFS BG4VOFS BG3VOFS and it would be usable... if obfuscatory. But you couldn't with the BGxHOFS registers.

But ... yeah ... viewtopic.php?p=183215#p183215


Top
 Profile  
 
PostPosted: Sun Dec 11, 2016 8:21 am 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
> I'm trying to understand the purpose of the strange assignment pattern.

I want to avoid speculation, but my opinion is that they're trying to reduce transistors infinitesimally through latching less bits of the BGnHOFS registers.

If you really want to know for sure why it's doing it, I'm afraid you'd need to analyze die scans.

Again, I'm sorry to say it, but opinions don't really matter. This is what it does, and it's what you have to emulate =(

By all means though, try to verify it, try to break the assumptions, maybe you'll find new edge cases we didn't know about, which can lead to making better sense of things.

> Additionally, Anomie's regs.txt states that the offset registers $210D-$2114 can only be written during F/V/H-blank (as denoted by the "ww+++-"). Is that actually true?

That's not true. Air Strike Patrol writes to the BG3dOFS registers during active display. It does it to show a hud on the left side of the screen, while rotationg the "player start" text on the same BG in the middle of the screen.

(obviously, use higan/accuracy if you want to see the effect. Other emulators don't animate the player start rotation effect.)

Don't forget: anomie quit the SNES scene without saying goodbye so he could go edit Wikipedia instead. He left a very long time ago, and his docs haven't been updated. I've learned a lot since then.

> Changing BGMODE mid-line produces garbage in the BG layers for a short period, but ultimately works in all cases tried so far

And I really need to stress that this is the most psychotic one of all. It completely breaks the idea of trying to have separate state machine paths for each BGMODE. You can't do that if you care about perfection.


Top
 Profile  
 
PostPosted: Sun Dec 11, 2016 1:18 pm 
Offline

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 430
lidnariq wrote:
Best guesses:
Quote:
Can anyone explain to me that insane horizontal offset assignment? Why does it do this??
The fine X scroll probably does something similar to how the NES PPU's fine X scroll is implemented using one output of a multiplexer. It may well be in an entirely different section of the IC, and it might have been easier to route the existing upper byte of the X scroll value instead of the FIFO.


I'm almost 100% certain that the bits of the BGnHOFS registers are actually split between the two chips that comprise the S-PPU: the low 3 bits are on PPU2, and the rest of the bits are on PPU1. VRAM addressing is controlled by PPU1, but the BG shift registers pretty much have to be on PPU2, because there's no data path to send rendered BG pixels between the two chips (there's only the 9 pins for sprite pixels). The low 3 bits of hscroll don't affect VRAM addressing, they affect which bit of the shift registers gets selected as output.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google Adsense [Bot] and 6 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