Appropriate handling of run-time errors is especially important in embedded systems. Here are some suggestions presented in a cookbook fashion. For a more detailed explanation see OPERATION OF CATCH AND THROW, page 146.
MESSAGES TO SERIAL PORT 1
Use this recommendation if serial Port 1 is used only during compiling, not by the application. If you structure the end of your program as follows you can .
q escape to Forth by connecting a terminal to serial Port 1 and pressing any key. This allows final debugging and later system maintenance and repair even though the program is by then fixed in PROM.
q see run-time error messages on a terminal attached to serial Port 1. For example these might include ADDR ERROR if the program mistakenly reads an odd numbered address or FULL STACK if you've accidentally left something on the stack each time round the main loop.
have the program
restart from the beginning after an error in the hope that this will at
least enable partial operation until the fault can be cleared.
You can redirect the messages elsewhere by redirecting the EMIT contained within the word ERROR . These are some possibilities that can be substituted for the plain ERROR in the above recommendation-the redirection words shown are in the places indicated:
If you want no messages on error just put SP0 @ SP! in place of ERROR in the above example. This will clear the stack and still cause the application to restart.
NO RESTART ON ERROR
In some circumstances it can be dangerous to operate an embedded computer with a run-time fault in the application software. In these cases it may be more prudent to stop operation on error.
To arrange this, eliminate the word WORK above and rename MAIN to WORK . Without the CATCH in your software the system will go to the CATCH inside the Forth loop QUIT , which is always set at power-up, even in a stand-alone system. In other words on a run-time error execution of your program will cease and processing will continue with interactive Forth on serial Port 1.
If you see your prototype halt you can attach a terminal and with interactive Forth discover the source of the bug.
SPECIFIC ACTION ON ERROR
The word ERROR in the above examples displays a message-see ERROR CODES, page 148. However you may want to take some special action after a run-time error. You can change ERROR to anything you want, remembering that the error number is provided on the stack and that you should clear the stack afterwards.
The following substitution for WORK in the above example would just count the number of errors by incrementing the variable ERROR-COUNT :
VARIABLE ERROR-COUNT \ Counter of run-time errors
: WORK ( - ) \ Word executed at power-up
ERROR-COUNT OFF \ clear counter
BEGIN ['] MAIN CATCH \ stick here if ok
1 ERROR-COUNT +! \ count error
SP0 @ SP! \ clear stack
OPERATION OF CATCH AND THROW
To implement more complex error handling you need to understand the CATCH and THROW mechanism. It is a way of handling exceptions without having to propagate flags up through multiple levels of nesting. It is similar to the 'non-local return' of other languages such as C's setjmp() and longjmp(), or LISP's CATCH and THROW. In ANS Forth THROW is used deep inside the code at a low level as a 'multi-level exit', with CATCH marking the location to which a THROW may return.
CATCH is similar to EXECUTE in that it takes the execution token of a Forth word and performs its action (execution token, or xt, is the new name for a code field address, or cfa, in Forth). The word being executed may have one or more THROWs buried in its sub-structure and will terminate either if it completes in the normal way, or if execution reaches one of the THROWs. In the first case a zero parameter is passed back from the word (on the stack as usual). In the second case the exception number associated with the THROW is given as you suddenly arrive after the CATCH several layers up.
An exception causing such action may be ABORT or ABORT" or an error condition like stack overflow caused by a program bug. On the TDS2020F it can also be a supervisory error generated by the H8/532 microprocessor from execution of an invalid instruction, address alignment or watchdog error, perhaps because an electrical spike has caused the microprocessor to jump out of its program.
By default a THROW will send you back to the CATCH already present within the Forth interactive QUIT loop, which is fine during debugging but often useless in a dedicated target system. You should use your own CATCH to determine operation in the case of exceptions. In the simplest case produce an outer 'error loop' surrounding the indefinite loop in which a dedicated system program should normally stay.
To take the specific example of the recommendation shown at the start of this section, INITIALISE would write to variables and set up hardware like data direction registers. TRY is one pass through the main loop, being defined in terms of simpler primitives to perform the required task. SET WORK is typed interactively after compilation to tell the TDS2020F that WORK is to be executed at power-up.
The execution token of MAIN , obtained by the phrase ['] MAIN , is passed to CATCH whose job is therefore to execute MAIN . This is a never-ending loop where the application should stay if all is well; there is no exit inside MAIN apart from any embedded THROWs.
WORK is the outer indefinite 'error loop' which makes the program restart in case of error. Should a THROW be reached the nesting of words will be abandoned and execution will resume after the word CATCH , leaving the error number on the stack. The word ERROR that then executes is not ANS Forth but is included in the TDS2020F as a default word for error processing. It takes the error number and displays a message describing the fault, also resetting the parameter stack.
For additional principles covering a multitasking system see ERRORS WHEN MULTITASKING, page 199,
The messages ADDR ERROR, INV INSTN and WATCHDOG indicate that the processor on the TDS2020F lost control via a trap. If this happens the hardware facilities are used to safely re-enter the Forth system. The message indicates what has happened.
Although this is a warm restart there can be no guarantee that the memory data remained intact while the processor was running out of control. However applications can be designed to tolerate most crashes from spikes etc.
Interrupts are disabled after an Address Error trap, but not after the other two. This trap re-enters the code via an NMI that disables interrupts.
The action to be taken on a crash can be altered either as described above or to something you define by changing the action of the appropriate exception interrupt. For more details see:
Here is an example that displays a message instead of the appropriate THROW on a watchdog timeout:
CODE RESET-DOG ( - ) \ Housekeeping
: MY-DOG ( - ) \ User version of watchdog trap
The default action on a processor trap is a warm restart via the CATCH and THROW mechanism. For the coldest possible restart install the utility #DOGCOLD.TDS as part of your application, or use this file as an example of how to trap to your own Forth code. However when using multitasking, do not use #DOGCOLD.TDS, but see ERRORS WHEN MULTITASKING, page 199.
Most error messages are for the system's use at compile-time. If the message is followed by the usual 'ok', for instance NOT UNIQUE, it is a warning only. In the absence of 'ok' this was a true error and should be corrected before compilation is attempted again.
If there is a syntax error, compilation stops. The position at which the problem was identified is shown, although the actual error may be a few lines earlier.
In this section is a table of error numbers used as parameters of THROW that are allocated on TDS2020F. For instance:
HEX -000D THROW
will produce the error message UNDEFINED if the previously executed CATCH is followed by the word ERROR provided in the Forth ROM.
The floating point errors are only seen when using the optional software TDS-FLOAT-ANS. All error codes are given here in hex: