home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
packet
/
mulrpt.lbr
/
HDLSIO.MZC
/
HDLSIO.MAC
Wrap
Text File
|
1985-11-24
|
12KB
|
447 lines
TITLE HDLSIO - Z80 SIO HDLC DRIVER ROUTINES
; Driver routines to operate a port of a Zilog Z80-SIO
; in the SDLC/HDLC mode for packet radio operations. These
; routines operate in the half-duplex mode. The SIO RTS
; line is used to turn the transmitter on. Transmission
; of data will not begin until the SIO CTS line is asserted.
;
; Interface to the main program is via subroutine calls.
; Each call must be made with the address of the SIO data
; structure in the IY register. This data structure is
; as follows:
INCLUDE STRUCT.LIB
; Upon activation, the main program should call the HDLINT
; initialization entry point to set up the SIO hardware.
; It is only necessary to call this routine once per
; SIO channel used. This routine is called only after a
; hardware reset as the routines will take care of all
; further SIO setup and disabling for the proper mode (Tx
; or Rx). When frame data is received, the external sub-
; routine NEXTHI will be called to accept each data byte
; or to flag the end of frame. When transmission is
; desired, the TXSKED entry point must be called to
; schedule the transmission. As each data byte is
; required by the SIO transmitter, the external sub-
; routine NEXTHO will be called. When this subroutine
; indicates the end of the data for the current transmission,
; the transmission will be terminated and the SIO placed
; back in receive mode. The external subroutine HODONE will
; then be called.
PAGE
; All routines must be entered with the data structure address
; in IY. IX and IY registers are not affected by any of these
; routines. All external subroutines should return with IY
; unchanged.
;
; ENTRY POINTS:
;
; HDLI - Initialization subroutine. The SIO registers
; will be initialized in the receive mode. CDS
; will be called.
; Entry: No parameters.
; Return: All registers undefined.
;
; XSKED - Schedule transmission.
; Entry: A = 0 if CW id only
; = 1 if frame data to transmit
; Return: all registers undefined
;
; CDS - Carrier detect status reporting.
; Entry: No parameters required
; Return: A = 0 if DCD off
; A = 0FFH if DCD on
; EXTERNAL ROUTINES
;
; All of these routines are called within interrupt service.
; External routines may destroy any registers except IY
; and those specified below with return parameters.
;
; NXTHO - Routine to supply next data byte for trans-
; mission.
; Entry: No parameters
; Return: A = 0FFH if next data byte
; = 0 if end of message (more to follow)
; = 1 if end of transmission (no CW id)
; = 2 if end of transmission and id request
; B = next data byte (if A = 0FFH)
;
; ODONE - Routine at end of transmission. Called after
; receive mode is re-entered. No parameters.
;
; NXTHI - Routine to accept received data. All data
; after a call with A = 0 is invalid if another
; call with A = 0 occurs before a call with
; A = 1.
; Entry: A = 0FFH if next data byte
; A = 0 if start of frame
; A = 1 if end of frame
; B = next data byte (if A = 0 or 0FFH)
; Return: No parameters
PAGE
.Z80
; SIO constants
;COMMANDS:
RESTXI EQU 28H ;Reset TX interrupt
RESEXT EQU 10H ;Reset external interrupt
RESTCR EQU 80H ;Reset TX CRC generator
RESEOM EQU 0C0H ;Reset TX end of message
RESERR EQU 30H ;Reset error status
;STATUS BITS AND MASKS, RR 0
ABORT EQU 7 ;Break/abort
MABORT EQU 80H
EOM EQU 6 ;TX underrun/EOM
MEOM EQU 40H
CTS EQU 5 ;Clear-to-send line
MCTS EQU 20H
DCD EQU 3 ;Data-carrier-detect line
MDCD EQU 8
TXBE EQU 2 ;TX buffer empty
MTXBE EQU 4
RXBF EQU 0 ;RX buffer full
MRXBF EQU 1
;STATUS BITS AND MASKS, RR 1
EOF EQU 7 ;End of SDLC frame
MEOF EQU 80H
FERR EQU 6 ;Framing error
MFERR EQU 40H
OVR EQU 5 ;RX overrun
MOVR EQU 20H
PERR EQU 4 ;Parity error
MPERR EQU 10H
MRES EQU 0EH ;Residue mask
ALL EQU 0 ;All sent
MALL EQU 1
RES8 EQU 0110B ;Byte boundry residue
ENTRY HDLI,XSKED
ENTRY CDS
ENTRY I.TBE,I.RBF,I.EXT,I.SRX
EXT SETTMR
SUBTTL 'Callable Subroutines'
PAGE
; HDLI - SIO initialization routine
HDLI:
LD HL,SIOBI ;SIO init data
LD B,SIOBIL ;Length of same
LD C,(IY+CPORT) ;SIO control port
OTIR ;Init the SIO (rx mode)
XOR A
LD (IY+TSTA),A ;Tx mode off (state 0)
LD (IY+RSTA),A ;Rx state 0 (hunt)
RET
; XSKED - Schedule transmission, either frame or CWID only
XSKED:
DI
LD (IY+TSTA),1 ;Tx state = 1
LD C,(IY+TXDLY) ;Get TXDLY value
LD B,(IY+(TXDLY+1))
LD A,B ;Check for no delay
OR C ;Well?
JR Z,XSKED1 ;No delay, skip timer
PUSH IY ;Get structure base addr
POP DE ;Timer service argument
LD HL,TSERVE ;Where timer should call
LD A,(IY+CHAN) ;Get channel #
CALL SETTMR ;Set the timer
LD (IY+TIMRUN),1 ;Show timer running
XSKED1: CALL RTSON ;Start modem up
EI
RET
; CDS - DCD line status reporting subroutine
CDS:
LD C,(IY+CPORT) ;SIO control port
IN A,(C) ;Get ext status
BIT DCD,A ;Test DCD line
LD A,0 ;Assume off
RET Z
LD A,0FFH ;Flag it on
RET
SUBTTL 'Tx Buffer Empty Interrupt Service'
PAGE
; Transmitter buffer empty interrupt service.
; Action is as follows:
; State 0 (idle transmitter)
; Spurious interrupt -- ignore it.
; State 1 (waiting for CTS/timer)
; Spurious interrupt -- ignore it.
; State 2 (transmitting data)
; Call NEXTHO for data byte. If NEXTHO
; returns data, send to SIO. Otherwise,
; stuff dummy data to SIO. If end of
; transmission, state = 3, else 4.
; State 3 (end of frame)
; Call STFRM to re-start transmission.
; State = 2
; State 4 (first EOT fill byte)
; Send dummy data to SIO, state = 5.
; State 5 (second EOT fill byte)
; Send dummy data to SIO, state = 6.
; State 6 (end of transmission)
; Set RTS off, call HODONE to flag
; end of transmission, state = 0.
I.TBE:
LD A,(IY+TSTA) ;Get current state
INC A
DEC A ;Idle state (0)?
JR Z,SPURTI ;Yes, ignore int.
DEC A ;Waiting state (1)?
JR NZ,TXS2 ;No
SPURTI: LD C,(IY+CPORT) ;SIO Control port
LD A,RESTXI ;Reset tx interrupt
OUT (C),A
RET
TXS2: DEC A ;Transmitting state (2)?
JR NZ,TXS3 ;No
CALL NEXTHO ;Get next byte
OR A ;Is it a data byte?
JP M,TXBYTE ;Yes, send it
LD C,(IY+CPORT) ;SIO control port
LD A,RESTXI ;Reset the interrupt
OUT (C),A
LD (IY+TSTA),3 ;Assume end of frame
RET Z ;NEXTHO says end of frame
LD (IY+TSTA),4 ;NEXTHO says end of transmission
RET
TXBYTE: LD C,(IY+DPORT) ;SIO data port
OUT (C),B ;Send data byte
RET
PAGE
TXS3: DEC A ;Fill 1 state (3)?
JR NZ,TXS4 ;No
CALL STFRM ;Restart transmission
RET
TXS4: DEC A ;Fill 2 state (4)?
JR NZ,TXS5 ;No
LD (IY+TSTA),5 ;State = 5
LD B,0 ;Data for fill
JR TXBYTE ;Send fill
TXS5: DEC A ;Fill 2 state (5)?
JR NZ,TXTERM ;No
LD (IY+TSTA),6
LD B,0
JR TXBYTE
TXTERM: LD (IY+TSTA),0 ;Show us stopped
CALL RTSOFF ;Stop transmitting
CALL HODONE ;Report finish
RET
SUBTTL 'External/Status Interrupt Service'
PAGE
; External/status interrupt handler. Check to see if
; rx frame aborted or DCD lost. If so, kill rx frame
; by setting rx state to 0. Then, if the tx state is 0,
; return. Otherwise, tx is active, so we will
; check the TX underrun status. If underrun and tx state
; is 2, execute tx state 8 routine (terminataion).
; If no underrun error, vector through either the CTS true
; or CTS false state table, as appropriate.
I.EXT:
LD C,(IY+CPORT) ;SIO control port
IN A,(C) ;Get status register
LD B,RESEXT ;Reset external status
OUT (C),B
LD B,A ;Save status
AND MABORT+MDCD ;Mask all but abort, DCD
CP MDCD ;Status ok?
CALL NZ,RXTERM ;Terminate rx frame
LD A,B ;Get status back
LD B,(IY+TSTA) ;Get tx state
INC B ;Set to check
DEC B ;Tx state = 0?
RET Z ;Yes, nothing to do
PUSH AF ;Save status
BIT EOM,A ;Is underrun status?
JR Z,I.XT10 ;No
LD A,(IY+TSTA) ;Get tx state
CP 2 ;State 2 (data xfer)?
JR NZ,I.XT10 ;No
POP AF ;Clean stack
JP TXTERM ;Terminate xmsn
I.XT10: POP AF ;Get status into A
CHKTX: BIT CTS,A ;Is CTS on?
RET Z ;No, nothing to do
LD A,(IY+TIMRUN) ;Is timer running?
OR A
RET NZ ;Yes, can't do anything
LD A,(IY+TSTA) ;Get tx state
CP 1 ;Waiting for it?
JR Z,STFRM ;Yes, start the frame
RET
SUBTTL 'Internal Tx Subroutines'
PAGE
; STFRM - Starts transmission of frame.
; Call NEXTHO for data byte. If none, ensure that RTS
; is off and set tx state = 0. Otherwise, reset Tx
; CRC generator, send the data byte to the SIO and set
; tx state = 2.
STFRM:
LD C,(IY+CPORT) ;SIO control port
LD A,RESTCR ;Reset TX CRC
OUT (C),A
CALL NEXTHO ;Get that byte
LD (IY+TSTA),2 ;State = 2
LD C,(IY+DPORT) ;SIO data port
OUT (C),B ;Send the data
LD C,(IY+CPORT) ;SIO control port
LD A,RESEOM ;Reset Tx EOM status
OUT (C),A
RET
; RTSON - Turns RTS on
RTSON:
LD C,(IY+CPORT) ;SIO control port
LD A,5 ;Select WR 5
OUT (C),A
LD A,0EBH ;Set RTS true
OUT (C),A
RET
; RTSOFF - Turn RTS off
RTSOFF:
LD C,(IY+CPORT) ;SIO control port
LD A,5 ;Select WR 5
OUT (C),A
LD A,0E9H ;Set RTS false
OUT (C),A
RET
; TSERVE - Timer service
TSERVE:
PUSH DE ;Get data structure base
POP IY
LD (IY+TIMRUN),0 ;Show timer stopped
LD C,(IY+CPORT) ;SIO control register
IN A,(C) ;Get status
JP CHKTX ;Go check transmission
SUBTTL 'Rx Buffer Full Interrupt Service'
PAGE
; Receive buffer full interrupt routine. Get received
; char into B and exwcute based on receive state.
I.RBF:
LD C,(IY+DPORT) ;SIO data port
IN B,(C) ;Get received data byte
LD A,(IY+RSTA) ;Get rx state
INC A
DEC A ;Is rx state 0?
JR NZ,RS1 ;No
; Rx State 0, the idle state, is maintained until the first
; receive interrupt. Due to the fact that the SIO passes
; FCS as data, a one byte buffer is used to insure that FCS
; never gets passed to NEXTHI.
; Store received char in buffer, state = 1
LD (IY+CBUF),B ;Buffer received char
LD (IY+RSTA),1 ;Next state = 1
RET
RS1: DEC A ;Is rx state 1?
JR NZ,RS2
; Rx states 1 and 2 - Place the received char in the
; buffer, sending the current buffer char to NEXTHI.
; Set state = 2
LD A,0 ;Flag SOM to NEXTHI
JR GIVERX
RS2: LD A,0FFH ;Flag next data byte to NEXTHI
GIVERX: LD C,(IY+CBUF) ;Save buffer char
LD (IY+CBUF),B ;Buffer received char
LD B,C ;Get old buffer char
CALL NEXTHI ;Give to upper level sub
LD (IY+RSTA),2 ;Next state = 2
RET
PAGE
; Special receive interrupt routine. Occurs on error
; or end of frame. If in state 2 and no error,
; execute state 3 routine (valid EOM). If error status,
; terminate frame. Possible errors: CRC error, rx
; underrun, invalid residue code (not 8-bit boundry)
I.SRX:
LD C,(IY+CPORT) ;SIO control port
LD A,1 ;Set RR 1
OUT (C),A
IN A,(C) ;Get special rx status
LD B,A ;Save it
LD A,RESERR ;Reset error status
OUT (C),A
LD C,(IY+DPORT) ;SIO data port
IN A,(C) ;Get last FCS byte
LD A,B ;Get status
AND MEOF+MFERR+MOVR+MRES
;Save the important bits
CP MEOF+RES8 ;Proper end of frame?
JR NZ,RXTERM ;No, terminate frame
LD A,(IY+RSTA) ;We in state 2?
CP 2
LD A,1 ;NEXTHI final flag
CALL Z,NEXTHI ;Tell NEXTHI is a good one
RXTERM: LD (IY+RSTA),0 ;Reset to state 0
RET
PAGE
; External subroutine calls
NEXTHO:
LD L,(IY+NXTHO) ;Get NXTHO address
LD H,(IY+(NXTHO+1))
JP (HL)
NEXTHI:
LD L,(IY+NXTHI) ;Get NXTHI address
LD H,(IY+(NXTHI+1))
JP (HL)
HODONE:
LD L,(IY+ODONE) ;Get ODONE address
LD H,(IY+(ODONE+1))
JP (HL)
; Fixed data
; SIO initialization block.
SIOBI: DB 18H ;Reset SIO
DB 4 ;WR 4
DB 00100000B ;SDLC mode, x1 clock
DB 5 ;WR 5
DB 11101001B ;DTR on, RTS off
DB 3 ;WR 3
DB 11111001B ;8 bits, enables
DB 7 ;WR 7
DB 01111110B ;SDLC flag byte
DB 1 ;WR 1
DB 00011111B ;Enable rx, ext ints
SIOBIL EQU $-SIOBI
END