PPU display background pattern

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

User avatar
StephenM
Posts: 13
Joined: Fri Aug 30, 2013 10:18 pm
Contact:

PPU display background pattern

Post by StephenM »

Goal: I would like to set the NES background as a single repeating pattern.

Something like this:
Image

Problem: I can't get my pattern to display. I have the pattern I want loaded into the pattern table, I have written the colors I want to the background palette, all name tables are pointing to tile zero, all my attribute tables are zero; yet nothing is being displayed.

Logical program flow (what I think my program is doing):
  • disable interrupts / set stack pointer
  • set PPU control #1 bits to %00001000 so that:
    • D0-D1: name table address set to $2000
    • D2: PPU increment is 1
    • D3: sprite pattern address is $1000
    • D4: background pattern address is $0000
    • D5: sprite size is 8x8
    • D6: ?
    • D7: disable NMI on Vblank
  • set PPU control #2 bits to %00011110 so that:
    • D0: color display
    • D1: no background clipping
    • D2: no sprite clipping
    • D3: background is visible
    • D4: sprites are visible (no sprites in this example)
    • D5-D7: color intensity is set to none
  • clear Vblank flag
  • first wait for Vblank
  • second wait for Vblank
  • enable NMI on Vblank
  • Branch:
    • Main loop constantly sets $00 to whatever is in the Xreg
    • on NMI interrupt
      • write two bytes to the background palette (first is transparency, second is the color I want the pattern to be)
      • write one byte of $00 to name table #0 and attribute table #0 (really does nothing)
I have set up my CHR-ROM to point to the second color I loaded into the background palette. Here is my pattern table and palette according to FCEUX:
Image

Here is my name tables according to FCEUX:
Image

Yet my emulator is only displaying:
Image

Secondary/tangent questions:
  • Why is so much of the NES memory mirrored? From a newb point of view this seems wasteful.
  • From (http://wiki.nesdev.com/w/index.php/Init_code); disabling IRQs (opcode SEI) is good if one might later desire to manually call the RESET routine. This makes sense to me but I have noticed that the order in which NMI and IRQs are enabled (I'm referencing my "INIT:" label in "test.s" below) determines whether or not PPU memory is written to (i.e. calling "CLI" before setting the 7th bit of PPU control #1 to 1 causes pattern table, name table, and attribute table to be empty; it might actually be causing the whole NES to crash, I'm not sure.)
    • Here I'm thinking it might be best to not manually disable IRQs (call SEI) and let the system do it naturally on interrupt for the benefit of simplicity.
"test.s"

Code: Select all

; TESTING
; cl65 -t none -C nes.cfg -o test.nes test.s

; Program ROM
.segment "PRG"

RESET:
	; set up a few things and wait for PPU
	
	SEI            ; in case of manual reset call
	CLD            ; generic 6502 debugger friendly
	
	LDX #$FF       ; setting value for stack pointer
	TXS            ; setting stack pointer
	
	LDX #%00001000 ; PPU control bits
	STX $2000      ; set PPU control register #1
	
	LDX #%00011110 ; PPU control bits
	STX $2000      ; set PPU control register #2

	BIT $2002      ; clears the Vblank flag on read (BIT sets the Neg flag to bit 7)
	
VBLANKWAIT1:
	; wait for PPU to stabilize
	
	BIT $2002       ; sets CPU Neg flag to Vblank flag
	BPL VBLANKWAIT1 ; if the Neg flag isn't set branch to VBLANKWAIT
	
VBLANKWAIT2:
	; wait a second time
	
	BIT $2002       ; sets CPU Neg flag to Vblank flag
	BPL VBLANKWAIT2 ; if the Neg flag isn't set branch to VBLANKWAIT
	
INIT:
	; enable interrupts
	
	LDX #%10001000 ; PPU control bits
	STX $2000      ; set PPU control register #1
	
	CLI
	
LOOP:
	; main loop
	
	STX $00
	JMP LOOP
	
	RTI

NMI:
	; Non-maskable interrupt
	
	LDA #$3F       ; set address pointer in VRAM to $3F00
	STA $2006
	LDA #$00
	STA $2006
	
	LDA #$17       ; write a little to background palette
	STA $2007
	LDA #$03
	STA $2007
	
	LDA #$20       ; set address pointer in VRAM to $2000
	STA $2006
	LDA #$00
	STA $2006
	
	LDA #%00000000 ; write a little to name table #0
	STA $2007
	
	LDA #$23       ; set address pointer in VRAM to $23C0
	STA $2006
	LDA #$C0
	STA $2006
	
	LDA #%00000000 ; write a little to attibute table #0
	STA $2007
	
	RTI

IRQ:
	; Interrupt request

	RTI

; iNES header
.segment "HDR"
	.byte "NES" ; signature
	.byte $1A   ; signature
	.byte $02   ; # of 16kb PRG-ROM banks
	.byte $01   ; # of 8kb CHR-ROM banks
	.byte $00   ; ROM control byte one
	.byte $00   ; ROM control byte two
	.byte $00   ; # of 8kb RAM banks
	.byte $00   ; reserved

; Vectors
.segment "VEC"
	.addr NMI
	.addr RESET
	.addr IRQ

; Pattern tables
.segment "CHR"
	; one tile

	; least significant bit one
	.byte %00011000
	.byte %00100100
	.byte %01011010
	.byte %01000010
	.byte %01000010
	.byte %01011010
	.byte %00100100
	.byte %00011000
	
	; least significant bit two
	.byte %00000000
	.byte %00000000
	.byte %00000000
	.byte %00000000
	.byte %00000000
	.byte %00000000
	.byte %00000000
	.byte %00000000

User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: PPU display background pattern

Post by koitsu »

I see no $2005 writes or clearing of $2006, which from what I can see looks to be the root cause (based on lines shown in the 3rd screenshot, which indicate where the X/Y scroll are at).

http://wiki.nesdev.com/w/index.php/PPU_scrolling
http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

I can give out about 5 or 6 URLs of threads here on the forum discussing all of this too, and they're just as convoluted. Just search for any posts from me with $2005 or PPUSCROL mentioned, but I guess the most applicable post would be this one from tokumaru:

viewtopic.php?p=108239#p108239
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Re: PPU display background pattern

Post by doppelganger »

I see two problems with your code.

First, there is something you need to know about the address register at $2006: it is also used by the PPU during rendering. It needs to be initialized during vertical blank after using it to update PPU RAM (tables, palette). There are two other registers that affect the internal address latch: $2000 and $2005. Ideally, you should do the following after updating whatever needs to be updated in PPU:

A. Set the scroll in $2005 to whatever horizontal and vertical scroll values you need, and
B. Set $2000 using the name table you need for bits 1 and 0 (making sure to appropriately set the NMI enable and sprite/background bits).

Second, you did not disable the 2a03 APU's frame counter by writing a 1 to bit 6 of $4017. This means that it will continue to send IRQs to the CPU until:

A. the frame interrupt is acknowledged by reading $4015, or
B. the frame interrupt is inhibited by writing a 1 to bit 6 of $4017.

The fastest way to deal with this, of course, is to simply do an SEI and be done with it, if you're not using any IRQs at all, which is the approach I would go with in this case.
Secondary/tangent questions:

Why is so much of the NES memory mirrored? From a newb point of view this seems wasteful.
From (http://wiki.nesdev.com/w/index.php/Init_code); disabling IRQs (opcode SEI) is good if one might later desire to manually call the RESET routine. This makes sense to me but I have noticed that the order in which NMI and IRQs are enabled (I'm referencing my "INIT:" label in "test.s" below) determines whether or not PPU memory is written to (i.e. calling "CLI" before setting the 7th bit of PPU control #1 to 1 causes pattern table, name table, and attribute table to be empty; it might actually be causing the whole NES to crash, I'm not sure.)
Here I'm thinking it might be best to not manually disable IRQs (call SEI) and let the system do it naturally on interrupt for the benefit of simplicity.
NES memory is mirrored because Nintendo wanted to keep manufacturing costs low, I think.

IRQs need to be acknowledged by the programmer (the method of this depends on what hardware causes the IRQ), or they will execute continuously. This, I think, was meant to allow for multiple IRQs occurring, so that each hardware that requested the interrupt could be serviced in turn. IRQs are not supposed to interfere with NMIs ideally. The only reason why it would happen on the NES is because the IRQs are firing off continuously before the PPU hardware is given a chance to be allowed to fire off NMIs.

Interrupts only disable IRQs until the RTI instruction is executed. The RTI instruction returns the I flag to whatever it was set to before. Therefore, you still need to disable IRQs outside of interrupt code if you don't want them to happen.

I hope this hasn't been too confusing, I will attempt to clarify if need be.
Be whatever the situation demands.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: PPU display background pattern

Post by tokumaru »

StephenM wrote:Why is so much of the NES memory mirrored? From a newb point of view this seems wasteful.
Quite the opposite! Mirroring memory requires less logic/hardware than NOT mirroring it. If you have only 2KB of memory to fill a space of 8KB, it's AUTOMATICALLY mirrored to fill the whole space. Since there are no negative side effects from the mirroring in most cases, it's cheaper/simpler to just leave the mirrors alone.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: PPU display background pattern

Post by blargg »

I think he meant wasteful of the address space. Like you say, though, it's a tradeoff: waste logical address space, or use more hardware. Given the lack of need for logical address space, they choose to use less hardware.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: PPU display background pattern

Post by koitsu »

Off-topic:

I've never understood, on the NES/6502, what purpose mirrored CPU addressing ranges served. I'm specifically referring to $0800 to $1FFF and $2008 to $3FFF.

I fully understand what it provides in the case of the SNES/65816, where for example portions of bank $00 are mirrored throughout other banks -- the purpose there should be obvious.

Likewise, on the Apple IIGS (again 65816), there were some "shadowed" (mirrored) registers and memory ranges which I was told time and time again by older/senior programmers should be used because, somehow at some particular level (hardware-wise), "they were faster than using the non-shadowed versions". I still don't understand how this can be the case, since it's going to cost the same number of CPU cycles no matter what the address is; I can see the benefit if there's a separate bus that runs at a higher clock speed that the mirrored/shadowed areas ties into, and that, say, a DMA chip could utilise (for memory copying/transfer), but the IIGS had no such thing. The only thing that made sense (in this regard) was the "mirroring" of banks $00 and $01 to banks $E0 and $E1 on the IIGS, where banks $00/01 ran at a slower clock speed (to be compatible with the earlier Apple II models) while banks $E0/E1 ran at a higher clock speed (reference; search for the phrases "shadowing is the term" and "$E0 and $E1 execute at standard clock speed"). I believe what I'm remembering are people telling me to access certain registers via $E0C0xx rather than $00C0xx to benefit from the higher clock speed; but how this matters I still don't understand (for example both sta $e0c034 and sta $00c034 would take 5 cycles (assuming 8-bit accum)).

Anyway, in the case of the NES/6502, I just don't see anything advantageous from the aforementioned mirroring.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: PPU display background pattern

Post by blargg »

2A03 has limited pins. PPU/SRAM/etc. decoding is done externally with a '139. This generates select signals for the cartridge, internal SRAM, and PPU. It would have taken 3 more pins on the 2A03. I'm guessing that this would have pushed it into a package size that cost noticeably more at the time (economics of size aren't just the small amount of extra plastic/pins, but the quantity produced, molds, etc.) 2A03 and 2C02 also both have 40 pins, so they probably get some economy by using the same count.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: PPU display background pattern

Post by rainwarrior »

koitsu: Why would there need to be a software advantage to justify the mirrors on the NES? If it simplifies the hardware to leave it mirrored, isn't that purpose enough?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: PPU display background pattern

Post by koitsu »

Well the 2A03 has 16 pins for A0-A15 (hence making up the full 16-bit address bus), and I understand that a 74LS139 is used to handle designation of "what speaks to what" (CPU vs. PPU vs. SRAM vs. external), but I still don't see how that justifies the $0800-1FFF and $2008-3FFF mirroring within CPU addressing space. Why is that needed? Why couldn't it just be left floating/open bus for the CPU? Or is there some kind of "commonality" (not sure what other word to use here) between the addressing spaces (as far as the 74LS139 goes) within the PPU vs. CPU vs. SRAM vs. external that justifies this need?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: PPU display background pattern

Post by koitsu »

rainwarrior wrote:koitsu: Why would there need to be a software advantage to justify the mirrors on the NES? If it simplifies the hardware to leave it mirrored, isn't that purpose enough?
How does it simplify the hardware design? That hasn't been explained. A reference to a 74LS139 decoder being used does not explain why said CPU addressing ranges needed to be mirrored (respectfully blargg, not arguing or being combative).
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: PPU display background pattern

Post by tepples »

Leaving certain address ranges as open bus would have required more hardware to generate the select signals for those ranges.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: PPU display background pattern

Post by blargg »

The '139 has two one-of-four decoders. Each has an active-low enable, two inputs, and four active-low outputs.

Code: Select all

A   B  /EN /Y0 /Y1 /Y2 /Y3
---------------------------
X   X   H   H   H   H   H
L   L   L   L   H   H   H
L   H   L   H   L   H   H
H   L   L   H   H   L   H
H   H   L   H   H   H   L
The NES feeds the first one A from PHI2 and B from A15, with /EN low so it's always enabled. This generates /Y1 on access to 0-$7FFF, and /Y3 on access to $8000-$FFFF. The latter goes directly to the cartridge. /Y0 and /Y2 aren't useful as they indicate the other half of a cycle.

/Y1 is tied to the second decoder's enable, so it's enabled on access to the low half of the address space. A goes to A13 and B to A14. This divides the low half into four segments, 0-$1FFF, $2000-$3FFF, $4000-$5FFF, and $6000-$7FFF. It uses /Y0 for SRAM and /Y1 for the PPU. To "fully decode" SRAM, it'd need to look at A12 and A11, only enabling then they're low. To fully decode the PPU, it'd need to additionally look at A3-A12 (10 additional address lines), only selecting the PPU when they are all low. This adds hardware and latency due to gate propagation delays.

Incomplete decoding is elegant in the context of doing enough to work and not wasting extra hardware on things that don't matter.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: PPU display background pattern

Post by rainwarrior »

Well, for example, mirroring a particular range 4 times means that there are 2 bits in the address decoding for it that don't have to do anything. The mirroring is simply a side effect of ignoring those bits.

Mirroring is a just a side effect of not using more address lines than are strictly needed. It's not a situation you would normally go out of your way to create, because mirrors aren't normally useful. (The Apple II thing you described is fairly unusual, I think.)
User avatar
StephenM
Posts: 13
Joined: Fri Aug 30, 2013 10:18 pm
Contact:

Re: PPU display background pattern

Post by StephenM »

I see no $2005 writes or clearing of $2006, which from what I can see looks to be the root cause
A. Set the scroll in $2005 to whatever horizontal and vertical scroll values you need, and
B. Set $2000 using the name table you need for bits 1 and 0 (making sure to appropriately set the NMI enable and sprite/background bits).
Thanks! Seems like scrolling can get quite complicated! I will eventually have to master scrolling in both horizontal and vertical directions.

I've added the following ASM, it seems to put my X, Y at (0, 0) and clear $2006 which is what I'm going for.

Code: Select all

LDA #$00       ; x position
STA $2005
LDA #$00       ; y position
STA $2005
	
LDA #$00       ; clear $2006
STA $2006
LDA #$00
STA $2006
(no reason why I'm setting the accumulator multiple times. I wouldn't do this in a real project)

It seems that the bigger problem was that PPU control byte #2 was being written to $2000 instead of $2001, that explains why nothing was being displayed. I must have copied and pasted the first PPU control line, changed the bits, but forgot to change the address it was being written to.

Success!
Image
3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Re: PPU display background pattern

Post by 3gengames »

StephenM wrote:

Code: Select all

LDA #$00       ; x position
STA $2005
LDA #$00       ; y position
STA $2005
	
LDA #$00       ; clear $2006
STA $2006
LDA #$00
STA $2006
Wrong, you have to not care about $2006, and write to $2005 two times, and then to $2000 to set the scroll. Only use $2006 to set scroll during rendering.
Post Reply