Jump to content
IGNORED

IntyBASIC Stack Overflow Check?


First Spear

Recommended Posts

Check your procedures in your code.  Makes sure that goto's are contained in the procedure itself or the main program.  Don't goto out of the procedure into the main loop because the return address is still in the stack.  Everytime a GOSUB is accessed, it push the return address to the stack.  When the code hit return:end, that address get loaded back into the program counter and the stack pointer recedes. 

I made a code that display the content of the stack:
 

maincode:
if cont.key=1 then goto debug
goto maincode

debug:
sprite 0,0,0,0
sprite 1,0,0,0
sprite 2,0,0,0
sprite 3,0,0,0
sprite 4,0,0,0
sprite 5,0,0,0
sprite 6,0,0,0
sprite 7,0,0,0

#debug=peek($2f0)
print at 20+0 color 2,<5> #debug

#debug=peek($2f1)
print at 20+7 color 2,<5> #debug

#debug=peek($2f2)
print at 20+14 color 2,<5> #debug

#debug=peek($2f3)
print at 40+0 color 2,<5> #debug

#debug=peek($2f4)
print at 40+7 color 2,<5> #debug

#debug=peek($2f5)
print at 40+14 color 2,<5> #debug

#debug=peek($2f6)
print at 60+0 color 2,<5> #debug

#debug=peek($2f7)
print at 60+7 color 2,<5> #debug

#debug=peek($2f8)
print at 60+14 color 2,<5> #debug

#debug=peek($2f9)
print at 80+0 color 2,<5> #debug

#debug=peek($2fa)
print at 80+7 color 2,<5> #debug

#debug=peek($2fb)
print at 80+14 color 2,<5> #debug

#debug=peek($2fc)
print at 100+0 color 2,<5> #debug

#debug=peek($2fd)
print at 100+7 color 2,<5> #debug

#debug=peek($2fe)
print at 100+14 color 2,<5> #debug

#debug=peek($2ff)
print at 120+0 color 2,<5> #debug

#debug=peek($300)
print at 120+7 color 2,<5> #debug

#debug=peek($301)
print at 120+14 color 2,<5> #debug

#debug=peek($302)
print at 140+0 color 2,<5> #debug

#debug=peek($303)
print at 140+7 color 2,<5> #debug

#debug=peek($304)
print at 140+14 color 2,<5> #debug

#debug=peek($305)
print at 160+0 color 2,<5> #debug

#debug=peek($306)
print at 160+7 color 2,<5> #debug

#debug=peek($307)
print at 160+14 color 2,<5> #debug


#debug=peek($308)
print at 187 color 6,<5> #debug

halt:
goto halt

If you know how to use the jzintv debugger, you may see the content of the stack that way.  It's address is $2f0-$308.  Anything get loaded into address $308 trip the stack detection.

Edited by Kiwi
  • Like 2
Link to comment
Share on other sites

IIRC, most IntyBASIC generated code only uses the stack to remember return addresses.  If you see a BEGIN statement in the generated code, that's really PSHR R5.  Otherwise, the only stack accesses are from the IntyBASIC support code in the prologue/epilogue files, and the 9 words of stack space the interrupt handler requires.  (Note: This could be reduced to 8 if the BEGIN/RETURN pair in _int_vector were removed, and the interrupt handler simply did B $1014 at the end.)

 

$2F0 - $307 is only 24 words of stack space.  That's not a lot of stack space.  Subtract 9 off the top for interrupts, and probably another 8 or so for the worst case library functions that might get invoked.   What that translates to is that you can't really GOSUB more than about 7 levels deep.  Note: I'm guessing on the 8 for the worst case library function.  It's probably less than that.

 

Different question:  Should the stack overflow check be sensitive to the --jlp or --cc3 flag?  If you use either of those flags, I believe all 16-bit variables go to the extended 16-bit memory.  In that case, you actually have stack space up to $319, and that gives you an extra 17 words.

  • Like 2
Link to comment
Share on other sites

The bug you are looking for is the use of GOSUB several times, maybe a game routine that does a GOSUB again to a higher-level PROCEDURE.

 

The latest IntyBASIC v1.4.2 would catch the original cause of Stack Overflow, the usage of GOTO to return to the main code from inside a PROCEDURE.

  • Like 1
Link to comment
Share on other sites

Fun facts while re-developing FUBAR:

 

1. I was getting the "Stack overflow" message and didn't know it.  I had written the code so everything happened inside of the "ON FRAME" procedure, using a variable to know what to do that frame (between rounds, etc.), and leaving the main code execution in an infinite loop.  When starting a new round, it took longer than a single frame to do everything, so I chopped it all up into multiple frames, knowing I had 2 seconds to get everything done before the action started.

 

Why I didn't know the message was there was because initializing the canvas caused the text to appear white-on-white, perfectly blending in with the canvas.  But then the AIs would start to "paint over the text" which caused all kinds of interesting screen artifacts, for example having the NEXT_COLOR bit become raised, which is not used in Colored Squares Mode for that purpose.

 

2. As a workaround, I commented out STACK_CHECK as I normally do before a game goes into production, and I replaced it with ASM DIS at the beginning of the ON FRAME Procedure and ASM EIS at the end.  That way, using too many CPU cycles during the procedure causes the screen to be blank on intermittent frames instead.  I discovered that simply using IntyBASIC's PRINT command to display seven 3-digit numbers took more than a single frame, so I wrote a little code of my own to replace that.

 

3. Just to be sure I wasn't living in a fool's paradise just before the game went into production, I uncommented STACK_CHECK and suddenly was running into trouble again.  Turns out the few extra cycles used by the Stack Check subroutine were enough to go overboard, due to my meticulous cycle count while rewriting the AI code (slowdown was one of the reasons I didn't come back to FUBAR until after JLP came onto the scene).  I left ASM DIS and ASM EIS intact, despite a comment to remove those lines before production.  Letting the game run all day for the two days of RetroGameCon 7 with no issues was more than enough evidence to me that it works fine.

  • Like 3
Link to comment
Share on other sites

Bonus FUBAR development fun fact still sort of related to this topic:

 

4. When I would least expect it, the game would suddenly display "Stack overflow" and hang.  But not in a way that jzintv would halt code execution with a "CPU off in the weeds" message or anything, more like what happens when a game crashes on real hardware.  After using my preferred low-tech debugging method of setting traps, I discovered the anomaly was within the final phase of the AI code, where the AI selects one of the directions to move in among all the directions flagged for having the highest value.

 

What I discovered was that this ASM "PROC" was called with none of the directions flagged as the best move, and so ran in a very tight infinite loop, searching for a recommended direction.  This would happen when all of the directions' values overflowed into a negative number, and so none of them were better than the initial value of 0.  The cause was an out-of-range value that I had set as a default for Player 3's AI, and the problem would manifest if that AI became surrounded with unpainted squares as a result of too many Griefers (or "Ghosts" as I called them in the documentation), particularly in Elimination Mode II, which reassigns players from eliminated teams to become Griefers.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...