This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

How to wait for vblank


by on (#59156)
In this post, tepples wrote:
If you're willing to make your game loop look like this:

I don't like to discuss the same old thing again, but I have to point out that there is an obvious disadvantage to this method: IT WILL MISS VBLANKS. Maybe not for Pong, Tetris or a card game, because those are likely to always finish all their frame calculations before VBlank. However, once the games get more complex and they are not guaranteed to finish the calculations in time, the NMI will fire but the game logic will soon be running again like nothing happened.

I know that it's possible to detect missed VBlanks because you use a counter, but that will not solve all problems. In my game for example I keep rendering disabled for some extra scanlines because I need the extra time for video updates and to hide vertical scrolling glitches. The thing is that even during lag frames I must blank those lines, even if I'm not writing anything to VRAM, otherwise the screen would jump.

And I need to know exactly when the NMI fires for timing reasons, otherwise I wouldn't be able to blank a constant number of lines, which also would cause the screen to jump.

I don't mean to be rude tepples, really, but I have to ask you this: Why do you keep teaching people your method (I know you are proud of it) when you know it's flawed under certain circumstances? It can be slightly friendlier to newbies who are used to polling $2002, but in the long run everybody wants to expand their games, so why teach them something that could break the games once they reach a certain point of complexity?

Hopefully the coders will be able to figure out the problem by themselves when their projects are more complex, but still. Besides being slightly friendlier to newbies, the only advantage I see it that it makes easier to have different VBlank routines for the different parts of the game, but that could easily be solved with a pointer in RAM (that can be changed whenever the programmer wants to) that the NMI jumps to as soon as it fires.

Quote:
It doesn't modify anything but the flags, so it doesn't need to push anything else.

So does the one I posted in this very thread, and it doesn't choke on lag frames.

You seem to be very proud of your solution, but I guess I am of the one I'm using in my game as well. It's actually a hybrid of both methods, that allows you to wait for VBlank or use a custom NMI routine. Look at it, straight from my game:

Code:
;-- INTERRUPT ---------------------------------------------------
;DESCRIPTION:
; This routine is responsible for indicating that VBlank started
; or for calling a custom NMI routine in case one is defined.
;----------------------------------------------------------------
NMI:

   ;branch if the program was waiting for a regular interrupt
   bit WaitingVBlank
   bmi +FlipFlag

   ;branch if there is no custom interrupt routine defined
   bit CustomNMI+1
   bpl +Return

   ;transfer control to the the custom routine
   jmp (CustomNMI)

+FlipFlag:

   ;indicate that the interrupt happened
   inc WaitingVBlank

+Return:

   ;return from the interrupt
   rti

If the program was not waiting for VBlank and there isn't a custom NMI defined (I have one for each section of the game, except the simple ones that can work simply waiting for VBlank) the interrupt simply goes unnoticed, but if you wanted you could use the "counter approach" to detect missed frames.

Sorry if I seem "pissed off" or something in this post, it's not like that, and I don't have anything against you, it's just that whenever I see someone suggesting a solution that they know is not optimal I wonder why the hell they do that... Is it so the person that asked for help later comes back when the flawed solution breaks?

by on (#59157)
I understand what your saying but it's fine that way he is showing, and yes, the more complex they get it does matter alot, but I think the coder/programmer could figure it out by then :D



Re-programming, not working still but let me fiddle with it a bit more before I upload again..... :roll:

by on (#59160)
If you want an example of a situation where the "wait for VBlank" approach would fail, you don't even have to think about very complex games. Everyone would like to make a side scroller like SMB, with a status bar at the top.

OK, in order to have that status bar, you have to set the scroll every frame so that it's locked into position and doesn't scroll with the level. Then, a common way to detect the end of the status bar and the start of the playfield is a sprite 0 hit. Now, can you imagine how this could go wrong if you miss a VBlank?

First, you will not reset the scroll and will not lock the status bar into place, so it will show up either moved to the left or to the right. Second, the detection of the sprite hit will not be reliable anymore, either because the background is offset and is not guaranteed to hit the sprite anymore (meaning the game would freeze) or because you might start waiting for it after it has already happened (meaning you'd reposition the X scroll for the playfield at the wrong scanline).

This is why it's important to have a VBlank method that still allows you to do critical operations (like setting up a status bar) during lag frames, because there *are* operations that need to be performed even during lag frames, and if you plan on gradually increasing the complexity of your games there will eventually be lag frames.

Now that I think of it, I seem to remember someone saying that SMB does have issues with its status bar when too much action is going on. I personally haven't seen it, but I wouldn't be surprised if this was the case, since SMB does not do the main / VBlank thread separation I suggested.

by on (#59167)
What's a semma for?

tokumaru wrote:
Why do you keep teaching people your method (I know you are proud of it) when you know it's flawed under certain circumstances?

I seem to remember it's good enough for Square. If your music is slowing down because you miss vblanks, your game is slowing down too, and you should either optimize your code or just do a Micronics and take the whole thing down to 30 fps. Otherwise, you'll have people complaining that they missed the jump because the frame rate changed.

Quote:
it's just that whenever I see someone suggesting a solution that they know is not optimal I wonder why the hell they do that

No solution is optimal in all cases. For each solution, one must trade off the time to get the solution running, the risk of a failure, and the consequences of a failure. For newbies, I just think a Square-style solution with a direct counterpart to vsync() in Allegro is easiest to understand.

Quote:
Is it so the person that asked for help later comes back when the flawed solution breaks?

Define a "break". A split-thread solution will "break" if you try to upload an inconsistent data set to the PPU, and I can think of situations where it would break hard if you don't know semaphores.

Quote:
OK, in order to have that status bar, you have to set the scroll every frame so that it's locked into position and doesn't scroll with the level. Then, a common way to detect the end of the status bar and the start of the playfield is a sprite 0 hit. Now, can you imagine how this could go wrong if you miss a VBlank?

The status bar code from my unreleased side-scroller engine has this:
Code:
@wait4endvbl:
  bit $2002
  bvs @wait4endvbl
@wait4s0:
  bit $2002
  bmi @s0giveup
  bvc @wait4s0

There are two loops here. The first waits for end of vertical blanking. The second waits for the sprite 0 hit on scanline 30 and prepares to set the X scroll position. The @s0giveup is a safety feature: if sprite 0 fails, it won't freeze like SMB1; instead, it will flicker a bit and continue.

And what happens if your status bar is at the bottom like in Gradius? Are you going to spend the whole frame in an NMI handler waiting for sprite 0?

by on (#59168)
Time Lord uses a DMC IRQ to assist the bottom status bar if the CPU usage of the game is too heavy.

by on (#59169)
Hey tepples! Hey tepples! Maybe a split is in order huh?

tepples wrote:
I seem to remember it's good enough for Square.

See , I don't get this. People is this scene always seem content to do something a certain way because some commercial game did it. How well do you think programmers back then knew the NES? We know for a fact that the companies back then didn't receive much support from Nintendo, and being companies they were just interest in getting games out and money in, doing things right was not a primary concern. Back then they would give programmers that never made a NES game before a crappy manual in engrish and expect them to come up with a finished game in a few months.

Now look at us. We've studied this freaking console inside and out, and had several years to digest that info. We know more than most coders did back then. There is absolutely no reason for us to be content with mediocre solutions we know are flawed.

Quote:
If your music is slowing down because you miss vblanks, your game is slowing down too, and you should either optimize your code or just do a Micronics and take the whole thing down to 30 fps. Otherwise, you'll have people complaining that they missed the jump because the frame rate changed.

You know it's not just the music. Like I said, status bars are very important too. As are scanline counters (you certainly don't want IRQs firing at the wrong times). Face it, there are several things that should be given high priority, and you just can't do that by simply waiting for VBlank.

And you are talking about optimizing and such, but you should know that in certain types of games it doesn't work like that. Or maybe you don't know, because so far your programs have always used a controlled number of game entities. But when you have dynamic entities they might end up accumulating, despite the effort you put into level design so that it doesn't happen too often. If by any chance you decided to optimize for the worst case where 20 enemies are on-screen, these enemies would probably not be more smart than balls moving left and right. And the game would be specially dull with only 2 of them on-screen.

Slowdowns have always happened, and still do to this day, even on computers with GHz of CPU power and powerful GPUs. The more dynamic a game world is, the harder it gets to control how much of it is active at any given time.

Quote:
For newbies, I just think a Square-style solution with a direct counterpart to vsync() in Allegro is easiest to understand.

It might be, but I kinda don't see the point in teaching something that will require them to modify the architecture of their code (something that is never easy) because this simple solution might break with something as simple as a status bar.

Quote:
Define a "break". A split-thread solution will "break" if you try to upload an inconsistent data set to the PPU, and I can think of situations where it would break hard if you don't know semaphores.

A simple "frame is ready" flag solves all the problems. Don't use the data unless it's flagged as consistent, it's not hard.

Quote:
There are two loops here. The first waits for end of vertical blanking. The second waits for the sprite 0 hit on scanline 30 and prepares to set the X scroll position. The @s0giveup is a safety feature: if sprite 0 fails, it won't freeze like SMB1; instead, it will flicker a bit and continue.

Yeah, so much for a simple solution... And it even comes with exclusive built in Visual Glitches™. SMB freezes? That sucks. See why we can't think of the old programmers as gods?

Quote:
And what happens if your status bar is at the bottom like in Gradius? Are you going to spend the whole frame in an NMI handler waiting for sprite 0?

Then you have to adapt. If in the end you can't think of a way to fix it, go with what you know will work well. Now, knowing how to fix something and not doing it, that's stupid.

by on (#59175)
SMB1 never freezes, but when it lags (go somewhere with two hammer bros to figure out) the music slow downs and the status bar shakes horizontally.

What happen is that it does it like that :
* A NMI fires and the game enter in it's game handler
* Do sprite DMA (so sprite 0 is correctly placed)
* Wait sprite-zero hit, set correct scroll
* Do frame logic (which takes too long)
* No NMI fires, but the PPU starts to draw a new frame with the status bar wrongly placed, and sprite zero hit might not occur - but it won't freeze as the game don't look for it
* Frame logic terminates and exit

It is bad that the status bar shakes and the music slows down, BUT it never freezes. The only games that I know that freezes is Castlevania (U) (PRG0), and I have no idea if it is because of sprite Zero hits or slowdowns.

by on (#59176)
tokumaru wrote:
You know it's not just the music. Like I said, status bars are very important too. As are scanline counters (you certainly don't want IRQs firing at the wrong times).

A lot of the time, resetting a scanline counter IRQ either doesn't need any registers, or it only needs A, not X and Y. I agree with you that those should go in the NMI handler even under a simple wait-for-vblank setup.

Quote:
But when you have dynamic entities they might end up accumulating

SMB1 has "optional" enemies that don't show up if the critter table is full.

Quote:
If by any chance you decided to optimize for the worst case where 20 enemies are on-screen, these enemies would probably not be more smart than balls moving left and right.

A critter doesn't have to be any brighter than a ball 90 percent of the time. It only has to think at points in its pattern where it has to react to something. The monsters in Pac-Man don't think unless either they're coming to a corner of the maze or Pac-Man just ate a power pellet. And here's where the 90 percent comes in: If you give each critter a full think cycle one out of every ten frames, you can give only two out of 20 critters a think cycle every frame and still come out ahead.

I should have my cousin ROM hack Super Mario Bros. to start at 8-1 and then randomly switch between 60 fps to 30 fps to show why slowdown isn't optimal. Missing a jump because more critters showed up is not fun.

Quote:
And the game would be specially dull with only 2 of them on-screen.

Not always: Two characters, one legendary franchise.

Quote:
A simple "frame is ready" flag solves all the problems. Don't use the data unless it's flagged as consistent, it's not hard.

Do you care to write a wiki page about a game loop that uses such locking?

by on (#59177)
I don't think there are excuses for making a game prone to freezing and/or shaking/flickering if you know how to fix it. I don't know about you, but I'm pretty sure I have some level of OCD that makes me extremely sensitive to visual glitches, I just can't stand them. I think they scream "lazy programmer", because in most cases they can be avoided.

by on (#59179)
Sometimes I wonder how programmers tested their games.

For example look in Mega Man 3 in Top Man's level there is a place where there is 2 trax mettaurs, and the game ALWAYS drop framerate and flicker here. Capcom testers really COULD have noticed that there was something wrong and remove one of them or do something so that it don't look that horrible.

The worst is without a double Parodius. As soon as you have one option or so, the game CONSTANTLY slows down and just sometimes go back to 60 FPS when there is no enemies on screen, it's barely playable. What were Konami thinking ? Couldn't they go back improve their routines and/or make less enemies on the screen until the game is playable ?

I mean it's not bad to have a good way to handle slow downs, but it's even better if you manage to avoid slow downs altogether. For example Parodius probably handles slow downs fine, having the music play a good speed and the status bar appear fine, BUT it is still really annoying to play. I'd rather have it almost never slow down and have its status bar shake in the very rare case it slows down like SMB or Double Dragon.
You'd still want to test a slow down case, just to make sure the game don't crash tough.

by on (#59180)
tepples wrote:
A lot of the time, resetting a scanline counter IRQ either doesn't need any registers, or it only needs A, not X and Y.

Does that even matter? Can't you just backup and restore?

I consider status bars as important as IRQs. The jumping/flickering effect resulting from lag frames are very similar in both cases.

Quote:
I agree with you that those should go in the NMI handler even under a simple wait-for-vblank setup.

But wouldn't you agree that once you start mixing things all the simplicity is gone?

Quote:
I should have my cousin ROM hack Super Mario Bros. to start at 8-1 and then randomly switch between 60 fps to 30 fps to show why slowdown isn't optimal. Missing a jump because more critters showed up is not fun.

Like I said, I don't think slowdowns should be a constant thing in a game. Of course you should try hard prevent them, but you should still be prepared for them. AFAIK, there is no 100% safe way to avoid slowdowns, and I'm kinda against wasting time to manage time, to me this is a paradox (if you didn't waste time managing time there could be enough time for you to not need to manage it).

Quote:

I'm sure they have more than 2 active game entities. There are things in the background you can break, people riding bikes, energy attacks and miscellaneous effects adorning the screen, etc.

Quote:
Do you care to write a wiki page about a game loop that uses such locking?

Sure. Let me know what's the best place for it and I'll try to format it accordingly.

by on (#59182)
Whenever you use a calendar or a day planner, you are "wasting time to manage time".

The background animations in SF2 are as dumb as balls, as are the projectiles.

Anyway, I think I now understand the technique well enough that I started on such an article, linked from the programming guide: NMI thread

by on (#59183)
tepples wrote:
Whenever you use a calendar or a day planner, you are "wasting time to manage time".

...hence why I don't! Really, I am a terribly disorganized person. It has worked out fine so far! =)

Quote:
The background animations in SF2 are as dumb as balls, as are the projectiles.

I know. But it's still more than 2 dumb balls like in the scenario I suggested in the other post, since at least the fighters are somewhat intelligent.

Quote:
Anyway, I think I now understand the technique well enough that I started on such an article, linked from the programming guide: NMI thread

Great. Do you mind if I make some adjustments/additions? I don't think it's very newbie friendly as it is, even I got confused a couple of times while reading it. I bet that more than 50% of the people that will read that page don't even know what a "thread" is.

EDIT: Does the wiki have a "status bar" page? The page about the NMI thread might be confusing if what makes a status bar isn't clear for the reader.

by on (#59184)
tokumaru wrote:
Great. Do you mind if I make some adjustments/additions? I don't think it's very newbie friendly as it is, even I got confused a couple of times while reading it. I bet that more than 50% of the people that will read that page don't even know what a "thread" is.

Go ahead. I added "thread" to the list of general CS topics.

by on (#59185)
Maybe I'm out of my league here, but I'd like to comment on this statement:
Quote:
Why do you keep teaching people your method (I know you are proud of it) when you know it's flawed under certain circumstances? It can be slightly friendlier to newbies who are used to polling $2002, but in the long run everybody wants to expand their games, so why teach them something that could break the games once they reach a certain point of complexity?

Newbies are newbies. They just want to see progress in what they are doing, and they cannot make progress if they are worrying about things such as optimization, best practices or standards which they cannot even understand yet. If they are constantly being corrected, told something is wrong, or are provided examples and solutions which are beyond their comprehension the slow progression will eventually deter them from even continuing. This goes for any project or task, not just learning how to program. Too much focus on what's not working in the best possible way takes away from what is actually working.

At some point, if someone is determined enough to make such a complex game, a newbie would become experienced enough to actually understand why another way would be better. The peculiarities of syntax or semantics is and should not be their main concern when just learning a language. No one learning English would learn it if they were told that they pronounced or formed every sentence improperly, and that it would be better in the long run if they corrected themselves now. That sucks the enjoyment of learning right out of everyone.

This is especially important for this community and the computer world in general. Every guide, tutorial or wiki for programming in NES is waaay too concerned with best practices, technical terms or proper functionality. The truth is, those who are actually motivated to do something worthwhile will learn those things as they go whether or not it's drilled into them from the beginning. Placing so much emphasis on specifics and exceptions, instead of an overall general understanding, will only deter many people from even attempting to learn in the first place.

If you guys truly wish to make NES development a happening scene, something which I would LOVE to see happening now that I've stumbled upon it, I strongly urge you to stop worrying about such small things when helping others. I, and other newbies, are learning because of enjoyment and one cannot enjoy learning by being taught small things which are insignificant to our current level. Lighten up! Those who choose not to correct their code and continue with bad coding practices are most likely not going to make anything grand anyways!

by on (#59190)
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.

by on (#59194)
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".

Quote:
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.

Quote:
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.

Quote:
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.

Quote:
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.

Quote:
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.

by on (#59196)
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.

by on (#59198)
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.

by on (#59201)
Hm. Why not improve the parts of the wiki you disagree with? Better to have an edit fight there if necessary (via Discussion).

by on (#59206)
@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.

by on (#59207)
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.

by on (#59210)
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.

Quote:
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.

Quote:
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...

by on (#59214)
Quote:
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.

by on (#59220)
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.

Quote:
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.

Quote:
Quote:
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.

Quote:
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.
Quote:
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.

Quote:
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.

Quote:
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. :(

by on (#59221)
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.

by on (#59222)
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.

Quote:
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.

Quote:
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.

Quote:
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".

Quote:
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.

Quote:
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.

Quote:
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... =)

by on (#59224)
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.

by on (#59225)
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.

by on (#59229)
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.

by on (#59253)
tokumaru wrote:
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.
Agreed. Your example also shows the simplicity very well.
Quote:
IMO what goes on in the NMI is hardly multi-threading [...] 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.
Which is what multi-threading is. Any shared data structures must be updated atomically. Basically you must use lock-free techniques.
Quote:
I did object to the dissemination of a piece of code that I considered flawed
Flawed, bad, same thing. It's only flawed if it doesn't meet the requirements. If the game were doing a status bar or whatever, or did VRAM updates and could fall to 30 FPS sometimes, then I agree it would be a flawed approach since it would glitch. If it won't glitch, AND it reduces complexity, I call that success, not flawed.
Quote:
Some of them [NES newbies] 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.
Absolutely. I at least have a vision of NES tutorial materials covering the spectrum. BTW, you referred to "clueless newbie". The only kind of clueless newbie I envision is one whose natural learning capacities have been destroyed by compulsory "education", and who now learn by rote. I always try to counter this by encouraging involvement and experimentation, so that deep understanding can be achieved. Even deep understanding of LDA immediate is notable in my book.
Quote:
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.
Everything has shortcomings, and those are liabilities in some contexts. In others, they are not a problem. If these shortcomings are due to benefits the approach also has, then it will be superior in some contexts. If you have a way that is just as good or better than tepples' in all aspects, THEN I won't object to you offering it as all-around better.
Quote:
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.
I'm all for discussion of the good and bad aspects of an approach, especially in a particular context, and comparisons to other approaches. But I'm against "this is bad, get rid of it" kinds of "discussion".

Your main argument for "your" approach seems to be that it will handle more advanced game designs better. But why not argue for an even more complex one, since it can handle even more than yours? I think tepples' approach is better than yours IN THE CONTEXT of people learning NES programming, up to the part where they do status bars, interrupts, etc. That's a lot of ground between.
Quote:
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?
Again, I'd love to have a discussion of the relative merits of each approach, without one side believing that his approach is better and that he simply needs to make the other believe the same. Even though I prefer clearing, I am open to discussion of both. Ideally, we'd explore the issue from a fresh perspective and consider all the approaches, even beyond clearing or not clearing. In your case, the bug would be easy to find: start the first level, let the player run through it, then start it again. If it behaves differently the second time, you forgot to initialize something.
Quote:
[...] 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... =)
That's a scary thought... I wish you hadn't mentioned that. A time when there are no more working NES units? *shudder*

by on (#59259)
blargg wrote:
Which is what multi-threading is.

Yes, but it's such a simplified version of it that it might be confusing to bring the term up right from the start. IMO there should be more like a note at the end of the page explaining the technique that says "this is a simple form of multi-threading, if you want to know more, go to wikipedia".

Quote:
Flawed, bad, same thing. It's only flawed if it doesn't meet the requirements.

The fact that I consider it flawed is probably just a consequence of me designing the kinds of game I like to design.

Quote:
The only kind of clueless newbie I envision is one whose natural learning capacities have been destroyed by compulsory "education", and who now learn by rote.

And wouldn't you agree that there are a lot of those? Some people simply want results, without caring much for what's behind those results.

Quote:
Even deep understanding of LDA immediate is notable in my book.

I agree.

Quote:
I think tepples' approach is better than yours IN THE CONTEXT of people learning NES programming, up to the part where they do status bars, interrupts, etc. That's a lot of ground between.

You are probably right, I shouldn't worry about this. When programmers get good enough to the point of adding those features they should be able to understand WHY a certain method would fail when it finally does.

I seem to remember we've had newbies here before asking for the recipe of a status bar though. But they probably wouldn't have any problems with lag frames anytime soon.

Quote:
In your case, the bug would be easy to find: start the first level, let the player run through it, then start it again. If it behaves differently the second time, you forgot to initialize something.

Yes, it's still debugable, but I feel like it encourages poor variable management. I think that newbies should be trained to pay attention to their variables, and if you spoil them by giving them zeroed out memory they will fail to assimilate how important initializing variables in assembly language is. IMO, that's even a poor simulation of what some high level languages do, because they also clear local variables, and in NES code I have never seen anyone bothering about clearing the variables used by each subroutine.

Quote:
A time when there are no more working NES units? *shudder*

Really scary. Fortunately there are people working hard to clone it, let's just hope they succeed! =)

by on (#59273)
@Blarg and Tokumaru

For the "clearing memory is evil", I don't know. I always initialize my variables so this pre-initialization doesn't seems to break anything for me. When you are in a early stage with a few variables, using a debugger and check the ram location, sometime the empty spot helps to find that you put N value a the wrong place because of the 00 values everywhere. It it was not initialized, sometime I would have never found those bugs has a beginner.

As for the "only the counter in the NMI", I never went that way. From the beginning, I was expecting that I may have to produce a lot of data that will take time to decode so I went with flags and updating the content in NMI on demand. It felt natural to me. And one extra thing I added recently it to put the address of the NMI in RAM so I can change the address of this function "on demand" but I would not suggest that for beginner. This is just some test code and it's working fine when I need a completely different NMI function.

edit:

The argument about cleared memory could make it easier with a debugger is weak so I guess we should pass this one. For now, either way doesn't seems problematic. I just personally prefer to put all memory to zero out of habit.

edit2:

Removed comment about lj65/concentration room since the structures of files changed. Comments could have increased since the last time I saw the code and my remark could be not appropriate.

by on (#59310)
tokumaru wrote:
blargg wrote:
Which is what multi-threading is.

Yes, but it's such a simplified version of it that it might be confusing to bring the term up right from the start.

I wasn't saying it should be presented as such, just noting that because it IS a form of multi-threading, that such issues as atomicity and inconsistency arise, and must be dealt with.

I was thinking some about a NES tutorial. It'd start with CPU instructions, then move to graphics. At that point, you'd be doing many that wait for NMI, move things, then repeat. You'd start out with the minimal NMI that increments a counter, and explain how that works. Later, you'd start doing too much in a frame and show how this causes glitches. That would set the stage for expanding the NMI routine to do more than increment the counter. At that point, the student wouldn't have been burdened with threading issues, and would see a clear need for something beyond the single-threaded structure. You could then move the graphic update to NMI, but have the main thread update the shared data non-atomically, so that you occasionally got a different glitch. Then you could introduce the notion of atomic updates and why they're critical. Again, the student would see the clear need for it, rather than simply being told about it but not seeing it in practice. If I ever work on some NES tutorials, my main goal will be to do as much as possible with the things taught so far. This allows the student to have fun doing things with his knowledge so far. Since I'm doing more with less, he has more of a chance of mastering those few things he knows so far, before he moves on.

Quote:
Quote:
The only kind of clueless newbie I envision is one whose natural learning capacities have been destroyed by compulsory "education", and who now learn by rote.

And wouldn't you agree that there are a lot of those? Some people simply want results, without caring much for what's behind those results.

A person who just wants results doesn't want to learn. This type of person is never my audience. You can't write NES games via a recipe approach.

Quote:
I think that newbies should be trained to pay attention to their variables, and if you spoil them by giving them zeroed out memory they will fail to assimilate how important initializing variables in assembly language is.

Yes, this is a good point in favor of not clearing. This is in favor of filling with random garbage that differs each run, in fact. Similar to tepples' shuffling idea for avoiding assumptions about variables' relative addresses.

One of the strong reasons I clear all RAM is that it greatly reduces the unknowns. If you don't, your program may run fine in all the situations you test it in, but there are nearly 2^16384 possible starting states of RAM that you haven't tested. By clearing, you greatly reduce the possible states.

by on (#59328)
Clearing RAM isn't always a bad thing. Lots of my variables are accumulative values, meaning they SHOULD start from 0 and accumulate, like the Vblank count (well, this isn't necessarily something that has to start at 0, but it is accumulative). A really good example is like the RAM for my sound engine. It contains a lot of indexes that are used to index music data, starting at 0, moving higher as the music plays (also there are indexes for volume envelopes). Not only that, it contains virtual registers which need to start out as 0, because my music engine sets bits of them individually. Since all 8 bits of a virtual register aren't updated every frame, and then they're copied to the actual sound registers, I cannot start out with a "random" or unknown value in them. It has to be initialized to 0.

There are many many variables that act like this in my code, and most of them are grouped together, so I can use a nice little loop that clears them all. Don't get me wrong, some values aren't supposed to be 0, in which case I don't necessarily need or want to clear them. But I also see Blargg's point, though it could be used as an argument against clearing RAM. If your code isn't working with a bunch of garbage in RAM, you're probably not properly initializing a value, in which case you'd like to find that out and fix the problem. But clearing RAM in that case is like a safety net. Should there be something you overlooked, you won't have something like a program crash because you know the exact values in RAM.

by on (#59329)
Celius wrote:
Clearing RAM isn't always a bad thing. Lots of my variables are accumulative values, meaning they SHOULD start from 0 and accumulate, like the Vblank count (well, this isn't necessarily something that has to start at 0, but it is accumulative).

And will they always accumulate, the whole time the program is running? Don't you ever have to clear them at a certain point to start out "fresh" (like when going from one engine to another - main game to bonus game, for example)?

Quote:
A really good example is like the RAM for my sound engine. It contains a lot of indexes that are used to index music data, starting at 0, moving higher as the music plays (also there are indexes for volume envelopes). Not only that, it contains virtual registers which need to start out as 0, because my music engine sets bits of them individually. Since all 8 bits of a virtual register aren't updated every frame, and then they're copied to the actual sound registers, I cannot start out with a "random" or unknown value in them. It has to be initialized to 0.

And don't you have to this on a per-song basis? Don't you have to do some sort of cleaning up/initialization every time a new song starts? Why not use this time to properly initialize all music-related variables?

I'm not suggesting people use the random values that might be in RAM, just that they initialize each variable as needed, as a form of guarantee that whenever the variable is used it will hold a valid value, as opposed to relying on the value it was given god knows how long ago by God knows what part of the program.

I often keep all my variable-resetting grouped by system, so each of the sub-systems in the game is responsible by initializing all of their variables, so I don't have to worry what was in RAM before. And it's not like clearing the memory only when necessary is slow or requires much code. I rarely need to clear arrays for example, because they usually have other variables that describe them. For example, a RAM slot used for dynamic objects doesn't need to have all the bytes cleared when an object is unloaded, I just have to flag the slot as empty. The next object that occupies that slot will initialize whatever it needs to, it won't have to worry about the trash left there by the previous object.

Quote:
If your code isn't working with a bunch of garbage in RAM, you're probably not properly initializing a value, in which case you'd like to find that out and fix the problem. But clearing RAM in that case is like a safety net.

My point exactly. Would you rather have this safety net cover your ass and hide a mistake you made or would you rather make the error visible so that you could fix it? I'd rather detect every error I can.

I don't know if I mentioned this here before, but during development I include at the start of my programs the opposite of a memory clearing routine, I have a memory trashing routine. If fills RAM with numbers from my pseudo-random number generator. Whenever I find a "fishy bug" I change the seed of the PRNG to see if there is any change in the buggy behavior. It doesn't happen very often, but I believe I found a bug or two that way. Once I consider the program finished I remove that code.

by on (#59342)
tokumaru wrote:
Celius wrote:
Lots of my variables are accumulative values, meaning they SHOULD start from 0 and accumulate, like the Vblank count (well, this isn't necessarily something that has to start at 0, but it is accumulative).

And will they always accumulate, the whole time the program is running? Don't you ever have to clear them at a certain point to start out "fresh" (like when going from one engine to another - main game to bonus game, for example)?

Not if the definition of the variable is "number of vertical blanks since reset". There are separate timer variables for game states.

Quote:
Quote:
A really good example is like the RAM for my sound engine. It contains a lot of indexes that are used to index music data, starting at 0

And don't you have to this on a per-song basis?

They have to be initialized before the game starts playing a song. Otherwise, the program would start playing garbage between power-on and when the first song starts. Setting sound_effect_time_left[ch] to 0, instrument_time_left[ch] to 0, and tempo to 0 helps suppress this.

Quote:
I'm not suggesting people use the random values that might be in RAM, just that they initialize each variable as needed

A lot of variables are needed from frame one, especially if you have an NMI routine that does more than just inc retraces. Such variables include vram_update_ready (0 = false), is_sprite_0_used (0 = false), and is_a_song_playing (0 = false). On a machine without unlimited space for init code, it can save space and time to define 0 to mean take no action, document this definition, and then spray zeroes.

by on (#59351)
tokumaru, you make good points about putting random values during debugging, but once you're ready for a release, leaving memory uninitialized seems a bad idea. You have to assume you still have bugs, perhaps some of the kind that depend on uninitialized memory. By clearing in a release build, you ensure that these will at least behave consistently on every machine, rather than breaking on that one guy's NES whose RAM powers up in a significantly different state than most others.

It is true that many modules will be reinitialized multiple times in one session, being the ones that handle a level or similar. These can't rely on RAM contents, regardless of whether you clear RAM at power/reset. So if you took a bug-free game that assumed memory was cleared with zero and converted it to not assume so (and without simply adding a memory clear at the beginning :) ) I doubt you'd add many source lines, perhaps 50 at most.

So comparing the two, I see that yes, not assuming RAM contents allows you to use more debugging techniques, like random RAM filling, or even a NES emulator with something like valgrind, to find reads from uninitialized RAM. On the other hand, because it forces you to initialize every variable, it introduces more opportunities to forget initialization.

At this point I'm thinking that the type of NES program is the main determiner of which gives the most benefit. Virtually all my NES programming has been of a shell-like environment for running test programs, where there is little module reinitialization, and where conciseness is a virtue. In a game where there is little that is initialized only once, I could see random-clear during dev/zero-clear during release being a better approach.

by on (#59352)
I don't think there is anything wrong or bad initializing the whole parts of memory. If you weren't doing it you would probably need to have a part of code that do something like this :
Code:
 lda #$00
 sta variable1
 sta blahblah
 sta blabhblahbalh
 .....
 ;one tousand lines long

Ok you don't clear other variables which are cleared with appropriate routines (such as stop_music) or that simply don't need any initialization, and in all cases you have to initialise some varialbles with other values than $00.

But it's still a waste of bytes as opposed to simply have a loop that clears $000-$7ff and that takes ~10 bytes.

by on (#59355)
blargg wrote:
So comparing the two, I see that yes, not assuming RAM contents allows you to use more debugging techniques, like random RAM filling, or even a NES emulator with something like valgrind, to find reads from uninitialized RAM.

Ah, I was wondering if something like this existed. Maybe this could be implemented in FCEUX for example?

Bregalad wrote:
But it's still a waste of bytes as opposed to simply have a loop that clears $000-$7ff and that takes ~10 bytes.

I know it might seem more compact to clear everything at the start, but the thing is I don't think there are many variables that are initialized only once. Most of them need to be reset at one point or another (when a new level starts, when a new song starts, etc), so why not organize your code so that these resetting codes always act as the initializers of the variables, in a way that you wouldn't need a general memory reset? Looks much more organized to me.