[comp.lang.pascal] chaining interrupts

cjveenm@cs.vu.nl (11/16/89)

From: cjveenm@cs.vu.nl ()
Newsgroups: comp.sys.ibm.pc
Subject: chaining interrupts
Expires: 
References: 
Sender: 
Reply-To: cjveenm@cs.vu.nl ()
Followup-To: 
Distribution: world
Organization: VU Informatica, Amsterdam
Keywords: 

	I have written several own interrupt handlers for the ibm pc,
and I wonder if it's possible to use the old interrupt routines by
chaining from the new one. One way to do this is by setting the old
vector on the address of an other interrupt number. A disadvantage
of this method is that you don't always know which interrupt is free
and you can run out of all possible interrupts.
	So is there an other way, from TP4 for instance:
		jmp oldvector (with inline code) 
doesn't succeed.

		thanks in advance, Cor

pelegrin@geocub.greco-prog.fr (11/16/89)

     It is absolutely harmless to link interrupt routines one to
another WITH THE SAME INTERRUPT VECTOR provided that, for interrupts
such as timer ticks, the total amount of time spent in the routines
does not exceed the tick clock rate...
     A general example of a resident interrupt routine installation
program (machine language) is given below :

 Initialization routine :
1) Save the old interrupt vector (INT 21H, FCN 25H) in a double word
   variable named, i.e. OLDVEC (defined with "DD OLDVEC").
2) Set the new interrupt vector (INT 21H, FCN 35H) to the segment:offset
   of your own interrupt routine NEWVEC, located within this program.
3) Make the program resident, including this routine (which will now
   be of no use but we have no way to eliminate it), and the next
   routine :
 Interrupt routine (starting at address NEWVEC) :
1) Push the registers you will use in your routine.
2) Perform whatever you want to... (8^D).
   Since it is an interrupt routine, DS and ES may have any value ; for
   small use of local variables, use the CS: prefix to access them
   within your code segment, else push DS and/or ES and set them equal
   to CS (for example...). If you use a large amount of stack, you can
   also switch to your own local stack.
3) Pop the registers you pushed before, in reverse order.
4) Use the JMP OLDVEC mnemonic (inter-segment jump from a memory operand)
   to link to the old interrupt vector.

 If you want to bypass the old interrupt vector, just perform at step 4)
a single IRET mnemonic for software interrupts, but if it was a hardware
interrupt (issued thru a Programmable Interrupt Timer), NEVER forget to use
the EOI mnemonic to warn the PIT of the end of the interrupt (for such
cases, I *strongly* recommend to link your interrupt to the previous one,
so that you don't have to hold those stinky cases...).

            Have fun.

                   f.p.

------------------------------------------------------------------------------
! Zeu<FP> : The craziest programmer in France !          _________           !
!---------------------------------------------!      /   |        \   \      !
! Francois Pellegrini is :                    !     /    |__   ___/    \     !
!         pelegrin@goofi.greco-prog.fr        !     \    |     |       /     !
!   uunet!mcsun!inria!geocub!goofi!pelegrin   !      \   |     |      /      !
!            pelegrin@goofi.UUCP              !                              !
------------------------------------------------------------------------------

johnl@esegue.segue.boston.ma.us (John R. Levine) (11/17/89)

In article <1484@geocub.greco-prog.fr> pelegrin@goofi.UUCP (Uncle Ben's) writes:
>     It is absolutely harmless to link interrupt routines one to
>another WITH THE SAME INTERRUPT VECTOR provided that, for interrupts
>such as timer ticks, the total amount of time spent in the routines
>does not exceed the tick clock rate...

Well, sometimes.  The problem is that many cards were not designed with
interrupt sharing in mind and so are not good citizens about the way that
they handle their interrupt line.  I have used cards (a WD8003 Ethernet, for
example) that keep anything else from interrupting on the same level.

-- 
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl@esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
"Now, we are all jelly doughnuts."

MATHRICH@umcvmb.missouri.edu (Rich Winkel UMC Math Department) (11/17/89)

I've done this many times with assembler, but not pascal.
Are you sure of the condition of the stack when you do the jump?
If you're doing this inside a TP INTERRUPT procedure, you need to read
about what TP does with the stack before your inline code gets control.
Basically it pushes ALL the registers except CS, SS, IP, SP and the flags
register.  You'll need to pop everything and then execute the jump.  See page
222 of the TP 5.0 manual.
Are you sure you're doing a far jump?
Are you using the jump seg & offset properly?  If the seg & offset of the
target routine is:
aabb:ccdd
then the jump could be coded as:
$EA/$dd/$cc/$bb/$aa         (immediate-operand form of far jump)
or
$FF/$2E/variable
assuming 'variable' is a four byte variable in the data segment (it must be
a global variable to be in the data seg).  The variable should have the
contents: $dd $cc $bb $aa.  One way to load it would be:
var intvec:longint absolute $0:yyyy;
    saveintvec:longint;
...
    saveintvec:=intvec; {save the old int vector}

Where yyyy is 4 times the interrupt number.

To be on the safe side, you should do a CLI before the jump (if you've done
an STI in your procedure).

Rich

KULOKARI@cc.helsinki.fi (Hannu Kulokari) (12/04/89)

In article <4543@solo5.cs.vu.nl>, cjveenm@cs.vu.nl writes:
> 	I have written several own interrupt handlers for the ibm pc,
> and I wonder if it's possible to use the old interrupt routines by
> chaining from the new one. One way to do this is by setting the old
> vector on the address of an other interrupt number. A disadvantage
> of this method is that you don't always know which interrupt is free
> and you can run out of all possible interrupts.
> 	So is there an other way, from TP4 for instance:
> 		jmp oldvector (with inline code) 
> doesn't succeed.
> 
> 		thanks in advance, Cor

You should CALL (not JMP to) the old interrupt routine, with a FAR
call. You should also push the flags (PUSHF) before the call. This is what
INT does (besides looking up the address of the routine from the interrupt
table).

Hannu Kulokari
CC, U of Helsinki, Finland