home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pctchnqs
/
1991
/
number2
/
comio.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-10-04
|
4KB
|
169 lines
{$R-,S-}
unit ComIO;
{ Low level serial interface routines using inline assembler
for interrupt service }
Interface
uses Dos, Crt;
const
Baud300 = $40; Baud1200 = $80; Baud2400 = $A0;
Baud4800 = $C0; Baud9600 = $E0;
EvenParity = $18; OddParity = $08; NoParity = $00;
WordSize7 = $02; WordSize8 = $03;
StopBits1 = $04; StopBits2 = $00;
COM1Port = $00; COM2Port = $01;
procedure ComInit(BufSize: Word);
procedure ComDone;
function ComAvail: Boolean;
function ComGet: Byte;
function ComOverflow: Boolean;
procedure ComPut(B: Byte);
procedure ComPutString(S: String);
function ComSetParam(APortNum, AParams: Word): Boolean;
Implementation
uses Objects;
const
UART_THR = $00; UART_RBR = $00; UART_IER = $01;
UART_IIR = $02; UART_LCR = $03; UART_MCR = $04;
UART_LSR = $05; UART_MSR = $06; I8088_IMR = $21;
FirstInit: Boolean = True;
var
Overflow: Boolean;
PortNum, Base, Max, Head, Tail: Word;
BufferPtr: PByteArray;
SaveCom1Int, SaveCom2Int: Pointer;
IRQ, IntNumber: Byte;
procedure STI; inline($FB);
procedure CLI; inline($FA);
procedure ComIntHandler; interrupt; assembler;
asm
STI
MOV DX,Base { Receive buffer register is at offset 0 }
IN AL,DX
LES DI,BufferPtr { get pointer into the buffer }
MOV BX,Head
MOV ES:[DI+BX],AL { put character into buffer }
INC BX { increment }
CMP BX,Max { do we need a wrap around ? }
JL @@1
MOV BX,0
@@1:
CMP Tail,BX { buffer overflow ? }
JNE @@2
INC Overflow
JMP @@3
@@2:
MOV Head,BX { put head pointer back }
@@3:
MOV AL,$20
OUT $20,AL { send non-specific EOI to interrupt controller }
end;
procedure BiosInitCom(APortNum, AParams: Word); assembler;
asm
MOV AX,AParams
MOV DX,APortNum
XOR AH,AH
INT 14H
end;
procedure ComInit(BufSize: Word);
begin
if not FirstInit then RunError(255);
FirstInit:=False;
GetIntVec($C, SaveCom1Int);
GetIntVec($B, SaveCom2Int);
GetMem(BufferPtr, BufSize);
Max:=BufSize;
end;
procedure ComDone;
begin
if not FirstInit then
begin
SetIntVec($C, SaveCom1Int);
SetIntVec($B, SaveCom2Int);
FreeMem(BufferPtr, Max);
CLI;
Port[I8088_IMR] := Port[I8088_IMR] or (1 shl IRQ);
Port[UART_IER + Base] := 0;
Port[UART_MCR + Base] := 0;
STI;
end;
FirstInit := True;
end;
function ComAvail: Boolean;
begin
ComAvail:= Head <> Tail;
end;
function ComGet: Byte;
begin
repeat until Head <> Tail;
ComGet := BufferPtr^[Tail];
CLI;
Inc(Tail);
if Tail >= Max then Tail := 0;
STI;
end;
function ComOverflow: Boolean;
begin
ComOverflow:=Overflow;
end;
procedure ComPut(B: Byte);
begin
while (Port[UART_LSR + Base] and $20) = 0 do;
CLI;
Port[UART_THR + Base] := B;
STI;
end;
procedure ComPutString(S: String);
var L: Integer;
begin
for L := 1 to Length(S) do ComPut(Ord(S[L]));
end;
function ComSetParam(APortNum, AParams: Word): Boolean;
var
BIOSPorts : array[1..2] of Word absolute $40:0;
Junk: Word;
begin
SetIntVec($C, SaveCom1Int);
SetIntVec($B, SaveCom2Int);
Overflow := False;
Head := 0;
Tail := 0;
Base := BIOSPorts[APortNum + 1];
IRQ := Hi(Base) + 1;
IntNumber := IRQ + $8;
if (Port[UART_IIR + Base] and $F8) = 0 then
begin
SetIntVec(IntNumber, @ComIntHandler); { install interrupt handler }
PortNum := APortNum;
BiosInitCom(APortNum, AParams); { use BIOS call for easy param setting }
CLI;
Port[UART_LCR + Base] := Port[UART_LCR + Base] and $7F;
Port[I8088_IMR] := Port[I8088_IMR] and ((1 shl IRQ) xor $FF);
{ enable PIC to recognize IRQ's }
Port[UART_IER + Base] := $01; { allow UART to generate IRQ's }
Port[UART_MCR + Base] := Port[UART_MCR + Base] or $0B;
Junk := Port[UART_LSR + Base]; { clear these registers }
Junk := Port[UART_RBR + Base];
STI;
ComSetParam:=True
end
else ComSetParam := False;
end;
end.