It is currently Wed Jun 20, 2018 8:08 pm

 All times are UTC - 7 hours

 Page 1 of 2 [ 20 posts ] Go to page 1, 2  Next
 Print view Previous topic | Next topic
Author Message
 Post subject: Attribute / TilePosted: Sat Apr 23, 2016 1:59 pm

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 291
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

 Post subject: Re: Attribute / TilePosted: Sat Apr 23, 2016 2:09 pm

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20162
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:
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

 Post subject: Re: Attribute / TilePosted: Sat Apr 23, 2016 2:35 pm

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
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

 Post subject: Re: Attribute / TilePosted: Sat Apr 23, 2016 2:50 pm

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 291
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

 Post subject: Re: Attribute / TilePosted: Sat Apr 23, 2016 3:38 pm

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501

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

 Post subject: Re: Attribute / TilePosted: Sun Apr 24, 2016 6:27 am

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 291
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

 Post subject: Re: Attribute / TilePosted: Sun Apr 24, 2016 8:20 am

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

 Post subject: Re: Attribute / TilePosted: Sun Apr 24, 2016 8:57 am

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 291
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 2:56 pm

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 399
Location: Central Illinois, USA
tepples wrote:
If you know C or Python or similar languages, you may understand this:
Code:
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:
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 4:58 pm

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6346
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 5:05 pm

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7217
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:
attraddr = whichnt | 0x03C0 | (attribute_y >> 4) | (attribute_x >> 2)
and then the rest works out...

Top

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 5:11 pm

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6346
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 5:13 pm

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 433
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 7:10 pm

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 399
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

 Post subject: Re: Attribute / TilePosted: Sun Sep 03, 2017 7:34 pm

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 433
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

 Display posts from previous: All posts1 day7 days2 weeks1 month3 months6 months1 year Sort by AuthorPost timeSubject AscendingDescending
 Page 1 of 2 [ 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 3 guests

 You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum

Search for:
 Jump to:  Select a forum ------------------ NES / Famicom    NESdev    NESemdev    NES Graphics    NES Music    Homebrew Projects       2018 NESdev Competition       2017 NESdev Competition       2016 NESdev Competition       2014 NESdev Competition       2011 NESdev Competition    Newbie Help Center    NES Hardware and Flash Equipment       Reproduction    NESdev International       FCdev       NESdev China       NESdev Middle East Other    General Stuff    Membler Industries    Other Retro Dev       SNESdev       GBDev    Test Forum Site Issues    phpBB Issues    Web Issues    nesdevWiki