It is currently Sat Oct 21, 2017 6:14 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Attribute / Tile
PostPosted: Sat Apr 23, 2016 1:59 pm 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
Hey all - first, I completely understand the relationship of attributes to tiles, understanding how they sit at $23c0, and how they're organized. In a routine, however, I'm attempting to find the easiest way to find the attribute group associated with the a given 16bit tile address. I get that there are 64 'attribute quad bytes' essentially, the last one being 'half'...and while there are 960 tiles...i can sort of think of the ratio between 1024 to 64...dividing the two byte address off the tile in question by 16 should give me the correct 'attribute quad' beyond $23c0...then I could evaluate down from there to figure which of the quads the tile is in...

Does this seem sound? Does anyone have a good or better method for this?

Just running through a thought experiment.

Thanks.


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sat Apr 23, 2016 2:09 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
It's not just a division by 16, but you're on the right track.

Each attribute byte covers a 4 tile by 4 tile area. So you need to divide the horizontal part (bits 4-0) of the tile address by 4 (the width of the area) and the vertical part (bits 9-5) by 4*4 = 16 (the area of the area).

If you know C or Python or similar languages, you may understand this:
Code:
whichnt = ntaddr & 0x3C00
coarse_y = ntaddr & 0x03E0
coarse_x = ntaddr & 0x001F
attraddr = whichnt | 0x03C0 | (coarse_y >> 4) | (coarse_x >> 2)


In 6502 assembly language, the best way to calculate this depends largely on the kind of update that you plan to do at any given time.


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sat Apr 23, 2016 2:35 pm 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
If I understand what you're asking, I believe it varies on implementation.

If you would let me know what you're aiming for (ie. scrolling in a horizontal row, scrolling in a vertical column, animating a tile already in the nametable) I can be more specific. However, since you're usually updating a group of tiles and attributes at one time, taking the nametable address of a tile, and then calculating the attribute nametable address from that, is usually not the most productive method.

It's better I think, to calculate a base address for tiles and a base address for attributes from a common variable, and then go from there with each. You can even share some of the math between the calculations.

For example, you'll usually be starting with a scroll position to find tiles from your map, so I did something like this:

Code:
  LDA hScrollLo
  LSR
  LSR   
  LSR               ; Number of tiles which have been scrolled horizontally in nametable
  STA nametableColumnLo

  LSR
  LSR                                 ; Number of attributes which have been scrolled horizontally
  CLC
  ADC #$C0
  STA nametableColumnAttributesLo, x


The math is pretty simple when it's just for rows or columns, and not 2-axis scrolling. From there you can use the PPU increment to fill out a column, (attribute columns would require manual addressing due to lack of +8 inc) with no need to calculate addresses on a tile-per-tile basis.

Hope this helps. Feel free to ask more questions.


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sat Apr 23, 2016 2:50 pm 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
Actually not even for scrolling. Just for spot updates to first nametable when screen is turned off.

Just trying to figure out how to extrapolate the attribute address from the figured tile address. :-)


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sat Apr 23, 2016 3:38 pm 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
How about this? I haven't tested it but it should work:

Code:
LDA nametableTileLo
LSR
LSR
CMP #$20
AND #%00000111
STA temp

LDA nametableTileHi
ROL
ASL
ASL
ASL
ORA #$C0
ORA temp
STA nametableAttributesLo

LDA nametableTileHi
ORA #$03
STA nametableAttributesHi


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Apr 24, 2016 6:27 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
Should nametableAttributesLo / Hi then give me the address to plug into 2006 to update the attribute? If so, this did not work. What I tried with the data was just wrote ntaLo to 2006, wrote ntaHi to 2006, and then wrote arbitrary values (#%01010101) to $2007 to see a change. There is no change.

Contrarily, when I put in values directly (#$23 into lo, #$C8 into hi), I get the expected results, so I know the routine is being called, and I know that it is set up right...it's just that the routine isn't getting the correct tile address.

Any thoughts?

Thanks!


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Apr 24, 2016 8:20 am 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
Hmmm. I tested it and it's working properly for me.

From what you described, I think it's the order in which you're giving the data to the PPU.

Unlike the rest of the hardware, the PPU expects to receive the high byte of the address first, so write nametableAttributesHi to $2006, then write nametableAttributesLo to $2006 and write your attribute value to $2007 and it should be good to go.

Quote:
Contrarily, when I put in values directly (#$23 into lo, #$C8 into hi)

You've got these backwards. #$23 is your high byte value and #$C8 is your low byte value.


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Apr 24, 2016 8:57 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
Yes sorry that was a mis-type.

Hmm, alright I'll run through and make sure of all my byte agreements, and make sure there aren't any variables mucking things up. I appreciate your help and testing it out!


*EDIT*

Just a gremlin, I guess. Went through it line by line, couldn't find the issue. Erased and rewrote...worked fine.

Thanks!


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 2:56 pm 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 213
Location: Central Illinois, USA
tepples wrote:
If you know C or Python or similar languages, you may understand this:
Code:
whichnt = ntaddr & 0x3C00
coarse_y = ntaddr & 0x03E0
coarse_x = ntaddr & 0x001F
attraddr = whichnt | 0x03C0 | (coarse_y >> 4) | (coarse_x >> 2)



Resurrecting this....unless I'm reading something wrong, I think this is off.

For PPU address 0x2820 (the leftmost column of the nametable, 2nd row), the attribute address should be 0x2BCO.

But this pseudocode gives 0x2BC2. course_y in my example would be 20, so course_y >> 4 is 2, which is not what we want, which is what ends up with that 2 at the end.

Please let me know if I'm mistaken, I'm probably overlooking something.

Code:
ntaddr = 0x2820
whichnt = ntaddr & 0x3C00      ;gives 2800, correct
coarse_y = ntaddr & 0x03E0     ;gives 20, correct
coarse_x = ntaddr & 0x001F     ; gives 0, correct
attraddr = whichnt | 0x03C0     ;2BC0, so far so good
  | (coarse_y >> 4)                  ; 2BC0 | 2 = 2BC2, seems wrong?.
  | (coarse_x >> 2)                  ; | 0, not important here

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 4:58 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
I am having trouble following most of those mask values. Here's an alternative from the wiki (PPU Scrolling):
Code:
 tile address      = 0x2000 | (v & 0x0FFF)
 attribute address = 0x23C0 | (v & 0x0C00) | ((v >> 4) & 0x38) | ((v >> 2) & 0x07)


In particular I don't understand why these were that way:
  • whichnt: $0C00 not $3C00 (sort of the same, but $0XXX,$1XXX,$3XXX aren't accessible nametables)
  • coarse_y: $0380 not $03E0 (?)
  • coarse_x: $001C not $001F (doesn't matter, bits are discarded anyway, but why keep them?)


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 5:05 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6293
Location: Seattle
coarse_x and coarse_y are clearly nametable granularity. (five bits each)

Attribute table is coarser by two more bits; just three bits per axis. I guess if you wanted to just add a few more variables to clarify:

Code:
attribute_y = ntaddr & 0x0380
attribute_x = ntaddr & 0x001C
attraddr = whichnt | 0x03C0 | (attribute_y >> 4) | (attribute_x >> 2)
and then the rest works out...


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 5:11 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
Well, for yet another explanation, the next paragraph behind that link I was quoting from is:
Code:
The low 12 bits of the attribute address are composed in the following way:

  NN 1111 YYY XXX
  || |||| ||| +++-- high 3 bits of coarse X (x/4)
  || |||| +++------ high 3 bits of coarse Y (y/4)
  || ++++---------- attribute offset (960 bytes)
  ++--------------- nametable select


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 5:13 pm 
Offline

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 429
One thing to keep in mind is that unless your game uses 4x4 metatiles and only scrolls along one axis at a time, you're going to have to read-modify-write attribute table bytes in order to update individual 2x2 tile cells. Since accessing PPU memory this way is extremely inefficient, you'll probably want to shadow the attribute tables in work RAM.


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 7:10 pm 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 213
Location: Central Illinois, USA
Yeah, I figured out a different way to calculate it, but wanted to make note of this seeming wrong, for any future readers :-)

AJW wrote:
One thing to keep in mind is that unless your game uses 4x4 metatiles and only scrolls along one axis at a time


Well, I am using 4x4 metatiles. But doing free all-directional scrolling - it's not obvious to me why I need to read the attribute tables for that, am I missing something?
(I'm using 4 name tables, if that makes a difference)

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
 Post subject: Re: Attribute / Tile
PostPosted: Sun Sep 03, 2017 7:34 pm 
Offline

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 429
gauauu wrote:
Yeah, I figured out a different way to calculate it, but wanted to make note of this seeming wrong, for any future readers :-)

AJW wrote:
One thing to keep in mind is that unless your game uses 4x4 metatiles and only scrolls along one axis at a time


Well, I am using 4x4 metatiles. But doing free all-directional scrolling - it's not obvious to me why I need to read the attribute tables for that, am I missing something?
(I'm using 4 name tables, if that makes a difference)


If you're doing all-directional scrolling without 4-screen mirroring, you're going to have fewer than 32 pixels of offscreen area in at least one axis, so you can't just draw an entire 32x32 metatile at a time or you'll produce visible garbage.


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: No registered users and 4 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