Crash Prevention For The Pet
This article is for beginners in machine code programming and for those who use machine code subroutines from various sources. It describes several reasons for crashes and how to avoid doing things that make it crash. It is geared mostly to the owners of the upgrade-ROM Pets (Basic 3.0), but some ideas should be useful to all Pet owners.
I define a "crash" as a situation where all control over the Pet is lost. It is an error condition of such severity that the cursor disappears, the keyboard does not work and you have to pull the plug. I also include in the definition of a crash a symptom of Pet behaving "silly", when, for instance, simple commands, like LIST or RUN lead to SYNTAX ERROR condition or a display of monitor registers.
I have heard people imply that these crashes are caused by a defect in the Pet. It is my experience that the overwhelming majority of such crashes are due to a defect in programming.
Let me illustrate some crashes by working in BASIC. These simple illustrations will show what can go wrong and why.
(1) Type WAIT 0,1. Since location 0 always contains 76 the Pet is made to wait forever for a 1. The stop key doesn't work while the Pet is waiting. You can now turn the Pet off and on or use the Butterfield procedure to regain control. (I strongly recommend that you build or buy an uncrashing device - Compute #1, p.89).
(2) Type in or load a very short program, two or three lines is enough. Now POKE41,7, and type RUN. You'll get SYNTAX ERROR. Type LIST and you'll get garbage. POKE 41,4 and all will be well again.
Such errors, as silly as they look, are very easy to make, even in Basic. If your variables are undefined, if you failed to add a constant to some address, etc. you will crash.
(3) Type POKE 81,15. Any value different from 76 will do. Now type PRINT PEEK(81) or PRINT FRE(0). The register display in this case tells you where the break occurred and that the Pet doesn't know where to go. Locations 81-83 contain a jump instruction to evaluate functions. Poking wrong values into 81-83 destroys Pet's ability to handle functions of which PEEK and FRE are just two examples. The Pet is alive at this moment and so long as you use no functions everything will work quite well. If you do use functions you will not recover from this sort of a crash even by the Butterfield procedure which preserves memory. Either power off or type POKE 81, 76 to get things back to normal.
(4) Type FOR J = 112 TO 118.POKE J,42 : NEXT.
The Pet is gone. Reset by the Butterfield procedure. The Pet will work in the monitor mode but not in BASIC mode. You can save the program that caused such a crash using the monitor. But if you exit the monitor by "X" and give a BASIC instruction, like LIST, the Pet will crash again. The only solution is to pull the plug. The reason is that locations 112-118 are one of many vital links between the monitor and BASIC. Destroying the contents of 112-118 destroyed Pet's ability to understand BASIC altogether. It is possible to regain BASIC using a method written by Robert Lando and shown to me by Mr. Wachtel. This method consists of copying the entire contents of the ROM CHRGET routine to locations 112-135 immediately after changing the SP value in the Butterfield procedure (hex: from $E0F9-$E110 to $70-$87).
I am grateful to Jim Butterfield for showing me those locations that are crucial for supporting BASIC. If the contents of these location are disturbed in any way, only restarting the Pet will allow you to regain control. They are, in decimal, USR vector (0-2), various indicators (13-15), string descriptors (19-21), start of BASIC program (40-41), top of the PET (52-53), garbage yardstick (80), and jump vector for functions (81-83). Further, interrupt system at 144-145, CHRGET routine at 112-135 and location 1024 which must be zero for BASIC to run from its normal position. If the CMD command is on all output goes elsewhere thus you can't communicate with the Pet. This list shows the most important locations. There are many others that if disturbed will cause unrecoverable crashes. Note again, that the Butterfield procedure will let you see what went wrong and permit you to save the offending program. But to be able to use BASIC commands you may have to reset the Pet completely.
As you can clearly see, we caused a lot of trouble without ever leaving BASIC. When you work with machine code, the most frequent reasons for crashing will be of the WAIT variety, jumping or branching to wrong locations and infinite loops. You will recover by the Butterfield procedure and prevent further crashes by fixing the code.
But how can you prevent the hard crashes described above? I have run into a lot of such trouble while trying to adapt machine code subroutines written for an old Pet to my "new" Pet, often without knowing for which Pet the code was written. The most notorious offenders were those routines that used the old Pet's input buffer (locations 10-89) for storage of variables and addresses. You can see that some of the most important locations in the new Pet are where the old Pet's input buffer is.
Many of the old Pet routines can be changed to run, without crashing, on the new Pet, if you're careful. Many of them do not use any BASIC ROM routines, thus we do not have to bother with that translation. Most of them use zero page addressing and use locations 10-89. It's a good idea to learn just enough about the machine code instructions of the Pet to be able to spot the addresses. You can then find locations in the new Pet that are safe and change the program accordingly. Some locations I think are safe are 1-2 if main program has no USR call, 15-16, 84-89, 60-63 if you're not using DATA lines in the main program, 177-195 if tape is not used. And there are others. When a large block of contiguous locations is needed and 177-195 cannot be used, you will have to redo some of the coding in the following way. Determine the zero-page locations you need, and how many. Attach a bit of code at the beginning of a machine code routine to move the contents of the locations you're interested in into the first cassette buffer. Just prior to exit from the subroutine, move the contents back from the cassette buffer to page zero. When control returns to BASIC nothing has been disturbed and the Pet cannot crash. Please note that inserting more code may require some changes in absolute addresses in the routine itself. This is not difficult to do.
We have now taken care of those problems where machine code routines can destroy important Pet pointers, BASIC connection and so on. But there is another problem, that of strings from the BASIC program destroying machine code routines placed at the top of the Pet. Michael Riley gave me a simple solution: after poking the appropriate top of the Pet pointers (52-53) it is necessary to either say CLR or RUN-next line for all pointers to be set. So if your machine code routine does not perform this operation, you can do it in direct mode or within the BASIC program. Just make sure you do not initialize any variables needed by the program before the CLR or RUN line.
I find it helpful to go over a routine looking for what might cause the Pet to crash and how to prevent it. Some routines work only with a main program they were designed for. They may not work for your calling program because of different BASIC commands you may use (see point 3 above). Adjust them, so they are as general as possible and you'll never have to worry about crashing, no matter what the calling program contains. There are many very useful routines in the press that are worth the trouble of conversion. The side benefit of making changes in well written programs you see in the magazines is that you can learn a lot from them. I did.
1. Jim Butterfield, Compute and personal communication
2. Michael Riley, personal communication
3. Nick Hampshire, The Pet Revealed, Computabits, England
4. Anselm Wachtel, Compute#2 and personal communication.