Hello NES dev
I have a question related to PPU pins.
http://wiki.nesdev.com/w/index.php/PPU_ ... escriptionI am confused with the address and data buses, mainly, what can I address other than the 8 PPU registers? and what else can I read on the data bus ?
I think they cannot access the internal memories as they have their own internal access registers, if so, why there are 13 bit in the address bus ? aren't 3 only enough and the CS for mapping ?
thank's in advance.
The PPU uses those address pins to address graphics memory (CHR ROM, CHR RAM). While the CPU really only needs to control A0-A2 to write to the PPU, the PPU will drive AD0-AD7 and A8 and upwards (A8 is not the 2A03's A8).
It's the adress bus of the PPU itself, adressingin the VRAM adress space.
On the CPU adress bus, the PPU is slave and responds to adress $2000-$2007 (and, if I'm not mistaken, mirrored up to $3fff). On the PPU address bus, the PPU is master and exept VRAM to respond at $0000-$1fff for pattern tables and at $2000-$3fff for name and attribute tables.
The palette is on yet anohter bus and is completely internal to the PPU, as is the OAM.
So, as I now understood ( and tell me if I get it right or not )
in the VBlank period , the CPU uses A2 A1 A0 to write to the registers, otherwise , during the rendering , A13-->A0 are used by the internal registers to access the VRAM
while the PAL memory and the OAM are on separate buses and have no relation with those.
Muhammad_R4 wrote:
So, as I now understood ( and tell me if I get it right or not )
in the VBlank period , the CPU uses A2 A1 A0 to write to the registers, otherwise , during the rendering , A13-->A0 are used by the internal registers to access the VRAM
I do not think that is quite correct - A2 A1 A0 are the 2A03's address pins, which are used for selecting PPU registers to write to. During rendering these pins aren't driven by the PPU externally, otherwise it would interfere with CPU operation.
I thinkMuhammad_R4 wrote:
the PAL memory and the OAM are on separate buses and have no relation with those.
Yes, they are only accessed indirectly by the CPU or internally by the PPU.
I think the description on the Wiki should really change its terminology. It's not appropriate for one pin to be labelled A0 for the CPU bus, and then also label something A9 for the PPU bus.
I'll just
make a quick change...
In my opinion, the label of those buses should be identical to those of the cartridge connector. That is, CPU Ax and CPU Dx are used for the CPU bus, and PPU Ax and PPU Dx are used for the PPU data bus. When not specified, the CPU bus is referred to by default. The PPU bus should never be menionned without prefixing signal names with "PPU", ever.
Quote:
So, as I now understood ( and tell me if I get it right or not )
in the VBlank period , the CPU uses A2 A1 A0 to write to the registers, otherwise , during the rendering , A13-->A0 are used by the internal registers to access the VRAM
while the PAL memory and the OAM are on separate buses and have no relation with those.
No, you don't appear to understand.
CPU A0-A2 registers is used to adress the PPU memory mapped IO registers at $2000-$2007, and at any time, VBlank or not.
The PPU has it's hard logic to fetch pattern, name and attribute table from VRAM outside of VBlank. During VBlank or forced blanking, the PPU Ax pins will pretty much mirror the address written to $2006 (I have no idea if they stay there when read/write signal is not active, but I don't see what other value the adress lines could take). A read or write to $2007 on the CPU side will be immediately followed by a similar read or write to the PPU bus. This also explains the buffered $2007 reads.
Writing to palette area will do something internally directly and will not mirror on the PPU bus, exept maybe the adresses will show up (this would have to be verified).
Bregalad wrote:
In my opinion, the label of those buses should be identical to those of the cartridge connector. That is, CPU Ax and CPU Dx are used for the CPU bus, and PPU Ax and PPU Dx are used for the PPU data bus. When not specified, the CPU bus is referred to by default. The PPU bus should never be menionned without prefixing signal names with "PPU", ever.
Ah, yeah,
that's a better idea. Thanks. There's an
old diagram that called them RS0-2 but I think "CPU A0" and "PPU A10" makes things crystal clear.
Quote:
No, you don't appear to understand.
CPU A0-A2 registers is used to adress the PPU memory mapped IO registers at $2000-$2007, and at any time, VBlank or not.
then the registers can be edited during rendering ? if so does the effect also appear outside the VBlank or their effect works when the frame ends ?
During forced blank (write $00 to $2001), video memory can be updated the same way as during vertical blank: through $2006 and $2007. Palette changes will produce visible artifacts though.
During rendering, scroll splits use $2005 and $2006.
Several of the registers are commonly used outside of vblank:
$2000 - less commonly used mid-screen, but can switch tile sets, etc.
$2001 - can be used to turn sprites on or off mid-screen to keep them from overlapping a status bar, toggle
colour emphasis for a water effect or
as a timing diagnostic.
$2002 - commonly polled for sprite 0 hit to time other effects (e.g. SMB status bar)
$2005 - commonly used for horizontal scrolling changes mid-screen (e.g. SMB status bar, again)
$2006 - required for vertical scrolling changes mid-screen
The other registers $2003/2004/2007 are not normally used outside of vblank.
I somehow got it, but still I have a question
as far as I know, the game should prepare the graphics for the next frame during the Vblank , and also the VRAM address, VRAM data -as I think - are able to modify the data for the next frame
that's why I thought that they are used in the Vblank only to update the graphics.
now you all said that they can be used any time, so:
1. why would I need to access them inside rendering ( I mean Vram addr, Vram data , OAM addr, OAM data)
2. Am I true that the PPU use those mentioned registers to update graphics ( nametables , patterns , attributes and OAM ) ??
When rendering is off and the screen is therefore blank, video memory can be modified at any time. When rendering is on, video memory can be modified only during vertical blank.
You change the video memory address during rendering to have the top and bottom of the screen use different scroll positions, such as for a status bar or parallax scrolling.
Quote:
then the registers can be edited during rendering ? if so does the effect also appear outside the VBlank or their effect works when the frame ends ?
The CPU can adress memory mapped I/Os at $2000-$2007 anytime. Rainwarrior summarized what usage of them can be done outside of Vblank, but the CPU can read and write them anytime, it will create an undefined behaviour when accessing VRAM (or OAM) during rendering.
Muhammad_R4 wrote:
now you all said that they can be used any time, so:
1. why would I need to access them inside rendering ( I mean Vram addr, Vram data , OAM addr, OAM data)
You should not access VRAM data ($2007) nor OAM adress or OAM data during rendering. This is undefined behaviour.
VRAM ADR ($2006) is shared with scrolling registers, so changing it affects scrolling and can create interesting raster effects.
Quote:
2. Am I true that the PPU use those mentioned registers to update graphics ( nametables , patterns , attributes and OAM ) ??
Yes, VRAM is accessed exculively with $2006 and $2007, with the exeption of OAM, which is mostly accessed through sprite DMA. via $4014. When the programm write to $4014, the NES CPU will automatically jaét tje 6502 and perform a chain of reads from memory followed by a write to $2004, and this 256 times. On the PPU side, it's as if $2004 was written to 256 times very quickly.
$2004 is very rarely used on it's own.
Quote:
VRAM is accessed exculively with $2006 and $2007
I have a question here, I searched in the PPU registers documentaion about how the PPU differentiate between the read to VRAM and the write to it through both registers , but I found nothing
Muhammad_R4 wrote:
Quote:
VRAM is accessed exculively with $2006 and $2007
I have a question here, I searched in the PPU registers documentaion about how the PPU differentiate between the read to VRAM and the write to it through both registers , but I found nothing
There is a read/write pin for the 2A03->PPU communication, as well as a read/write pin for the PPU's VRAM bus. The former is driven by the CPU, and the latter is driven by the PPU when appropriate.
mikejmoffitt wrote:
Muhammad_R4 wrote:
Quote:
VRAM is accessed exculively with $2006 and $2007
I have a question here, I searched in the PPU registers documentaion about how the PPU differentiate between the read to VRAM and the write to it through both registers , but I found nothing
There is a read/write pin for the 2A03->PPU communication, as well as a read/write pin for the PPU's VRAM bus. The former is driven by the CPU, and the latter is driven by the PPU when appropriate.
the first for writing to registers I think
but the pin-out says the the other rd,wr are output from the PPU , shouldn't them be inputs ? to make the CPU access the VRAM ?
Muhammad_R4 wrote:
but the pin-out says the the other rd,wr are output from the PPU , shouldn't them be inputs ? to make the CPU access the VRAM ?
VRAM is not inside the PPU, it's a separate RAM chip on the board (or sometimes a RAM or ROM chip inside the cartridge), they are outputs from the PPU to this external device.
Muhammad_R4 wrote:
to make the CPU access the VRAM ?
The CPU never has access to VRAM. When writing to VRAM, the CPU sends the data to the PPU, and then the PPU forwards it to VRAM. The opposite happens when reading, but since the PPU can't read from the PPU and forward the byte to the CPU fast enough, PPU reads are buffered, so every time the CPU reads from $2007, it gets the value that was fetched during the previous read, and a new byte is buffered for the next read.
OK I understood this all , but I think I haven't explained it well
my question is how to tell the PPU to write to ( or read from ) the VRAM
for both reading and writing , both registers are used , so I think there must be an input signal according it the PPU will know if the data in the registers is write to VRAM or the opposite.
The CPU R/W pin is connected to the PPU, so the PPU can detect if the registers mapped at $2000-$2007 are written to or read from. A read to $2007 will trigger a VRAM read on next cycle (and the value currently in the buffer is returned to the CPU), a write to $2007 will trigger a VRAM write on next cycle. I am not 100% sure, but I think it is yet unknown if the read buffer is also used when writing, or if a separated buffer is used. This would be very easy to verify, though.
Muhammad_R4 wrote:
my question is how to tell the PPU to write to ( or read from ) the VRAM
Whenever the CPU accesses an address between $2000 and $3FFF, an address decoder inside the NES will tell the PPU to react to this, and the PPU will decide what to do based the address (register) being accessed and on the CPU's R/W signal.
Bregalad wrote:
I am not 100% sure, but I think it is yet unknown if the read buffer is also used when writing, or if a separated buffer is used. This would be very easy to verify, though.
It has been verified not to be the same buffer. This was that case where capacitance holds the output data on an internal bus long enough until it's written out. (You can find more info by searching.)
I will illustrate my question with example
we know that the CPU can't access the VRAM directly, so we need to first to write in 2006 and 2007 ( if writing )
I am not familiar with NES assembly but i will try.
assume i will write FF to the VRAM in address 0x1000
Code:
LDA 00 ; load accumulator
STA 2006 ; 1st write
LDA 10
STA 2006
LDA FF
STA 2007
now I want to read what I wrote in 0x1000
Code:
LDA 00
STA 2006
LDA 10
STA 2006
both codes will access the VRAM , one for write and one for read
how will the PPU understand that the CPU wants to write to the VRAM in the first code and wants to read from the VRAM in the second code ?
I hope my question is now obvious.
Muhammad_R4 wrote:
how will the PPU understand that the CPU wants to write to the VRAM in the first code and wants to read from the VRAM in the second code ?
Distinguishing reads from writes is easy:
STA $2007 writes to the PPU.
LDA $2007 reads from the PPU.
The tricky part is that reads are buffered by the PPU, so it's actually always one byte behind.
Code:
LDA #$10
STA $2006
LDA #$00
STA $2006
LDA $2007
LDA $2007 ; this actually gets the byte you were looking for
Muhammad_R4 wrote:
I am not familiar with NES assembly but i will try.
You got the basic idea, but you need a # if you want to load immediate values into the CPU registers. And you also need a $ if you're using hex numbers. For example, LDA 00 will put the contents of memory location $0000 into A, while LDA #$00 will put the value 0 into A. Another thing worth pointing out is that addresses written to $2006 are written high byte first.
Quote:
how will the PPU understand that the CPU wants to write to the VRAM in the first code and wants to read from the VRAM in the second code ?
For the $2006 writes, it simply doesn't matter, because nothing is being written or read yet, as the PPU is just seeing up a pointer to access memory later. Once the actual read/write from/to $2007 happens, the CPU will output a signal indicating whether it's reading or writing data. This signal is essential even for memory to work correctly, because memory chips need to know whether they're being written to or read from. Anyway, the PPU too can see this signal, so it knows whether to read from our write to VRAM.
Quote:
the CPU will output a signal indicating whether it's reading or writing data. This signal is essential even for memory to work correctly, because memory chips need to know whether they're being written to or read from. Anyway, the PPU too can see this signal, so it knows whether to read from our write to VRAM
That's I am talking about , where is this signal in the PPU pinout ?
http://wiki.nesdev.com/w/index.php/PPU_ ... escription
It's pin 1 (R/W), apparently:
Quote:
R/W, CPU D0-D7, and CPU A0-A2, are signals from the CPU.
Quote:
It's pin 1 (R/W), apparently:
but I think those for reading/ writing to PPU internal registers
Yes, and $2007 is a PPU register too. When $2007 is accessed, the PPU will check the R/W signal in order to decide whether to read from or write to VRAM.
So, what I understood ( and tell me if I am wrong )
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 ?
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.
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.
Sorry I didn't get it , explain more please.
What was the first word in tokumaru's post that you failed to understand? If you don't tell us
what part you misunderstood, it will be much more difficult for us to help you understand. ("Much detail" was the catchphrase:
1 2 3)
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:
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
Of the preceding code, which was the first line that you misunderstood?
So , as I understood from the code , when I request a read from VRAM , what I really get on the data bus is the previous read
Code:
read #1
read #2
read #3
as I understood , what I get in read#2 is the result from read#1 and in read#3 is the read#2
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 ?
You understand the video memory read buffer correctly.
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:
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
Most games won't need this because the PPU never uses video memory $3000-$3FFF during rendering. The vast majority of cartridge boards just make it a mirror of $2000-$2FFF.
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.
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.
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.