|70h||UT$ENTR||establish a control region|
|Input||X register - Address of routine to be entered.
D register - Parameter to be passed to the routine.
|Output||B register - Code number (generally an
C-flag - Clear if B register is zero, else set.
Allows a routine at X to be called in such a way that it may be exited from any of the routines nested within it. The parameter in D is passed to the routine at X.
The most important use for UT$ENTR (together with UT$LEAV) is for error handling: they can mimic the ON ERROR and RAISE facilities in OPL.
UT$ENTR establishes a new control region, meaning that an entered routine can be terminated early by a call to UT$LEAV. That is, any of the routines (to any depth) used within the entered routine can call UT$LEAV which will cause 'immediate' return to the instruction after the call to UT$ENTR. The B register will then contain the value passed to UT$LEAV.
So, in the same way that an 'RTS' instruction causes control to return from a normal subroutine to the calling routine, the call to UT$LEAV causes control to return from within UT$ENTR to the routine that called UT$ENTR. In both cases the stack is adjusted appropriately for return.
Calls to UT$ENTR can be nested to any depth, with a control region for each call. UT$LEAV dis-establishes only the most recently established region, returning to the instruction after the last UT$ENTR call.
Note that a new control region is disestablished either by normal return from UT$ENTR, or by a call to UT$LEAV within the new region (unless called within a nested control region).
The entered routine must return an appropriate code number (generally 0 to indicate non-error) in the B register.
The locations UTW_S1 through UTW_S5 may be used for passing parameters to the entered routine. UTW_S0 is corrupted prior to entry, however.
See also UT$LEAV.
This routine is best illustrated by the examples.
To enter ROUTINE_1, which calls other routines, any of which may call
UT$LEAV on error. Pass the value 1 to ROUTINE_1.
ENTER_ROUTINE_1: LDX #ROUTINE_1 ; UT$ENTR calls the routine at address X LDD #1 ; Set parameter for ROUTINE_1 OS UT$ENTR ; Establish new control region ; Region now dis-established BCS ERROR ; On error, B set to error code, C-flag set RTS ROUTINE_1: STD ROUTINE_1_PARAMETER BCC NO_ERROR_1 LDAB #ERROR_CODE_1 OS UT$LEAV ; return B to ENTER_ROUTINE_1, setting C-flag NO_ERROR_1: JSR ROUTINE_2 ; if either of these 2 routines call JSR ROUTINE_3 ; UT$LEAV, control doesn't return to ; this routine CLRB ; B must be cleared to indicate non-error RTS ROUTINE_2: . . BCC NO_ERROR_2 LDAB #ERROR_CODE_2 OS UT$LEAV ; return B to ENTER_ROUTINE_1, setting C-flag NO_ERROR_2: RTS ; no need to clear B here as not called ; directly by UT$ENTRThe following example establishes nested control regions, clarifying where control continues after calling UT$LEAV. (In this example, 0 in the B register is used to signify non-error return from UT$ENTR).
MAIN: . . LDX #REGION_1 LDD P1 ; set D to parameter for REGION_1 Establish a new control region OS UT$ENTR ; Establish a new control region ; REGION_1 now dis-established BCS ERROR ; On error, B set to error code, C-flag set RTS REGION_1: STD PARAMETER_1 . . BCC NO_ERROR_1 LDAB #CODE1 OS UT$LEAV ; return B register to MAIN, setting C-flag NO_ERROR_1: JSR RTN1 ; if RTN1 calls UT$LEAV, . ; control returns to MAIN . LDX #REGION_2 LDD P2 ; set D to parameter for REGION_2 OS UT$ENTR ; Establish a new control region ; REGION_2 now dis-established BCS ERROR ; On error, B set to error code, C-flag set CLRB ; B must be cleared for normal return RTS REGION_2: STD PARAMETER_2 . . BCC NO_ERROR_2 LDAB #CODE2 OS UT$LEAV ; return to REGION_1, setting C-flag NO_ERROR_2: JSR RTN2 ; if RTN2 calls UT$LEAV, ; control returns to REGION_1 . . LDX #REGION_3 LDD P3 ; set D to parameter for REGION_3 OS UT$ENTR ; Establish a new control region ; REGION_3 now dis-established BCS ERROR ; On error, B set to error code, C-flag set CLRB ; B must be cleared for normal return RTS
|Errors||- none -|