[Back to COMM SWAG index] [Back to Main SWAG index] [Original]

    {
    FRANCK DUMONT

    ------------------------------------------ ASM ------------------------------

    ;//////////////////////////////////////////////////////////////////////////
    ;///                                                                    ///
    ;///           Turbo-Pascal V24-Interrupt-Support      V2.00            ///
    ;///                                                                    ///
    ;///                 (c) Christian Philipps, Moers                      ///
    ;///                    June 1988 / West-Germany                        ///
    ;///                                                                    ///
    ;///                Turbo Pascal 4.0 or above required                  ///
    ;///                                                                    ///
    ;//////////////////////////////////////////////////////////////////////////

    ; This module is hereby donated to the public domain.

    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
    ;                    Datensegment
    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    DATA     SEGMENT BYTE PUBLIC

             ; Turbo-Pascal Variable
             EXTRN V24HP      : WORD
             EXTRN V24TP      : WORD
             EXTRN V24BuffEnd : WORD
             EXTRN V24Buff    : BYTE
             EXTRN ComBase    : WORD

    DATA     ENDS

    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
    ;                        Codesegment
    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    CODE     SEGMENT BYTE PUBLIC

             ASSUME CS:CODE, DS:DATA

             PUBLIC V24Int

    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

    ;CS-relative Daten

    _Turbo_DS DW  DATA                              ; Turbo data segment
          ; (inserted by linkage editor)

    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
    ;                    Codebereich
    ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
    ;PROCEDURE V24Int; interrupt;
    ;  this routine is executed whenever a character arrives

    V24Int   PROC  FAR                               ; Interrupt-Routine

    V24Int   ENDP

      push ds                                 ; save registers
             push ax
             push bx
             push dx
      mov  ds,CS:_Turbo_DS                    ; set Turbo DS

      mov  bx,V24TP                           ; ds:bx -> next free slot
      mov  dx,ComBase                         ; dx = port base-address
             in   al,dx                              ; RBR -> al
      mov  byte ptr [bx],al                   ; move byte into buffer
      inc  bx                                 ; pointer to next slot
      cmp  bx,V24BuffEnd                      ; past the end of the buffer?
      jle  L1                                 ; no
      mov  bx,OFFSET V24Buff                  ; yes, so wrap around

    L1:      cmp  bx,V24HP                           ; TP=HP --> overflow!
      jz   L2                                 ; yes, ignore character
      mov  V24TP,bx                           ; no, save new tail pointer

    L2:      mov  al,20H                             ; EOI -> 8259
             out  20H,al
      pop  dx                                 ; restore registers
             pop  bx
             pop  ax
             pop  ds
             iret

    CODE     ENDS

    END
    }
    (*////////////////////////////////////////////////////////////////////////////
    ///                                                                        ///
    ///         T U R B O  -  P A S C A L  V24-Interrupt-Support V2.00         ///
    ///                (c) Copyright June 1988 by C.Philipps                   ///
    ///                                                                        ///
    ///               (Turbo Pascal V4.0  or higher required)                  ///
    ///                                                                        ///
    //////////////////////////////////////////////////////////////////////////////
    ///                                                                        ///
    ///            Low-level interrupt-handling for the serial ports. Speeds   ///
    ///            up to 115200 bps are supportet, one port at a time.         ///
    ///            Parts of the basics were taken from Mike Halliday's pop-    ///
    ///            ular ASYNC-package (Turbo Pascal 3.0, PD).                  ///
    ///                                                                        ///
    ///       This module is hereby donated to the public domain.              ///
    ///                                                                        ///
    ///       Christian Philipps                                               ///
    ///       D�sseldorfer Str. 316                                            ///
    ///       4130 Moers 1                                                     ///
    ///       West-Germany                                                     ///
    ///                                                                        ///
    ///       Last modified: 07/89                                             ///
    ///                                                                        ///
    ////////////////////////////////////////////////////////////////////////////*)

    {$R-,S-,I-,D-,F-,V-,B-,N-,L- }

    UNIT V24;

    INTERFACE

    USES
      DOS;

    TYPE
      ComType      = (com1, com2, com3, com4, com5, com6);
      BaudType     = (b110, b150, b300, b600, b1200, b2400, b4800,
                      b9600, b19200, b38400, b57600, b115200);
      ParityType   = (Space, Odd, Mark, Even, None);
      DataBitsType = (d5, d6, d7, d8);
      StopBitsType = (s1, s2);

    CONST
      V24Timeout : BOOLEAN = FALSE;  {SendByte-Timeout}
      IntMasks   : ARRAY [Com1..Com6] OF WORD = ($EF,$F7,$EF,$F7,$EF,$F7);
      IntVect    : ARRAY [Com1..Com6] OF BYTE = ($0C,$0B,$0C,$0B,$0C,$0B);

    VAR
      V24TP      : WORD; {Buffer Tail-Pointer Im Interface-Teil, da zur
                          Ereignis-steuerung im Multi-Tasking ben�tigt.}
      ComBaseAdr : ARRAY [Com1..Com6] OF WORD;

    FUNCTION  V24DataAvail : BOOLEAN;
    FUNCTION  V24GetByte : BYTE;
    PROCEDURE InitCom(ComPort : ComType; Baudrate : BaudType; Parity : ParityType;
                      Bits : DataBitsType; Stop : StopBitsType);
    PROCEDURE DisableCom;
    PROCEDURE SendByte(Data : BYTE);

    IMPLEMENTATION

    CONST
      Regs : Registers =
        (AX : 0; BX : 0; CX : 0; DX : 0; BP : 0;
         SI : 0; DI : 0; DS : 0; ES : 0; FLAGS : 0);
      RBR = $00;          {xF8 Receive Buffer Register            }
      THR = $00;          {xF8 Transmitter Holding Register       }
      IER = $01;          {xF9 Interrupt Enable Register          }
      IIR = $02;          {xFA Interrupt Identification Register  }
      LCR = $03;          {xFB Line Control Register              }
      MCR = $04;          {xFC Modem Control Register             }
      LSR = $05;          {xFD Line Status Register               }
      MSR = $06;          {xFE Modem Status Register              }
                                      {--- if LCR Bit 7 = 1  ---              }
      DLL = $00;          {xF8 Divisor Latch Low Byte             }
      DLH = $01;          {xF9 Divisor Latch Hi  Byte             }
      CMD8259 = $20;      {Interrupt Controller Command Register  }
      IMR8259 = $21;      {Interrupt Controller Mask Register     }
                          {Should be evaluated by any higher-level send-routine}
      LoopLimit   = 1000; {When does a timeout-error occur        }
      V24BuffSize = 2048; { Ringpuffer 2 KB }

    VAR
      BiosComBaseAdr : ARRAY [Com1..Com2] OF WORD ABSOLUTE $0040:$0000;
      ActivePort     : ComType;
      { The Com-Port base adresses are taken from the BIOS data area }
      ComBase        : WORD;         {Hardware Com-Port Base Adress          }
      OldV24         : Pointer;
      V24HP          : WORD;         {Buffer Head-Pointer                    }
      V24BuffEnd     : WORD;         {Buffer End-Adress                      }
      V24Buff        : ARRAY [0..V24BuffSize] OF BYTE;
      OExitHandler   : Pointer;    {Save-Area f�r Zeiger auf Org.-Exit-Proc}

    PROCEDURE V24Int; external;
    {$L v24.obj}

    PROCEDURE ClearPendingInterrupts;
    VAR
      N : BYTE;
    BEGIN
      WHILE (PORT[ComBase + IIR] AND 1) = 0 DO  {While Interrupts are pending}
      BEGIN
        N := PORT[ComBase + LSR];               {Read Line Status}
        N := PORT[ComBase + MSR];               {Read Modem Status}
        N := PORT[ComBase + RBR];               {Read Receive Buffer Register}
        PORT[CMD8259] := $20;                   {End of Interrupt}
      END;
    END;

    FUNCTION V24DataAvail:BOOLEAN;
    { This function checks, whether there are characters in the buffer }
    BEGIN
      V24DataAvail := (V24HP <> V24TP);
    END;

    FUNCTION V24GetByte:BYTE;
    { Take a byte out of the ring-buffer and return it to the caller.
      This function assumes, that the application has called V24DataAvail
      before to assure, that there are characters available!!!!
      The ISR only reads the current head-pointer value, so this routine
      may modify the head-pointer with interrupts enabled. }
    BEGIN
      V24GetByte := Mem[DSeg:V24HP];
      Inc(V24HP);
      IF V24HP > V24BuffEnd THEN
        V24HP := Ofs(V24Buff);
    END;

    PROCEDURE SendByte(Data:BYTE);
    VAR
      Count : BYTE;
    BEGIN
      Count := 0;
      V24Timeout := FALSE;
      IF ComBase > 0 THEN
      BEGIN
        REPEAT
          Count := SUCC(Count);
        UNTIL ((PORT[ComBase + LSR] AND $20) <> 0) OR (Count > LoopLimit);
        IF Count > LoopLimit THEN
          V24Timeout := TRUE
        ELSE
          PORT[ComBase+THR] := Data;
      END;
    END;

    PROCEDURE InitCom(ComPort : ComType; Baudrate : BaudType; Parity : ParityType;
                      Bits : DataBitsType; Stop : StopBitsType);
    CONST
      BaudConst   : ARRAY [b110..b115200] OF WORD =
        ($417,$300,$180,$C0,$60,$30,$18,$0C,$06,$03,$02,$01);
      ParityConst : ARRAY [Space..None] OF BYTE = ($38,$08,$28,$18,$00);
      BitsConst   : ARRAY [d5..d8] OF BYTE = ($00,$01,$02,$03);
      StopConst   : ARRAY [s1..s2] OF BYTE = ($00,$04);
    BEGIN
      V24HP       := Ofs(V24Buff);
      V24TP       := V24HP;
      V24BuffEnd  := V24HP + V24BuffSize;
      FillChar(V24Buff, Succ(V24BuffSize), #0);
      V24Timeout := FALSE;                           {Reset Timeout-Marker}
      ComBase := ComBaseAdr[ComPort];                {Get Com-Port base adress}
      ActivePort := ComPort;                         {Keep Active-Port for EOI}
      ClearPendingInterrupts;
      GetIntVec(IntVect[ComPort], OldV24);
      SetIntVec(IntVect[ComPort], @V24Int);
                                                     {Install interrupt routine}
      INLINE($FA);                                   {CLI}
      PORT[ComBase + LCR] := $80;                    {Adress Divisor Latch}
      PORT[ComBase + DLH] := Hi(BaudConst[Baudrate]);{Set Baud rate}
      PORT[COMBase + DLL] := Lo(BaudConst[Baudrate]);
      PORT[ComBase + LCR] := ($00 OR ParityConst[Parity] {Setup Parity}
                                OR BitsConst[Bits]   {Setup number of databits}
                                OR StopConst[Stop]); {Setup number of stopbits}
      PORT[ComBase + MCR] := $0B;                    {Set RTS,DTR,OUT2}
    (*
      PORT[ComBase+MCR] := $1B;                      {Set RTS,DTR,OUT2,Loop}
    *)
      PORT[ComBase + IER] := $01; {Enable Data-Available Interrupts}
      PORT[IMR8259] := PORT[IMR8259] AND IntMasks[ComPort]; {Enable V24-Interrups}
      INLINE($FB);  {STI}
    END;

    PROCEDURE DisableCom;
    BEGIN
      IF ComBase = 0 THEN
        Exit;
      INLINE($FA);                           {CLI}
      PORT[ComBase + MCR] := 00;             {Disable Interrupts, Reset MCR}
      PORT[IMR8259] := PORT[IMR8259] OR $18; {Disable Interrupt Level 3 and 4}
      PORT[ComBase + IER] := 0;              {Disable 8250-Interrupts}
      ClearPendingInterrupts;                {Clean up}
      ComBase := 0;                          {Reset Combase}
      SetIntVec(IntVect[ActivePort], OldV24);{Reset old IV}
      INLINE($FB);                           {STI}
    END;

    {$F+}
    PROCEDURE V24ExitProc;

    BEGIN {V24ExitProc}
      DisableCom;
      ExitProc := OExitHandler;                 { alten Exit-Handler reaktivieren }
    END;  {V24ExitProc}
    {$F-}

    BEGIN
      {Grund-Init, damit irrt�mliche Aufrufe von V24DataAvail nicht zu
       endlosen Ausgaben von Speicherschrott f�hren!}
      Move(BiosComBaseAdr, ComBaseAdr[Com1], SizeOf(BiosComBaseAdr));
      Move(BiosComBaseAdr, ComBaseAdr[Com3], SizeOf(BiosComBaseAdr));
      Move(BiosComBaseAdr, ComBaseAdr[Com5], SizeOf(BiosComBaseAdr));
      ComBase    := 0;
      V24HP      := Ofs(V24Buff);
      V24TP      := V24HP;
      V24BuffEnd := V24HP + V24BuffSize;

      OExitHandler := ExitProc;
      ExitProc     := @V24ExitProc;
    END.

[Back to COMM SWAG index] [Back to Main SWAG index] [Original]