(* In order to use the 8087 with the Series-III, you must supply
an interrupt handler to field the hardware interrupt generated
by the 8087 -> 8259A.  On the Series-III board, the iSBC-337
multi-module connects the 8087 interrupt to level 7 on the on-board
8259A.  The Series-III initialization sequence maps the 8259A
interrupts to interrupt numbers 56 to 63, so level 7 is at
interrupt 63.

An interrupt handler for level 63 is supplied which clears the
8259A to allow it to accept subsequent 8087 interrupts, and
also enables the 8086 interrupt mask disabled (by the hardware) at
entry to the interrupt handler.  This combination must be done before
invoking the "common" numeric trap handler (common to both the
hardware 8087 and the software emulator), so that the trap
handler can use the 8087.  Otherwise, if an 8087 exception occurred
in the trap handler, the processor would hang up, since
either the 8259A or the 8086 would hold the 8087 interrupt pending. *)

MODULE MYSIII8087CONFIG;
PUBLIC MYSIII8087CONFIG;
   TYPE ARBPTR = ^INTEGER; (* Actually a pointer to the trap routine. *)
   FUNCTION TQWheresTrap87(VAR TrapHandlerAddress: ARBPTR): WORD;

PUBLIC UTS;
$INTERRUPT(TQ_TRAP87)
   PROCEDURE TQ_TRAP87;

PRIVATE MYSIII8087CONFIG;

$INTERRUPT(My8087Trap=63)
PROCEDURE My8087Trap;
BEGIN
   OUTBYT (0C0H, 20H); (* Send End Of Interrupt to 8259A *)
   EnableInterrupts;   (* Allow 8086 interrupts to be accepted. *)
   CauseInterrupt(16); (* Transfer to "common" 8087 trap handler *)
END;

FUNCTION TQWheresTrap87(VAR TrapHandlerAddress: ARBPTR): WORD;
  TYPE Interrupts = (IR0, IR1, IR2, IR3, IR4, IR5, IR6, IR7);
   VAR
       (* Define a SET containing 8 elements, one for each interrupt
          level on the 8259A.  Pascal-86 will map this set to a byte,
          with elements mapped to bits right-to-left in the
          byte.  This allows us to use SET operations
          to enable level 7, where the 8087 is attached on the
          SBC 86/12A board. *)
       InterruptMask: SET OF Interrupts;
BEGIN

   (* Clear the leftmost bit (IR7), to enable level 7. *)
   DisableInterrupts;
   INBYT(0C2H, InterruptMask);
   OUTBYT(0C2H, InterruptMask * [IR0..IR6]);
   EnableInterrupts;

   (* Set up interrupt level 16 as the 8087 interrupt handler.
      This is done in this routine, with the SetInterrupt procedure,
      so that we don't have to pass back the address of TQ_Trap87,
      since this is difficult to do in Pascal. *)
   SetInterrupt(16, TQ_Trap87);

   (* Return value indicates to the run-time system which interrupt
      table entry must be initialized.  If set to zero, this indicates
      that no entry is to be initialized. *)
   TQWheresTrap87 := 0;
END;
.
