How to wait for vblank

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Yes, tepples' suggested method only involves one thread, and is therefore simpler to understand. I don't understand
tokumaru's objection to it, and why there has to be ONE TRUE WAY of writing something. This good/bad thinking destroys intelligent thought. There are many ways of coding a game, each with tradeoffs. A new programmer should trade off as much as possible for simplicity and ease-of-understanding. Keeping one thread of control is a big help. If I were writing a game, I'd try to use a single thread if possible.

I don't see how putting the code in a NMI handler helps a lot. It still doesn't give you exact timing. Even if you could have your NMI fire at a particular PPU clock every frame, after you do your PPU operations during blanking, you won't be synchronized anymore, unless you painstakingly cycle-time all your code AND ensure it always runs the same number of clocks regardless of what it's doing. Thus, you need to synchronize with the PPU at the end of blanking, perhaps with a sprite #0 hit or something. This kind of code is very specialized and not something to be burdening anyone with unless really necessary.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

blargg wrote:I don't understand tokumaru's objection to it, and why there has to be ONE TRUE WAY of writing something.
My objection in this case is that I don't really consider one method much harder than the other. One has a counter, the other has a flag. Both wait for the flag/counter to change, both use an instruction to modify the flag/counter... They are not all that different. So if both methods are so similar, why not use the one that's more versatile, that will not require a huge deal of refactoring of your code once it gets more complex?

Of course there are several acceptable ways of doing things, but newbies usually just pick a tutorial and go, so as far as they are concerned there is ONE TRUE WAY of writing it, and it's the one used in the tutorial. We could of course present both options and let them pick, but then that would be considered "too difficult".
This good/bad thinking destroys intelligent thought.
Intelligent thought involves presenting the options, the pros and cons of each one and letting people make informed decisions, and you are proposing exactly the opposite by suggesting we simply teach the "simpler" method, 'cause they're too stupid to get the other one.
If I were writing a game, I'd try to use a single thread if possible.
And you'd fail when it got complex enough that you'd have to fall back to having two threads.
I don't see how putting the code in a NMI handler helps a lot. It still doesn't give you exact timing.
Being off by 6 or 7 cycles is much better than being off by 100, 300 or 3000. 6 or 7 cycles is still a lot less than the time of HBlank, so you can at least stay safely aligned to the scanline level.
Even if you could have your NMI fire at a particular PPU clock every frame, after you do your PPU operations during blanking, you won't be synchronized anymore, unless you painstakingly cycle-time all your code AND ensure it always runs the same number of clocks regardless of what it's doing.
It's not as painstaking as it sounds, and I am in fact doing that in my game. I simply coded the basic things first (maintaining flags, updating sprites, setting the scroll, etc), timed it and divided the remaining time into equally sized slots. Each type of VRAM update takes the exact time of a slot, and the tasks are assigned to slots dynamically during the frame based on a priority system. Works like a charm, and the blanked scanlines at the top of the screen that hide the scrolling glitches and extend VBlank are steady as a rock, even on lag frames.

But even if you don't need that kind of precision, just being warned about the start of VBlank helps a lot. Like I said before, it's crucial for properly displaying a status bar at the top of the screen and for setting up mapper IRQs in case of lag frames, unless you are OK with a glitchy frame here an there, which I'm not. I refuse to accept you don't see it, after having seen you release all those meticulous tests of yours.
Thus, you need to synchronize with the PPU at the end of blanking, perhaps with a sprite #0 hit or something. This kind of code is very specialized and not something to be burdening anyone with unless really necessary.
I don't know why I bother anymore... It looks like you guys like to be stuck with simplistic games for some masochistic reason. OK, be my guests, keep forever making these boring uninteresting games while the few ones that like to think outside of the box make something worthwhile.
User avatar
Banshaku
Posts: 2404
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

I think there is no right or wrong answer for this topic. People have their opinion on the subject and will stick to it, no mater what.

Both opinion are valid in someway but let face it: even thought we know more than the people back in the days, how many projects near what we could call a real game "went out of door"? We cannot count many, not even on one hand.

It is good to strive for perfection but let face it: beginners are bound to make mistake, no mater what and this is actually a good thing. Without those mistake, they will not learn anything at all. What they will do is copy/paste what is in the wiki or something and see it as the ultimate truth because they don't understand what the hell is going on.

Let the beginner enjoy their "noobness", if that word ever exist ;) Let them experiment with simple concept so they can learn the rope. They will never do the next super mario bros on their first shot: that's dreaming. And let the senior debate was is good or not for more advanced programming. But for one thing, we shouldn't shovel down their throat too much complicated concept since they will not get it, no matter what. 2 years ago I would have not understand any of the stuff we're talking at the moment. Now that I have experience on the subject, everything is smoother.

When your learn CS in C, you don't start right away to explain how to use pointer and that but more with what are variables, loops etc. the basics. At a latter stage, the student will learn more advanced concept. From there, by himself, he will figure out what is better or not, if he has the skill for programming in the first place.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

You are right Banshaku. Back when I started there wasn't much accurate code floating around, and I still managed to get by. I made a lot of silly mistakes, like all good newbies, but eventually learned to do things the right way. I guess that's the natural order of things.

What bothers me about this is that I like to help. Whenever someone asks something about NES development I do my best to help. But lately every aspiring programmer that shows up has the same piece of code. A mix of GBAGuy's code and code from the wiki. A few people simply decided on what pieces of code are newbie friendly (including the evil memory clearing routine I seriously disagree with) and it kinda upsets me that I don't agree with much of this code that's being "taught" (more like "dumped").

And when I voice my own opinions of how I think is the best way to do things, bringing up the flaws in other methods, like in this thread, I get yelled at like I'm doing something wrong. Blargg said what I did was against intelligent thought but I think it's quite the opposite: people here would rather keep doing things like they always have instead of welcoming new ideas for the overall betterment of the community.

This kind of thing makes me think that my time would be better spent on projects than wasted with words here that never change anything. Hopefully by completing a good game I will change people's opinions more than I ever could with words, so maybe I should focus on that.
cadahl
Posts: 27
Joined: Wed Mar 17, 2010 6:29 am

Post by cadahl »

Hm. Why not improve the parts of the wiki you disagree with? Better to have an edit fight there if necessary (via Discussion).
User avatar
Banshaku
Posts: 2404
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

@Tokumaru:

There is nothing wrong in trying to help beginners and correct them: this is a noble cause as long as they show effort to learn and try on their own. If they don't, we're just putting our energy on the wrong thing.

And it's not because people shoot down your opinion that automatically mean that you're wrong. At least we're not burn on the stake for our opinions ;)

But one point you said is right: we should maybe stop being "forum dwellers" and start to put our energy on our projects. The result would be better in the end. Or with all your experience, adding some article on the wiki with appropriate information would be a very nice contribution for the community instead of raw discussions in the forum. You are a big contributor to this community and you may not realize it yet ;)

Edit:

And to add to this discussion, the one that realized is project is the one that is speaking the least on this forum. Maybe we should learn from him.
User avatar
Orsi
Posts: 26
Joined: Sun Mar 21, 2010 7:15 am

Post by Orsi »

What I would really love as a newb learning is some small, nice games with the source code to study from. After looking through all the stuff on the NesDev main site, there are absolutely no actual 'games' with decent, readable source code available to read. Everything is either a demo or too complicated to read. The best thing I could find was a Christmas card demo.

I think the community would benefit most if some industrious vets decided to pause their dream projects for a bit and just write some simple games with nice, clean, well-documented source code. It could be Pong, a one-level Mario clone, Tic-Tac-Toe, or anything. I don't need a tutorial, just the assembly equivalent of some Harry Potter or Goosebumps. Easy reads, nothing crazy.

As for the Wiki. my two cents: it needs better organization. It's like a car manual.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Banshaku wrote:And to add to this discussion, the one that realized is project is the one that is speaking the least on this forum. Maybe we should learn from him.
I recently thought the exact same thing. Maybe being a person of few words is the key to success.
Orsi wrote:What I would really love as a newb learning is some small, nice games with the source code to study from.
You are right. I too have always learned better from code than from text. The problem is that not everybody is like that, and there will always be the cut&paste maniacs that chaotically try to make something happen without understanding what they are doing, and also the losers that will modify a thing or two in such games and claim it's theirs. I think there are more people who would just copy these games irather than study and draw inspiration from them.
The best thing I could find was a Christmas card demo.
And even then demos are completely different programs from games. Demos are often made of a collection of optimized effects that directly access the hardware, while games are usually a collection of sub-systems that are used as interfaces for working with the hardware.
As for the Wiki. my two cents: it needs better organization. It's like a car manual.
Agreed. The other day I needed a PPU memory map (wanted to check something about mirrors) and wasn't able to find it. I wonder if it's even there somewhere...
User avatar
Banshaku
Posts: 2404
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

As for the Wiki. my two cents: it needs better organization. It's like a car manual.
Yes, it need better organization. But for now, at the least, there is some information that could be considered valuable in it. Hopefuly it will be organized by someone that has the skill for it.

For now, the nes reference guide is for explaining about the hardware. We need a better tutorial section to help beginners to find the right information.
tokumaru wrote: Agreed. The other day I needed a PPU memory map (wanted to check something about mirrors) and wasn't able to find it. I wonder if it's even there somewhere...
It should have been in the nes reference guide under PPU but I cannot see it either. Maybe it was never put on the wiki? I will give it a look.

Edit:

I added to the wiki a PPU memory map in the PPU section, like were it should be. It's a quick copy of the nestech document and will need to be revised for the formatting and for the naming convention of the wiki, if any.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

tokumaru wrote:
blargg wrote:I don't understand tokumaru's objection to it, and why there has to be ONE TRUE WAY of writing something.
My objection in this case is that I don't really consider one method much harder than the other. One has a counter, the other has a flag. Both wait for the flag/counter to change, both use an instruction to modify the flag/counter... They are not all that different.
Maybe I didn't read your objection carefully. I thought you were suggesting an NMI handler that did more than increment a counter, as something to teach a new programmer before the model tepples described.
Of course there are several acceptable ways of doing things, but newbies usually just pick a tutorial and go, so as far as they are concerned there is ONE TRUE WAY of writing it, and it's the one used in the tutorial. We could of course present both options and let them pick, but then that would be considered "too difficult".
In the teaching context, the simpler wins, period. Teach the simpler first, then the more complex. If a student believes he can do the complex first, he can skip to it. If he finds he was wrong, he can fall back on the simpler. There is no benefit to leaving the simple steps out of a tutorial (to a point of course; having the steps like "LDA #1" loads A with 1. "LDA #2" loads A with 2 etc. is clearly absurd). It's not about thinking the student is stupid, it's delivering on one's goal as a teacher by making learning possible without major frustration. Multi-threaded programming is a subject even experienced programmers regularly screw up, and spend hours or days tracking down bugs in. It's true that an NMI routine is simpler in that the NMI "thread" can't be interrupted by the main thread, but it's still tricky when there are shared data structures you can't atomically update.
If I were writing a game, I'd try to use a single thread if possible.
And you'd fail when it got complex enough that you'd have to fall back to having two threads.
How would I fail? If it weren't possible, I wouldn't try to. What I meant was that I wouldn't start out with multiple threads (main thread + NMI interrupt routine) unless it offered benefits worth its cost.
I don't know why I bother anymore... It looks like you guys like to be stuck with simplistic games for some masochistic reason.
Where have I argued that there is only one way? I'm arguing that every manner of writing a NES program is proper in some context, and that tepples' suggestion to have an NMI routine that does nothing more than increment a counter is valid for a good number of NES programs and games.
OK, be my guests, keep forever making these boring uninteresting games while the few ones that like to think outside of the box make something worthwhile.
Thinking outside the box, at least for me, involves treating everything as valid, only with differing tradeoffs for particular situations. The kind of thinking that limits me is that of "method X is the one to use in all cases, method Y should never be considered". Again, I may be reading your wrong, in which case I apologize.
Whenever someone asks something about NES development I do my best to help. But lately every aspiring programmer that shows up has the same piece of code.
The solution to lack of originality is to help give programmers a firm grasp of what's going on inside. Giving them an advanced method they aren't ready for will make them even more mindless, because they'll run into many more mysterious bugs that they won't be able to understand well. The best way to make original students is to give them a good grasp of fundamentals. One way to do that is to give them the simplest possible things that work, so that they have a higher chance of understanding them fully before they move on to something more complex. IMO.
And when I voice my own opinions of how I think is the best way to do things, bringing up the flaws in other methods, like in this thread, I get yelled at like I'm doing something wrong.
The problem I had was that it seemed you were arguing for ONE TRUE APPROACH, that tepples' method was bad because it couldn't handle every possible game. Again, if this isn't what you were arguing, then disregard most of my commentary. :)

But hell, I stopped visiting here for many months last year because it was too overwhelming for me, and I see it still is. I couldn't find the energy to work on the Wiki, and I'm sorry about that. So I have little ground to stand on. I've got projects I need to complete, that aren't NES-related, and I should focus on those. I worry that once I am ready to focus on Nesdev, everyone will have left for other systems. :(
User avatar
Banshaku
Posts: 2404
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

blargg wrote:But hell, I stopped visiting here for many months last year because it was too overwhelming for me, and I see it still is. I couldn't find the energy to work on the Wiki, and I'm sorry about that.
Don't worry about the wiki, there was no obligation and sometime there is things in life that have more priority. Contribute once you feel up to it, that's all. You were gone for a while so I was starting to supect you could have been hit by a truck or something. Good thing it's not the case :P
blargg wrote: So I have little ground to stand on. I've got projects I need to complete, that aren't NES-related, and I should focus on those. I worry that once I am ready to focus on Nesdev, everyone will have left for other systems. :(
<TryingToBeFunny>As long as the "geezers" on nesdev like me, Tepples, Tokumaru, Bregalad, Memblers, Dwedit, Zeppers, Celius etc contribute, nesdev will live on!! </TryingToBeFunny> ... Or something like that ;) It's not ready to go away yet by all means.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

blargg wrote:Maybe I didn't read your objection carefully. I thought you were suggesting an NMI handler that did more than increment a counter, as something to teach a new programmer before the model tepples described.
This was my original suggestion. I don't think it's too overwhelming. I think it's only more complex than tepples' solution because there is a special check for incomplete frames, but the remaining elements are basically the same. Also the VRAM updates are inside the NMI routine. Since the OP wasn't a clueless newbie I figured it would would be OK to offer him that solution.
Multi-threaded programming is a subject even experienced programmers regularly screw up, and spend hours or days tracking down bugs in. It's true that an NMI routine is simpler in that the NMI "thread" can't be interrupted by the main thread, but it's still tricky when there are shared data structures you can't atomically update.
IMO what goes on in the NMI is hardly multi-threading, because in fact we don't expect the two threads to run concurrently at all, we just take advantage of the fact that they do in case calculations took too long.

I think all that a person has to understand in order to not be confused by this is the concept of interrupts. They must understand that the main program WILL be interrupted at certain points in time and they must write a separate piece of code to handle that situation.
How would I fail? If it weren't possible, I wouldn't try to. What I meant was that I wouldn't start out with multiple threads (main thread + NMI interrupt routine) unless it offered benefits worth its cost.
You probably wouldn't fail if it was a card game, but could you write a side-scrolling engine that has a status bar at the top that never flickers or shakes during lag frames without making use of the NMI thread? I don't think there's a way. Unless you use IRQs, but the concept of an IRQ thread is basically the same of an NMI thread so there would be no point in that.
I'm arguing that every manner of writing a NES program is proper in some context, and that tepples' suggestion to have an NMI routine that does nothing more than increment a counter is valid for a good number of NES programs and games.
I guess it is. Maybe I just can't stop thinking about its drawbacks because of the kind of game I'm used to design, so to me it seemed wrong to suggest something that might (I know it's a big "might") cause problems in the future while another valid suggestion was already given and apparently understood by the OP. But I realize that for most people tepples' approach "just works".
The kind of thinking that limits me is that of "method X is the one to use in all cases, method Y should never be considered". Again, I may be reading your wrong, in which case I apologize.
I did object to the dissemination of a piece of code that I considered flawed, but I didn't say my way was THE way. I surely consider it better than the other one, but not the absolute best one.

Sometimes it seems that the beginners don't have a choice, since it's the simplest things that are always offered to them. But not all beginners are absolute programming newbies... Some of them come from other systems or languages, and have enough knowledge to experiment with the "difficult" stuff, so I think that information should be offered somewhere. I found it good that tepples decided to make a page about NMI threads.
The problem I had was that it seemed you were arguing for ONE TRUE APPROACH, that tepples' method was bad because it couldn't handle every possible game.
I DID say tepples' was bad because of it's limitations, but I DIDN'T say the other method was the best, I just mentioned it didn't have the same shortcomings. Since there seems to be some kind of consensus that tepples' way to handle VBlanks is the easiest one for newbies, I'll just have to shut up on this one, even though I don't agree with it. But I'm sure there will eventually be people asking "why is my status bar jumping", if these newbies persist enough to make a scrolling game.

Another thing I happen to not agree with is clearing the whole memory to 0. Say, if a person forgets to initialize a variable before starting a level, but everything works fine because the variable was cleared at the beginning of the program. Now, when the second level starts and the variable is no longer 0, something goes wrong. Wouldn't you say this bug would be harder to catch, since the first level worked fine but the second one didn't? Personally I'd rather not clear the memory and use soft resets to verify if my programs work the same every time or if I forgot to initialize something.
I worry that once I am ready to focus on Nesdev, everyone will have left for other systems. :(
Some people (myself included) have been around for too long to just leave now, so I wouldn't worry about that. I don't think I'll even abandon NESDEV, even when I'm 80 years old or so. I just hope that by then someone will have successfully made an accurate NES clone, otherwise we'll probably have to rely solely on emulators... =)
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

Well it gets firey here...
I just think there is not an option better than the other. The wiki might just mention the existance of 3 ways you do it :
- Everything in main
- Everything in NMI
- Separate thread

And not make any advertisement for one over another, but objectively states the inconvenient of each ones. Anyone, newbie or experienced, should be able to choose the one he likes best.
Useless, lumbering half-wits don't scare us.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Banshaku wrote:but let face it: even thought we know more than the people back in the days, how many projects near what we could call a real game "went out of door"?
They got paid to develop for NES. Most of us don't, apart from Sivak.
tokumaru wrote:A few people simply decided on what pieces of code are newbie friendly (including the evil memory clearing routine I seriously disagree with)
What exactly do you mean by this? If you mean the loop that clears $0200-$07FF to zero, then remember that ca65 was originally designed for use with cc65. The C language requires uninitialized static-allocated variables to start at 0 (for ints) or NULL (for pointers) by the first line of main().
tokumaru wrote:And when I voice my own opinions of how I think is the best way to do things, bringing up the flaws in other methods, like in this thread, I get yelled at like I'm doing something wrong.
Perhaps they just disagree that there is one best way. I just shied away from trying to explain a separate thread because preemptive multitasking operating systems don't have a concept of uninterruptible threads. On NES, if thread N interrupts M, every change that N makes appear atomic to M. But on PC, threads M and N can interrupt each other, and newbie attempts at threading lead to race conditions on one hand and deadlocks on the other. But once I realized when your method is useful and how the locking is easier than on a preemptive multitasking system, I put it on the wiki right away.
tokumaru wrote:but could you write a side-scrolling engine that has a status bar at the top that never flickers or shakes during lag frames without making use of the NMI thread?
You can't write a side-scroller that never flickers unless you never have more than four things in play at one time. More than four, and at least the sprites will flicker once they are horizontally aligned due to the PPU's 25% overdraw limit.
tokumaru wrote:But I'm sure there will eventually be people asking "why is my status bar jumping", if these newbies persist enough to make a scrolling game.
Most of them don't even know how to make a scrolling field longer than 512 pixels because they've never cared to watch a program update the nametable "at the seam". But I guess this discussion did have a positive result: an answer to the question has been added to the wiki.

-- Why is my status bar jumping?
-- You could have lag frames, and your program isn't seeing the NMI or sprite zero hit during those frames.
-- How do I fix it?
-- Optimize your code to make lag frames happen less often. Or do your VRAM updates in the NMI thread. Or both.
Orsi wrote:there are absolutely no actual 'games' with decent, readable source code available to read. Everything is either a demo or too complicated to read.
Read through LJ65 and Concentration Room and let me know about anything you don't understand so I can add better comments.
Ian A
Posts: 115
Joined: Sat Feb 27, 2010 8:32 am
Location: Maine

Post by Ian A »

One of the reasons why I check the forum frequently is to get different views on how to do things. Sometimes someone explains something in a way that is easier for me to understand, though not necessarily for everyone else to understand.

That being said, I'm interested to hear more about this memory clearing routine.
Post Reply