First reading from $2007

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
sdm
Posts: 412
Joined: Tue Apr 11, 2006 4:08 am
Location: Poland

First reading from $2007

Post by sdm »

I would like to clarify one thing:

Reading from VRAM
-----------------
1) Write upper address byte into $2006
2) Write lower address byte into $2006
3) Read data from $2007. The first read from $2007 is invalid, and
therefore should be taken care of before actual data is read.
4) Read data from $2007. From here on, after each read, the address will
auto-increment by 1, or 32 (if Bit #2 of $2000 is 1).

The first read through $ 2007 after setting $ 2006 is always invalid. Only the next one is correct. But why if I set $ 2006 TWO times, the second time the FIRST reading through 2007 is correct?

Code: Select all


	lda addrHI
	sta 2006
	lda addrLO
	sta 2006

	lda 2007			; junk read
	lda 2007			; correct read
	sta variable

Code: Select all


	lda addrHI
	sta 2006
	lda addrLO
	sta 2006

	lda 2007			; junk read
	sta variable

	lda addrHI
	sta 2006
	lda addrLO
	sta 2006

	lda 2007			; correct read (This is the first reading of 2007 after the address has been set so it should be incorrect)
	sta variable

Does this cause the PPU address to be set the same for the second time? It should read incorrectly again.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: First reading from $2007

Post by Quietust »

When you read from $2007, the PPU gives you the contents of a special 1-byte buffer, and then afterwards the PPU will perform the VRAM read (in the background) and store the resulting byte in that buffer when it finishes. This is because the PPU isn't fast enough to complete the VRAM read in time - if the CPU was significantly slower, this wouldn't be necessary.

The first time you read from $2007, you're just getting whatever happened to be there previously - it isn't necessarily "invalid", but it's highly unlikely to be the value you actually wanted to read. In your second code sample, your first $2007 read returned an "invalid" value and set the buffer to the first byte of VRAM, and when you reset the VRAM address and read $2007 again, you got the contents of the buffer which just happened to be the first byte of VRAM you were trying to read. However, it was just a result of doing things "incorrectly", and if you were to read from $2007 again, you'd receive the first byte of VRAM again (and then fill the buffer with the second byte).


If you want to read a sequence of N bytes you always have to read $2007 N+1 times - the first time will return a "garbage" byte and queue up the first actual read, the Nth time will return the 2nd-last byte and queue up the final VRAM read, and the very last one will return your last desired byte and queue up another read which will be the "garbage" byte you get the next time.

It's also notable that reading from the palette region ($3F00-$3FFF) does not incur this delay, but instead directly returns the palette byte (because it doesn't have to wait for external I/O); it will, however, still trigger a background VRAM read from the nametables that are mirrored "behind" the palette (i.e. at $2F00-$2FFF).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: First reading from $2007

Post by rainwarrior »

sdm wrote: Fri Jun 18, 2021 8:35 am 3) Read data from $2007. The first read from $2007 is invalid, and
therefore should be taken care of before actual data is read.
4) Read data from $2007. From here on, after each read, the address will
auto-increment by 1, or 32 (if Bit #2 of $2000 is 1).
Both of these reads will increment the PPU address. There is a delay on the data received, but the increment still happens in both cases.
Post Reply