DEFINITION MODULE InnerKernel; (* off) *) (*>*) (****************************************************************) (* *) (* This is the nonportable part of the PMOS kernel. *) (* It contains procedures whose implementation depends *) (* not only on the processor, but also on compiler *) (* conventions (which registers are saved, etc.). *) (* *) (* Programmer: P. Moylan *) (* Last edited: 21 March 1995 *) (* Status: Working *) (* *) (****************************************************************) FROM Types IMPORT (* type *) FarPointer; TYPE (**) TaskSelector = FarPointer; FloatSaveSelector = CARDINAL; (************************************************************************) (* (bx,cx,dx,si,di,ds,es,st1,st2)) *) (*>*) PROCEDURE EnterKernel (): CARDINAL; (* Saves the processor flags word, including the current "interrupt *) (* enable" status, and returns with interrupts disabled. *) (* NOTE: this procedure and the following one should be used as a *) (* matched pair. *) (* (ax), reg_saved => (ax,bx,cx,dx,si,di,ds,es,st1,st2)) *) (*>*) PROCEDURE LeaveKernel (PSW: CARDINAL); (* Restores the processor flags word, including the "interrupt *) (* enable" status. NOTE: this procedure and the one above should *) (* be used as a matched pair. *) (* (bx,es), reg_saved => (dx,si,di,ds,st1,st2)) *) (*%T _fptr *) (*# call(reg_param => (ax,bx,cx,dx)) *) (*%E*) (*%F _fptr *) (*# call(reg_param => (ax,cx,dx)) *) (*%E*) (*>*) PROCEDURE TaskInit (StackBase: ADDRESS; StackSize: CARDINAL; EnableInterrupts: BOOLEAN; TaskExit, StartAddress: PROC): TaskSelector; (* Initialises the stack for a new task. Parameter StackBase *) (* points to a block of memory which can be used to hold the stack *) (* (note that this is a pointer to the start of the memory block, *) (* not to the bottom of the stack); and StackSize is the size of *) (* this block. The next parameter specifies whether processor *) (* interrupts should be enabled when the task is started. *) (* StartAddress and TaskExit are the start address of the task code *) (* and the start address of the code to execute when the task *) (* terminates. The value returned is a selector for the new task. *) (* (ax,cx,dx,si,di,ds,st1,st2)) *) (*>*) PROCEDURE InitMainTask (): TaskSelector; (* Like TaskInit, but for the special case of the original task *) (* which is running at program startup. The function of this *) (* procedure is simply to ensure that the main stack layout is *) (* consistent with what we do for all other tasks. *) (* (ax,bx,cx,dx,si,di,ds,es,st1,st2)) *) (*%T _fptr *) (*%T _fdata*) (*# call(reg_param => (si, ds, ax, bx)) *) (*%E*) (*%F _fdata*) (*# call(reg_param => (si, cx, ax, bx)) *) (*%E*) (*%E*) (*%F _fptr *) (*# call(reg_param => (si, ax, bx)) *) (*%E*) (*>*) PROCEDURE Transfer (VAR (*OUT*) source: TaskSelector; destination: TaskSelector); (* Performs a task switch to the destination task, at the same time *) (* saving a selector for the outgoing task in variable "source". *) (* This allows a subsequent call to Transfer to resume the *) (* original task. By the time this procedure has returned to the *) (* caller, then, we are again executing the calling task. *) (* Special case: if this procedure is called by an interrupt task, *) (* the call is interpreted as a requiring a task switch from the *) (* interrupted task - i.e. the source parameter must specify the *) (* interrupted task - to the destination task. In this case the *) (* actual switch to the destination task does not happen until the *) (* interrupt task makes its next call to IOTransfer. The reason *) (* for this interpretation is that task switching to and from *) (* interrupt tasks is managed internally by this module; the *) (* occurrence of an interrupt is not something that can be *) (* controlled by the caller. *) PROCEDURE IOTransfer; (* May be called only from an interrupt task. Performs a task *) (* switch from the current interrupt task to the task which it *) (* interrupted. Unlike Transfer, no parameters are required *) (* because (a) the selector for the destination task is already *) (* known to this module, having been saved at the time of the *) (* interrupt; and (b) selectors for interrupt tasks are maintained *) (* directly by this module rather than by the caller. *) (* (ax, bx, cx)) *) (*>*) PROCEDURE StartInterruptTask (TS: TaskSelector; InterruptNumber: CARDINAL); (* Starts an interrupt task by running its initialisation section *) (* - i.e. everything up to the first IOTransfer - and arranging *) (* that from then on it will be activated by the given interrupt. *) (* (ax, ds)) *) (*%E*) (*%F _fdata*) (*# call(reg_param => (ax, bx)) *) (*%E*) (*>*) PROCEDURE DisconnectFromInterrupt (TS: TaskSelector); (* Restores the interrupt vector to which TS was connected to its *) (* state before TS was established as an interrupt task. (N.B. The *) (* result could be chaotic if there was no previous call to *) (* StartInterruptTask.) *) (* (ax,bx), reg_return => (bx)) *) (*>*) PROCEDURE MakeFloatSaveSelector (selector: TaskSelector): FloatSaveSelector; (* Creates the special form of selector which must subsequently be *) (* used in calls to save and restore the floating point state. *) (* The parameter supplied must be the value of the task selector *) (* as created by TaskInit. *) PROCEDURE NPXsave (selector: FloatSaveSelector); (* Saves the state of the Numeric Processor Extension coprocessor. *) PROCEDURE NPXrestore (selector: FloatSaveSelector); (* The operation complementary to NewNPXsave. Restores the *) (* previously saved state of the floating point coprocessor. *) (**) PROCEDURE PrepareForShutdown; (* This procedure is needed just before executing the "exit from *) (* program" operation, and is provided to get around a problem *) (* with some memory models in TopSpeed version 3. (With other *) (* compilers, this can afford to be a dummy procedure.) *) (* A (deliberate) side-effect of calling this procedure is that *) (* the stack is corrupted, so do NOT call it except as the final *) (* step of termination processing. *) END InnerKernel.