This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Approach to write attributes for the PPU

Approach to write attributes for the PPU
by on (#48581)
Let's say I have a map that uses 2x2 metatiles. I write on the screen in column mode my metatile columns. When I finish to write my first column of metatile, I want to update the attribute tables. Now I'm not sure how to approach it.

I don't think that staying in column mode would help because it skips 32 bytes per write and I think I need to revert to normal mode for the address increment. But since I'm writing column of data, this mean that for every attribute write I must increment the address pointer (by 8 bytes) to the next attribute? If this is the case, this mean I have to keep a copy of the address and increment it put it back in the controller for every write? That's my guess and will try it tonight but I don't know if there is any other way. This way it just seems a lot of processing for the attribute (that you already had to put back together from your metatile color attributes) compared to just writing the metatile. Is there any easier way that I may have miss?
Re: Approach to write attributes for the PPU
by on (#48584)
Banshaku wrote:
But since I'm writing column of data, this mean that for every attribute write I must increment the address pointer (by 8 bytes) to the next attribute? If this is the case, this mean I have to keep a copy of the address and increment it put it back in the controller for every write?

That's pretty much it. Although you can in fact take advantage of the "increment 32" feature. Attribute rows are 8 bytes long, which means that by incrementing 32 you skip 4 rows. Since there are 8 rows, it's possible to write to the whole column updating the address only 4 times instead of 8. It works like this: set address, write to rows 0 and 4; add 8 to address and set it; write to rows 1 and 5; add 8 to address ans set it; write to rows 2 and 6; add 8 to address and set it; write to rows 3 and 7.

Quote:
Is there any easier way that I may have miss?

I don't think so. Attributes are a pain to work with, sometimes more sometimes less, depending on the size of your metatiles or the type of scrolling in use.

If you only scroll horizontally, which I believe is your case, I suggest you update the attributes every 32 scrolled pixels, much like metatiles are updated every 16 scrolled pixels. Just scan across both metatile columns forming the 8 attribute bytes you'll need. This would be a fairly constant process, without many branches or special cases.

by on (#48588)
I see. So the increment 32 methods seems interesting then. I write 2 column of metatiles so on the first column, I want to update the attributes. I will see if I can test it tonight.

One behavior I saw while testing how attributes works, when I was in column mode, after the second column of tiles, if I wrote in the attributes 1 byte, it wrote 4 for some reason. I don't know if it's a normal behavior and why it is like that.

by on (#48617)
Banshaku wrote:
One behavior I saw while testing how attributes works, when I was in column mode, after the second column of tiles, if I wrote in the attributes 1 byte, it wrote 4 for some reason.

I have no idea what you are talking about here...! What do you mean it wrote 4?

by on (#48619)
Here I explain. Once I wrote 2 columns of tiles, column 0 and 1 in inc32 mode. Before writing a column, I set the address ($2000) then write the column. The set the second address ($2001) for column 1 and write the column of tiles.

After writing the second column, I decided to test the attributes right away, to write 1 byte to see what happens. For some reason, I forgot to set the address for the attribute table to $23C0 and wrote right away 1 attribute for testing. After the write, that 1 byte write updated 4 attributes.

But now since I still have some bugs in my code, it could be just a coding error BUT... when I set the address before writing to the attribute table for this test, the behavior was gone. hmm....

I will try to reproduce that behavior again if I have a chance. I want to know why the attribute was written 4 time, make sure that it's a real behavior or not.

by on (#48620)
A write is supposed to update four attributes in a square. Did you mean that it actually updated four 2x2 blocks of attributes?

by on (#48622)
Each attribute byte affects an area of 32x32 pixels (except for the last row, which affects 32x16-pixel areas), which would be 4 "standard" metatiles (each one has the palette selected by 2 bits). So if you meant that 4 metatiles (or an equivalent area) changed colors, that's supposed to happen. In fact, this is the reason I suggested you update the attributes every 32 scrolled pixels while scanning 2 columns of metatiles. If you mean something else though, something really wrong is going on...!

by on (#48625)
tepples wrote:
A write is supposed to update four attributes in a square. Did you mean that it actually updated four 2x2 blocks of attributes?


tokumaru wrote:
If you mean something else though, something really wrong is going on...!


Exactly. 4 4x4 blocks were updated with 1 write in inc32 at the end of the column 1 write when I forgot to set the address back to 23C0. I didn't bother too much about it yesterday since I was just testing how to write attributes in inc32 but I want to know how it happened. Either it's a programming bug or an emulator bug, the former more probable. I will see if I can reproduce it since I'm curious about that.

Edit:

Retracted comment about tests since I tested too fast. There could be chance that I made some mistake so I want to test more to be 100% sure that it's not a coding error (which probably is).

Edit2:

I'm just too tired, it's must be my own bug and I will figure it out tomorrow.

by on (#48660)
You had posted an idea of automatically entering the attribute table after rendering a column of tiles... and at first I thought it was a good idea, but on a second thought it probably won't work, because when the address crosses from the NT into the AT, the AT byte pointed at is not necessarily part of the column that's related to the column of tiles just completed (I guess it's only so for the first column).

by on (#48661)
tokumaru wrote:
You had posted an idea of automatically entering the attribute table after rendering a column of tiles... and at first I thought it was a good idea, but on a second thought it probably won't work, because when the address crosses from the NT into the AT, the AT byte pointed at is not necessarily part of the column that's related to the column of tiles just completed (I guess it's only so for the first column).


Yes, I was wrong and it only worked for the first column only. I was soooo tired and really wanted to fix it that issue that I was seeing solution that didn't exist ;) I had a long work day and was exhausted but I was still working on my nes code until 1h30. Bad idea!

The only time it would work is if you had a complete screen decoded. But if you have a complete screen then... Just write it is normal mode, there is no advantage in column mode.

I was going to write a long message with some source snippet but while writing and documenting my code in this message, I found the cause. I mixed some order by accident (doh!). I was not seeing that details anymore.

My attributes are now working. Now I can focus on scrolling, map transition and start the engine.

Thanks everyone for the comments.