A few questions from a 6502 Assembly noob

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
User avatar
BioMechanical Dude
Formerly AlienX
Posts: 137
Joined: Fri Apr 18, 2014 7:41 am
Location: Bulgaria

A few questions from a 6502 Assembly noob

Post by BioMechanical Dude »

So, I've been reading BunnyBoy's "Nerdy Nights" tutorials, to learn the basics of 6502 NES Assembly. Everything, featured in the tutorials works great, when I compile the code. However, when I try to experiment, things don't work out at all, for the most part. So, I hope I can get some answers.
(Note: I'm on a different computer right now, so unfortunately I can't show any of the code I've written by now. I hope I can explain the problems well. :? )

1. Do all the graphic updates have to happen in the NMI section?
So, in his example code, BunnyBoy adds these two Vblankwait loops. From what I understand, every time the screen is being drawn, these loops check if that is happening, and if it is, they keep looping until there's a VBlank (or VBI). Then the rest of the code executed. I wonder, when the RTI function is executed, does the CPU go back to the Vblankwait loops? If that's so, then judging by the code, the CPU's RAM would get wiped every frame and it would establish the same colors and sprite positions every single time. But if that was so, how would the sprites be able to move? Is the code executed only once? That would explain why when I try to establish new positions for three other sprites, based on sprite 0's position, it doesn't work in the regular sections, yet it does only in the NMI section. But why? Where does the RTI function lead to? What is the chronological path of this code and why does it work differently than in any other languages, I've used? (They are high-level, but I don't think it should make that big a difference) None of this stuff is explained in the tutorials, so I hope someone can give me a straight-forward explanation.

2. When writing values to the palettes, do you have to write all the values?
Let's say I just want change one color from the background palette. I write down all the code, telling the CPU to write values to the PPU. Once I start putting in color values, do I have to write every single color for both palettes, or can I just write the value for the first color and then start doing something else?

There may be more questions in the future. Sorry if they sounded (or looked) like ramblings. Right now, I hope I can get these answered, since they're vital. What BunnyBoy explains in his tutorials, he explains well. What he doesn't explain... he doesn't explain. This can create some knowledge holes, that will bite a future NES programmer in the ass one day.
Greetings! I'm That Bio Mechanical Dude and I like creating various stuff like movies, games and of course chiptunes!
You can check out my YouTube Channel.
You can also follow me on Twitter.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: A few questions from a 6502 Assembly noob

Post by tokumaru »

AlienX wrote:1. Do all the graphic updates have to happen in the NMI section?
Yes. The NMI fires when VBlank starts, and the vertical blank is the time when the PPU is "resting", and not accessing graphics, which means you are free to modify them.

You can (and should) however calculate all the data you need to change beforehand and buffer it, so that during VBlank you can blast those buffers into VRAM, instead of wasting precious VBlank time calculating stuff.
So, in his example code, BunnyBoy adds these two Vblankwait loops. From what I understand, every time the screen is being drawn, these loops check if that is happening, and if it is, they keep looping until there's a VBlank (or VBI).
No, these VBlank waits are part of the initialization code and run only once, when the program first starts. When the console is powered on, the PPU has some internal initialization of its own, so you gotta wait a couple frames before it's ready to be used.
I wonder, when the RTI function is executed, does the CPU go back to the Vblankwait loops?
No. It probably goes back to an empty loop that runs forever, located after the initialization code. It looks something like this:

Code: Select all

Forever: jmp Forever
Looks weird, but when the whole logic is in the NMI handler, the main thread doesn't have anything to do, so it sits in an empty loop that never ends.
Where does the RTI function lead to? What is the chronological path of this code
First the initialization runs, cleaning up the room before the game starts and initializing everything that won't be changing every frame. At this time, the PPU is requested to fire IRQs every time VBlank starts, which makes the NMI handler a handy place to put your PPU updates and perform periodical tasks, since VBlanks occur at steady 60Hz (60 times per second).

Once the NMIs are enabled, and the NMI handler will take care of both graphical updates and game logic, the main thread doesn't have anything else to do and enters an infinite loop.

Note that this was a design decision made by the person writing the tutorial. There are other setups that involve dividing the work between the main thread (game logic) and NMIs (PPU updates), or using only the main thread (NMIs are only used to signal the start of VBlank). Eachmethod has advantages and disadvantages, and programmers often pick the one they're most comfortable with.

The CPU will then be stuck in this endless loop doing nothing, bur 60 times per second this loop will be interrupted and the NMI handler will run. The RTI at the end of it causes the CPU to go back to the endless loop, where it waits for the next interruption, when the NMI handler will run again. This will repeat forever, and the NMI handler is responsible for updating the game state and the graphics by 1 frame each time it's called.
2. When writing values to the palettes, do you have to write all the values?
No, you can as many/few colors as you'd like. Just write the address of the first color you want to change to $2006 and write the new colors to $2007. This is true for the name tables as well, you can change a few individual tiles if you want to.
User avatar
Tsutarja
Posts: 123
Joined: Sun Oct 12, 2014 11:06 am
Location: Finland

Re: A few questions from a 6502 Assembly noob

Post by Tsutarja »

Adding to what tokumaru said:

1. You can update outside NMI, but you need to turn off the PPU with the PPU Mask register $2002. Some games uses this type of "bulk drawing" in transitions between levels and such, since the screen goes black when you turn off the PPU. However, most of the graphical updates still should be done in NMI. That's why we have it after all.

I'd suggest you read this. It helped me a lot trying to understand NMIs and how the PPU works. I had the exact same issues after reading Nerdy Nights as you did, but I don't now if there are any better tutorials. Read bunch of articles around Nesdev's wiki section. I'm sure they will be a big help.

2. A good way to update any PPU data is to set up some variables in your game logic for the NMI to use to define things like:
-Does this specific data need updating (if not, branch over that section)
-Starting address of where you start storing data with $2007 (two stores to $2006 after resetting the latch by reading $2002)
-Where the data to be stored to the PPU is located (starting RAM or ROM address depending on whether you have buffered the data or not)
-How many bytes you want to store (simple counter to count down by one after every stored byte)
UP SIDE DOWN A B A B B A B A Hidari migi
L R L R STOP & DASH & UP & TALK Ijou nashi
Pokun
Posts: 1923
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: A few questions from a 6502 Assembly noob

Post by Pokun »

AlienX wrote:What is the chronological path of this code and why does it work differently than in any other languages, I've used? (They are high-level, but I don't think it should make that big a difference).
As others has explained it's about interrupts. The code normally behaves as you expect but if NMI are enabled, every 60th of a second the program counter will stop where it is, jump to your NMI vector, run that code that you put there and finally jump back to wherever it was before the interrupt happened.

The NMI is designed this way so that you know when the TV is in vertical blanking, and it's OK to update graphics.
Last edited by Pokun on Fri Jan 30, 2015 6:53 pm, edited 1 time in total.
User avatar
Tsutarja
Posts: 123
Joined: Sun Oct 12, 2014 11:06 am
Location: Finland

Re: A few questions from a 6502 Assembly noob

Post by Tsutarja »

Pokun wrote: The NMI is designed this was so that you know when the TV is in vertical blanking, and it's OK to update graphics.
Not the TV, it's the PPU. VBlank is the leftover time from each frame where the PPU has done rendering that frame. The article from Nesdev wiki I posted to my post above explains this very well.
UP SIDE DOWN A B A B B A B A Hidari migi
L R L R STOP & DASH & UP & TALK Ijou nashi
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: A few questions from a 6502 Assembly noob

Post by tokumaru »

Tsutarja wrote:Not the TV, it's the PPU. VBlank is the leftover time from each frame where the PPU has done rendering that frame.
I don't see anything wrong with what Pokun said. The only reason the PPU has this idle time is because the TVs (well, old ones) need time to move the electron beam back to the top left corner of the screen after each picture is displayed. It's not "leftover" time, the PPU intentionally "rests" during that time so that the programmer can manipulate VRAM, since the TV isn't drawing anything at that time anyway.
User avatar
Tsutarja
Posts: 123
Joined: Sun Oct 12, 2014 11:06 am
Location: Finland

Re: A few questions from a 6502 Assembly noob

Post by Tsutarja »

tokumaru wrote: I don't see anything wrong with what Pokun said. The only reason the PPU has this idle time is because the TVs (well, old ones) need time to move the electron beam back to the top left corner of the screen after each picture is displayed. It's not "leftover" time, the PPU intentionally "rests" during that time so that the programmer can manipulate VRAM, since the TV isn't drawing anything at that time anyway.
I see, well I have never heard anyone mention the TV's relation to the PPU any more than just saying that the PPU sends the video signal to it.
Also, the "leftover time" I mentioned, is what I meant when you explained it as "rest". Maybe I just chose a wrong word to describe it...
UP SIDE DOWN A B A B B A B A Hidari migi
L R L R STOP & DASH & UP & TALK Ijou nashi
Post Reply