home *** CD-ROM | disk | FTP | other *** search
-
- Type tComPort = (Com1, Com2);
- tBaud = (b110, b150, b300, b600, b1200, b2400, b4800, b9600);
- tParity = (pSpace, pOdd, pMark, pEven, pNone);
- tDatabits = (d5, d6, d7, d8);
- tStopbits = (s1, s2);
-
- Type tSaveVector = record { Saved Com interrupt vector }
- IP: integer;
- CS: integer;
- end;
- Type regpak =
- record AX, BX, CX, DX, BP, SI, DI, DS, ES, FLAGS:integer end;
-
- Const ourDS: integer = -1; { Will be init to contents of our DS
- for later use in Interrupt routine }
-
- { Define address adders for the various
- Async card registers. }
- Const 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 }
- DLL = $00; { xF8 Divisor Latch Least Significant }
- DLM = $01; { xF9 Divisor Latch Most Significant }
- { ASynch Interrupt Masks }
- imlist: array[Com1..Com2] of integer = ($EF, $F7);
- { ASynch hardware interrupt addresses }
- ivlist: array[Com1..Com2] of integer = ($000C, $000B);
- PICCMD = $20; { 8259 Priority Interrupt Controller }
- PICMSK = $21; { 8259 Priority Interrupt Controller }
-
- { Asynch base port addresses are
- in the ROM BIOS data area }
- Var ComBaseAddr: array[Com1..Com2] of integer Absolute $0040:$0000;
-
- {
- Define a ring buffer for Asynch_Interrupt to write into
- and ReadCom to read from.
- }
- Var ringbuf: array[0..8000] of char;
- readptr, writptr: 0..80000; { Index which ReadCom will next read from
- Index which Asunch_Interrupt will next
- write into. If readptr=writptr then
- the buffer is empty. }
-
- Var LSRstat: byte; { Line Status Reg at interrupt }
- ComSaveVec: tSaveVector; { saved Async Interrupt vector }
- ComBase :integer; { Opened Com port base address }
- ActiveComPort: tComPort; { Opened Com }
- imvalue: integer; { Interrupt Mask value in use }
- type lstring = string[255];
-
- Procedure SwapIntVector(IntVect: integer;
- Var SaveVector: tSaveVector);
- Var dosregs: regpak;
- Begin
- inline($FA); { cli disable interrupts }
-
- With dosregs Do Begin
- ax := ($35 * 256) + IntVect;
- MsDos(dosregs); { DOS function 35 - get vector }
- ds := SaveVector.CS;
- dx := SaveVector.IP;
- SaveVector.CS := es;
- SaveVector.IP := bx;
- ax := ($25 * 256) + IntVect;
- MsDos(dosregs); { DOS function 25 - set vector }
- End;
- inline($FB); { sti re-enable ints }
- End;
-
- { This routine gets control upon an Asynch Interrupt }
-
- Procedure Asynch_Interrupt;
- Var dummy: array[1..8] of integer; { Leave room for our push's }
- MSRstat, IIRreg: byte;
- Begin
- {
- BP-4 Return IP
- BP-2 Return CS
- BP---> Caller's BP
- }
- { Push regs but DON'T enable - we can't
- handle another interrupt now }
- inline($50/$53/$51/$52/$57/$56/$06);
- inline($1E); { push ds save ds, also }
- inline($2E/$8E/$1E/ourDS); { mov DS,CS:ourDS ;Setup our DS }
-
- IIRreg := PORT[ComBase + IIR]; { Get Interrupt Identification }
- If (IIRreg and $01) = 0 then Begin { If interrupt pending }
- IIRreg := IIRreg and $06; { Leave bits 2 and 1 on }
- Case IIRreg of { Determine cause of interrupt (we
- actually only expect (and handle)
- the Data Available interrupt }
-
- $04: Begin { Received Data Available Interrupt }
- If LSRstat = 0 then Begin { If Line Status is OK }
- { If there is Room in Buffer }
- If (SUCC(writptr) <> readptr then Begin
- { Receive byte into our buffer }
- ringbuf[writptr] := CHR(PORT[ComBase + RBR]);
- { Increment writptr }
- writptr := SUCC(writptr) mod 256;
- End
- { If buffer full, pretend overrun }
- Else LSRstat := (LSRstat or $02);
- End;
- End;
- $06: LSRstat := PORT[ComBase + LSR] and $1E;
- $02: Begin End;
- $00: MSRstat := PORT[ComBase + MSR];
- Else Begin End;
- End; { Case }
- End;
- PORT[PICCMD] := $20; { Send End Of Interrupt to 8259 }
-
- inline($1F); { pop ds }
- inline($07/$5E/$5F/$5A/$59/$5B/$58); { pop rest of regs }
- inline($89/$EC); { mov sp,bp }
- inline($5D); { pop bp }
- inline($CF); { iret ;Return from interrupt }
- End;
-
-
- { Open COM1 or COM2, a la Basic }
-
- Procedure OpenCom(ComPort: tComPort;
- Baud: tBaud;
- Parity: tParity;
- Databits: tDatabits;
- Stopbits: tStopbits);
- Const baudcode: array[b110..b9600] of integer =
- ($417, $300, $180, $C0, $60, $30, $18, $0C);
- paritycode: array[pSpace..pNone] of byte =
- ($38, $08, $28, $18, $00);
- databitscode: array[d5..d8] of byte = ($00, $01, $02, $03);
- stopbitscode: array[s1..s2] of byte = ($00, $04);
- Var LCRreg: byte;
-
- Begin
- { Init the Const "ourDS" for use by
- the Async_Interrupt routine }
- inline($1E); { push ds }
- inline($2E/$8F/$06/ourDS); { cs:pop ourDS }
- { Swap Com interrupt vector }
- With ComSaveVec Do Begin
- CS := CSEG;
- IP := OFS(Asynch_Interrupt);
- End;
- SwapIntVector(ivlist[ComPort], ComSaveVec);
- ActiveComPort := ComPort;
- inline($CD/$01);
- ComBase := ComBaseAddr[ComPort];
- LSRstat := 0; { Reset LSR status }
- imvalue := imlist[ComPort]; { Select Interrupt Mask val }
- ComBase := ComBaseAddr[ComPort]; { Select Input Port }
- readptr := 0; { Init buffer pointers }
- writptr := 0; { Init buffer pointers }
- PORT[PICMSK] := PORT[PICMSK] and imvalue; { Enable ASynch Int }
- PORT[IER+ComBase] := $01; { Enable some interrupts }
- { Note: OUT2, despite documentation,
- MUST be ON, to enable interrupts }
- PORT[MCR+ComBase] := $0B; { Set RTS, DTR, OUT2 }
- LCRreg := $80; { Set Divisor Latch Access Bit in LCR }
- LCRreg := LCRreg or paritycode[Parity]; { Setup Parity }
- LCRreg := LCRreg or databitscode[Databits];{ Setup # data bits }
- LCRreg := LCRreg or stopbitscode[Stopbits];{ Setup # stop bits }
- PORT[LCR+ComBase] := LCRreg; { Set Parity, Data and Stop Bits
- and set DLAB }
- PORT[DLM+ComBase] := Hi(baudcode[Baud]); { Set Baud rate }
- PORT[DLL+ComBase] := Lo(baudcode[Baud]); { Set Baud rate }
- PORT[LCR+ComBase] := LCRreg and $7F; { Reset DLAB }
- inline($CD/$01);
- End;
-
-
- { Close any initialized COM }
-
- Procedure CloseCom;
- Begin
- { Disable Async interrupt }
- PORT[PICMSK] := PORT[PICMSK] or ($FF - imvalue);
- PORT[IER+ComBase] := $00; { Disable Data Avail interrupt }
- { Restore Com interrupt vector }
- SwapIntVector(ivlist[ActiveComPort], ComSaveVec);
- End;
-
- {
- Read a stream of data from the initialized COM port. If Line
- Status is not currently zero, then return immediately with
- the Line Status byte. If there is no data currently in the
- buffer then return stream:=null with function:=0. If there
- is data in the buffer, then return all the data up to, but
- not including, a CR($0D). If a CR is not found in the buffer
- then loop here until one arrives.
- }
-
- Function ReadCom(var stream: lstring): byte;{ Returned LSR, or zero}
-
- Function ReadChar: char; { Return char, or SPIN !!!! }
- Begin
- If readptr = writptr then
- Repeat Begin End Until (readptr <> writptr);
- ReadChar := ringbuf[readptr];
- readptr := SUCC(readptr) mod 256;
- End;
-
- Begin
- stream[0] := CHAR($00); { Init returned string to null }
- ReadCom := LSRstat; { Return LSR, or zero }
- If LSRstat = 0 then Begin
- If readptr <> writptr then Begin { If buffer not empty }
- Repeat Begin { Get chars from ring buffer}
- { Increment returned string len }
- stream[0] := CHAR(ORD(SUCC(stream[0])));
- { Get a char from buffer, or SPIN}
- stream[ORD(stream[0])] := ReadChar;
- End
- Until (stream[ORD(stream[0])] = CHR($0D)); { Until see a CR }
- stream[0] := CHR(ORD(stream[0]) - 1); { strip the CR }
- End;
- End;
- End;
-
- {
- Write a stream of data to the initialized COM port, then
- append a CR and LF.
- }
-
- Procedure WriteCom(stream: lstring);
- Var LSRreg: byte;
- i: integer;
- Begin
- inline($FA); { disable interrupts until we get all
- the data sent. }
- For i := 1 to LENGTH(stream) Do Begin
- { Spin until Transmitter Holding
- Register (THRE) is empty }
- Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
- PORT[THR+ComBase] := ORD(stream[i]); { Output the caharacter}
- End;
- Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
- PORT[THR+ComBase] := $0D; { Output a CR }
- Repeat LSRreg := (PORT[LSR+ComBase] and $20) Until LSRreg <> 0;
- PORT[THR+ComBase] := $0A; { Output a LF }
- inline($FB); { Reenable interrupts }
- End;
-
- begin end.