Question about NMI / displaying new background

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
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Question about NMI / displaying new background

Post by NeverCameBack » Wed Mar 18, 2020 10:09 pm

Can anyone let me know if this is a correct summarized order?

1. Initialize title screen:
- Read from the PPU to reset it's stack count
- Basically send 1024 bytes of data to $2007 (one Nametable + 32 attributes)

2. NMI interrupt
- Store #$00 into $2003, and store #$02 into $4014 - This will start the transfer of backgrounds, attributes, and sprites from the CPU to PPU memory.

3. If you want to change the background screen:
- Have something activate code that is the same thing as #1., the only difference is that this code has different pointers to pull the next set of 1024 bytes.

4. The RTI brings you back to "jump forever" or what have you to wait for the next NMI to hit.

5. When the next NMI hits, it sends your new background data that was put into $2007 into the PPU memory to be displayed.


I'm trying to make a simple two screen program.
When you press "a", it should put a second set of 1024 bytes into $2007. Then the next NMI, I would think it should throw that into the PPU memory.
The first set of 1024 bytes is located at $E000 - $E3FF, the second set starts at $E400 - $E7FF.

However when I press "a", the second screen shows up as a jumbled mess (of what looks to be not even the second set of 1024 bytes).

The first screen is the test title screen (shows up fine)
The second screen should have a #2 graphic.

Thanks for any help anyone can offer. Sorry to blow up the newbie center with help questions. I've used the debugger on FCEUX, but couldn't tell what was going wrong from there.
SwitchingScreens1.PNG

SwitchingScreens2.PNG
Attachments
background3.asm
(19.91 KiB) Downloaded 33 times

lazigamer
Posts: 23
Joined: Mon Oct 10, 2011 9:05 am

Re: Question about NMI / displaying new background

Post by lazigamer » Thu Mar 19, 2020 12:38 am

You need to disable background and sprite rendering before writing the second background to the PPU then re enable them afterwards bits 3 and 4 of $2001. The PPU can't be written to while it is rendering, it produces unstable writes, only while rendering is disabled or while you're in vblank or hblank does writing work.

User avatar
tokumaru
Posts: 11692
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about NMI / displaying new background

Post by tokumaru » Thu Mar 19, 2020 12:40 am

NeverCameBack wrote:
Wed Mar 18, 2020 10:09 pm
1. Initialize title screen:
- Read from the PPU to reset it's stack count
- Basically send 1024 bytes of data to $2007 (one Nametable + 32 attributes)
What do you mean by "stack count"? Reading $2002 (PPU STATUS) resets the latch that controls whether the high byte or the low byte of the PPU address is being written... is that what you mean? You first reset the latch by reading $2002, then set the address by writing the high byte of the address to register $2006 (PPU ADDRESS), then the low byte. Then you write all the data via register $2007 (PPU DATA). And the 1024 bytes that form a complete background are actually divided into 960 (32x30) name table bytes + 64 (8x8) attribute bytes.
2. NMI interrupt
- Store #$00 into $2003, and store #$02 into $4014 - This will start the transfer of backgrounds, attributes, and sprites from the CPU to PPU memory.
The procedure is correct, but it only transfers sprite attributes from RAM to the OAM (which IS memory inside the PPU, but it's NOT part of VRAM). Backgrounds, patterns, etc. are transferred directly via $2006/$2007 (as you described in step 1).
3. If you want to change the background screen:
- Have something activate code that is the same thing as #1., the only difference is that this code has different pointers to pull the next set of 1024 bytes.
Another difference is that you can't just do it out of the blue, you first have to wait for vblank, turn rendering off, and then you have unrestricted access to VRAM again. If you try to write to the PPU "whenever", you'll end up trying to transfer data while the PPU is rendering, and that's a very catastrophic thing in NES world.
4. The RTI brings you back to "jump forever" or what have you to wait for the next NMI to hit.
"Jump forever" is a quick and dirty way to structure an NES program, but it's good enough for simpler programs. Hey, it's good enough for SMB!
5. When the next NMI hits, it sends your new background data that was put into $2007 into the PPU memory to be displayed.
That's not really how it happens. $2007 is not any kind of buffer, it's a direct port to VRAM: When you write to $2007, the data immediately goes to VRAM. That's why you can't do that whenever you want, you have to wait for vblank (i.e. the NMI handler) and update a modest amount of PPU data before the vblank ends (a sprite DMA plus a 100 or so bytes worth of other stuff is easily doable) OR you need to disable rendering if you need unrestricted VRAM access in order to write larger amounts of data (this is what you'd do to update an entire screen).

I'm trying to make a simple two screen program.
Looking at your code, it does look like you're immediately trying to draw a new screen after detecting that A was pressed. Problem is, drawing a new screen takes a lot of time, what more than there is in a single vblank, so by the time the next frame starts being rendered, you're still trying to write data to VRAM, and you just can't write to VRAM while the PPU is reading it to render the screen. The result is a bunch of corrupted data.

Writing a new screen is a big procedure, and you kinda have to stop everything else for a while in order to do it. Your input code is doing the correct thing: it's signaling that a screen change was requested, instead of doing it right on the spot. But right after the controller handling you're updating the background on the spot anyway, so that's gotta change. Updating the current screen or changing to a new one is a big decision, so you should probably make that decision early on in the NMI handler. Here's a rough idea of what your NMI handler could look like:

Code: Select all

NMI:

	;check whether a new screen has to be loaded
	lda NewScreenIndex ;get the new screen index
	cmp CurrentScreenIndex ;compare it with the current one
	beq UpdateCurrentScreen ;if they're the same, don't change screens
	jmp LoadNewScreen ;if they're different, go load a new screen
	
UpdateCurrentScreen:

	;do a sprite DMA
	lda #$00
	sta $2003 ;reset the OAM address
	lda #$02
	sta $4014 ;copy 256 bytes from $0200 to OAM

	;configure the PPU
	lda #%10010000 ;enable NMI, etc.
	sta $2000
	lda #%00011110 ;enable rendering, etc.
	sta $2001
	
	;reset the scroll
	lda #$00
	sta $2005
	sta $2005

	;GAME LOGIC GOES HERE

	;return from the interrupt
	rti

LoadNewScreen:

	;double the index so we can use it to read from a table of 16-bit addresses
	asl
	tax

	;disable rendering and NMIs
	lda #$00
	sta $2000
	sta $2001

	;copy the address of the screen data to a pointer
	lda ScreenTable+0, x
	sta ScreenPointer+0
	lda ScreenTable+1, x
	sta ScreenPointer+1

	;set the output address
	lda #$2002
	lda #$20
	sta $2006
	lda #$00
	sta $2006

	;copy the screen to VRAM
Copy1024Bytes:
	ldx #$04
Copy256Bytes:
	ldy #$00
Copy1Byte:
	lda (ScreenPointer), y
	sta $2007
	iny
	bne Copy1Byte
	inc ScreenPointer+1
	dex
	bne Copy256Bytes

	;enable NMIs
	lda $2002 ;avoid getting a partial vblank
	lda #%10000000
	sta $2000

	;return from the interrupt
	rti

ScreenTable:
	.dw Screen0, Screen1, Screen2, Screen3, Screen4
Note that this code can load any background as long as it's listed in the table at the bottom, so you don't need different loops to read each background (in an actual game, you could expand LoadNewScreen to do more than just load a new background - it could load new enemies, palettes, music, etc.). You can even load the very first screen this way - just set NewScreenIndex to the index of the first screen and CurrentScreenIndex to anything other then that, and the very first time the NMI handler runs it will detect that you want to change screens and it will load the first screen for you.

There's another very important thing you have to change in your code: in your main thread, enabling NMIs has to be the very last thing you do before entering the "forever" loop, otherwise an NMI may fire while you're doing other stuff and it'll screw up whatever the main thread was doing, since the NMI handler changes registers, the VRAM address, and so on.

And you also want to read $2002 before enabling NMIs (like I did in the code above) in order to clear the vblank flag. If you turn NMIs on while the vblank flag is set (i.e. the PPU is in the middle of vblank), an NMI will fire right away, and that's bad because that instance of the NMI handler won't have the full duration of vblank to do its work, since the PPU was in the middle of it!

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: Question about NMI / displaying new background

Post by NeverCameBack » Thu Mar 19, 2020 6:13 pm

Thank you on an extreme level for the detailed reply. If I can help you in some way a newbie could, like creating a sprite or testing something, let me know. I'm dabbling in a little Famitracker on the side right now too.

About the "Stack count" - Yes, the way I thought of it was that reading the PPU status would reset the address where the PPU is going to place the next byte back to the bottom, or starting point. It was news to me that what I considered step #2 only wrote sprite data.

Is it correct to say that if you start sending bytes to $2007, which is the highway leading to the PPU's VRAM, at any time the sending of these bytes might get cut off (NMI happens), or the receiving might get cut off (VBLANK ends). However, if you turn off the PPU's rendering, and THEN send the bytes to the CPU address $2007, THEN the PPU can intercept these bytes uninterrupted. Turning off the NMI interrupt also insures the CPU completes the send. Once you turn back on the NMI interrupt, the CPU program can continue. Once you turn back on the PPU rendering, the PPU is then ready to render the new 1024 bytes that it received in it's VRAM.

Does that sound like the idea of it?

I tried to implement a simplified version of the code you had sent (just starting with one background rendered after an NMI) - However I was still getting the image that appears in my second picture from before... However I then made the $2007 write only happen once per "screen change request", by using a kind of "one-shot" variable that resets itself to 0 after the $2007 write. It is now working for two screens! Now I'm gonna work on enhancing it as per your sample code (one loop to write to $2007 instead of two).

Attached is the code in case another newbie wants to see it.

background3.asm
(21.2 KiB) Downloaded 31 times

User avatar
dougeff
Posts: 2680
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Question about NMI / displaying new background

Post by dougeff » Thu Mar 19, 2020 7:38 pm

might get cut off (NMI happens)
The way you have it (all in the NMI), you would get an infinite loop if NMI happened in the middle of the NMI code.

The other concern, the reason 0 stored to 2001, is that PPU writes during active screen time will be corrupted gibberish.

So, NMI off to avoid infinite loop. Screen off, so your writes work.

I think you have the basics of it, but your code could be improved.

For example, consider... after finishing writing to the PPU, wait for v-blank before turning the screen on, to avoid a possible 1 frame of misalignment.

Another consideration. Don't repeat yourself. DRY. Writing to the screen is something a sub-routine can handle. That way, the code doesn't need to be written twice or more. For example, write the address to the pointers, then call a function JSR to loop through 1024 writes. Then return RTS.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
tokumaru
Posts: 11692
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about NMI / displaying new background

Post by tokumaru » Thu Mar 19, 2020 8:34 pm

Another point where you can avoid repeating yourself is if you only enable rendering in the NMI handler. You're already doing that there and the NMI runs every frame, so there's no point in doing it anywhere else. This will also guarantee that you only turn rendering back on vblank.

Anyway, you do seem to get the general idea now, and with time you'll probably figure out how you can improve the little things that are still a bit off but shouldn't cause any problems for now.

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: Question about NMI / displaying new background

Post by NeverCameBack » Fri Mar 20, 2020 1:12 am

Thank you both.

One more thing I'd like to confirm:
Is there not a way to utilize both nametables (0 and 1) for a single background?

I'm trying to break up my loop to where it loads 960/2 = 480 bytes from nametable 0.
Then I would write #%10010000 to $2000 (I was hoping this would cause the next bytes to come from Nametable 1).
Then I'd continue the loop and send the next 480 + 64 attribute bytes to $2007.

I'm finding it doesn't work like that.
It would make sense that it doesn't, if we only tell the PPU once which nametable to map the $2007 bytes to. It does it's render, and that is that.
If there is no way around it, maybe it is just a limitation of the NES. But I seem to remember games with almost full screen images.. Like Batman.. I turned on Die Hard the other day and it had some images too. Maybe they're just cleverly re-using tiles from only one of the name-tables.


P.S.
Just discovered, using GIMP (A free tool probably like Photoshop) - I set a palette to four colors back when I was preparing images to display on the virtual boy. I found that you can use snipping tool to take any image, paste it into GIMP... Then GIMP will convert it into the four colors (not always perfect, but mostly works good). I can then copy from GIMP and paste into YY-CHR. A pretty quick way to get a detailed image in a .chr file.
I'm sure most know a better way, but I just found this out.

GIMPtoYYCHR.PNG

User avatar
Quietust
Posts: 1556
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Question about NMI / displaying new background

Post by Quietust » Fri Mar 20, 2020 5:59 am

NeverCameBack wrote:
Fri Mar 20, 2020 1:12 am
Thank you both.

One more thing I'd like to confirm:
Is there not a way to utilize both nametables (0 and 1) for a single background?

I'm trying to break up my loop to where it loads 960/2 = 480 bytes from nametable 0.
Then I would write #%10010000 to $2000 (I was hoping this would cause the next bytes to come from Nametable 1).
Then I'd continue the loop and send the next 480 + 64 attribute bytes to $2007.

I'm finding it doesn't work like that.
It would make sense that it doesn't, if we only tell the PPU once which nametable to map the $2007 bytes to. It does it's render, and that is that.
If there is no way around it, maybe it is just a limitation of the NES. But I seem to remember games with almost full screen images.. Like Batman.. I turned on Die Hard the other day and it had some images too. Maybe they're just cleverly re-using tiles from only one of the name-tables.
When you are writing to VRAM, you should only be using $2006 to specify your target address, and you'll need to take into account your current nametable mirroring configuration - for example, if you're using Horizontal Mirroring, you'll need to write the first nametable to VRAM $2000 and the second one to VRAM $2800.

The nametable bits in $2000 are only used for setting up rendering at the beginning of the next frame, along with $2005 for specifying the horizontal and vertical scrolling offset relative to that nametable.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

tepples
Posts: 21973
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Question about NMI / displaying new background

Post by tepples » Fri Mar 20, 2020 7:46 am

Perhaps what you meant is ability to display from both pattern tables. This can be done by setting up a sprite 0 hit and writing with the opposite pattern table. You can get over 500 tiles in a picture that way.

But I don't see a need for that quite yet. Your illustration already has a lot of duplicate tiles, and if there end up being fewer than 256 unique tiles, you can use one pattern table throughout the whole image. And if there are more, JRoatch wrote a tool to search for similar tiles and make them the same.

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: Question about NMI / displaying new background

Post by NeverCameBack » Fri Mar 20, 2020 6:01 pm

tepples wrote:
Fri Mar 20, 2020 7:46 am
Perhaps what you meant is ability to display from both pattern tables. This can be done by setting up a sprite 0 hit and writing with the opposite pattern table. You can get over 500 tiles in a picture that way.

But I don't see a need for that quite yet. Your illustration already has a lot of duplicate tiles, and if there end up being fewer than 256 unique tiles, you can use one pattern table throughout the whole image. And if there are more, JRoatch wrote a tool to search for similar tiles and make them the same.
Can you tell me what is meant by a sprite 0 hit?
I was thinking to use the sprites to show the rest of the image, but then I remembered, it is not possible to show more than 8 sprites in one scanline.
So the most I could do is display an 8 x 30 pixel column ?
Now that you mention it, I guess that is one way that I could display the whole image. Left half is made of sprites, right half is made of background tiles. I'll give it a try, and will check that link. Thank you.

Also, the screenshot is just the first .chr table doubled. There should be the bottom half of the woman shown too.

User avatar
tokumaru
Posts: 11692
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about NMI / displaying new background

Post by tokumaru » Fri Mar 20, 2020 7:41 pm

Sprites can be used to add detail and color to large background images, but with only 64 of them and the limit of 8 per scanline you can't really fill large areas with them.

A sprite zero hit is a way to synchronize the CPU with the PPU, so you can change rendering parameters as the image is rendered and affect the resulting image on the fly.

Since the name tables are made of 8-bit entries, there's no way to reference more than 256 unique tiles. What you can do is switch the pattern table mid-screen, so that the top of the screen uses one set of 256 tiles, and the bottom uses another set of 256 tiles.

Keep in mind that the NES redraws the entire picture every frame. It is constantly reading name table bytes, fetching the corresponding patterns from the pattern table, reading the attribute bits and combining them with the pattern bits to get the indices of the palette entries to figure out which pixels to output. This means that if you interfere with that process at the correct times and change some of the rendering parameters, you can sometimes do more than the raw limitations of the system would have you believe is possible.

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: Question about NMI / displaying new background

Post by NeverCameBack » Fri Mar 20, 2020 9:12 pm

It is constantly reading name table bytes, fetching the corresponding patterns from the pattern table, reading the attribute bits and combining them with the pattern bits to get the indices of the palette entries to figure out which pixels to output. This means that if you interfere with that process at the correct times and change some of the rendering parameters, you can sometimes do more than the raw limitations of the system would have you believe is possible.
[/quote]

So maybe it is not that the PPU, right before rendering the screen, goes and maps each background byte sent to $2007 (00 - FF) to whichever of the two .chr tables (0 or 1) is currently specified for background rendering? It is instead the case that it considers each background byte at a time, and maps it to whichever .chr table was specified for background rendering at the time that byte was sent on the $2007 highway?


It looks like I have two options for displaying a 500+ tile background:

#1 - Zero sprite hit:
- 64 bytes are sent to $0200 to be rendered (but can't have more than 8 out of these 64 in one row).
- NMI interrupt and PPU rendering is turned back on.
- Repeat the two above steps three more times - copying a total of 256 bytes.
My perceived problem with this method is that: Wouldn't the PPU only display the most recent 64 bytes written to it each render? As in it would forget about the previous 64 written, and ultimately only be displaying 64 bytes at a time? Also, if you ran a loop to repeat the four 64 byte sprite writes, wouldn't there be a noticeable flicker on the screen as it cycles through displaying one 64 byte "group" at a time and infinitely repeats?


#2 - Switch which pattern table my background is being composed of - mid screen
- Write 480 bytes of background tiles while specifying #%00000000 to $2000 (tell backgrounds to render from .chr table #0)
- Attribute data will be filled in with the remaining background tiles during the next loop.
- Re-enable NMI and PPU rendering - let the PPU write the top half of the screen from .chr table #0.
- Write #%00010000 to $2000 (tell backgrounds to render from .chr table #1)
- Write the second 480 background tiles, plus the 64 attribute bytes.
- Re-enable NMI and PPU rendering - let the PPU write the BOTTOM half of the screen from .chr table #1.

The second one I've tried with no success, however I did not let the first half of the screen be rendered, followed next by the second half + attributes. Instead I tried to switch the .chr table after the first 480 bytes were written, then load the next 480 bytes + 64 attribute bytes in the second loop - THEN enable NMI and rendering. Doing it this way resulted in the whole screen being rendered from .chr table #0.

User avatar
tokumaru
Posts: 11692
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about NMI / displaying new background

Post by tokumaru » Fri Mar 20, 2020 10:09 pm

NeverCameBack wrote:
Fri Mar 20, 2020 9:12 pm
So maybe it is not that the PPU, right before rendering the screen, goes and maps each background byte sent to $2007 (00 - FF) to whichever of the two .chr tables (0 or 1) is currently specified for background rendering? It is instead the case that it considers each background byte at a time, and maps it to whichever .chr table was specified for background rendering at the time that byte was sent on the $2007 highway?
It's none of those. The pattern table selection has no effect at all on the data that is sent to VRAM via $2007. That is just a data transfer, whatever you send through $2007 will be transferred as is to the current VRAM address and then that address will increment (by 1 or by 32, you can pick which beforehand via register $2000). The PPU doesn't know or care what the bytes you're sending mean, they're just written as is to whatever address you specify.

Up until rendering starts, all of those bytes are just numbers in memory with no meaning at all. It's the "program" inside the PPU that gives meaning to those values, every frame. You don't have to memorize it or even understand it right now, but look at the diagram at the end of this page and you'll see what the PPU does on every pixel of every scanline. It constantly fetches data from VRAM and from other memory (OAM, palette RAM) and combines all that data in order to calculate the colors of the pixels it sends to the TV. That's when all those numbers are given a meaning, when the PPU combines them in a certain way according to certain parameters. If you change some of those parameters as the PPU is rendering the picture, that will affect how the PPU combines the data that forms the final pixels.

There are two main reasons why the PPU was designed this way:

1- Memory was expensive. It would have been much easier if each pixel on the screen was represented by one byte and programmers had the freedom to draw whatever they wanted, but that would take over 60KB of memory for a single screen. The NES has only 2KB built in + 8KB it can access on the cartridge, so that idea was out.

2- CPUs were slow. If each pixel on the screen had its own byte in memory, you'd have to manipulate an insane amount of bytes in order to change anything on the screen, and there's no way a 1.79MHz 8-bit CPU could handle the job. By breaking things up in smaller parts they made it possible for a primitive CPU to manipulate the screen fast enough to create smooth gaming experiences. We do lose on fidelity, of course, but everything is a compromise when it comes to technology.
#1 - Zero sprite hit:
- 64 bytes are sent to $0200 to be rendered (but can't have more than 8 out of these 64 in one row).
Using the sprite 0 hit doesn't mean that you're gonna draw the picture using sprites. The sprite 0 hit is just a means of synchronizing the CPU with the PPU, so you know WHEN to switch to the other pattern table. It goes like this: You place sprite 0 on the scanline where you want to switch patterns, and make sure that it has an opaque pixel overlapping an opaque background pixel. As the PPU renders the screen, it will eventually reach that pixel, and when that happens it will set the "sprite 0 hit flag" (in register $2002), allowing the program running on the CPU to know that the PPU reached that specific point.
My perceived problem with this method is that: Wouldn't the PPU only display the most recent 64 bytes written to it each render? As in it would forget about the previous 64 written, and ultimately only be displaying 64 bytes at a time? Also, if you ran a loop to repeat the four 64 byte sprite writes, wouldn't there be a noticeable flicker on the screen as it cycles through displaying one 64 byte "group" at a time and infinitely repeats?
64 sprites is not the same as 64 bytes. Each sprite needs 4 bytes of information in order to be displayed, and that's 256 bytes total for the 64 sprites.
- Write 480 bytes of background tiles while specifying #%00000000 to $2000 (tell backgrounds to render from .chr table #0)
Like I said, the pattern table selection is irrelevant at the time you're writing the tile indices to VRAM.
- Re-enable NMI and PPU rendering - let the PPU write the top half of the screen from .chr table #0.
- Write #%00010000 to $2000 (tell backgrounds to render from .chr table #1)
Yes, and you'll know when to do that $2000 write when the sprite 0 hit happens.
- Write the second 480 background tiles, plus the 64 attribute bytes.
Nope, all the data has to be written beforehand, when rendering is turned off.

If you disable rendering mid-screen to transfer data to VRAM you'll get a huge section of "blank" on the screen. The PPU never stops sending a video signal to the TV, so if you turn rendering off mid-screen it will start sending blank pixels to the TV.

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: Question about NMI / displaying new background

Post by NeverCameBack » Sat Mar 21, 2020 1:26 am

I think I understand.

That sprite 0 hit is the bottom part of the status bar coin in SMB1.
If I put sprite 0 at a position at the middle of the screen, I can use the resulting trigger to immediately do a write of $10010000 to $2000, causing the background after that moment to be sourced by the PPU from .chr table #1.

I read the wiki on sprite 0 - so as I understand it resets itself at the beginning of the next frame.

I believe I'm getting sprite 0 to hit with the following:

Code: Select all

- Up here #%10001000 is stored to $2000 - meaning .chr table 0 will be used for the background

NMI:

  LDA WaitForZero ; This will be set to 1 after "A" is pressed and a background is written to $2007
  CMP #$01
  BEQ WaitForSpZero
  JMP UpdateCurrentScreen
  
  
WaitForSpZero:
  LDA $2002
  CMP #%01000000
  BEQ SetBGtoOne
  JMP WaitForSpZero
  
SetBGtoOne:
  LDA #%10011000   ; enable NMI, background from Pattern Table 1
  STA $2000
  LDA #$00
  STA WaitForZero
  
- Continue with check


My hope was that this would catch the PPU midway though rendering the background when it hits sprite 0, and instruct it to continue loading the rest of the background tiles from .chr table #1.

It didn't seem to work though - I'm almost sure that I'm detecting the sprite 0 hit (when I change the #%0100000 value in the compare instruction, I get stuck in the infinite loop "WaitforSpZero").

Now when I push "A" I get a flash of two imaged stacked vertically from .chr table 0, followed by a solid screen of two images stacked vertically from .chr table 1... I may be getting closer.. Will work on it more tomorrow.

User avatar
tokumaru
Posts: 11692
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Question about NMI / displaying new background

Post by tokumaru » Sat Mar 21, 2020 1:43 am

A few things to keep in mind:

- Put the sprite 0 check at the end of the NMI handler. You are able to do updates AND have a split screen, but the updates must come first. Only start waiting for the sprite hit once everything else that's PPU-related (including setting the scroll) is done.

- Before waiting for the flag to be set, wait for it to be cleared. The reason for this is that the flag is automatically cleared at the END of vblank, so if your NMI handler finishes its job too quickly and you start checking the flag before vblank ends, the flag will still be set from the previous frame.

We recently talked about sprite 0 hits in another thread: http://forums.nesdev.com/viewtopic.php? ... 03#p247581

Post Reply