Turbo C User's Guide:
Embedded Assembly Language. Part II - Interrupts.

> The 80x86 reserves the first 1024 bytes of memory for a set of 256 far pointers--known as interrupt vectors--to special system routines known as interrupt handlers. These routines are called by executing the 80x86 instruction

> > int int#

> where int# goes from 0h to FFh. When this happens, the computer saves the code segment (CS), instruction pointer (IP), and status flags, disables the interrupts, then does a far jump to the location pointed to by the corresponding interrupt vector. To write an interrupt handler in Turbo C++, you must define the function to be of type interrupt; more specifically, it should look like this:

> > void interrupt myhandler(bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags, ... );

> As you can see, all the registers are passed as parameters, so you can use and modify them in your code without using the pseudovariables discussed earlier in this online file. You can also pass additional parameters (flags, ...) to the handler; those should be defined appropriately.

> A function of type interrupt will automatically save (in addition to SI, DI, and BP) the registers AX through DX, ES, and DS. These same registers are restored on exit from the interrupt handler.

> An interrupt function can modify its parameters. Changing the declared parameters will modify the corresponding register when the interrupt handler returns. This may be useful when you are using an interrupt handler to act as a user service, much like the DOS INT 21 services. Also, note that an interrupt function exits with an IRET (return from interrupt) instruction.

> Low-Level Practices

> Let's start with an interrupt handler that beeps whenever it's called. First, write the function itself. Here's what it might look like:

> > #include <dos.h>
> > void interrupt mybeep(unsigned bp, unsigned di, unsigned si,
> > unsigned ds, unsigned es, unsigned dx,
> > unsigned cx, unsigned bx, unsigned ax)

> > { int i, j;

> > > char originalbits, bits;
> > > unsigned char bcount = ax >> 8; /* Get port setting */
> > > bits = originalbits = inportb(0x61);
> > > for (i = 0; i <= bcount; i++) /* Turn off speaker */
> > > { outportb(0x61, bits & 0xfc);
> > > for (j = 0; j <= 100; j++);
> > > outportb(0x61, bits | 2); /* Turn on speaker */
> > > for (j = 0; j <= 100; j++) ;
> > > }

> > > outportb(0x61, originalbits); /* Restore port setting */

> > }

> Next, write a function to install your interrupt handler. Pass it the address of the function and its interrupt number (0 to 255 or 0x00 to 0xFF).

> > void install(void interrupt (*faddr)(), int inum)
> > {
> > setvect(inum, faddr);
> > }

> Finally, call your beep routine to test it out. Here's a function to do just that:

> > void testbeep(unsigned char bcount, int inum)
> > {
> > _AH = bcount;
> > geninterrupt(inum);
> > }

> Your main function might look like this:

> > main()
> > { char ch;
> > install(mybeep,10);
> > testbeep(3,10);
> > ch = getch();
> > }

> You might also want to preserve the original interrupt vector and restore it when your main program is finished. Use the getvect and setvect functions to do this.

This material was copied from the BASM.DOC file supplied with the Turbo-C software.
F. J. Looft, fjlooft@ee.wpi.edu.