Jump to content
IGNORED

Weird glitch happening...


Recommended Posts

Not sure if anyone can help on this, but my Space Taxi game seems to have a bug or glitch or something. The game works most of the time but at what seems to be random points, certain things stop working.

 

The character sprite lands on pads (pad 1, pad 2, etc.) (which I use a collision to detect). The pad numbers are stored in an Array that randomizes the order of 1 to 6...  ex random_array(1) = 5 ,random_array(2)= 1

 

When the "glitch" happens, the pad variable (wanted_pad) which stores the next pad, becomes 0. (Not sure how as there is no 0 value in the array). Also one (not all) of the pads no longer detects the collision.

 

I am wondering if maybe I am running out of memory or RAM? 

 

Any thoughts :)

  • Like 1
Link to comment
Share on other sites

Since variables are allocated at compile time, I don't think you can run out of RAM. Sure, you could index arrays outside of their range, and strange things happen. Perhaps the variable you use to select which pad in the array, is used elsewhere and gets contaminated at some point?

Link to comment
Share on other sites

1 hour ago, carlsson said:

Since variables are allocated at compile time, I don't think you can run out of RAM. Sure, you could index arrays outside of their range, and strange things happen. Perhaps the variable you use to select which pad in the array, is used elsewhere and gets contaminated at some point?

It’s just weird that there is also a collision issue at the same time. The collision sets an on-pad variable to 1 and assigns a y value for the sprite.

Link to comment
Share on other sites

Is "wanted_pad" a 16-bit variable? If so, and if it is defined earlier in memory, it could be wiped out by a stack overflow.

 

In IntyBASIC, a stack overflow could happen in mostly two situations:

  • Too many "Gosub" calls in a chain.
  • An "On Frame" routine that takes too long to complete.

I can't think of any other way it could happen accidentally, but there could be others.

 

If "wanted_pad" is an 8-bit variable, the above does not apply.

 

Here are some reasons why a variable could be overwritten:

  • You assigned the expected value to the wrong variable. (It happens!)
  • You wrote to an array using an index out of bounds.
  • You had a typo in the name of the variable somewhere and inadvertently the assignment was applied elsewhere (or a new variable was created for that value).
  • There is a logic error elsewhere which caused your program to not follow the code path you expected, and therefore the assignment was done correctly, but with the wrong value.

There could be others.  Logic problems are hard to troubleshoot, but there are some low-hanging fruit in there that we could dismiss quickly.

 

Naming issues and typos (which, in my experience helping others, is a more prominent problem than many imagine) can be detected by using OPTION EXPLICIT at the top of your program.

 

Unfortunately, if you haven't so far, doing so now will force you to declare all your variables with DIM before using them, typically at the beginning of the program.  However, doing this will immediately show whether a variable name was mistyped somewhere.

 

For example, if you DIM a variable "wanted_pad" and assigned it a value, then later inadvertently typed "wantd_pad" when reading the value, the compiler will tell you that "wantd_pad" is not valid.  Without OPTION EXPLICIT, it will just automatically declare a brand new variable with the bad name, and read zero (the default value).

 

Another "easy" thing you can do is to put a "watch" on the variable in the debugger.  I say "easy" because it may seem a bit scary and intimidating at first if you've never done it, but it is really not such a big deal if you know how to do it.

 

If you wish to do that, I'll gladly guide you through it.  Just let me know. :)

 

    dZ.

 

 

Link to comment
Share on other sites

12 hours ago, Brian's Man Cave said:

It’s just weird that there is also a collision issue at the same time. The collision sets an on-pad variable to 1 and assigns a y value for the sprite.

First, what emulator are you using?  In jzIntv, you can use the debugger to watch for changes to a memory value.  I use that often.

 

Second, you mention that the bug happens sporadically, and that it's connected to collision.  That brings two things to mind.  One is that there might be a calculation based on FRAME, when it rolls over from 65,535 to 0, roughly every 20 minutes.  Another would have to do with the behavior of the Intellivision STIC regarding collision detection.

Link to comment
Share on other sites

1 hour ago, Zendocon said:

First, what emulator are you using?  In jzIntv, you can use the debugger to watch for changes to a memory value.  I use that often.

 

Second, you mention that the bug happens sporadically, and that it's connected to collision.  That brings two things to mind.  One is that there might be a calculation based on FRAME, when it rolls over from 65,535 to 0, roughly every 20 minutes.  Another would have to do with the behavior of the Intellivision STIC regarding collision detection.

I am using Jzintv, I couldn't figure out how to use the debugger! ... All I was able to do was print some of the variables to the screen so I could see what was going on!

Edited by Brian's Man Cave
  • Like 1
Link to comment
Share on other sites

1 hour ago, Brian's Man Cave said:

I am using Jzintv, I couldn't figure out how to use the debugger! ... All I was able to do was print some of the variables to the screen so I could see what was going on!

When running Jzintv just add the -d option to the command line and it will enter directly into the debugger.

 

There is a good tutorial here http://wiki.intellivision.us/index.php/Introducing_jzIntv's_Debugger

 

I don't know how to watch positions of memory for changes, but typically I only use R 10000 (run for 10000 cycles) and the breakpoint command.

  • Like 1
Link to comment
Share on other sites

2 hours ago, Brian's Man Cave said:

I am using Jzintv, I couldn't figure out how to use the debugger! ... All I was able to do was print some of the variables to the screen so I could see what was going on!

Without knowing your environment or any other details, you could do this:

 

  • Set a "write watch" in the debugger on the variable in question.
  • Notice when and where the variable is set to the wrong value.
  • Find that address in the listing file.
  • Identify the IntyBASIC statement that compiled into that line.
  • Find that statement in your source and try to deduce the logic that lead to it getting the wrong value.

So, here is how to do this:

  • Enable the debugger in jzIntv (-d in command line or INTYDBGUG in the SDK).
  • While the game is running, hit F4 to halt emulation and activate the debugger command prompt.
  • Type "w <name of symbol or memory address>" at the prompt and hit <enter>.

The name of the symbol is easy to discover:  it is the name of the variable, all in UPPER-CASE prefixed with either "var_" (for 8-bit) variables, or "var_&" (for 16-bit variables).


For example:

Dim SomeVariable
Dim #SomeOtherVariable

will result in the symbols:

var_SOMEVARIABLE
var_&SOMEOTHERVARIABLE

 

If it is an array, it's a little more involved:  you will need to find the symbol of the array in the listing (lst) or symbols (sym) file, identify its address, and add the index of the element.

 

  • After entering the watch command, type "r <enter>" in the debugger to continue the emulation.
  • Play the game normally until the glitch happens, then stop the emulation again.
  • Look at the output of the debugger in the console: every time the variable was written to, it would have issued an entry in the output console.

 

Watch entries look like this (this is from the top of my head, but it should illustrate it):

WR a=var_SOMEVARIABLE d=1234 (PC=$FFFF) 123345678901233

Each entry tells you the action that occurred (WR means "write"; there are also read watches, but that's a separate debugger command), the memory address or symbol that was written to (a=var_SOMEVARIABLE), the value saved there (d=1234), the address of the program instruction that did it (PC=$FFFF), and a few other things that you can ignore for now.

 

  • Use the saved value column (d=xxxx) to know which entry is the one with the bad value.
  • Then identify the address of the program instruction (PC=xxxx).
  • Open the listing file (lst) and search for that address at the far left column until you find it.  It needs to be at the far left, on the very first column.
  • as soon as you find that line, scan carefully above it until you find the closest IntyBASIC statement.

 

The listing file will contain the IntyBASIC statements, prefixed with their line numbers in your source file, followed by the assembly code that was generated from it.  You have identified one of the assembly instructions that updated the variable, now you want to know to which IntyBASIC statement it belongs.

 

It will look something like this:

     ; [120] SomeVariable = 1234
5500 MVII #1234, R0
5503 MVO R0, var_SOMEVARIABLE
...

That's just a made up example to illustrate what you are looking for.  In this example, assembly instructions at $5500 and $5503 were compiled from IntyBASIC line number #120.


Let me know if you have any questions.

 

    dZ. 

 

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

22 minutes ago, nanochess said:

When running Jzintv just add the -d option to the command line and it will enter directly into the debugger.

 

There is a good tutorial here http://wiki.intellivision.us/index.php/Introducing_jzIntv's_Debugger

 

I don't know how to watch positions of memory for changes, but typically I only use R 10000 (run for 10000 cycles) and the breakpoint command.

The write watch is done with the "w" command, followed by the memory address (in Hex), or the name of the symbol (munged by the compiler, in the case of IntyBASIC).

 

    dZ.

  • Like 1
Link to comment
Share on other sites

Sorry, I just realized that you were asking how to enable the debugger itself.  I missed that.

 

@nanochess’s response above should help with that.


My comment above walks you through setting up a “write watch” on a variable for troubleshooting.

 

    dZ

Edited by DZ-Jay
Link to comment
Share on other sites

36 minutes ago, DZ-Jay said:

Sorry, I just realized that you were asking how to enable the debugger itself.  I missed that.

 

@nanochess’s response above should help with that.


My comment above walks you through setting up a “write watch” on a variable for troubleshooting.

 

    dZ

Thanks, I will give it a try!! I am using the SDK version :)

  • Like 2
Link to comment
Share on other sites

5 hours ago, Brian's Man Cave said:

Thanks, I will give it a try!! I am using the SDK version :)

Great!  In that case, you run “INTYDBUG”. For information on the SDK tools and how to use them, you should consult the Tool Guide documentation that comes with it.

 

Pro Tip:  you run INTYDBUG the same way you run INTYRUN.

 

    dZ.

Link to comment
Share on other sites

A few other points to add:

  • At compile time, you can have three additional files generated: .lst, .sym, and .smap.  You can have jzIntv open these files for use with the debugger.  That will display actual lines of your IntyBASIC code, as well as your variable names.  My PIDEGS tool does all this automatically.
  • You can also create a debugger script file and have jzIntv auto execute it at startup.  Here is what I use:
> 160
r

The first line tells jzIntv the width of your terminal window.  The jzIntv documentation indicates it wants at least 160 characters to display lines of IntyBASIC code.  It also wasn't built to autodetect your terminal width.

The second line is "r" for "run", which starts emulation.  That's because when you use the "-d" or "--debugger" switch, jzIntv leaves you at the debugger prompt at startup by default.

Loading this script is also automated by my PIDEGS tool.

  • In the debugger, you can enter "?" to get a list of commands.  These are the ones I commonly use:
    • In addition to "w" for "watch" which @DZ-Jay mentioned already, I often use "b [address]" to set a Breakpoint.  Once you know the offending memory address, you can set a breakpoint at that address, and jzIntv will automatically Break to the debugger when that address is reached.
    • While at a breakpoint, you can use the "s" command to Step through the next instruction.  This will display the contents of the registers.  If you want to step through multiple lines at one time, enter "s [number]".
    • A similar command is "t" which works like "s" but skips over procedure calls.  I use that often when hacking original games, especially when those calls are to Exec procedures (they are in the $1xxx address range).
    • The command to remove a breakpoint is "n [address]" to uNset that breakpoint.
    • Similarly, if you want to stop watching for Writes to an address, just type "w [address]" a second time.
    • "rs" will ReSet the game.
    • "q" will Quit jzIntv right from the debug prompt.
Link to comment
Share on other sites

4 minutes ago, Zendocon said:

A few other points to add:

  • At compile time, you can have three additional files generated: .lst, .sym, and .smap.  You can have jzIntv open these files for use with the debugger.  That will display actual lines of your IntyBASIC code, as well as your variable names.  My PIDEGS tool does all this automatically.
  • You can also create a debugger script file and have jzIntv auto execute it at startup.  Here is what I use:

> 160
r

The first line tells jzIntv the width of your terminal window.  The jzIntv documentation indicates it wants at least 160 characters to display lines of IntyBASIC code.  It also wasn't built to autodetect your terminal width.

The second line is "r" for "run", which starts emulation.  That's because when you use the "-d" or "--debugger" switch, jzIntv leaves you at the debugger prompt at startup by default.

Loading this script is also automated by my PIDEGS tool.

  • In the debugger, you can enter "?" to get a list of commands.  These are the ones I commonly use:
    • In addition to "w" for "watch" which @DZ-Jay mentioned already, I often use "b [address]" to set a Breakpoint.  Once you know the offending memory address, you can set a breakpoint at that address, and jzIntv will automatically Break to the debugger when that address is reached.
    • While at a breakpoint, you can use the "s" command to Step through the next instruction.  This will display the contents of the registers.  If you want to step through multiple lines at one time, enter "s [number]".
    • A similar command is "t" which works like "s" but skips over procedure calls.  I use that often when hacking original games, especially when those calls are to Exec procedures (they are in the $1xxx address range).
    • The command to remove a breakpoint is "n [address]" to uNset that breakpoint.
    • Similarly, if you want to stop watching for Writes to an address, just type "w [address]" a second time.
    • "rs" will ReSet the game.
    • "q" will Quit jzIntv right from the debug prompt.


IntyBASIC SDK handles the assembler files creation automatically and the mapping of the symbols and everything and prepares the debugger for use.
 

IntyBASIC source-level debugging and symbol mapping is already handled when using the INTYDBUG tool.

 

Breakpoints, variable watches, memory peeks and pokes can all be done symbolically, plus the debugger itself can display the BASIC code alongside the disassembly.

 

The problem is that it is still mostly Assembly Language and Hex, which is not what most IntyBASIC programmers use in their programs.

 

The biggest hurdle in my opinion is bridging the gap between BASIC and Assembly, especially for someone who’s not experienced in the latter.  The debugger is very useful, but can be intimidating.

 

It can get even worse if someone is not familiar with debuggers in general and what they can do or how.
 

I would like to offer a tutorial on how to use the SDK to debug common issues and perform basic troubleshooting on an IntyBASIC program.  This could obviously extend to those who do not use the SDK, but will require more effort on their part to set up the symbols and everything.

 

That said, it is not clear to me how basic or advanced such a tutorial has to be, how much hand-holding it will require in order to make it useful, or which topics specifically should be covered first to have the most impact.

 

I am willing to make some videos, so if anybody has any ideas of what they want, let me know. :)

 

    dZ.

 

  • Like 1
Link to comment
Share on other sites

On 7/20/2022 at 6:22 AM, DZ-Jay said:

In IntyBASIC, a stack overflow could happen in mostly two situations:

  • Too many "Gosub" calls in a chain.
  • An "On Frame" routine that takes too long to complete.

    dZ.

One quick way to determine if the program doing stack overflow is to add STACK_CHECK anywhere in code(I usually put it at the first line.). So whenever a number is loaded into a specific address, this routine fires. It sets the screen mode to colorstack mode and then write on top, stack overflow in lower case.  When stack overflow happens, make sure you're not jumping out of the procedure brackets otherwise it won't pop the value off the stack.

Other weirdness may happen if your ROM segment is too large. 

I think what's happening the randomizer is picking 0 because random(5) is 0-4.  You probably need want_pad = 1 + random(5), so the value is 1-5, and zero isn't in the pool.

  • Like 1
Link to comment
Share on other sites

On 7/21/2022 at 3:59 PM, Kiwi said:

One quick way to determine if the program doing stack overflow is to add STACK_CHECK anywhere in code(I usually put it at the first line.). So whenever a number is loaded into a specific address, this routine fires. It sets the screen mode to colorstack mode and then write on top, stack overflow in lower case.  When stack overflow happens, make sure you're not jumping out of the procedure brackets otherwise it won't pop the value off the stack.

Other weirdness may happen if your ROM segment is too large. 

I think what's happening the randomizer is picking 0 because random(5) is 0-4.  You probably need want_pad = 1 + random(5), so the value is 1-5, and zero isn't in the pool.

Yes I do have a +1 to the value! I think I figured out why I was getting a zero value, it’s a logical error where a variable gets reset after the car crashes and I didn’t have a code to set it back. But this still doesn’t explain why the pad collision fails! 

  • Like 1
Link to comment
Share on other sites

6 hours ago, Brian's Man Cave said:

Yes I do have a +1 to the value!

There's an old computer science joke that goes like this:

The two most common errors in software engineering are:  Cache invalidation, naming things, and off-by-one error.

 

LOL! :lol:

 

Quote

I think I figured out why I was getting a zero value, it’s a logical error where a variable gets reset after the car crashes and I didn’t have a code to set it back. But this still doesn’t explain why the pad collision fails! 

Unfortunately, without looking at your code, we can't help you much.  ;)

 

     -dZ.

 

 

 

P.S.  Did you try the debugger?  If not, why not?  I ask in case there is something I can do to help to make it easier or less intimidating.  Perhaps some additional tool assistance or better instructions?

 

I was thinking that I could add a tool to the SDK bestiary that will offer the following:

  • Give it a variable name and it will return the assembly symbol and address.
  • Give it an array name and index and it will return the base's assembly symbol and the element's address.
  • Give it some values in decimal and it will convert them to hex, and vice versa (since the debugger operates with hex).
  • Give it a BASIC file line number and it will return its assembly address.
  • Give it an assembly address and it will return the BASIC statement and file line number from which it was assembled.
  • etc.

Do you think that sort of thing would help?  It would be a shame if IntyBASIC programmers are forgoing the use of the debugger, because it really is a very useful tool (just a bit arcane).

 

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
On 7/23/2022 at 5:39 AM, DZ-Jay said:

There's an old computer science joke that goes like this:

The two most common errors in software engineering are:  Cache invalidation, naming things, and off-by-one error.

 

LOL! :lol:

 

Unfortunately, without looking at your code, we can't help you much.  ;)

 

     -dZ.

 

 

 

P.S.  Did you try the debugger?  If not, why not?  I ask in case there is something I can do to help to make it easier or less intimidating.  Perhaps some additional tool assistance or better instructions?

 

I was thinking that I could add a tool to the SDK bestiary that will offer the following:

  • Give it a variable name and it will return the assembly symbol and address.
  • Give it an array name and index and it will return the base's assembly symbol and the element's address.
  • Give it some values in decimal and it will convert them to hex, and vice versa (since the debugger operates with hex).
  • Give it a BASIC file line number and it will return its assembly address.
  • Give it an assembly address and it will return the BASIC statement and file line number from which it was assembled.
  • etc.

Do you think that sort of thing would help?  It would be a shame if IntyBASIC programmers are forgoing the use of the debugger, because it really is a very useful tool (just a bit arcane).

 

After painfully going through code and constant testing, I was able to narrow my problems down to some problematic code! Mainly when the last man of the level appeared, if I crashed with him in the car then problems. I also had some code that tried to detect when you are on the same pad as the man when he appeared... also caused problems. 

 

anyways, I am still trying to figure out how to invoke the debugger. 

 

I am using SDK and the command line I use is: intybasic --title "Space Taxi" --jlp taxi.bas taxi.asm

Link to comment
Share on other sites

1 hour ago, Brian's Man Cave said:

After painfully going through code and constant testing, I was able to narrow my problems down to some problematic code! Mainly when the last man of the level appeared, if I crashed with him in the car then problems. I also had some code that tried to detect when you are on the same pad as the man when he appeared... also caused problems. 

 

anyways, I am still trying to figure out how to invoke the debugger. 

 

I am using SDK and the command line I use is: intybasic --title "Space Taxi" --jlp taxi.bas taxi.asm

That calls the compiler, not the emulator/debugger.  It is also not using the SDK.

 

With the SDK you don't call "intybasic" directly, you use "intybuild" to compile and "intyrun" to run your program.

 

To engage the debugger, you use "intydbug" instead of "intyrun".


If you are using the IntyBASIC SDK, it comes with documentation on how to use these tools.

 

In short, the command lines are quite simple:


To create a new project, you use:

intynew myproject -t "My Project"

Where "myproject" is the name of the project, which will be used to run and debug the program, and "-t" is an option to give a nice title name for the title screen.
 

To compile and assemble you use:

intybuild myproject

That will run the compiler followed by the emulator and report errors in each, if any.


 

To run, you use:

intyrun myproject

That will run the emulator in a window with your program.

 

 

To run the emulator with the debugger on, you use:

intydbug myproject

That will run the debugger with the symbol tables and listing files and enables source level debugging.


 

To build, run, and debug in one single step, you use:

intytest myproject

That will run the compiler, assembler, and the debugger.  It is a one-step command that runs intybuild and intydbug together.

 

 

These tools will automatically take care of all the proper command line arguments for the compiler, assembler, and emulator.  Seriously.  This includes running the IntyMap tool that maps the symbol table of the compiler with the assembler's, to enable source level debugging.

 

If that is not how you are doing it, then you are not using the IntyBASIC SDK.  That's fine, I just need to know in order to help you adequately.

 

    dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

42 minutes ago, Kiwi said:

From Zendocon you would need to add --debugger to the command line:

example: intybasic --title "Space Taxi" --debugger --jlp taxi.bas taxi.asm
 

If he is using the SDK he does not need to.

 

He said he was using the SDK, and if he is, all this command line stuff is just going to cause unnecessary confusion and extra work.

 

If he is not using the SDK, then sure, but he said he was.  The SDK abstracts all that stuff and bypassing the tools will just add more unnecessary work.

 

Besides, "intybasic" is the compiler.  It won't run the debugger.  That's "jzIntv" with the "-d" option.

 

    dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

2 minutes ago, Kiwi said:

You're correct.  Been awhile I programmed in Intybasic. 

No worries.  Also, that's a shame -- I really was looking forward to those games you were making.  Whatever happened to that Fire Fighting game?

 

  -dZ.

Edited by DZ-Jay
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...