PPUDATA = $2007
.proc loadNT
; Put a pointer to title screen data in zero page locations 0-1
lda #<titledata
sta 0
lda #>titledata
sta 1
; Loop through four 256-byte "pages", using register Y to keep
; track of where we are in the page and register X to keep track
; of how many pages remain to be copied.
ldx #4
ldy #0
loop:
lda (0),y
sta PPUDATA
iny
bne loop
; If y = 0, we've finished a page, so increment the high byte of the pointer.
inc 1
; Count how many pages remain
dex
bne loop
rts
.endproc
Sivak wrote:If I ever want to modify the BG in-game, do I need to do another full write to $2007?
If your game is "screen-by-screen" (like Zelda), yeah, this would be the easiest approach. But in a game that scrolls, you typically just update rows and/or (depending on the type of scrolling) columns of tiles, with the contents that are just entering the viewing area.
The NES has a drawing area of 512x480 pixels, but half of that is replicated from the other half (because the built-in memory can only hold that much), and you get to choose if this mirroring is vertical or horizontal, so the drawing area is actually 512x240 pixels or 256x480 pixels. By using the scrolling registers you can have the viewing area start anywhere in this space, so games just slide the viewing area over the name tables, updating rows and columns of tiles as necessary.
Updating tiles is the easy part... handling the attribute tables is the most frustrating part, specially when scrolling in both directions.
I'm not using any scrolling elements (yet), but for this first project I'm going to avoid that. I'll look more into that maybe for a second project.
So if I wanted to just, say, change some text in the BG after the player presses a button, could I just place a certain string of hex into the memory location $2007 + X where X is the spot the string starts?
I'm also having some issues getting the BG attribute table setup... Although I'll have to look into that later. Right now I tried just writing some stuff into $23C0 to see if the colors would change, but they didn't... Must be a trick to it! Heh.
Thanks for all the help so far. If I can manipulate the BG and understand how to do that, I can probably get a full-blown project going. Audio will come later...
The 2 attribute bits select which out of the 4 palettes that a tile is using. You don't have 2 bits for every tile though, they are shared on a 2x2 tile basis. So each attribute table byte contains attributes for 4x4 tiles (2x2 + 2x2 + 2x2 + 2x2).
Sivak wrote:
So if I wanted to just, say, change some text in the BG after the player presses a button, could I just place a certain string of hex into the memory location $2007 + X where X is the spot the string starts?
No, this is the whole point of $2006. You must point to a certain location in the PPU. If you did the whole $2007,x thing, you'd end up with things you really don't want. Say X was $10. You'd end up writing to $2017.
To point to a tile with $2006, you must write to it with the high byte of the Name Table address, and then write to it again with the low byte. So this:
lda #$21
sta $2006
lda #$C9
sta $2006
Is telling the PPU that when I write something to $2007, it will show up at location $21C9. Depending on the status of a certain bit in $2000, the PPU will either move on to the tile right next to it, or the one right below it.
Yeah, PPU memory is not directly accessible. It's always accessed by 2 registers, mapped to the memory locations $2006 and $2007. The first is the address register. Whenever you want to write something to the PPU, you must tell it where you want to write it, and you do that by writing the address to $2006. $2007 is the data register. After the address is set, whatever is written to $2007 will go to the address you specified, and the address will auto-increment, by 1 or 32 depending on how the PPU is set.
The increments of 32 are useful for writing columns of tiles, since the name tables are 32 tiles wide, adding 32 to the address makes the PPU point to the tile below the one that was just written.
So, to calculate the starting position of a string the correct formula is: NTBase + (Y * 32) + X
"NTBase" is the base address of the name table you are using. In the case of the first name table, it's $2000. X and Y are the tile coordinates (0 to 31 for X, 0 to 29 for Y). If you write the result of this calculation to $2006 (high byte first), you can then just write the string to $2007, one character at a time. Remember to set the PPU to auto-increment by 1 first.
Remember that you can only use $2006 and $2007 when rendering is disabled. So, if you want to update something as the program runs, be sure to do it during VBlank (inside your NMI routine). Be careful not to spend much time on updates, or you might go beyond VBlank time and screw the display up.
As for the attributes not working... well, first make sure that you have set different background palettes. If the palettes are not different, it doesn't matter which one is used and the screen will look the same. Also make sure that the are you are trying to modify contains non-transparent tiles. If a tile is transparent, what you get is color 0, which is the same across all palettes. Last, make sure to understand what bytes affect what areas of the screen, so that you know exactly what address to manipulate.
Well, I've had luck getting the attributes to work, so I'm good there. Pretty easy stuff with that. The only thing I can't seem to do now is change the BG after it's loaded to something different...
I tried calling the subroutine that draws the whole BG again, but it doesn't seem to like that. I also tried turning off the PPU, doing that, and turning it back on with no luck...
On another note, I did finish a program that was for test purposes. Basically, it's my own palette tester showing colors from $00 to $0C and their +$10, $20, and $30 counterparts. $0D-$0F are just black colors. Plus I heard $0D is bad for TV's.
That's pretty good! The first demos I made were sloppily put together, and were really dumb. I like that actually. You should try making one that displays all the colors at once. I actually could use a test ROM like that... Maybe I'll try making one.
Hey again. I actually have gotten background mods working, and I'm now taking a different approach to loading them.
Basically, instead of using a file with everything, I break it down into smaller parts. For instance, if I have a bunch of blank space, I just use a loop and write $00 to $2007 a bunch of times. This way I think takes less space too rather than having all that data and a whole bunch of $00 in a list.
Anyway, I have two questions:
1. Is this a good method?
2. Should my BG writing start at $2000 or $2020? Some guides seem to say either or. I'm using $2020 right now and ending at... $23C0
Basically, I have read that $3C0 of tile data gets written and one should start at $2020 since $2000-$2020 is never seen.
I'm getting fine results with this, but I want to know if it's okay. Thanks.
You described RLE (run-length encoding), which is good. It can easily save space on any amount more than 3 repeated bytes.
2. Should my BG writing start at $2000 or $2020? Some guides seem to say either or. I'm using $2020 right now and ending at... $23C0
If it won't be displayed on NTSC TVs (and a lot of emulator default settings) it won't matter, but I would say to just avoid putting garbage in there at least.
I put stuff up there no matter what. My first attempt at a Final Fantasy style map engine had me putting stuff starting at $2020 and ending before the last row. It was a total disaster. On my NTSC TV, you can just barely see the middle of the top row (I can see the updates on FF1 if I look at the very top of the screen). So I would definitely start at $2000.
Writing $00 to the screen is good to do at your reset routine, because if someone does a soft reset while playing your game, you'll most likely want to have a clear screen before you do anything to it.
I'd say you should draw the full name table. Just because most TV's will not show those lines this is no reason to leave crap there. If, during a game, you don't want to write anything there in order to save time, at least clear them at the start and never touch those tiles again. At least you will be sure they are blank.
Celius wrote:Writing $00 to the screen is good to do at your reset routine, because if someone does a soft reset while playing your game, you'll most likely want to have a clear screen before you do anything to it.
Personal opinion: I never clear blocks of memory, I'd rather write clean code that does not assume values in RAM that was not initialized. And I initialize EVERYTHING before using. In a complex program, it's hard to be sure what was in the name tables before, so you'd better clear it all when redrawing it, and not risk displaying crap by accident.