It is currently Wed Nov 22, 2017 3:21 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
PostPosted: Tue Jan 17, 2017 2:19 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1017
Location: Gothenburg, Sweden
Following the discussion on where to keep logic/state handling, i got a little confused.

In the thread, there's a recommendation to keep it in the reset handler. Pardon my inexperience.
My first impulse on what to put there is a routine that wipes RAM and sets the state handler(s) to point to title init (or point to start of program init directly). Or am i confusing the code at the address of the reset vector with something else? And if i'm not; why?

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 2:31 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
Sometimes we call it "Reset" just because that's the entry point that eventually leads to the dedicated game loops. You can also call it the "main thread".

At the beginning of the reset handler you should indeed initialize the system (although I advocate against wiping the RAM, but let's not focus on that), but right after that you'd normally jump to the first game loop (introduction, title screen, whatever).


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 3:35 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1017
Location: Gothenburg, Sweden
Thanks! So to verify, something like "keeping logic in the Reset handler" simply means "keeping logic in main", as opposed to NMI (or IRQ/BRK, even though not likely applicable here), and not necessarily assuming the very top of reset/main? The latter part is what i think originally confused me the most.

If you want to, i'd also be interested to hear your advice against wiping RAM.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 3:38 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
First time in my life I've ever heard someone say "reset" (particularly mention the RESET vector, because said thread was discussing NMI and RESET) referring to the main loop of a game. o_O;; I had the same reaction as WheelInventor but chose to say nothing.


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 4:11 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
Yeah, calling the main thread "reset" can be a bit confusing, I wouldn't normally do that, but that's what the post I was replying to called it, and I didn't want to make things more confusing by changing the terminology.

The main thread does indeed start at the reset vector, but any game that's not trivially simple will not have any game loops particularly close to the reset code.


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 6:26 pm 
Offline
Formerly ~J-@D!~
User avatar

Joined: Sun Mar 12, 2006 12:36 am
Posts: 445
Location: Rive nord de Montréal
I did several smallish assembly programs for some small microcontrollers, and the main loop was right below the "Reset" label, so I named the main thread simply "reset"; the documentation would say, "[this subroutine] must be called from reset" instead of "(...) from main thread".


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 7:22 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1017
Location: Gothenburg, Sweden
Interesting. So, maybe it's a high level / low level programming discourse thing, possibly obscured by time, seeing less use? Or maybe an electronics engingeering / programming one.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 7:56 pm 
Offline

Joined: Thu Aug 20, 2015 3:09 am
Posts: 288
My compiler traces seperate call graphs from each vector to avoid interrupts clobbering local variables without resorting to a software stack. So "called from RESET" vs. "called from NMI" makes perfect sense to me.


Top
 Profile  
 
PostPosted: Tue Jan 17, 2017 8:14 pm 
Offline
User avatar

Joined: Sun May 27, 2012 8:43 pm
Posts: 1311
Given the name of the vector, and what it represents, I think it's weird to say "put the logic in reset". I consider that the entry point that represents initialization, which then jumps to a main loop elsewhere. In the end, it's semantics and not functionally different.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 3:06 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 874
Location: Sweden
WheelInventor wrote:
If you want to, i'd also be interested to hear your advice against wiping RAM.

I think it's about hiding bugs. If you always make sure every RAM register that you are going to read is initialized there's no need to wipe the RAM (like in C you would also initialize every variable somehow). And if you forget to initialize a certain variable, something might not work as expected (since RAM can be anything at boot). But if you wipe RAM then initialization bugs won't show. FCEUX might not show these bugs though since it initializes RAM in a pattern at boot like: 0000FFFFF...

But I'm not sure how Tokumaru means wiping RAM is different from initializing variables. Most variables may be 0 anyway so it makes sense to use a loop that does it with much less code. Then you only need to initialize variables that shouldn't be 0.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 4:13 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
WheelInventor wrote:
If you want to, i'd also be interested to hear your advice against wiping RAM.

Sorry, I missed this part!

Pokun wrote:
I think it's about hiding bugs.

That, and I find it redundant. Every variable has to be initialized before it's used anyway (specially if it's reused!), so clearing everything to $00 at the beginning is pointless, since every variable, in theory, will be initialized afterwards anyway. My reasoning is that it wastes ROM (hey, you never know when you're gonna need every last byte of it! :mrgreen:) and may hide bugs, So I see absolutely no reason to do that.

In fact, during development, I often do the very opposite of clearing RAM, I fill it with garbage. I pick a seed for my random number generator and fill the RAM with crap. From time to time I change the seed to see if anything obvious changes, which would indicate that something wasn't being initialized properly.

Quote:
But I'm not sure how Tokumaru means wiping RAM is different from initializing variables. Most variables may be 0 anyway so it makes sense to use a loop that does it with much less code. Then you only need to initialize variables that shouldn't be 0.

The problem with that is that the full wipe only happens once, but several parts of the program run more than once. Say you wipe all the RAM and everything appears to work when you do it the first time. The title screen, the title card, the first level. Then you die, the level restarts and everything is buggy. But why, since it was fine before? Well, you might very well have forgotten to initialize some gameplay variables, which were all $00 the first time but now have been corrupted after you played the level for the first time. My point is that most of the time you have to initialize the variables prior to using them, because they're often reused in games. And if you're gonna initialize the relevant variables before running each module of your game, why bother clearing it all in the beginning, since all it really does is hide bugs?

I guess that you you have a lot of state that survives the entire game without ever being reset, and the initial state for most of that is $00, then I guess you could save a little space by wiping the entire RAM in one go, but I personally never felt like I'd benefit from that. Very few things in my code begin at $00, and very few things live from power on to power off without ever needing to be reset, so...


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 6:15 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 874
Location: Sweden
OK now I see. Variables that are initialized more than once of course don't benefit from a RAM wipe.

I do have a lot of flags and other variables that needs to be initialized to 0 once though, so a simple RAM wipe loop is much smaller than clearing each variable individually.

Individually:
Code:
init_variables:
  lda #$00              ;clear variables
  sta var0
  sta var1
  sta score
  sta graphic_flag
  sta ☆☆☆
  sta tjingtjong
  ...
  sta var100000


Simple loop:
Code:
init_ram:
  lda #$00
  ldx #$00
@loop:
  sta $0000,x           ;clear each RAM page
  sta $0100,x
  sta $0200,x
  sta $0300,x
  sta $0400,x
  sta $0500,x
  sta $0600,x
  sta $0700,x
  inx
  bne @loop

Then I might skip page 2 and page 7 to use them as shadow OAM and highscore respectively. They'd need their own initialization loops.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 7:10 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5827
Location: Canada
Pokun wrote:
WheelInventor wrote:
If you want to, i'd also be interested to hear your advice against wiping RAM.

I think it's about hiding bugs. If you always make sure every RAM register that you are going to read is initialized there's no need to wipe the RAM (like in C you would also initialize every variable somehow). And if you forget to initialize a certain variable, something might not work as expected (since RAM can be anything at boot). But if you wipe RAM then initialization bugs won't show. FCEUX might not show these bugs though since it initializes RAM in a pattern at boot like: 0000FFFFF...

But I'm not sure how Tokumaru means wiping RAM is different from initializing variables. Most variables may be 0 anyway so it makes sense to use a loop that does it with much less code. Then you only need to initialize variables that shouldn't be 0.

Almost all emulators initialize RAM to a consistent state on power on, not just FCEUX. The only exception I can think of is thefox's custom build of Nintendulator?

FCEUX now has an option to initialize it as random, if you like, but it is not the default setting.

Personally I don't believe that failing to initialize RAM is any kind of defense against bugs. What it will do is make bugs unreliable and difficult to reproduce (i.e. unlikely to be caught in production, and difficult to diagnose once released). If initializing it to 0 doesn't cause a bug to occur, then it's not a bug. :P

When you release software, it will always have bugs somewhere. Some of those bugs might read areas of RAM you didn't intend. If you initialize the whole thing, at least it's going to go wrong the same time every time, and you have some hope of the conditions on your test being the same as the conditions where it's failing on someone's playthrough.

If you want to track unexpected reads, put breakpoints on your empty memory regions, or use/write some other kind of memory dianostic tool. Leaving it uninitialized is probably the worst way I can think of to try and catch and fix that problem; there's a million better ways to do this.

So, if you're asking for opinions on whether to do this, I am 100% in the initialize everything you can camp.

(And use an emulator with randomized RAM on startup anyway, it's a good emulator feature and there's a reason I added it to FCEUX, I just don't think it's appropriate for the purpose stated-- you should STILL INITIALIZE RAM in your game's reset code.)


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 8:50 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
rainwarrior wrote:
If initializing it to 0 doesn't cause a bug to occur, then it's not a bug. :P

But what If the bug doesn't occur the first time you forget to initialize a variable, but does occur the second time?

I know that randomizing RAM doesn't guarantee that bugs will manifest themselves sooner, but non-zero values tend to cause more obvious side effects. And randomizing RAM in your code (as opposed to letting the emulator do it every time) has the benefit that you can decide when to change the seed, because you may want to maintain a certain RAM configuration if it happens to expose a bug. If you randomize every time, a bug can vanish before you have the chance to debug it.

Quote:
you should STILL INITIALIZE RAM in your game's reset code.)

Oh well, to each his own. FWIW, I never told him not to do it, I just said I don't do it.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 10:32 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
rainwarrior wrote:
Almost all emulators initialize RAM to a consistent state on power on, not just FCEUX. The only exception I can think of is thefox's custom build of Nintendulator?

It's optional in NDX. When option is enabled, the randomization pattern is always the same after the emulator is started (and changes on each power-on). I decided to not seed the RNG for the reason that tokumaru mentioned (reproducibility of bugs), although it could be improved by allowing the user to specify the seed.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 52 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group