Hey, I have (working) timing code in my NMI routine that fires every second.
In the timing routine I have added some code to get a background tile to change but when I attempt this all the background tiles disappear.
Here's my test 'updating' code:
Code:
ldx $213F
inx ; Read tile and add 1 to X, as to skip to the next tile but in the same position
lda $2002 ; Reset high/low
lda #$21
sta $2006
lda #$3F
sta $2006 ; Write 213F address
stx $2007 ; Store updated tile
Please point out where I'm going wrong so I can further learn the basics
Thank you
One approach: slowly remove your updating code until the bug goes away. The last thing you removed is (one) thing that was causing it. I predict that it goes away once you've removed the $2006 and $2007 writes, as those upset the scrolling position.
Next, what is the LDA $213F supposed to do? (to others, I'm asking the original poster, as I know what it actually does)
213F is an invalid address.
NES Memory Map: (don't get too picky about simplifications here, I'm also excluding mirrors and obscure areas)
0000-07FF: RAM
2000-2007: PPU communication
4000-4017: IO Regsiters (sound, joystick, sprite DMA, etc)
6000-7FFF: Cartridge RAM (if present), some mappers can put ROM here
8000-FFFF: Cartridge ROM
In my reset routine I start the background at $213F to position it center screen like I want:
The reason I start at $213F is because my background name table is more than 255 bytes and I don't know how to read the rest of it 'properly'. This way seems to save ROM space anyway.
Then in my NMI routine my end goal is to get PRESS START to flash every second, but I'm just testing basic updating code first.
The LDX $213F is reading from invalid memory, and not doing you any good.
Setting the PPU address to 213F makes sense, since that's inside the first nametable, but asking the CPU to read the CPU Memory address 213F does not.
CPU and PPU have separate memory spaces. CPU can only talk to the PPU through addresses 2000-2007. PPU has its own memory.
0000-1FFF: Tile graphics (CHR), can either be RAM or ROM.
2000-23FF: Nametable #1 (top left)
2400-27FF: Nametable #2 (top right)
2800-2BFF: Nametable #3 (bottom left)
2C00-2FFF: Nametable #4 (bottom right)
3FE0-3FFF: Palette
The current "Mirroring Mode" determines whether nametables are copies of the others or not. "Horizontal Mirroring" makes nametables #2 and #4 copies of #1 and #3, so you have two distinct nametables for vertical scrolling. "Vertical Mirroring" makes nametables #3 and #4 copies of #1 and #2, so you have two distinct nametables for horizontal scrolling.
So I'm writing in nametable #1. I've just tried reading $2007 after writing the $213F address to $2006, incrementing it and storing it and that just kills the background too :S
EDIT: this happens on the first write to $2006, so I'm meant to do something before that?
I'm guessing you are trying to read the tile at $213F, modify it and write it back, right?
Well, you can't simply read from the name tables with LDX. When you do 'LDX $213F' you are trying to read from CPU memory, not PPU memory. All work on PPU memory has to be done through the registers $2006 and $2007. You have learned to use them for writing to the background, and if you want to read from it you have to use them as well.
To read the byte at $213F you have to do:
Code:
lda $21
sta $2006
lda $3F
sta $2006
ldx $2007
ldx $2007
You have to read ldx twice because it takes a while for the PPU to deliver the value you requested, so the first returned value is not valid. This dummy read is only needed for the first byte you read.
You can just replace the 'LDX $213F' with the code above and it will work, but from this you can see that reading-modifying-writing to the PPU will be a very slow process, because you'll have to set the address for every read and for every write. So in this case I suggest you keep a copy of the data you are modifying in CPU ROM, so you can manipulate it freely.
Are you resetting the name table index ($2000) and the scroll ($2005) after using $2006 and $2007? If not, this is most likely what's killing your background. Using $2006 and $2007 fucks up the scroll, so after you're finished with them you have to reposition the scroll using $2000 and $2005, like you probably did when setting up the background the first time.
I updated my code to fit with the suggestions but it still kills it :S
By the way, I haven't used $2005 anywhere in my code apart from here.
Updated code:
Code:
lda #$00
sta $2000
sta $2001
sta $2005
lda $2002 ; Reset high/low
lda #$21
sta $2006
lda #$3F
sta $2006 ; Write 213F address
ldx $2007
ldx $2007
inx
stx $2007 ; Store updated tile
lda #%10000000
sta $2000
lda #%10011110
sta $2001
Reading or writing from 2007 increments the PPU address by 1. Need to read the byte, then write the address again if you want to rewrite the byte.
Also, scrolling and the PPU address use the same internal registers on the PPU, so every time you change stuff on the screen, you need to reset the scrolling. Scrolling first then writing new ppu data won't do any good. Need to scroll last.
Yeah, you can't simply write it back, you have to set the address using $2006 again. This is why I said it would be super slow.
Still not working. As I said before it dies on the first $2006 write.
Current code:
Code:
lda #$00
sta $2000
sta $2001
sta $2005
; First read
lda $2002 ; Reset high/low
lda #$21
sta $2006
lda #$3F
sta $2006 ; Write 213F address
ldx $2007
ldx $2007
;Second read then write
lda $2002 ; Reset high/low
lda #$21
sta $2006
lda #$3F
sta $2006 ; Write 213F address
inx
stx $2007
lda #%10000000
sta $2000
lda #%10011110
sta $2001
EDIT: I understand this method would be slow like you said but what are the better/other ways to do it?
Louix94 wrote:
Still not working.
OK, you reset $2000, but what about $2005? You need:
Code:
lda #$00
sta $2005
sta $2005
...at the end of the code you posted.
Quote:
I understand this method would be slow like you said but what are the better/other ways to do it?
Keep a copy of the data you want to read-modify-write in CPU addressable RAM. That way you can read from CPU RAM, modify, write to PPU RAM.
It's still not clear to any of us what your entire NMI handler looks like. You keep leaving out some of the code that might be relevant. Since you don't know why your code isn't working, you can't know what parts are causing/not causing it.
I just realised I wasn't resetting $2005 until after the setting of the tile
I now have something that's nearly working, except now when the tile I want updates for the first time every background tile moves up once. I'll try find a solution myself then post back here if it works.
Thank you everyone for what I have so far
Okay I've fixed that problem now lol so I guess now I can figure out how to do it in a neater way.
Thank you all for all your tips
"I understand this method would be slow like you said but what are the better/other ways to do it?"
Somebody already mentioned this, but store the graphics data that needs to be modified in the CPU's RAM (with the value you initially write to the PPU).
Later when you need to modify the graphics data, retrieve the value from RAM first, modify it, then write it to the PPU. That saves you from setting the PPU address twice for a read and write to the PPU.