home *** CD-ROM | disk | FTP | other *** search
- {$V-} { These compiler directives should not be changed }
- {$K-}
- {$C-}
- {$R-}
-
- program Demonstrate_Interrupt_Handlers;
-
- { This program is placed in the public domain by Steve Wood, author of
- the book Using Turbo Pascal, published by Osborne McGraw-Hill. The
- techniques used are based on those presented by Jim Camelford in the
- T.U.G. Lines. This example has been modified to be activated directly
- by the calling program rather than by the timer interrupt or the
- keyboard interrupt. The advantage of this approach is that you can
- be certain that the interrupt does not occur during DOS/Turbo I/O
- processing. This means that your interrupt handler may use Turbo's
- I/O without fear of problems caused by the fact that neither Turbo nor
- DOS is re-entrant.
-
- Compile as a .COM program with segment sizes specified as follows:
- For cOde enter 3B The cOde & Data values were determined by
- For Data enter 4 compiling the program.
- For mAx enter 400 mAx is important because it limits the heap
- For mIn enter 400 so that all of memory is not allocated. The
- ---- value selected must be large enough to satisfy
- cOde+Data+mAx 73B the heap/stack requirements of the program.
- When you enter the cOde and Data values note
- the modified values that Turbo displays in the
- option list. The sum of those two values plus
- the value entered for mAx is the amount of memory
- that must be allocated for this program. See
- mem_size in the const section below.}
-
- const ZERO = $00;
- INTR_VECTOR = $80; { Defines the interrupt vector for the
- interrupt routine being defined.
- Be sure it does not conflict with
- other interrupt handlers that have
- been or will be installed. }
-
-
-
- { Typed constants hold values pertinent to the calling
- program (hold_xxx) and the interrupt program (new_xxx). }
-
- hold_sseg : Integer = ZERO;
- hold_sp : Integer = ZERO;
- new_dseg : Integer = ZERO;
- new_sseg : Integer = ZERO;
- new_sp : Integer = ZERO;
- mem_size : Integer = $073B; { Indicates the amount of memory
- ( in 16 byte paragraphs )
- to be reserved for the resident
- interrupt handler. This should be
- equal to or greater than the sum
- of the code segment size, data
- segment size and heap/stack size,
- all of which must be specified
- when the program is compiled. }
-
-
- type RegPack = record
- case Boolean of
- TRUE : (ax,bx,cx,dx,bp,si,di,ds,es,flags : Integer);
- FALSE : (al,ah,bl,bh,cl,ch,dl,dh : Byte);
- end;
-
-
- var regs : RegPack;
-
-
- procedure Demo_Intr; { This is the procedure that is activated by
- interrupt $80. }
-
- const ARROW = #205#205#16#32; {Displays as a right arrow.}
-
- var hold_vid : array[1..2000] of Integer;
- hold_x,
- hold_y : Integer;
- inchr : Char;
-
-
- function Mono_Monitor: Boolean;
- var video_type : Byte;
-
- begin
- video_type := (Mem[$0000:$0410] and $30);
- case video_type of
- $20 : Mono_Monitor := FALSE;
- $30 : Mono_Monitor := TRUE;
- else begin
- WriteLn(#7); Halt; { Somethings awry? }
- end;
- end; {case}
- end; { Mono_Monitor }
-
-
- begin { Demo_Intr }
- if Mono_Monitor then
- Move(Mem[$B000:$0000],hold_vid,4000) {Save current video screen.}
- else
- Move(Mem[$B800:$0000],hold_vid,4000);
- hold_x := WhereX; hold_y := WhereY; {Save cursor position.}
- ClrScr; GoToXY(1,12);
- WriteLn('Control has been transferred to this memory resident program');
- WriteLn('via the interrupt facility provided by MS-DOS.'); WriteLn;
- WriteLn('When you press a key, control will revert back to the program');
- WriteLn('that was suspended in order to process this interrupt.');
- Write('Press ANY KEY ',ARROW); Read(Kbd,inchr);
- if Mono_Monitor then
- Move(hold_vid,Mem[$B000:$0000],4000) {Restore current video screen.}
- else
- Move(hold_vid,Mem[$B800:$0000],4000);
- GoToXY(hold_x,hold_y); {Restore the cursor.}
- end; { Demo_Intr }
-
- procedure Save_Turbo_Values; { Store the data segment, stack segment and
- stack pointer addresses in the resident
- code segment using typed constants. }
-
- begin
- new_dseg := Dseg; { Save Dseg }
- new_sseg := Sseg; { Save Sseg }
- inline($2E/$89/$26/new_sp); { MOV [cs:new_sp],sp }
- end; { Save_Turbo_Values }
-
- procedure Interrupt;
-
- { ***** This is the entry point for the interrupt handler ***** }
-
- begin
- inline($2E/$8C/$16/hold_sseg/ { Save current Sseg }
- $2E/$89/$26/hold_sp/ { Save current sp }
- $2E/$8E/$16/new_sseg/ { Point Sseg to new stack seg.}
- $2E/$8B/$26/new_sp); { Points sp to new TOS }
-
- inline($50/$53/$51/$52/$57/$56/$06/$1E); { PUSH ax, bx, cx, dx,
- di, si, es, ds }
-
- inline($2E/$A1/new_dseg/ { MOV ax,[cs:new_dseg] }
- $8E/$D8/ { MOV ds,ax Point to new ds }
- $FB); { STI }
-
- Demo_Intr; { This may be replaced with any defined procedure identifier }
-
- inline($FA/ { CLI }
- $1F/$07/$5E/$5F/$5A/$59/$5B/$58/ { POP ds, es, si, di,
- dx, cx, bx, ax }
- $2E/$8E/$16/hold_sseg/ { MOV ss,[cs:hold_sseg] }
- $2E/$8B/$26/hold_sp/ { MOV sp,[cs:hold_sp] }
- $5D/$5D/$CF); { POP return addr and IRET }
-
- end; { Interrupt }
-
- { The main program starts here. Its purpose is to install the address
- of Interrupt in the interrupt vector table as interrupt $80 and to
- allocate enough memory to make the program memory resident. When
- executed it will produce no visible results unless interrupt $80
- is already used. }
-
- begin { Demonstrate_Interrupt_Handler }
- Save_Turbo_Values; { So you can set up the environment in Interrupt. }
- FillChar(regs,SizeOf(regs),ZERO); { Just to be safe. }
- with regs do
- begin
-
- { Check to see if interrupt has already been installed using DOS Fn $35. }
-
- ah := $35; al := INTR_VECTOR; MsDos(regs);
- if es <> $00 then
- begin
- WriteLn(' Interrupt handler already installed.');
- halt; { Quit if already installed }
- end;
-
- { Install Interrupt procedure address at interrupt vector INTR_VECTOR.
- using DOS Fn $25. }
-
- ah := $25; al := INTR_VECTOR;
- ds := Cseg; dx := Ofs(Interrupt);
- MsDos(regs);
-
- { Make program memory resident reserving memory indicated by mem_size using
- DOS Fn $31. }
-
- ax := $3100; dx := mem_size; MsDos(regs);
- end; {with}
- end. { Demonstrate_Interrupt_Handlers }