This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Reading and saving $2000: Why does this change the behavior?

Reading and saving $2000: Why does this change the behavior?
by on (#153054)
When I write this:
Code:
   LDA $2000
   STA $2000

this shouldn't do anything useful, right? It reads the value and writes it back.

So, how come that if I do this and then I do some background graphics work, that my new tiles are drawn vertically while they would be drawn horizontally without these two calls?

The acual code:
Code:
   LDA $2000
   STA $2000
   ; --> Should actually be useless, but influences the following output.
   
   LDA $2002
   LDA $20
   STA $2006
   LDA $00
   STA $2006
   
   LDX #$00
@loop:
   LDA TilesForUpdate, X
   STA $2007
   INX
   CPX #TILES_FOR_UPDATE_COUNT
   BNE @loop
Re: Reading and saving $2000: Why does this change the behav
by on (#153056)
I believe $2000 is a write-only register, which means trying to read it will give you some sort of open busweird behaviour? It doesn't give you the contents of the register. (You need to store that in a variable if you want to recover it later.)

Edit: tepples explains in detail below.
Re: Reading and saving $2000: Why does this change the behav
by on (#153057)
O.k., I'll do. I didn't know that you cannot read from it. But it makes sense since all these $200x values are just for writing.
Re: Reading and saving $2000: Why does this change the behav
by on (#153059)
$2002 is just for reading.

$2004 and $2007 are read-write, though there are some big caveats about reading from $2007 (there is a buffer delay, it's... weird)

wiki: PPU registers
Re: Reading and saving $2000: Why does this change the behav
by on (#153077)
Reading any write-only PPU port will give you the last value written to or read from any PPU port. For example, if you just wrote to $2001 or $2007, then reading $2000 will return that last value you wrote. Reading video memory through $2007 also sets the previous value. Reads from $2002 return the status in bits 7-5 and bits 4-0 of the previous value in bits 4-0. (Low-level explanation: The PPU uses an 8-bit internal data bus for communication with the CPU, which functions as a dynamic latch.)

But I'd recommend against relying on that behavior, as a dynamic latch decays at an unspecified rate, and emulators and famiclones are unlikely to implement it perfectly. If you want to do read-modify-write on a PPU port, save a backup copy of the port in a variable in RAM:
Code:
VRAM_DOWN = $04

  lda last_PPUCTRL
  ora #VRAM_DOWN
  sta last_PPUCTRL
  sta $2000
Re: Reading and saving $2000: Why does this change the behav
by on (#153103)
tepples wrote:
a dynamic latch decays at an unspecified rate, and emulators and famiclones are unlikely to implement it perfectly

I'm trying to imagine an emulator with a room temperature setting, and simulation of heat dissipation within the NES.
Re: Reading and saving $2000: Why does this change the behav
by on (#153110)
tepples wrote:
But I'd recommend against relying on that behavior

Exactly. After reading all your posts, I won't try to read any of these values at all. If I still need the value, I'll save it into an own variable.
Re: Reading and saving $2000: Why does this change the behav
by on (#153354)
rainwarrior wrote:
tepples wrote:
a dynamic latch decays at an unspecified rate, and emulators and famiclones are unlikely to implement it perfectly

I'm trying to imagine an emulator with a room temperature setting, and simulation of heat dissipation within the NES.

Can you also simulate ZIF stress if region is not set to Japan? :mrgreen:
Re: Reading and saving $2000: Why does this change the behav
by on (#153367)
bootmii wrote:
Can you also simulate ZIF stress if region is not set to Japan? :mrgreen:

Not if we're also simulating a Blinking Light Win.
Re: Reading and saving $2000: Why does this change the behav
by on (#153380)
tepples wrote:
But I'd recommend against relying on that behavior, as a dynamic latch decays at an unspecified rate, and emulators and famiclones are unlikely to implement it perfectly.

Interestingly, it's not a true dynamic latch - the value just sits on the bus lines (via capacitance). Furthermore, writing to VRAM via $2007 actually "stores" the to-be-written value directly on the bus, relying on it not decaying within the dozen or so cycles it takes for the VRAM write to finish. If you were somehow able to write to another PPU register before the VRAM write finished, you'd overwrite the value to be written.