+atari2600land Posted July 22 Share Posted July 22 I'm making a game and sometimes the emulator just shuts off. What am I doing wrong? What are the possible reasons this would happen? Quote Link to comment Share on other sites More sharing options...
carlsson Posted July 22 Share Posted July 22 Most likely your program continues into a "bad" memory area so it goes "into the woods" or how it says. Check your CFG file, add ASM ORG statements where necessary. Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 23 Author Share Posted July 23 It's not that big of a file. [mapping] $0000 - $14FF = $5000 Quote Link to comment Share on other sites More sharing options...
Arnauld Posted July 23 Share Posted July 23 As long as your project is in development, I'd recommend to run in debug mode with history enabled even if you just want to play the game without using any other specific debugging feature. This is useful for post-mortem analysis. Quote Link to comment Share on other sites More sharing options...
carlsson Posted July 23 Share Posted July 23 How is your usage of GOSUB and properly returning from those, so you don't exhaust the stack pointer? Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 23 Share Posted July 23 11 hours ago, atari2600land said: I'm making a game and sometimes the emulator just shuts off. What am I doing wrong? What are the possible reasons this would happen? Check your GOTOs, make sure they are not going off into the weeds. 10 hours ago, Arnauld said: As long as your project is in development, I'd recommend to run in debug mode with history enabled even if you just want to play the game without using any other specific debugging feature. This is useful for post-mortem analysis. I think the lack of exposure to the debugger and its features, is something that haunts many IntyBASIC programmers when trying to troubleshoot their programs. The focus on Assembly Language and Hexadecimal values can be intimidating, for sure. Even with the “source-level debugging” integration with IntyBASIC, there is no escaping the complexity for those not used to working with the assembler — e.g., the symbol names are mangled, the register values are in Hexadecimal, the labels and constants do not translate directly, etc. I’ve toyed with the idea of preparing a series of short videos to illustrate how to use the most useful and basic features of the debugger. I may do that if there is interest. dZ. Quote Link to comment Share on other sites More sharing options...
Zendocon Posted July 23 Share Posted July 23 The error message is "CPU off in the weeds." Another common one is "H[a]LT instruction reached." Quote Link to comment Share on other sites More sharing options...
Zendocon Posted July 23 Share Posted July 23 I set up my Portable Intellivision Development Environment to automate the following command-line parameters at assemble-time: -j [romfile].smap -s [romfile].sym -l [romfile].lst -o [romfile].bin [main].asm and to automate the following command-line parameters at run-time: --src-map=[romfile].smap --sym-file=[romfile].sym --script=dbscript.txt --debugger This creates additional files that will allow you to see lines of your IntyBASIC source code in the debugger. jzIntv also likes your terminal window to be at least 160 characters wide, and you might want to automate that as well with a script file (which I named dbscript.txt) containing the following lines: > 160 r The first line tells jzIntv that your terminal window is 160 characters wide. The second line runs jzIntv automatically. Normally, when you open jzIntv with the --debugger switch, it waits for you to start running emulation with the command "r". Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 23 Share Posted July 23 11 minutes ago, Zendocon said: I set up my Portable Intellivision Development Environment to automate the following command-line parameters at assemble-time: -j [romfile].smap -s [romfile].sym -l [romfile].lst -o [romfile].bin [main].asm and to automate the following command-line parameters at run-time: --src-map=[romfile].smap --sym-file=[romfile].sym --script=dbscript.txt --debugger This creates additional files that will allow you to see lines of your IntyBASIC source code in the debugger. jzIntv also likes your terminal window to be at least 160 characters wide, and you might want to automate that as well with a script file (which I named dbscript.txt) containing the following lines: > 160 r The first line tells jzIntv that your terminal window is 160 characters wide. The second line runs jzIntv automatically. Normally, when you open jzIntv with the --debugger switch, it waits for you to start running emulation with the command "r". If you use the IntyBASIC SDK, that is handled for you automatically. The command "intybuild" will set up set up the symbol and map files, and the command "intydbug" will run the debugger. You break to the debugger while running the program using F4, or you can add "-s" in the command line for "intydbug" to start the program in the debugger console. -dZ. Quote Link to comment Share on other sites More sharing options...
Zendocon Posted July 23 Share Posted July 23 (edited) As for the debugger, the F4 key pauses emulation, and the debugger takes over. For a list of commands, type "?" Commands I use often are: w [RAM address (range size)]: Watch for a change to a particular memory address or range of addresses. The terminal window will display a message when a change occurs, along with the ROM address which triggered the change. Using this command a second time on the same address turns off watching. b [ROM address]: Break to the debugger when code execution reaches the specified address. n [ROM address]: A negation of the previous command. Stop breaking to the debugger when code execution reaches the specified address. s [number of commands]: Step through the specified number of CPU commands. "s" by itself steps only through 1 command. t [number of commands]: Same as above, but skips over function calls. r [number of commands]: Run emulation only until the specified number of CPU commands are executed. "r" by itself runs indefinitely until you press the Break key again (F4). m [RAM address (range size)]: Memory dump. Display contents of the specified RAM address. By default, the range size is 64, so if you don't specify a size, you will get the specified address and the next 63 after it. They are displayed in groups of 8 per line, so if you start at $15d, you'll see $158-15f in the first line, with a '*' after $15d, which you had specified. These are the RAM address ranges: $100-1ef: 8-bit RAM (original games which use Executive ROM start at $15d). $31d-35c: 16-bit RAM (original games which use Executive ROM only have $324, $32c, $334, $33c, $344, $34c, $354, and $35c available for general use). $8000?-9???: 16-bit JLP RAM. If you enable JLP, your program will use 16-bit RAM in this range. $4000-47ff: 8-bit ECS RAM. Chances are, your program doesn't utilize this, even if you use ECS. $360-fff: 16-bit Tutorvision RAM. Chances are, your program doesn't utilize this. By default, these address are frozen to a value of -1, so if I want to autodetect whether or not extra Tutorvision RAM is available, I try to set one of the addresses to 0 and check for a 0 value at that same address. Edited July 23 by Zendocon Additional information about ECS and Tutorvision RAM address ranges Quote Link to comment Share on other sites More sharing options...
Zendocon Posted July 23 Share Posted July 23 1 minute ago, DZ-Jay said: If you use the IntyBASIC SDK, that is handled for you automatically. The command "intybuild" will set up set up the symbol and map files, and the command "intydbug" will run the debugger. You break to the debugger while running the program using F4, or you can add "-s" in the command line for "intydbug" to start the program in the debugger console. -dZ. Ah yes, the IntyBASIC SDK. That's a good one too. Since my Portable Intellivision Development Environment and its Graphical Suite, PIDEGS, is a sort of competitor, I've never used that myself. Both are good tools for serious developers. My advertised advantage is that my PIDE runs on Android, and I prefer carrying around a tablet for development on-the-go instead of a laptop. Quote Link to comment Share on other sites More sharing options...
carlsson Posted July 23 Share Posted July 23 I wonder if Chris interleaves code with data, subroutines to GOSUB or even GOTO after data blocks. From previous sneak peeks of his code, it seems to happen. If so, I would strongly recommend try to order everything so you have code in one sequence of routines, then your data areas. Not that it should matter much, but it reduces possible causes of errors. Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 23 Author Share Posted July 23 Here's my code. Could anyone suss through and try to figure out what's going on? pactwo6.bas Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 24 Share Posted July 24 It seems that you are smashing the stack by "printing" to the wrong address. I caught the crash in procedure "new_column1" -- when it ended, it tried to return but got a bogus address from the top of the stack. It seems that when the following code executed: new_column1: procedure print at ghost1pos," " print at ghost2pos," " print at dot1pos, " " ' ... The value of "ghost2pos" was pointing beyond the BACKTAB and wrote into the memory reserved for the stack itself. You may want to check the values of your variables. -dZ. 2 Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 24 Share Posted July 24 @atari2600land, let me know if you need help troubleshooting the variable values. dZ. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 24 Share Posted July 24 So, a quick inspection of the variables and I see that it is precisely what I suspected: The variable"ghost2pos" is decremented below zero, turning it into -1 ($FFFF), which is stored in the 8-bit variable as 255 ($FF). This value is then used in procedure "new_column1" as the BACKTAB offset in which to print, which happens to be outside the range and right smack at the start of the stack. At that point, your program is hopelessly broken, for the next "return" statement will pull a corrupted return address from the stack. The culprit is in the following code in the "main_loop": offset_x=offset_x-1 if offset_x=0 then offset_x=7 row1timer=row1timer-1 row2timer=row2timer-1 row3timer=row3timer-1 ghost1pos=ghost1pos-1 ghost2pos=ghost2pos-1 ' <-- some hanky panky afoot here! ghost3pos=ghost3pos-1 ghost4pos=ghost4pos-1 ghost5pos=ghost5pos-1 ghost6pos=ghost6pos-1 dot1pos=dot1pos-1 dot2pos=dot2pos-1 dot3pos=dot3pos-1 end if A quick looksie into your code, and I see that the "ghost2pos" is only assigned a new value in procedure "new_column1" under some specific conditions: ghostpattern2=(rand/64) ghost2color=3 if ghostpattern2=0 and ghostpattern1>0 then ghost2pos=19 : ghost2color=0 if ghostpattern2=1 then ghost2pos=99 if ghostpattern2=2 then ghost2pos=119 if ghostpattern2=3 then ghost2pos=139 Intuitively, I see a flaw right there: If both "ghostpattern2" and "ghostpattern1" happen to be zero at the same time -- which is a distinct possibility -- then the first condition will return false, and "ghost2pos" will not be updated. Moreover, if at that point "ghost2pos" happens to be zero, it will be decremented to a negative value, leading to some mischief. This explains the observed behaviour. It also explains why it appears to be random: the conditions themselves are driven by the values of "rand." Honestly, the above analysis is based on my superficial view of your code's behaviour -- I have not analyzed your program to understand what those variables do, nor how it all works in practice. I hope the description of the problem at least gives you an idea for how to solve it. At minimum, I would suggest guarding against negative values when decrementing a variable. Also, you should ensure that "ghost2pos" always gets a valid value by guaranteeing that every condition that leads to its update is accounted for. Let me know if you need further help or if any of the above does not make sense. -dZ. Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 24 Author Share Posted July 24 I think I understand what is going on. Honestly, I don't know what I was thinking when I wrote that code. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 24 Share Posted July 24 3 hours ago, atari2600land said: I think I understand what is going on. Honestly, I don't know what I was thinking when I wrote that code. No worries. Let me know if you need any more help. -dZ. Quote Link to comment Share on other sites More sharing options...
carlsson Posted July 24 Share Posted July 24 Good catch! Though, shouldn't the PRINT AT function take the value modulo the size of BACKTAB, or is it a design choice that you can write data to any subsequent address using PRINT? @nanochess might know if it is a design feature or not. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 24 Share Posted July 24 11 minutes ago, carlsson said: Good catch! Though, shouldn't the PRINT AT function take the value modulo the size of BACKTAB, or is it a design choice that you can write data to any subsequent address using PRINT? @nanochess might know if it is a design feature or not. I do not think it is a feature. For one thing, it adds $200 automatically, so it seems designed to work for values in the System RAM area, which includes the BACKTAB and ... the CPU stack. Because IntyBASIC abstracts away the stack and all its internal memory, it seems weird to me that someone would provide a feature that would allow for such a clumsy accident to occur on purpose. More likely, it is just an optimization to avoid the cost of checking for bounds. In fact, the manual says so explicitly: Quote PRINT [AT [expr]][COLOR [expr]][,]"string"[,"string"] ... Notice that the cursor position is not limited so you can write outside of the screen and this will make your program crash! So ... I guess like with many other common problems, it could be solved by a simple rule: RTFM. 😄 -dZ; Quote Link to comment Share on other sites More sharing options...
nanochess Posted July 24 Share Posted July 24 2 hours ago, carlsson said: Good catch! Though, shouldn't the PRINT AT function take the value modulo the size of BACKTAB, or is it a design choice that you can write data to any subsequent address using PRINT? @nanochess might know if it is a design feature or not. There are no boundary checkings done in PRINT AT. IntyBASIC trusts the programmer basically this is to save an expensive comparison that would use also precious words in ROM. 2 Quote Link to comment Share on other sites More sharing options...
+atari2600land Posted July 27 Author Share Posted July 27 edit : nvm, I asked this before. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 27 Share Posted July 27 12 hours ago, atari2600land said: edit : nvm, I asked this before. Then we probably answered it already. 😁 dZ. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.