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

{
I am using a PCCOM 4-port serial card and this unit works with a small test
program but when I use it in a larger program (executable approx 48k) I only
get some of the characters from the port.
The serial card is 16450 based with vector at $02BF..
I have done very little interrupt programming so I don't know if that is the
problem.

Thanks........
}
unit mycom;

interface

procedure Async_ISR; interrupt;
procedure XmitChar(Serial_IOPort:byte;C: char);  { Uses variable and constant declarations from}
function  RemoteReadKey(Serial_IOPort:byte): char;  { Uses var and const from above }
function  RemoteKeyPressed(Serial_IOPort:byte):boolean;  { Uses vars and consts from above }
procedure InitPort(Serial_IOPort:byte);
procedure InitInter;
procedure TerminateInter;
function  COM_BufSize (Serial_IOPort:byte):byte;

implementation


USES DOS,crt;

var COM_mask:byte;
    COM_Buffer: array [0..3] of array[0 .. 129] of char;  { A buffer for input}
    COM_Temp,  { Varible to hold various modem statuses }
    COM_CommPort: byte;  { Comm Port in use }
    COM_Head : array [0..3] of byte;  { Size of the buffer }
    OldInt0Dh :pointer;
    OldPIC:byte;

const COM_IRQ_Number = $07;
      COM_IRQ_Vector = $0F;


const
  BaseAddr: array[0 .. 3] of word = ($02A0, $02A8, $02B0, $02B8);
  Baud=38400;                     { Speed required }
  Divisor:word = 115200 div Baud; { or 1843200 / (16 * Baud) }
                                  {    ^   UART clock speed  }

procedure Async_ISR;
   CONST Buf_Pnt:POINTER=@COM_Buffer;

  begin
{  WRITE('*'); }
  asm
  STI { STI - Disable interrupts }
  PUSHA
  PUSH SS
  MOV CL,00           { Com Port Counter 0 - 3 => COM5 - COM8}
@NextVector:
  MOV DX, 02BFh               { WHO WANTED AN INTERRUPT ? }
  MOV BL,01
  SHL BL,CL
  IN AL,DX
  TEST AL,BL
  JNZ @CheckNextVector
  MOV DX, 02A0h               { BASE OF FIRST PORT }
  MOV AL,08
  MUL CL
  ADD DX,AX                  { GOT BASE ADDRESS IN DX }
@GoBackForMore:
  ADD DX,02h
  IN AL,DX                   { CHECK INTERRUPT ID REGISTER }
  SUB DX,02h
  TEST AL,01h                { NO IRQ PENDING }
  JNZ @CheckNextVector
  AND AL,06h
  CMP AL,04h                  { DID WE RECEIVE A CHARACTER }
  JNZ @CheckMore               { NO ? THEN WHAT ELSE }
  IN AL,DX                    { READ INPUT FROM PORT }
  MOV BH,AL                   { PUT DATA IN BH FOR LATER }
  LDS SI,Buf_Pnt
  LES DI,Buf_Pnt
  MOV AL,130            { SIZE OF BUFFER + 2 for size & tail pointer }
  MUL CL
  ADD SI,AX
  ADD DI,AX                    { FOUND BUFFER[COM_PORT] }
  LODSB
  CMP AL,127                  { IF BUFFER FULL IGNORE CHARACTER }
  JA @CheckForAnotherIRQ
  INC AL                      { INC SIZE IF ROOM }
  STOSB                       { WRITE BACK TO SIZE COUNTER }
  LODSB                        { tail pointer }
  MOV BL,AL                    { PUT TAIL POINTER IN BL }
  INC AL
  CMP AL,128
  JB @WriteTail
  MOV AL,0
@WriteTail:
  STOSB
  MOV AL,BH                    { GET BACK DATA FROM BH }
  MOV BH,0
  ADD DI,BX                    { ADD CONTENTS OF TAIL POINTER TO POINTER }
  STOSB                        { WRITE DATA TO BUFFER }
  JMP @CheckForAnotherIRQ
@CheckMore:
  CMP AH,02h                  { THD EMPTY }
  JNZ @CheckMore2

  
  { FOR LATER ADDITION OF INTERRUPT SEND ROUTINE }


  JMP @CheckForAnotherIRQ
@CheckMore2:
  CMP AH,06h                  { ERROR OR BREAK }
  JNZ @CheckForAnotherIRQ
  IN AL,DX                    { READ FROM PORT TO CLEAR OVERRUNS }
  ADD DX,05h
  IN AL,DX                    { READ LINE STATUS REGISTER }
  SUB DX,05h
@CheckForAnotherIRQ:
  JMP @GoBackForMore        { ANOTHER INTERRUPT ON THIS PORT }

@CheckNextVector:
  INC CL
  CMP CL,04h
  JNZ @NextVector
  MOV DX,0020h
  MOV AL,20h
  OUT DX,AL    { RESET PIC }
  POP SS
  POPA
  CLI          { CLI - Enable interrupts }

  end;
end;



procedure XmitChar(Serial_IOPort:byte;C: char);  { Uses variable and constant declarations from}
begin                         {  the previous example }
  repeat
{  write ('.');}
  until (port[BaseAddr[Serial_IOPort] + $05] and $20 = $20);  { Wait for THR }

  port[BaseAddr[Serial_IOPort]] := Ord(C);  { Send character }

{  textcolor(red);
  write(ord(c));
  write('.');
  textcolor(lightgray);}
end;


function RemoteReadKey(Serial_IOPort:byte): char;  { Uses var and const from above }
begin
  if ord(COM_Buffer[Serial_IOPort][0]) > 0 then begin
RemoteReadKey := COM_Buffer[Serial_IOPort][COM_Head[Serial_IOPort]+2];  {Get the character }
inc(COM_Head[Serial_IOPort]);  { Move Head to the nextcharacter }
if COM_Head[Serial_IOPort] > 127 then COM_Head[Serial_IOPort] := 0;  { Wrap Head around if necessary }
dec(COM_Buffer[Serial_IOPort][0]);  {Remove the character }  end
  else RemoteReadKey:=chr(0);
end;


function RemoteKeyPressed(Serial_IOPort:byte): boolean;  { Uses vars and consts from above }
begin
  RemoteKeyPressed := ord(COM_Buffer[Serial_IOPort][0]) > 0;  { A key was pressed if there is data in}
  end;                             {  the buffer }

procedure InitPort(Serial_IOPort:byte);
          var COM_tt:byte;
          begin
          inline($FB); { STI - Disable interrupts }
          Port[BaseAddr[Serial_IOPort]+$03]:=Port[BaseAddr[Serial_IOPort]+$03] or 128;
          { Ready to set Port speed }
          Port[BaseAddr[Serial_IOPort]]:= Lo(Divisor);
          Port[BaseAddr[Serial_IOPort]+$01]:= Hi(Divisor);  { Set Speed to 38400 }
          Port[BaseAddr[Serial_IOPort]+$03]:= $03 or $08 or $00;
                  { end set port speed and set 8  -   O  -   1 }
          Port[BaseAddr[Serial_IOPort]+$01]:= $01;
                   { set Interrupt enable on Rx Data }
          COM_tt:=Port[BaseAddr[Serial_IOPort]];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+1];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+2];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+3];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+4];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+5];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+6];
          Port[BaseAddr[Serial_IOPort]]:=0;

  COM_Head[Serial_IOPort]:=0;
  COM_Buffer[Serial_IOPort][1]:=CHR(0);  { tail }
  COM_Buffer[Serial_IOPort][0]:=chr(0);  { size }

  inline($FA);  { CLI - Enable interrupts }
          end;


procedure InitInter;
           begin
           InitPort (0);
           InitPort (1);
           InitPort (2);
           InitPort (3);
               Port[$02BF]:=$ff;
               GetIntVec(COM_IRQ_vector, OldInt0Dh);
               SetIntVec(COM_IRQ_vector, @Async_ISR);
               COM_mask := (1 shl (COM_IRQ_number)) xor $00FF;
               OldPic:=Port[$21];
               Port[$21] := OldPIC and COM_mask;
           end;

procedure TerminateInter;
          var Serial_IOPort,com_tt:byte;
          begin
{             COM_mask := 1 shl (COM_IRQ_number);}
             SetIntVec(COM_IRQ_vector, OldInt0Dh);
          for Serial_IOPort := 0 to 3 do begin
                   { set Interrupt enable off }
          COM_tt:=Port[BaseAddr[Serial_IOPort]];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+1];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+2];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+3];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+4];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+5];
          COM_tt:=Port[BaseAddr[Serial_IOPort]+6];
          Port[BaseAddr[Serial_IOPort]]:=0;
          Port[BaseAddr[Serial_IOPort]+$01]:= $00;
             Port[$21] := Port[$21] and OldPIC;
          end;
             END;

function COM_BufSize (Serial_IOPort:byte):byte;
         begin
         COM_BufSize:=ord(COM_Buffer[Serial_IOPort][0]);
         end;

end.


Com_Buffer Structure:
Byte 0 -  number of characters in buffer
Byte 1 -  tail ponter in buffer
2-129  -  128 bytes (the buffer)

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