Black screen but debugger shows nametable

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

Post Reply
casprog
Posts: 70
Joined: Fri Oct 28, 2016 12:37 pm

Black screen but debugger shows nametable

Post by casprog »

Hi all,

so everything was working fine with my project until I decided to use some RAM for a collision map (basically an array to hold a 0 for empty space, 1 for occupied space).

After creating the collision map I lose my picture, however the debugger shows my nametable is all there and looks fine on the PPU.

First question is, is there a common denominator to help debug through when the screen is black but the nametable looks fine?

Second question is, does anything in the code stand out as obvious? By the way, prior to updating the nametable I wait for vblank, turn off rendering, write to the PPU, then try to update my collision map. I wait for vblank again, then turn rendering back on.

Code: Select all

nt_collision_ptr .rs 2 ; pointer to nametable collision map

Code: Select all

Reset_nt_collision_ptr:
	; set collision pointer to page 2 in RAM
	LDA #$00 ; low byte
	STA nt_collision_ptr
	LDA #$01 ; high byte
	STA nt_collision_ptr + 1
	;done, $0100
	RTS
Full disclosure on this next bit, originally I added the collision update logic in my nametable loader code but this was also giving me a black screen, so to test I broke it out into its own subroutine but I'm getting the same result. And I know this loop will read an extra 64 bytes from the attribute table but I planned on making this work first (I can save the 64 bytes after this works). What is very weird is, if I remove the STA command under the solid_tile label then my picture comes back..

Code: Select all

Update_collision_map:
	JSR Reset_nt_collision_ptr
	
	LDX #$00
	LDY #$00
update_collision_loop:
	LDA [nametable_ptr], y
	CMP #TILE_CLEAR
	BNE solid_tile
	; empty space
	LDA #$00
	STA [nt_collision_ptr], y
	JMP resume_collision_load
solid_tile:
	LDA #$01
	STA [nt_collision_ptr], y
resume_collision_load:
	INY
	CPY #$00 ; wrap around = 256 tiles 
	BNE update_collision_loop
	; see if next set needs to be processed
	INC nt_collision_ptr + 1
	LDY #$00
	INX
	CPX #$04
	BNE update_collision_loop
	RTS
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Black screen but debugger shows nametable

Post by rainwarrior »

If your nametables and palettes are showing up in the debugger, but the screen is black, there are a few possibilities:

1. Rendering is not turned back on, maybe the write to $2001 never happened?

2. The scroll position is pointing at the second nametable, which might be an empty black page? (When you've finished uploading all 1024 bytes of nametable, the scroll pointer will actually be currently pointed at 0,0 on the subsequent nametable.)

For #1, a possible cause is failing to enable the NMI again (via $2000), your NMI handler will never be able to do that write to $2001.
User avatar
Broke Studio
Formerly glutock
Posts: 181
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Black screen but debugger shows nametable

Post by Broke Studio »

Be careful when using page $0100 in RAM, that's where the stack lives. Try to use another area like $0300 for example.
My first game : Twin Dragons available at Broke Studio.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Black screen but debugger shows nametable

Post by dougeff »

Unrelated, you could make this loop more efficient.

For example

LDA #$00
STA [nt_collision_ptr], y
JMP resume_collision_load

Lda #0 sets the zero flag
sta changes no flags
so we could do...
beq resume_collision_load
and save a byte.

both options do
STA [nt_collision_ptr], y

so you could throw both after resume_collision_load: and save a few bytes.

INY
CPY #$00 ; wrap around = 256 tiles
BNE update_collision_loop

the CPY #0 is redundant.
INY sets the zero flag if its result is zero, so all you need is...

INY
BNE update_collision_loop

and you don't need the LDY #0 below that. It's already zero.

And lastly, if X isn't doing anything but counting, you could start it at #4 and count down to zero, and remove the CPX.

LDX #4
loop:
...
DEX
BNE loop


So, let's optimize it...


Code: Select all

   LDX #$04
   LDY #$00
update_collision_loop:
   LDA [nametable_ptr], y
   CMP #TILE_CLEAR
   BNE solid_tile
   ; empty space
   LDA #$00
   BEQ resume_collision_load
solid_tile:
   LDA #$01
resume_collision_load:
   STA [nt_collision_ptr], y
   INY
   BNE update_collision_loop
   ; see if next set needs to be processed
   INC nt_collision_ptr + 1
   DEX
   BNE update_collision_loop
   RTS
nesdoug.com -- blog/tutorial on programming for the NES
casprog
Posts: 70
Joined: Fri Oct 28, 2016 12:37 pm

Re: Black screen but debugger shows nametable

Post by casprog »

Be careful when using page $0100 in RAM, that's where the stack lives. Try to use another area like $0300 for example.
I'm such a noob :roll: , this resolved the issue glutock.. thank you!


Thanks rainwarrior, I wanted to address your points in case I'm doing these things incorrectly;
1. Rendering is not turned back on, maybe the write to $2001 never happened?
Here is the heart of it. By the way I also swap the background palette when I change my nametables, so I'm setting a flag and doing that part in NMI. The code below is outside of my NMI.

Code: Select all

; turn off rendering
	JSR Wait_vblank
	JSR Disable_rendering
	
	; update palette
	LDA #LOW(select_palette)
	STA palette_ptr
	LDA #HIGH(select_palette)
	STA palette_ptr + 1
	LDA #$01
	STA swap_palette
	JSR Wait_vblank
	
	; load starting nametable
	LDA #LOW(select_nametable)
	STA nametable_ptr	
	LDA #HIGH(select_nametable)
	STA nametable_ptr + 1
	JSR Load_nametable	; this now also updates the collision map so I read from the nametable pointer once
	
	; turn rendering back on
	JSR Wait_vblank
	JSR Enable_rendering	

Code: Select all

; only call this during vblank
Disable_rendering:
	; turn off ppu
	LDA #%00000000
	STA PPUMASK
	RTS

; only call this during vblank	
Enable_rendering:
	; turn on ppu on
	LDA #%00011110
	STA PPUMASK
	RTS
The scroll position is pointing at the second nametable, which might be an empty black page? (When you've finished uploading all 1024 bytes of nametable, the scroll pointer will actually be currently pointed at 0,0 on the subsequent nametable.)
I have this at the end of my NMI, right before I pop the stack

Code: Select all

	; scroll pos
	LDA #$00
	STA $2005
	STA $2005

And thanks for those tips doug! I'm new to assembly, it's interesting to see how the zero flag can work to save some opcodes.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Black screen but debugger shows nametable

Post by rainwarrior »

casprog wrote:I have this at the end of my NMI, right before I pop the stack

Code: Select all

	; scroll pos
	LDA #$00
	STA $2005
	STA $2005
So, going back to one of my earlier suggestions, did you remember to turn the NMI itself back on so that this scroll code can take effect? ($2000 / PPUCTRL)
casprog
Posts: 70
Joined: Fri Oct 28, 2016 12:37 pm

Re: Black screen but debugger shows nametable

Post by casprog »

So, going back to one of my earlier suggestions, did you remember to turn the NMI itself back on so that this scroll code can take effect? ($2000 / PPUCTRL)
Well I leave my NMI running, I never turn it off anymore, I just disable / enable rendering now.

EDIT:: do I need to update $2000 again even if I don't turn it off explicitly?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Black screen but debugger shows nametable

Post by tepples »

I would recommend writing $2000 every frame, as it contains the upper bit of the X and Y scroll position.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Black screen but debugger shows nametable

Post by rainwarrior »

casprog wrote:Well I leave my NMI running, I never turn it off anymore, I just disable / enable rendering now.

EDIT:: do I need to update $2000 again even if I don't turn it off explicitly?
Okay, well have you re-enabled rendering then?

As tepples is suggesting, setting the scroll normally takes 3 writes, $2000, $2005, $2005. All need to be done during vblank. (They take effect at the beginning of the visible frame, if rendering is on.)

They definitely shouldn't be happening every NMI though, only when you have your flag to let your NMI handler do PPU interaction. Otherwise, writing $2005 while you're in the middle of doing updates to your nametables will mess up the address you're trying to write to.


Anyway, the main question is whether these things you expect to be happening are actually happening. Whether or not you wrote code to do them is only part of it. Make sure that code is being executed. Put a breakpoint on the code, or put a breakpoint on writes to $2001 etc.

BTW if you post a ROM someone could use a debugger to answer this question immediately. Reading fragments of your code mostly just creates a lot of questions that only you can answer.
casprog
Posts: 70
Joined: Fri Oct 28, 2016 12:37 pm

Re: Black screen but debugger shows nametable

Post by casprog »

Thanks rainwarrior,

Yes I was enabling rendering again, looks like the issue was my collision map was written to an area of memory which was conflicting with the stack.
They definitely shouldn't be happening every NMI though, only when you have your flag to let your NMI handler do PPU interaction. Otherwise, writing $2005 while you're in the middle of doing updates to your nametables will mess up the address you're trying to write to.
I'll be sure to move that logic under my ppu on flag. And to be safe I added a call to turn NMI back on in my NMI as was suggested earlier.

I appreciate all the help and advice.
Post Reply