-*-TEXT-*- Notes on the 68000 Scheme Interpreter Interrupt/Error System. * Microcode Errors The interpreter requires that the system implementor supply a table of error handlers, one handler for each possible microcode error. This table must be a Scheme vector, and it must be located in a particular slot (FOBJECT_SYSTEM_ERROR_VECTOR) of the fixed objects vector. Each entry of the error vector must contain a procedure. When an error occurs, the state of the interpreter is saved in a control point, the error code is used as an index to fetch the appropriate procedure from the error vector. The procedure is then called with three arguments: (1) The error code for the error (a fixnum). (2) The control point containing the saved state of the process. (3) The interrupt-enables word at the time of the error. All interrupt enables are disabled just before the procedure is called. Thus a typical error-handler would be: (define (error-handler error-code control-point int-enables) (set!-interrupt-enables int-enables) ...) ************** From the microcode implementor's point of view, errors can be generated simply by doing: MOVE.L #,ERRCODE(REGS) JMP MICROCODE_ERROR The error system is smart enough to unwind the hardware stack, so it is not crucial to make sure that the stack is clean before signalling an error. Current error codes and their meanings are described below. The names of the errors are assembly symbols. Numbers in parentheses are the current values of those symbols. ERROR_CODE_BAD_ERROR_CODE (0) This error will only occur if the error code given to MICROCODE_ERROR is invalid. This usually means that the error code is larger than the size of the installed error vector. The error code passed to the handler is the code which caused the error, rather than zero. ERROR_CODE_BAD_INTERRUPT_CODE (30) This is like BAD_ERROR_CODE, but for interrupts. ERROR_CODE_UNBOUND_VARIABLE (1) A bad variable lookup was attempted. The expression causing this can be either a variable reference, an ACCESS, or a SET! (ASSIGNMENT). ERROR_CODE_UNDEFINED_FUNCTION (2) An attempt was made to apply an object which was not a recognized function object. *** The next four errors should probably be flushed. *** They make it difficult to figure out what actually *** happened, since they don't really say where the *** problematic data object is located. ERROR_CODE_NON_LIST_POINTER (3) ERROR_CODE_NON_HUNK3_POINTER (4) ERROR_CODE_NON_VECTOR_POINTER (6) ERROR_CODE_BAD_LOCATIVE (11) ERROR_CODE_UNEXPECTED_POINTER (29) Something other than the expected type of object was encountered. ERROR_CODE_BAD_HUNK3_INDEX (5) ERROR_CODE_BAD_VECTOR_INDEX (7) The index given for a hunk3 or vector operation was either of the wrong type or was too large. ERROR_CODE_EXECUTE_FUNCTION (8) The interpreter attempted to execute some function, such as a closure or control point, as an expression. It is not clear that this is a reasonable thing to do. ERROR_CODE_BAD_FRAME (9) The environment frame encountered at INTERNAL_APPLY was not a valid type. This is not a user error -- it indicates that the interpreter is damaged, or that someone has broken the system data structures. ERROR_CODE_BROKEN_CVARIABLE (10) A compilable variable data structure had a bad manifest type. This is a system error. ERROR_CODE_UNDEFINED_USER_TYPE (12) ERROR_CODE_UNDEFINED_RETURN_TYPE (13) ERROR_CODE_UNDEFINED_PRIMITIVE_OPERATION (14) A bad dispatch code was found while the interpreter was running. This is a system error. ERROR_CODE_USED_CONTROL_POINT (15) An attempt was made to use a control point that had already been activated. ERROR_CODE_EXTERNAL_RETURN (16) The Pascal interface returned an error, probably because it was unable to handle one of the arguments passed in. This can also occur if the Pascal subroutine had an error. ERROR_CODE_EXECUTE_MANIFEST_VECTOR (17) One of the manifest types used to mark vectors was encountered during the expression dispatch. This is a system error. ERROR_CODE_WRONG_NUMBER_OF_ARGUMENTS (18) A function was called with the wrong number of arguments. If the function is a lexpr, it was called with too few arguments. ERROR_CODE_WRONG_TYPE_ARGUMENT_0 (24) ERROR_CODE_WRONG_TYPE_ARGUMENT_1 (25) ERROR_CODE_WRONG_TYPE_ARGUMENT_2 (26) Indicates that the given argument register contains an object which is the wrong type for the primitive being executed. ERROR_CODE_BAD_RANGE_ARGUMENT_1 (23) ERROR_CODE_BAD_RANGE_ARGUMENT_2 (22) Indicates that the given argument register contains an object of the right type, but which exceeds some set of bounds which is a property of the primitive being executed. An example of this would be a bad vector index. ERROR_CODE_DIVIDE_BY_ZERO_ARGUMENT_1 (27) This error is a variant on BAD_RANGE, which is included because it is so important. ERROR_CODE_EMPTY_COMBINATION (28) Indicates that an attempt was made to execute combination with no function or arguments. This is a system error. ERROR_CODE_FASL_FILE_TOO_BIG (32) A fasl file (binary image file) is too large to fit in the available free space. ERROR_CODE_FASL_FILE_BAD_DATA (33) A fasl file had pointers that exceeded the bounds of the file's image. ************** The following error codes are signalled when fatal errors occur. The action taken in this case is that ERRCODE is stuffed with the error code, and then the interpreter is stopped. Control is returned to the Pascal top level. TERMINATION_CODE_EXECUTE_HALT (19) The normal way the interpreter should stop. TERMINATION_CODE_EXECUTE_BROKEN_HEART (17) A broken heart object was encountered by the interpreter. This is an indication that the system data space is corrupted. TERMINATION_CODE_NON_POINTER_RELOCATION (20) A Garbage Collector logic error which should never happen. * Interrupts Interrupts are handled very much the same as errors. There is a table of interrupt handlers, each of which is a procedure of two arguments: (1) The interrupt code which caused the interrupt. (2) The interrupt enables word at the time of the interrupt. The interpreter guarantees that the logical AND of the two words is non-zero. Interrupts are disabled just before the interrupt handler is called, and will not be re-enabled unless done explicitly by the handler. Returning from the handler restores the interrupted process. Both the interrupt code and the interrupt enables word have the following structure. Each bit represents a single interrupt line; anytime that the AND of the two words is non-zero, the resulting masked set of interrupts is used directly as an index into the table of interrupt vectors. Thus the table must contain (-1+ (^ 2 N)) vectors if there are N valid interrupts. This organization allows the system designer to have complete control over the "priority structure" of the interrupt system. Currently N=3, and the bits are: 0 - Garbage Collector GC is done by forcing an interrupt, thus giving the user a hook into the Garbage Collection process. 1 - External Usually an interrupt character being typed. 2 - Single-step This is a hook to allow a program to be stopped every time an application cycle happens.