{***********************************************************************}
{									}
{ UNIT_ISR  Interrupt service routine support				}
{									}
{ This unit implements the POWER TOOLS PLUS Interrupt Service		}
{ Routine Support.  These routines provide the capabilities to install	}
{ a Turbo Pascal procedure as an ISR.  The exported identifiers are:	}
{									}
{  _IdentStr	ISR and Intervention code identifier string  (type)	}
{  _Signature	ISR and Intervention code signature string   (type)	}
{  _IsrCtrl	ISR control block			     (type)	}
{									}
{  _ExecIsrAddr Address of the ISR dispatcher		     (variable) }
{									}
{ __InsIsr	Install an interrupt service routine			}
{ __CallIsr	Invoke an interrupt service routine via an address	}
{ __IsInsIsr	Check for the presence of an ISR			}
{ __ResetIsr	Reestablish the original vector for an ISR		}
{ __IsStiIsr	Are interrupts enabled? 		     (macro)	}
{ __CliIsr	Disable interrupts			     (macro)	}
{ __StiIsr	Enable interrupts			     (macro)	}
{ __EOIIsr	Send a nonspecific EOI to the 8259	     (macro)	}
{ __ToTicIsr	Convert time to ticks since midnight			}
{ __FmTicIsr	Convert ticks since midnight to time			}
{									}
{ Version 4.00	(C)Copyright Blaise Computing Inc.  1987		}
{_______________________________________________________________________}

unit Unit_Isr;

interface
  uses DOS,			       { Turbo Pascal DOS unit		}
       Unit_Sup;		       { POWER TOOLS PLUS Support unit	}

  type
    _IdentStr  = string[9];
    _Signature = string[3];

    { The _IsrCtrl structure is the ISR control block.	It has all the	}
    { information needed by the ISR dispatcher to transfer control to	}
    { the ISR, set up the proper environment (stack and data segment),	}
    { and then return control to the caller.				}

    _IsrCtrl  = record
		  _IsrFarCode	 : word;    { NOP followed by far call	}
		  _IsrDispPtr	 : pointer; { Address of the dispatcher }
		  _IsrStackSeg	 : word;    { Allocated ISR stack space }
		  _IsrStackSize  : word;    { Size of ISR stack instance}
		  _IsrStackPar	 : word;    { Paragraph size of stack	}
		  _IsrStackDepth : word;    { Total para used by stack	}
		  _IsrSS	 : word;    { Current stack segment, SS }
		  _IsrSP	 : word;    { Current stack pointer, SP }
		  _IsrDS	 : word;    { DS value required (DSeg)	}
		  _IsrAddress	 : pointer; { Address of ISR itself	}
		  _IsrPSP	 : word;    { PSP of the ISR		}
		  _IsrPreVector  : pointer; { Previous value of vector	}
		  _IsrLevel	 : word;    { Current level of nesting	}
		  _IsrLimit	 : word;    { Maximum nesting level	}
		  _IsrSignature  : _Signature;	  { ISR Block signature }
		  _IsrIdent	 : _IdentStr;	  { ISR identification	}
		end;

  var
    _ExecIsrAddr : pointer;		    { Dispatcher address	}

  procedure __InsIsr  (var IsrBlock	: _IsrCtrl;
			   IsrIntType	: byte;
			   IsrStackSize : word;
			   IsrStackNum	: word;
			   IsrAddress	: pointer;
			   IsrIdent	: _IdentStr);
  procedure __CallIsr ( Vector : pointer; var Reg : registers);
  function  __IsInsIsr(  IntType : byte;
			   Ident : _IdentStr;
		       var PSPPtr,
			   EnvPtr,
			 PrevVec : pointer)   : boolean;
  function  __ResetIsr(  IntType : byte;
			   Ident : _IdentStr) : word;

  { The following macros return the state of the interrupt flag,	}
  { disable and enable interrupts, and send a nonspecific EOI to the	}
  { 8259 programmable interrupt controller chip.			}

  function  __IsStiIsr : boolean;
		      Inline(
				$9C		      { pushf		}
			       /$9C		      { pushf		}
			       /$58		      { pop ax		}
			       /$25/$00/$02	      { and ax,20h	}
			       /$51		      { push cx 	}
			       /$B1/$09 	      { mov cl,10h	}
			       /$D3/$E8 	      { shr ax,cl	}
			       /$59		      { pop cx		}
			       /$9D);		      { popf		}
  procedure __CliIsr; Inline($FA);     { Disable interrupts		}
  procedure __StiIsr; Inline($FB);     { Enable interrupts		}
  procedure __EOIIsr; Inline(	       { EOI to the 8259		}
			      $B0/$20		      { mov al,20h	}
			     /$E6/$20); 	      { out 20h,al	}

  procedure __ToTicIsr(    Hours,Mins,Secs,Tics : word;
				      var Ticks : longint);
  procedure __FmTicIsr(var Hours,Mins,Secs,Tics : word;
					  Ticks : longint);

implementation

  {$L execisr.obj }		       { Dispatcher object code 	}
  procedure __ExecIsr; external;

  {$L callisr.obj }		       { Invoke interrupt object code	}
  procedure __CallIsr(Vector : pointer; var Reg : registers); external;

  {$I insisr.imp  }		       { Install an ISR 		}
  {$I isinsisr.imp}		       { Check for ISR presence 	}
  {$I resetisr.imp}		       { Reestablish the original	}
				       { vector for an installed ISR.	}
  {$I toticisr.imp}		       { Convert time to ticks		}
  {$I fmticisr.imp}		       { Convert ticks to time		}

  begin {Initialization}

    _ExecIsrAddr := @__ExecIsr	       { Return ISR dispatcher address, }
				       { vention code control block.	}
  end.	{Initialization}
