📄 rtexec.c
字号:
/* We located the task with the specified name. Activate it and
return to the caller. */
_AX = i;
ExecActivateFunction();
return;
}
}
}
unsigned TaskSwitchDisallowed,JustReturn;
unsigned InterruptedSS,InterruptedSP;
unsigned NewISRSS,NewISRSP;
unsigned GPISRSegTemp,GPISROffTemp;
static tcbstruc *CurrentTaskTCB;
int OldCurrentTask;
#if InUncontrolledCodeChecking
unsigned InUncontrolledCode,InterruptedCS;
#endif
unsigned InDOS;
extern unsigned BeepFrq,BeepDur; /* See module BEEP. */
/****************************************************************************
* Function: void far interrupt GPISR(__CPPARGS)
*
* Obtains control of the processor approximately every 505 microseconds, in
* response to the GP2021 correlator interrupt. It's extremely likely that
* any GPS designer who ports the GPS Builder-2 to an embedded processor will
* need to restructure correlator interrupt processing.
*
* This routine cannot declare any local variables. On a correlator interrupt,
* a sequence of loosely connected functions saves the context of the
* interrupted task. The PC hardware pushes the status register, CS, and IP on
* the current stack. The Borland C++ interrupt routine invocation then stores
* 16-bit registers (compiler version 3.1, and 4.0 in 16-bit mode) or 32-bit
* registers (version 4.0 in 32-bit mode) on the stack, loads BP with a stack
* frame pointer, and loads DS with the DGROUP segment's base address (but
* alas, only in large memory models). GPS Builder-2 application code saves
* the 32-bit register context if Version 3.1 of the compiler was used in
* 32-bit code gen mode.
*
* If a numeric coprocessor is used, its context should also be saved. But
* here we know that the ISR will not use floating point, so we can defer a
* floating point context save until we contemplate a task switch, thus
* saving a considerable amount of processor time.
*
* Some other considerations are as follows. There is a lot of system software
* in any given PC, some of which switches to local stacks. You aren't sure
* how much space has been allocated on these stacks, so in self-defense you
* are forced to switch to your own local stack for any serious interrupt
* processing. (As soon as the first person started using local stacks, it
* forced everyone else to follow suit.)
*
* Processing GP2021 interrupts is problematical. GPS signal processing has
* several characteristic time scales ranging from 505 microseconds to several
* hundreds of milliseconds. The 505-usec interrupt MUST be serviced, but on
* the other hand one of those interrupts may initiate a processing sequence
* that requires several milliseconds to complete. Generally when this type of
* situation occurs, you have to make the ISR reentrant. Tom Swan, in his book
* "Mastering Turbo Assembler", writes indelicately but accurately that
* "Attempting to write a completely reentrant ISR that switches to a local
* stack will certainly put hair on your chest". This may or may not be
* literally true, but it IS a difficult task. Chapter 10 of Swan's book is
* highly recommended as an introduction to PC interrupt processing. Quoting
* further, "You'll need fresh stack space and variables for each ISR
* invocation or, at the very least, an inProgress flag...to prevent a
* reentered ISR from corrupting a stack used by a previous call to the same
* routine." This is the approach taken for GP2021 correlator interrupt
* processing.
*
* After the initial partial context save at ISR invocation, a fresh local
* stack is assigned from a previously allocated array of stacks. The actual
* reentrant correlator service routine, SVTRACK, is written so that there is
* a maximum nesting depth of three. After the switch* to the fresh local
* stack has been accomplished, the ISR determines whether or not a task
* switch would be possible. It pushes a flag on the fresh local stack to
* indicate this.
*
* Then the actual GP2021 correlator handler, SVTrack, is called.
*
* When SVTRACK returns, the flag indicating the possibility of task switching
* is popped off the stack. If task switching is disallowed, the ISR simply
* restores the saved context and resumes the interrupted process. If task
* switching is possible, and if a correlator TIC event has occurred, the
* current task state is saved. Tasks on the suspend list whose suspend
* interval has expired are removed from the list and marked active. Then the
* ISR restores the context of the highest priority active task and resumes it.
*
* Input: None.
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void far interrupt GPISR(__CPPARGS)
{
/* No local variables can be declared in this routine, either
explicitly, or implicitly by certain compiler optimization
options. */
disable();
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x60 /* PUSHA. */
}
#endif
#if InUncontrolledCodeChecking && (CompilerVersion==31)
asm{
mov ax,[bp+20]
}
InterruptedCS = _AX; /* CS of interrupted process */
#endif
#if InUncontrolledCodeChecking && (CompilerVersion>31) && (INSTRMODE==32)
asm{
mov ax,[bp+32]
}
InterruptedCS = _AX; /* CS of interrupted process */
#endif
#if InUncontrolledCodeChecking && (CompilerVersion>31) && (INSTRMODE==16)
asm{
mov ax,[bp+20]
}
InterruptedCS = _AX; /* CS of interrupted process */
#endif
GPIntCtr++;
/* Pick up a local stack for the interrupt. On this stack, save the
interrupted context's stack pointers. */
NewISRSS = IStkSS[ISRNEST];
NewISRSP = IStkSP[ISRNEST];
asm{
mov ax,ss
mov bx,sp
mov InterruptedSS,ax
mov InterruptedSP,bx
mov cx,NewISRSS
mov dx,NewISRSP
mov ss,cx
mov sp,dx
push ax
push bx
}
/* Read the MS-DOS InDOS byte. A nonzero value indicates that the
program has called DOS and is therefore in a state which disallows
task switching. InDOS checking is mandatory for PC environments
but may be removed for some embedded environments. */
InDOS = (*InDOSPtr)&0xFF; /* The InDOS byte is in the 8 LSB's. */
#if InUncontrolledCodeChecking
/* If the interrupted process was not executing between ProgStartSeg
and ProgEndSeg, it was outside the reentrant GPS Builder-2
environment. We cannot assume that such uncontrolled routines are
reentrant, and we must regretfully disallow task switching in this
case. In an embedded environment where the GPS Designer controls all
such external routines and can guarantee reentrancy, there may be no
need to disallow task switching under those circumstances. */
InUncontrolledCode = (InterruptedCS<ProgStartSeg)
|| (InterruptedCS>ProgEndSeg);
TaskSwitchDisallowed = PROTECT || InDOS || (InterruptedSS != CurrentStack)
|| InUncontrolledCode;
#else
TaskSwitchDisallowed = PROTECT || InDOS
|| (InterruptedSS != CurrentStack);
#endif
if(TaskSwitchDisallowed)
{
/* Task switching is disallowed by the interrupted process because:
1) It is in a protected region of code,
2) It is in an uncontrolled region of code, or
3) It has switched to a local stack (i.e., not the stack
assigned to one of the application tasks). This includes
the case of the correlator ISR still active from a
previous interrupt.
After processing the interrupt, we will simply return without
switching application tasks, so there is no need to do a full
context save. */
asm{
push 1 /* Means to just return where interrupted. */
}
}
else
{
/* After processing the interrupt, a task switch is possible, so
save the full context, except the coprocessor state. */
CurrentTaskTCB = &TCB[CurrentTask];
CurrentTaskTCB->SAVSS = InterruptedSS;
CurrentTaskTCB->SAVSP = InterruptedSP;
if(InterruptedSP < CurrentTaskTCB->MinSP)
{
CurrentTaskTCB->MinSP = InterruptedSP; /* Monitor stack usage. */
}
asm{
push 0 /* Means a task switch could be done. */
}
}
/* SVTRACK must be entered with interrupts disabled. It becomes
interruptible during processing, but it always returns with interrupts
disabled. */
if(TestingInterface)
InterfaceTestInterruptRoutine();
else
SVTrack();
/* Retrieve the flag which tells us whether the interrupted context
was reentrant (0=reentrant, 1=nonreentrant). */
asm{
pop ax
mov JustReturn,ax
}
/* Start/stop PC speaker beeps. See module BEEP. */
if(BeepDur)
{
if(BeepFrq)
{
sound(BeepFrq);
BeepFrq = 0;
}
else
{
BeepDur--;
if(BeepDur==0)
nosound();
}
}
if(EXECUTIC==0 || JustReturn)
{
/* Just restore the interrupted context and return (no task switch)
because 1) the application code is non-reentrant, 2) No TIC
has occurred, or 3) correlator interrupt processing is still in
progress. */
asm{
pop ax
pop bx
mov ss,bx
mov sp,ax
}
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x61 /* POPA. */
}
#endif
return;
}
/* Count down the suspend list's timer chain by one TIC. As the
suspend intervals expire, remove tasks from the suspended list
and reactivate them. */
while(EXECUTIC)
{
if(SuspTask == -1) /* If no tasks are suspended. */
{
EXECUTIC=0;
break;
}
EXECUTIC--;
if(TCB[SuspTask].SuspTics==0)
{
/* The suspension interval has expired for the task at the head
of the suspended task list. Remove it from the suspended list
and mark it active. Note that several tasks may complete
suspend intervals at the same time. */
while(SuspTask != -1)
{
if(TCB[SuspTask].SuspTics)
break;
TCB[SuspTask].Active += 1;
SuspTask = TCB[SuspTask].NxtSusp;
}
if(SuspTask != -1)
TCB[SuspTask].SuspTics--;
}
else
{
/* No task is ready to go yet. Decrement the timer of the task at
the head of the suspended list. */
TCB[SuspTask].SuspTics--;
}
}
/* Select the highest priority active task and make it the new Current
Task. */
OldCurrentTask = CurrentTask;
for(CurrentTask=0;CurrentTask<=MainTask;CurrentTask++)
if(TCB[CurrentTask].Active)
break;
CurrentTaskTCB = &TCB[CurrentTask];
CurrentStack = CurrentTaskTCB->STRTSS;
CurrentTaskTCB->Slices++;
/* Switch to CurrentTask. */
NewStackSeg = CurrentTaskTCB->SAVSS;
NewStackPtr = CurrentTaskTCB->SAVSP;
asm{
pop ax /* Discard saved stack pointer. */
pop ax
mov cx,NewStackSeg
mov dx,NewStackPtr
mov ss,cx
mov sp,dx
}
if(_8087 && (OldCurrentTask != CurrentTask))
{
/* Save the current coprocessor state of OldCurrentTask, then reload
the old coprocessor state of the task which we are going to switch
to. If using floating point emulation, this is not necessary. */
GPISRSegTemp = FP_SEG(TCB[OldCurrentTask].SAV8087);
GPISROffTemp = FP_OFF(TCB[OldCurrentTask].SAV8087);
asm{
mov es,GPISRSegTemp
mov bx,GPISROffTemp
fnsave es:[bx]
fwait
}
/* Reload the saved state of the new task into the coprocessor. On
slow machines it is important that frstor not be followed by an
fwait. The coprocessor will take several hundred cycles to
reload itself, and we need to get out of the ISR as soon as
possible. We can omit the fwait because the coprocessor save
area is in a static memory area which will not be deallocated
or altered while the restore is occurring. */
GPISRSegTemp = FP_SEG(CurrentTaskTCB->SAV8087);
GPISROffTemp = FP_OFF(CurrentTaskTCB->SAV8087);
asm{
mov es,GPISRSegTemp
mov bx,GPISROffTemp
frstor es:[bx]
}
}
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ: */
db 0x61 /* POPA */
}
#endif
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -