Strange PPU Internal Data Bus Behaviour

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
WedNESday
Posts: 1284
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Strange PPU Internal Data Bus Behaviour

Post by WedNESday »

I am currently writing a test ROM that puts an emulator's memory map under scrutiny. WedNESday already fully supports the Famicom's memory map as according to the NESdev wiki. However, I have noticed some strange, random behaviour in regards to one aspect.

As you probably already know, writing anywhere between $2000 - $2007 will also update the PPU's 8-bit internal data bus with the same value. Reading a 'write-only' PPU register should return the last value written to the same area.

Here is an example. Observe the following code:

Code: Select all

LDA #$1F
STA $2007
LDA $2000
Technically speaking, you would expect A to contain the value $1F, correct? If the wiki is to be believed then that would certainly be the case. However, when attempting to test this exact theory on my Famicom, the actual values returned from any 'write-only' PPU registers actually seemed to be quite random.

Here are 2 screenshots of WedNESday and my Famicom running the test ROM. You can ignore everything on the screen except for the top 3 blue lines of + and -. They represent bits (7 ... 0) read from $2000, $2001 and $2002 respectively. You can also ignore bits 7, 6 and 5 of $2002 as they are readable. The 2 Famicom screen captures themselves were captured about 10 seconds apart with the console being switched off in the meantime.

http://www.frontendjames.com/TestA.png
http://www.frontendjames.com/TestB.png

Can anyone shed more light as to what is happening here? Does this have anything to do with the value decaying after a while? I would not have thought this was the case as the value is tested immediately after being written to.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Strange PPU Internal Data Bus Behaviour

Post by Quietust »

The value is definitely known to decay over the course of several seconds, but short-term it should be consistent. It's possible that $2007 is a special case, though, because the "internal bus" whose contents can be read from write-only registers is also where the $2007 write value hangs around before being written to VRAM.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
WedNESday
Posts: 1284
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Re: Strange PPU Internal Data Bus Behaviour

Post by WedNESday »

I have just been testing this strange behaviour a little further.

The following code...

Code: Select all

LDA #$1F
STA $2007
LDA $2000
...is now executed at the very start of every NMI as soon as all the other tests have completed. It now returns $1F consistently.

I also wonder whether this has something to do with the fact that the PPU isn't really in a usable state the first frame.
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: Strange PPU Internal Data Bus Behaviour

Post by Fiskbit »

It's hard to say what's going on without being able to see the code from when you were getting inconsistent results. And how were you running it? Flash cart? From power on or from reset? On a Famicom, you only have to worry about PPU init from power-on (not reset), and because the PPU gets a head start, it's not known how long it's even an issue there.
User avatar
aquasnake
Posts: 515
Joined: Fri Sep 13, 2019 11:22 pm

Re: Strange PPU Internal Data Bus Behaviour

Post by aquasnake »

#define PPU_CTRL1 0x2000 // (w)
#define PPU_CTRL2 0x2001 // (w)
#define PPU_STATUS 0x2002 // (r)
#define PPU_SPR_ADDR 0x2003 // (w)
#define PPU_SPR_IO 0x2004 // (r/w)
#define PPU_VRAM_SCRL 0x2005 // (w)
#define PPU_VRAM_ADDR 0x2006 // (w)
#define PPU_VRAM_IO 0x2007 // (r/w)
#define PPU_SPR_DMA 0x4014 // (w)



Only $2002, $2004, $2007 and their mirror addresses are allowed to be read.


When reading other addresses, the parasitic capacitance of the CPU address bus is returned (for a short period, depending on the address line impedance to GND or VCC) If the CPU data bus has pull-up or pull-down resistors, the static level is returned.

I tried to use CPLD to set bi-directional IO and put latched data on $2000 and $2001. The results were as expected, which was applied to the save state function
Last edited by aquasnake on Sun Mar 27, 2022 10:03 pm, edited 1 time in total.
User avatar
aquasnake
Posts: 515
Joined: Fri Sep 13, 2019 11:22 pm

Re: Strange PPU Internal Data Bus Behaviour

Post by aquasnake »

1. Reading register $2007: If the internal VRAM address pointer is set to $0 - $3eff by writing $2006, the data bus returns the value of the internal output buffer, which means the data value on the last VRAM address. Therefore, if you read VRAM randomly, you need to read $2007 twice. If you read continuously, the first reading of $2007 SHOULD be discarded, and the rest will be normal

2. If the read VRAM is between $3f00 - $3fff, $2007 only needs to be read once, and the internal output buffer is bypassed

3. Reading other addresses: If the data bus of the CPU is an open bus, it returns the address value of the upper 8 bits of the CPU set in the previous instruction in a short time, but this is not the influence of IO buffer, but the effect of parasitic capacitance. The residual value is kept for a short time, and if the data bus has pull-up or pull-down resistors, it will be driven to a fixed level tied to VCC or GND

4. Some pirate carts use the high address residual effect of rule No. 3 to impement copy protection, or deliberately use the bus conflict to connect a resistor between PRG ROM and CPU in series, and the parasitic capacitance of the open bus will win the competition, so that CRC can produce another verification result
Post Reply