[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]