the read/write signal to 2007 determines if I will write to VRAM or not
if read from 2007 then the PPU will read the VRAM of address in 2006
if write to 2007 then the PPU will take the data in 2007 and write to VRAM of address in 2006
but , what about the timing of all this ?
Sorry I didn't get it , explain more please.tokumaru wrote:That's correct. I don't know much about the timing, just that there's a delay when reading, because there's not enough time for the PPU to fetch a byte from VRAM and return it to the CPU during the load instruction that triggered the read. For this reason, the byte fetched from VRAM is buffeted, and the CPU will get it on the NEXT read from $2007.
Getting this right is essential to making the title screen of Super Mario Bros. work.
The following is an example of writing a string to VRAM and reading it back:
Code: Select all
PPUCTRL = $2000 VBLANK_NMI = $80 VRAM_DOWN = $04 PPUSTATUS = $2002 PPUADDR = $2006 PPUDATA = $2007 ; Set write increment lda #VBLANK_NMI sta PPUCTRL ; set address increment to +1 (not +32) bit PPUSTATUS ; set first/second write latch to first ; Video memory address $2222 means (2, 17) on the first nametable lda #$22 sta PPUADDR ; set high byte of address: rows 16-23 of nametable 0 sta PPUADDR ; set low byte of address: 1 row down, column 2 ; Write "HELLO". (In production code, you'd probably use a loop.) lda #'H' sta PPUDATA ; $2222 = 'H' lda #'E' sta PPUDATA ; $2223 = 'E' lda #'L' sta PPUDATA ; $2224 = 'L' sta PPUDATA ; $2225 = 'L' lda #'O' sta PPUDATA ; $2226 = 'O' ; Point the video memory address at the start of the message again lda #$22 sta PPUADDR sta PPUADDR ; Reading PPUDATA returns the value in a latch holding the most ; recently read byte and then reads another byte into that latch. ; This means you have to read one byte and discard its value ; before making use of the rest of the bytes that you read. lda PPUDATA ; A = unspecified ; PPU reads 'H' from $2222 lda PPUDATA ; A = 'H' ; PPU reads 'E' from $2223 lda PPUDATA ; A = 'E' ; PPU reads 'L' from $2224 lda PPUDATA ; A = 'L' ; PPU reads 'L' from $2225 lda PPUDATA ; A = 'L' ; PPU reads 'O' from $2226 lda PPUDATA ; A = 'O' ; PPU reads from $2227
Code: Select all
read #1 read #2 read #3
so generally, the read to 2007 transfers the content of the buffer to the output data bus and the the VRAM of address 2006 to this buffer.
first , am I true ?
then , is writing to VRAM works the same ?
Palette memory ($3F00-$3FFF) does not use the read buffer because it is inside the PPU. Instead of returning the value in the read buffer, the PPU directly returns the value in that palette location, though it still reads the VRAM address "behind" that palette entry into the read buffer. So you can read video memory $3F13 (not the palette) like this:
Code: Select all
lda $3F sta PPUADDR lda $13 sta PPUADDR lda PPUDATA ; Returns the value in palette[$13] then reads $3F13 into buffer lda #$00 sta PPUADDR sta PPUADDR lda PPUDATA ; Returns the buffer then reads $0000
From the CPU's point of view, writing goes straight to memory. First the value goes to a write buffer, and then the PPU completes the write to video memory within four cycles, before the CPU gets a chance to make another write to any other PPU register. I'm guessing (but don't quote me on this because I haven't tested it on my own NES) that the write buffer and the read buffer use the same 8-bit latch. If this is true, it means that the first read after you've written something will be the value you just wrote.
It's been established (and confirmed from Visual 2C02) that they are not the same buffer - reading $2007 returns the contents of a dedicated buffer (which is physically located just to the right of the sprite render units), while writing $2007 simply puts the value on the internal data bus and relies on capacitance (i.e. open bus) to maintain it until the VRAM write actually goes through.tepples wrote:I'm guessing (but don't quote me on this because I haven't tested it on my own NES) that the write buffer and the read buffer use the same 8-bit latch. If this is true, it means that the first read after you've written something will be the value you just wrote.
P.S. If you don't get this note, let me know and I'll write you another.