mirror of
https://github.com/livingcomputermuseum/Darkstar.git
synced 2026-04-20 09:46:12 +00:00
39 lines
32 KiB
Plaintext
39 lines
32 KiB
Plaintext
head 1.1;
|
||
branch 1.1.1;
|
||
access ;
|
||
symbols start:1.1.1.1 Xerox:1.1.1;
|
||
locks ; strict;
|
||
comment @;; @;
|
||
|
||
|
||
1.1
|
||
date 2001.08.12.22.22.26; author freier; state Exp;
|
||
branches 1.1.1.1;
|
||
next ;
|
||
|
||
1.1.1.1
|
||
date 2001.08.12.22.22.26; author freier; state Exp;
|
||
branches ;
|
||
next ;
|
||
|
||
|
||
desc
|
||
@@
|
||
|
||
|
||
|
||
1.1
|
||
log
|
||
@Initial revision
|
||
@
|
||
text
|
||
@{ File: [Iris]<WMicro>DLion>RS232CInterrupts.asm
|
||
Modification History:
|
||
JAC : 11-Nov-85 17:04:35 fix for continuous Xons/Xoffs
|
||
Dennis DEG : 1-Sep-84 17:10:49 Add copyright notice
|
||
Mike MAT : 29-Aug-84 22:49:50 fix to output Xon/Xoff after receiving an Xoff
|
||
Mike MAT : 23-Aug-84 18:14:10 fixed TxBufferPointer check after Xon
|
||
Mike MAT : 21-Aug-84 17:14:16 add EI in Xoff1 interrupt
|
||
Mike MAT : 13-Aug-84 6:22:54 Fix for saving completion code in RxAsyncSpecialInt and CheckFifoBoundary
|
||
Mike MAT : 27-Mar-84 9:49:41 Fix to flow control glitch
|
||
Mike MAT : 13-Jan-84 14:26:02 Incorporate DEG 's fixes for aborting when FifoOverflow and EXPort OverflowFlag.
|
||
Mike MAT : 3-Jan-84 15:03:49 Added Async Flow Control
|
||
Tom TXC : 17-May-83 14:44:40 Make sure only use 3 SIO interrupt bits
|
||
CrF CRF : 17-Nov-82 18:10:24: Fix FifoOverflow handling; move all stack POPs
|
||
before EIs to avoid potential stack overflow memory smash; change RxIllegalInt
|
||
and TxIllegalInt to press on rather than crash with MP 515.
|
||
Jim JXF : September 17, 1982 8:51 AM: Allow any block size in Async mode.
|
||
Jim JXF : May 25, 1982 3:56 PM
|
||
Jim JXF : April 13, 1982 11:32 AM: Created file.
|
||
}
|
||
|
||
{ Copyright (C) 1982, 1983, 1984 by Xerox Corporation. All rights reserved.}
|
||
|
||
|
||
Get "SysDefs"
|
||
Get "RS232CDefs"
|
||
Get "CommonDefs"
|
||
|
||
IMP AsyncTimerCounter ;From SIOSubs
|
||
IMP AsyncTimerStoppedFlag ;From SIOSubs
|
||
IMP GetByteCount ;From RS232CGet
|
||
IMP ErrorReport ;From Common
|
||
IMP RxFIFO ;From Buffer
|
||
IMP RxMaxFrameSize ;From BisyncInput
|
||
IMP StatusChangeFlag ;From RS232CGet
|
||
IMP TxBisyncStateSwitch ;From BisyncInterrupts
|
||
IMP TxUnderrunDetectedFlag ;From RS232CPut
|
||
|
||
EXP AsyncRS232CInterrupt
|
||
EXP AsyncTimerValue
|
||
EXP CharactersLeftInClientBuffer
|
||
EXP CharactersUntilBoundary
|
||
EXP CharLengthMask
|
||
EXP CharLengthMask1
|
||
EXP PrevAsyncDCD
|
||
EXP PrevCTS
|
||
EXP PrevSdlcDCD
|
||
EXP CurrentFrameToFillPtr
|
||
EXP CurrentFrameToSendPtr
|
||
EXP EndOfFrame
|
||
EXP ExitInterrupt
|
||
EXP FCState
|
||
EXP FifoStateSwitch
|
||
EXP FirstFrameToFillPtr
|
||
EXP FirstRxCharPtr
|
||
EXP FirstMaxFrameBoundary
|
||
EXP FlowControlFlag
|
||
EXP LastBufferFlag
|
||
EXP LastNewFrameAddressHigh
|
||
EXP LastNewFrameAddressLow
|
||
EXP LastTxBufferAddressHigh
|
||
EXP LastTxBufferAddressHigh1
|
||
EXP LastTxBufferAddressLow
|
||
EXP LastTxBufferAddressLow1
|
||
EXP MaxFrameSize
|
||
EXP NoMoreBytesToSend
|
||
EXP OutputXoff
|
||
EXP OutputXon
|
||
EXP OverflowFlag
|
||
EXP PutCompletedFlag
|
||
EXP PutFinishedSwitch
|
||
EXP RxAsyncDataInt
|
||
EXP RxAsyncExternalInt
|
||
EXP RxAsyncSpecialInt
|
||
EXP RxFifoState
|
||
EXP RxFifoEnd
|
||
EXP RxIllegalInt
|
||
EXP RxSdlcDataInt
|
||
EXP RxSdlcExternalInt
|
||
EXP RxSdlcSpecialInt
|
||
EXP SetLastBufferFlag
|
||
EXP StoreFrameHeader
|
||
EXP TxAsyncDataInt
|
||
EXP TxAsyncExternalInt
|
||
EXP TxBisyncExternalInt
|
||
EXP TxBufferPointer
|
||
EXP TxSdlcExternalInt
|
||
EXP SdlcFrameFlag
|
||
EXP SdlcRS232CInterrupt
|
||
EXP TerminateFrame
|
||
EXP TxIllegalInt
|
||
EXP XoffReceivedFlag
|
||
EXP XoffChar
|
||
EXP XonChar
|
||
;
|
||
{This is what a frame looks like:}
|
||
|
||
|
||
FrameKey:
|
||
EQU 0 ;# FrameValid => frame has been stored over
|
||
FrameReadyFlag:
|
||
EQU 1 ;#0 => frame is ready to send
|
||
FrameLastCharLow:
|
||
EQU 2
|
||
FrameLastCharHigh:
|
||
EQU 3 ;stored by interrupt routine
|
||
FrameCPAddrLow:
|
||
EQU 4 ;low byte of CP address
|
||
FrameCPAddrMid:
|
||
EQU 5 ;middle byte of CP address
|
||
FrameCPAddrHigh:
|
||
EQU 6 ;high byte of CP address
|
||
FrameSizeLow:
|
||
EQU 7 ;number of data bytes in frame
|
||
FrameSizeHigh:
|
||
EQU 8
|
||
FrameCommand:
|
||
EQU 9 ;WriteBlock command for CP micrrocode
|
||
FrameData:
|
||
EQU 10 ;First character of data
|
||
FrameValid EQU 7EH
|
||
;
|
||
AsyncRS232CInterrupt:
|
||
{ Come here in Async mode from Common when we get a RST 6.5 Interrupt from the Zilog SIO chip. Save state }
|
||
PUSH PSW
|
||
PUSH H
|
||
|
||
{Read the interruptVector to determine the cause of the interrupt. Multiply the vector by 2. This gives us a number which we can OR into the low bits of the jump table address. The jump table is in the Common so that we can assure its exact address and guarantee that the low 5 bits of the address are zero. }
|
||
MVI A,PointToWR2
|
||
OUT TxCont
|
||
IN TxCont ; Read Interrupt Vector
|
||
{added the following}
|
||
ANI 0EH ; just allow rightful three bits, 5/17/83
|
||
RLC ; Interupt Vector * 2
|
||
ORI 60H ; Low address is 60H
|
||
MOV L,A
|
||
MVI H,20H ;High address is 20H
|
||
PCHL ;Jump to JumpTable
|
||
|
||
{AsyncJumpTable: @@2060H
|
||
JMP TxAsyncDataInt ; When Vecter =0 Tx Buffer Empty
|
||
DB 0
|
||
JMP TxAsyncExternalInt ; When Vecter =2 Ex Stat
|
||
DB 0
|
||
JMP TxIllegalInt ; When Vecter =4 Rx Char
|
||
DB 0
|
||
JMP ExitInterrupt ; When Vecter =6 Sp Rx Cond
|
||
DB 0
|
||
JMP RxIllegalInt ; When Vecter =8 Tx Buffer Empty
|
||
DB 0
|
||
JMP RxAsyncExternalInt ; When Vecter =A Ex Stat
|
||
DB 0
|
||
JMP RxAsyncDataInt ; When Vecter =C Rx Char
|
||
DB 0
|
||
JMP RxAsyncSpecialInt ; When Vecter =E Sp Rx Cond
|
||
}
|
||
|
||
{The following interrupts should never happen, but occasionally they do, perhaps because of crosstalk on the DLion RS232 cable. Therefore, we just ignore them, rather than crash with an MP code. The one that seems to happen is RxIllegalInt. The counters are for debugging use, for instance of new cables.}
|
||
|
||
RxIllegalInt:
|
||
LXI H,RxIllegalIntCount
|
||
INR M ;Increment illegal interrupt counter
|
||
JMP ExitInterrupt
|
||
TxIllegalInt:
|
||
LXI H,TxIllegalIntCount
|
||
INR M ;Increment illegal interrupt counter
|
||
JMP ExitInterrupt
|
||
|
||
RxIllegalIntCount:
|
||
DB 0
|
||
TxIllegalIntCount:
|
||
DB 0
|
||
;
|
||
TxAsyncDataInt:
|
||
{Come here when we get an interrupt for Tx Buffer Empty. See if the last character has already been sent.}
|
||
DB opMVIA ;A ¬ XoffReceivedFlag
|
||
XoffReceivedFlag:
|
||
DB 0
|
||
ORA A ;IF XoffReceivedFlag
|
||
JNZ ResetTxInterrupt ;THEN stop sending data
|
||
|
||
TestTxEnd:
|
||
LHLD TxBufferPointer ;ELSE IF ~lastCharacter sent
|
||
DCX H
|
||
LDA LastTxBufferAddressLow
|
||
CMP L
|
||
JNZ SendNextAsyncCharacter
|
||
|
||
LDA LastTxBufferAddressHigh
|
||
CMP H
|
||
JNZ SendNextAsyncCharacter ; THEN send next character
|
||
|
||
PutCompleted:
|
||
{We already sent the last character.}
|
||
MVI A,ResetTxIntPending ;ELSE putCompleted
|
||
OUT TxCont
|
||
STA PutCompletedFlag
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
ResetTxInterrupt;
|
||
LDA FCState
|
||
ORI StoppedTx
|
||
STA FCState
|
||
MVI A,ResetTxIntPending
|
||
OUT TxCont
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
SendNextAsyncCharacter:
|
||
INX H
|
||
MOV A,M ;Get byte from buffer
|
||
OUT TxData ;Send byte
|
||
INX H ;Point to next character
|
||
SHLD TxBufferPointer ;Update buffer pointer
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
;
|
||
RxAsyncDataInt:
|
||
{ Come here when the SIO chip has another character of data ready. Reset the Async timer.}
|
||
DB opLXIH ;HL ¬ AsyncTimerValue
|
||
AsyncTimerValue:
|
||
DW 0
|
||
SHLD AsyncTimerCounter ;Set iteration counter
|
||
MVI A,0B0H ;timer channel 2, mode 0, binary
|
||
OUT TimerMode
|
||
LXI H,TimerCount2+8000H
|
||
MVI M,0FEH ;Send low byte of 1840 decimal
|
||
MVI M,47H ;Send high byte
|
||
XRA A
|
||
STA AsyncTimerStoppedFlag
|
||
|
||
{Fetch the next character and mask it, depending on the length of the character. Store the character, increment the pointer to the next character position.}
|
||
IN RxData ;A ¬ RxData
|
||
DB opANI ;A ¬ RxData AND CharLengthMask
|
||
CharLengthMask:
|
||
DB 0
|
||
STAX B ;Store character in Fifo
|
||
INX B
|
||
|
||
{Check for flow control, if true look for receiving an xoff/xon character and set appropriate flags. If no xon/xoff charater then determine if high water mark has been reached in the buffer. Because of the buffering scheme, the high water mark(HWM) is set to MaxFrameSize + 138. This is not looked for until there is less then 2*MaxFrameSize left in the buffer. The LastBufferFlag is set when this state has occured}
|
||
MOV L,A ;Temporary save character
|
||
LDA FlowControlFlag ;IF ~FlowControl
|
||
ORA A
|
||
JZ CheckClientSpace ;go check space left in client's buffer
|
||
|
||
MOV A,L ;ELSE restore received character
|
||
DB opLXIH ;H¬XonChar, L¬XoffChar
|
||
XoffChar:
|
||
DB 0
|
||
XonChar:
|
||
DB 0
|
||
CMP L ; IF ~Xoff Char THEN
|
||
JNZ TestXon ; go test for Xon
|
||
DCX B ; ELSE
|
||
STA XoffReceivedFlag ;set XoffReceived Flag
|
||
JMP Out ; return
|
||
|
||
TestXon:
|
||
CMP H ;IF ~Xon Char THEN
|
||
JNZ TestSpaceLeft ; test space left
|
||
DCX B ;ELSE
|
||
LDA XoffReceivedFlag
|
||
ORA A ;Check if previously Xoff
|
||
JZ Out ;If previously Xoff
|
||
XRA A ;then clear Xoff flag and
|
||
STA XoffReceivedFlag;trigger Tx buffer empty int
|
||
XRA A ; reset XoffReceivedFlag
|
||
STA XoffReceivedFlag
|
||
LDA PutCompletedFlag
|
||
ORA A ;IF ~PutCompleted
|
||
JNZ Out
|
||
|
||
SendChar:
|
||
LDA FCState
|
||
ANI -StoppedTx-1
|
||
STA FCState
|
||
JMP TestTxEnd
|
||
|
||
TestSpaceLeft:
|
||
PUSH D
|
||
CALL CheckFifoBoundary
|
||
POP D
|
||
|
||
CheckClientSpace: ;ELSE Null
|
||
{See if we are have filled the Iocb.}
|
||
DB opLXIH ;HL ¬ CharactersUntilBoundary
|
||
CharactersLeftInClientBuffer:
|
||
DW 0
|
||
DCX H ;Decrement count
|
||
MOV A,H
|
||
ORA L
|
||
JZ ClientBufferFull
|
||
SHLD CharactersLeftInClientBuffer
|
||
|
||
{See if we are at the end of a block.}
|
||
DB opLXIH ;HL ¬ CharactersUntilBoundary
|
||
CharactersUntilBoundary:
|
||
DW 0
|
||
DCX H ;Decrement boundary count
|
||
MOV A,H
|
||
ORA L
|
||
JZ BlockFull
|
||
SHLD CharactersUntilBoundary
|
||
|
||
Out:
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
ClientBufferFull:
|
||
{Come here if this character has filled the client's buffer. End this frame, mark it EOF, and start a new frame. This is a normal completion for Asynchronous mode. In asynchronous mode, a frame ends either when it fills the IOCB or when we get a timeout, whichever comes first.}
|
||
PUSH D ;Save DE
|
||
MVI E,80H ;Set EndOfFrame
|
||
JMP TerminateFrame
|
||
|
||
BlockFull:
|
||
{Come here if this character has filled the block. This happens when a client's buffer is larger than our input buffer. End this frame, mark it end of block, and start a new frame. The Get routine will send this data to the CP.}
|
||
PUSH D ;Save DE
|
||
MVI E,4 ;Set EndOfBlock
|
||
JMP TerminateBlock
|
||
;
|
||
RxAsyncExternalInt:
|
||
{ Come here when we get an External/Status interrupt. Register RR0 indicates the cause of the interrupt:
|
||
|
||
80: 10000000 Break Asynchronous
|
||
08: 00001000 Data Carrier Detect (DCD)}
|
||
|
||
IN RxCont ;Read RR0
|
||
MOV H,A ;Save RR0 in H
|
||
ANI DCD
|
||
DB opCPI ;Compare to previous DCD
|
||
PrevAsyncDCD:
|
||
DB 0
|
||
STA PrevAsyncDCD ;Save current DCD
|
||
MVI A,ResetExternalStatusInterrupts
|
||
OUT RxCont
|
||
JZ TestRxAsyncBreak
|
||
|
||
{Continue if DataCarrierDetect has changed state. Notify the Get loop so that it will do a NakedNotify. We store ResetExternalStatusInterrupts in StatusChangeFlag.}
|
||
STA StatusChangeFlag
|
||
|
||
TestRxAsyncBreak:
|
||
ORA H ;RR0 will be negative if Abort bit is set
|
||
JM AsyncBreakAbortDetected
|
||
|
||
POP H
|
||
POP PSW
|
||
EI ;Exit Interrupt
|
||
RET
|
||
|
||
AsyncBreakAbortDetected:
|
||
{We got a Break/Abort. We end the current frame and return it to the CP with aborted status in the Iocb. Set FrameCompletionCode to Aborted. NOTE: If this frame does not contain any characters, we will not send any. We check for this at StartFrameTransfer.}
|
||
PUSH D ;Save DE
|
||
MVI E,1 ;Set CompletionCode to Aborted
|
||
|
||
TerminateFrame:
|
||
{We get called from Get when we get a timeout or an abort. E = CompletionCode: 1 for Aborted or 80H for Timeout. End this frame and start a new one.}
|
||
LHLD GetByteCount
|
||
SHLD CharactersLeftInClientBuffer
|
||
|
||
TerminateBlock:
|
||
{RxMaxFrameSize is the number of characters until our next boundary.}
|
||
LHLD RxMaxFrameSize
|
||
SHLD CharactersUntilBoundary
|
||
JMP EndOfFrame
|
||
;
|
||
RxAsyncSpecialInt:
|
||
{ Come here when we get a Special interrupt. Register RR1 indicates the cause of the interrupt:
|
||
|
||
40: 01000000 Framing error in Async
|
||
20: 00100000 RxOverrun
|
||
10: 00010000 Parity error
|
||
|
||
A Framing Error occurs if the character is assembled without any stop bits. This bit is set only for the character on which it occurred.
|
||
|
||
RxOverrun means data is being overwritten because the channel's three-byte receiver buffer is full and a new character is being received.
|
||
|
||
A Parity Error occurs when the parity bit of the character does not match with the programmed parity. Once this bit is set, it remains set until the Error Reset Command is given.}
|
||
|
||
PUSH D ;Save DE
|
||
{Read the character that caused the interrupt and place it in the RxFifo as we would a normal character.}
|
||
IN RxData ;A ¬ RxData
|
||
DB opANI ;A ¬ RxData AND CharLengthMask
|
||
CharLengthMask1:
|
||
DB 0
|
||
STAX B ;Store character in Fifo
|
||
INX B
|
||
LXI H,8000H+RxCont ;Point to RxCont register
|
||
MVI M,PointToWR1
|
||
MOV A,M ;Read CompletionCode from RR1
|
||
ANI 0F0H
|
||
MOV E,A ;Save CompletionCode in E
|
||
MVI M,ErrorReset
|
||
|
||
{RxMaxFrameSize is the number of characters until our next boundary.}
|
||
LHLD RxMaxFrameSize
|
||
SHLD CharactersUntilBoundary
|
||
|
||
{Check if need to send Xon/Xoff}
|
||
LDA FlowControlFlag ;IF ~FlowControl
|
||
ORA A
|
||
JZ EndOfFrame
|
||
PUSH D ;Save completion code
|
||
CALL CheckFifoBoundary
|
||
POP D ;restore completion code
|
||
JMP EndOfFrame
|
||
;
|
||
SdlcRS232CInterrupt:
|
||
{ Come here in Sdlc mode from the EXEC when we get a RST 6.5 Interrupt from the Zilog SIO chip. Save state }
|
||
PUSH PSW
|
||
PUSH H
|
||
|
||
{Read the interruptVector to determine the cause of the interrupt. Multiply the interrupt vector by 2. This gives us a number which we can OR into the low bits of the jump table address. The jump table is in the Common so that we can assure its exact address and guarantee that the low 5 bits of the address are zero.}
|
||
MVI A,PointToWR2
|
||
OUT TxCont
|
||
IN TxCont ; Read Interrupt Vector
|
||
{removed ORA A, replaced by the following}
|
||
ANI 0EH ; just allow rightful three bits, 5/17/83
|
||
|
||
PutFinishedSwitch:
|
||
{This opcode will be changed to a JMP when the last character has been sent. The jump table will then pass control to NoMoreBytesToSend.}
|
||
DB opJNZ
|
||
DW BranchOnSdlcInterruptVector
|
||
|
||
TxSdlcDataInt:
|
||
{Come here when we get an interrupt for Tx Buffer Empty. Send another character to the SIO chip.}
|
||
DB opLXIH ;HL ¬ TxBufferPointer
|
||
TxBufferPointer:
|
||
DW 0
|
||
|
||
{We want to send the character and then test for last so as to service the interrupt as fast as possible.}
|
||
MOV A,M ; get byte from buffer
|
||
OUT TxData ; send byte
|
||
DB opMVIA ;A ¬ LastTxBufferAddressLow
|
||
LastTxBufferAddressLow:
|
||
DB 0
|
||
CMP L
|
||
JZ LastTxBufferAddressLowEqual
|
||
|
||
INX H ; increment buffer pointer
|
||
SHLD TxBufferPointer ; update buffer pointer
|
||
|
||
ExitInterrupt:
|
||
{Come here to restore state and exit. }
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
LastTxBufferAddressLowEqual:
|
||
DB opMVIA ;A ¬ LastTxBufferAddressHigh
|
||
LastTxBufferAddressHigh:
|
||
DB 0
|
||
CMP H
|
||
JZ LastByteToSend
|
||
|
||
INX H ; increment buffer pointer
|
||
SHLD TxBufferPointer ; update buffer pointer
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
LastByteToSend:
|
||
{We have just sent the last byte. The next time we get a TxData interrupt, we will JMP to NoMoreBytesToSend.}
|
||
MVI A,opJMP
|
||
STA PutFinishedSwitch
|
||
STA PutCompletedFlag
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
NoMoreBytesToSend:
|
||
MVI A,ResetTxIntPending
|
||
OUT TxCont ; disable this interrupt & exit
|
||
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
;
|
||
|
||
BranchOnSdlcInterruptVector:
|
||
RLC ;Interupt Vector * 2
|
||
MVI H,20H ;High address is 20H
|
||
ORA H ;Low address is 20H
|
||
MOV L,A
|
||
PCHL ;Jump to JumpTable
|
||
|
||
{SdlcJumpTable: @@2060H
|
||
JMP NoMoreBytesToSend ; When Vecter =0 Tx Buffer Empty
|
||
DB 0
|
||
JMP TxSdlcExternalInt ; When Vecter =2 Ex Stat
|
||
DB 0
|
||
JMP TxIllegalInt ; When Vecter =4 Rx Char
|
||
DB 0
|
||
JMP ExitInterrupt ; When Vecter =6 Sp Rx Cond
|
||
DB 0
|
||
JMP RxIllegalInt ; When Vecter =8 Tx Buffer Empty
|
||
DB 0
|
||
JMP RxSdlcExternalInt ; When Vecter =A Ex Stat
|
||
DB 0
|
||
JMP RxSdlcDataInt ; When Vecter =C Rx Char
|
||
DB 0
|
||
JMP RxSdlcSpecialInt ; When Vecter =E Sp Rx Cond
|
||
}
|
||
;
|
||
TxSdlcExternalInt:
|
||
TxAsyncExternalInt:
|
||
TxBisyncExternalInt:
|
||
{Tx Sdlc External Interrupt processing routine
|
||
Come here if we get Break, Clear To Send, Data Carrier Detect, or Tx Underrun. Notify the Sdlc Put Loop if we get underrun.}
|
||
IN TxCont
|
||
MOV H,A ;Save RR0 in H
|
||
ANI TxUnderrun
|
||
STA TxUnderrunDetectedFlag
|
||
|
||
{Test for change in Clear To Send.}
|
||
MOV A,H
|
||
ANI CTS
|
||
DB opCPI ;Compare to previous CTS
|
||
PrevCTS:
|
||
DB 0
|
||
STA PrevCTS ;Save current CTS
|
||
MVI A,ResetExtStatusInterrupts
|
||
OUT TxCont
|
||
JZ NoChangeInCTS
|
||
|
||
STA StatusChangeFlag
|
||
|
||
NoChangeInCTS:
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
;
|
||
RxSdlcDataInt:
|
||
{Well here it is folks! This is what we have all been waiting for. This is why Domino never uses registers B and C. They are reserved for NextRxCharPtr so that SDLC will run at 56KB in interrupt mode.
|
||
|
||
Fetch the next character and store the character, increment the pointer to the next character position. Note that we do not check for any boundary. We depend on the EndOfFrame interrupt to stop the receiver. At 56KB, we don't have time to check the boundary.}
|
||
|
||
{Set SdlcFrameFlag so we know we're in a frame if we get an abort. A = 18H from the InterruptVector*2. This seems to waste 13 cycles, but Abort is the longest interrupt, and it will cause Overruns if we try a longer method of finding out if we are in a frame.}
|
||
STA SdlcFrameFlag
|
||
IN RxData ;A ¬ RxData
|
||
STAX B ;Store character in Fifo
|
||
INX B
|
||
POP H
|
||
POP PSW ; Restore Registers
|
||
EI
|
||
RET
|
||
;
|
||
RxSdlcExternalInt:
|
||
{ Come here when we get an External/Status interrupt. Register RR0 indicates the cause of the interrupt:
|
||
|
||
80: 10000000 Break
|
||
08: 00001000 Data Carrier Detect (DCD)}
|
||
|
||
IN RxCont ;Read RR0
|
||
MOV H,A ;Save RR0 in H
|
||
ORA H
|
||
JP TestSdlcStateChange
|
||
|
||
{We got a Break/Abort. Check to see if we are processing a frame. Breaks detected when the SIO is not synchronized to the data stream are not interesting.}
|
||
DB opMVIA ;A ¬ SdlcFrameFlag
|
||
SdlcFrameFlag:
|
||
DB 0
|
||
ORA A
|
||
JZ TestSdlcStateChange
|
||
|
||
{If we are in a frame, we end the current frame and return it to the CP with aborted status in the Iocb. Set FrameCompletionCode to Aborted. NOTE: If this frame does not contain any characters, we will not send any. We check for this at StartFrameTransfer.}
|
||
PUSH D ;Save DE
|
||
MVI E,1 ;Set CompletionCode to Aborted
|
||
JMP EndOfFrame
|
||
|
||
TestSdlcStateChange:
|
||
MOV A,H ;A ¬ RR0
|
||
ANI DCD
|
||
DB opCPI ;Compare to previous DCD
|
||
PrevSdlcDCD:
|
||
DB 0
|
||
STA PrevSdlcDCD ;Save current DCD
|
||
MVI A,ResetExternalStatusInterrupts
|
||
OUT RxCont
|
||
JZ ExitSdlcExternalInt
|
||
|
||
{DataCarrierDetect has changed state. Notify the Get loop so that it will do a NakedNotify. We store ResetExternalStatusInterrupts in StatusChangeFlag.}
|
||
STA StatusChangeFlag
|
||
|
||
ExitSdlcExternalInt:
|
||
POP H
|
||
POP PSW
|
||
EI ;Exit Interrupt
|
||
RET
|
||
;
|
||
RxSdlcSpecialInt:
|
||
{ Come here when we get a Special interrupt. Register RR1 indicates the cause of the interrupt:
|
||
|
||
80: 10000000 End Of Frame
|
||
40: 01000000 CRC error
|
||
20: 00100000 RxOverrun
|
||
10: 00010000 Parity error
|
||
|
||
RxOverrun means data is being overwritten because the channel's three-byte receiver buffer is full and a new character is being received.
|
||
|
||
A Parity Error occurs when the parity bit of the character does not match with the programmed parity. Once this bit is set, it remains set until the Error Reset Command is given.}
|
||
|
||
PUSH D ;Save DE
|
||
|
||
{Read the character that caused the interrupt and place it in the RxFifo as we would a normal character.}
|
||
IN RxData ;A ¬ RxData
|
||
STAX B ;Store character in Fifo
|
||
INX B
|
||
LXI H,8000H+RxCont ;Point to RxCont register
|
||
MVI M,PointToWR1
|
||
MOV A,M ;Read CompletionCode from RR1
|
||
ANI 0F0H ;Mask off CRC residue
|
||
MOV E,A ;Save CompletionCode in E
|
||
MVI M,ErrorReset
|
||
|
||
;
|
||
{This is the Get Fifo processing system. The interrupt routine puts characters into the Fifo, and the Get routine removes one frame at a time. Each time a frame is ready, the Fifo routine notifies the Get routine by posting a completion code in the frame header. The interrupt routine fills a frame and sets the FrameCompletionFlag # 0 when a frame is ready to send. The interrupt routine stores the address of the last character stored + 1 in FrameLastChar.
|
||
|
||
We never start a new frame unless there is room in the Fifo for the maximum frame size + the size of the frame header. RxMaxFrameSize contains the maximum frame size. We get an overflow when there is no room in the Fifo for a new frame.
|
||
|
||
The first frame begins at RxFifo. The next frame begins at the next address following the first frame. If the following calculation is negative, we need to start a new frame at the beginning of the RxFifo: LastNewFrameAddress - NextFrameToFillPtr.}
|
||
|
||
{The Fifo has two states: Open and Closed. The Fifo is in the Open state when its boundary is the end of the Fifo. The Fifo is in the Closed state when its boundary is the next frame to send. In the Closed state, we have to be careful not to run into the next frame to send. It is in the Closed state that we are in danger of overflow. An overflow condition occurs when there is no room for a maximum size frame.
|
||
|
||
The Fifo starts in the Open state. We pass from the Open state to the Closed state when the interrupt routine wraps around and begins a new frame to fill at the beginning of the Fifo. We pass from the Closed state to the Open state when the Get routine wraps around and begins a new frame to send at the beginning of the Fifo.}
|
||
|
||
|
||
EndOfFrame:
|
||
{Come here when a frame has terminated. E = CompletionCode. BC points to the last character stored + 1. We have satisfied the Rx interrupt condition. Since this is EndOfFrame, we won't have to worry about another input character for a while, but we do have to worry about the transmit buffer becoming empty. This is a good time to check for it.}
|
||
MVI A,PointToWR2
|
||
OUT TxCont
|
||
IN TxCont ; Read Interrupt Vector
|
||
ORA A
|
||
JZ HandleTxDataInEOF
|
||
|
||
StoreFrameHeader:
|
||
{Enter here for Bisync end of frame.}
|
||
DB opLXIH ;HL ¬ CurrentFrameToFillPtr
|
||
CurrentFrameToFillPtr:
|
||
DW 0 ;HL points to CompletionCode
|
||
|
||
{The CompletionCode is in E. OR this with the fifo OverflowFlag in case this frame already had a fifo overflow.}
|
||
DB opMVIA ;A ¬ OverflowFlag
|
||
OverflowFlag:
|
||
DB 0 ;0 => no overflow, 2 => overflow
|
||
ORA E
|
||
MOV M,A ;Store CompletionCode
|
||
XRA A ;WARNING! Note side effect on FifoStateSwitch below
|
||
STA OverflowFlag ;Turn off fifo overflow flag for next time
|
||
INX H ;Point to count field of Frame
|
||
MOV M,C ;Store low pointer to last char
|
||
INX H ;Point to count field high of frame
|
||
MOV M,B ;Store high pointer to last char
|
||
|
||
{Now initialize the NextFrameToFill depending on the state of the Fifo: Open or Closed. The following op code will be JMP if the Fifo State is Closed, or JNZ if the Fifo State is Open. Because of the XRA instruction above, the ConditionCode will always be = 0 when we come here. When the Fifo wraps around in the Get routine, we set the Switch to opJNZ for Open. When the Fifo wraps around in the interrupt routine, we set the Switch to opJMP for Closed.}
|
||
FifoStateSwitch:
|
||
DB opJNZ
|
||
DW FifoClosed
|
||
|
||
FifoOpen:
|
||
{JNZ will always fall through when the State is Open. Come here if the next frame to send is behind us. This means we have until the end of the Fifo for another frame. See if we have enough room in the Fifo to start another frame. If the following calculation is negative, we have to start the next frame at the beginning of the Fifo: LastNewFrameAddress - NextFrameToFillPtr.}
|
||
|
||
DB opMVIA ;A ¬ LastNewFrameAddressLow
|
||
LastNewFrameAddressLow:
|
||
DB 0
|
||
SUB C
|
||
DB opMVIA ;A ¬ LastNewFrameAddressHigh
|
||
LastNewFrameAddressHigh:
|
||
DB 0
|
||
SBB B
|
||
JM StartFirstAsyncFrame
|
||
|
||
{Continue if we have room for another frame. Now we can initialize CurrentFrameToFillPtr and BC (NextRxCharPtr). Set HL to point to new frame.}
|
||
MOV D,B
|
||
MOV E,C ;DE ¬ CurrentFrameToFillPtr
|
||
LXI H,FrameData
|
||
DAD D ;HL ¬ new NextRxCharPtr
|
||
XCHG ;HL ¬ CurrentFrameToFillPtr
|
||
MOV B,D
|
||
MOV C,E ;BC ¬ NextRxCharPtr
|
||
MVI M,FrameValid ;Set FrameValid
|
||
INX H
|
||
SHLD CurrentFrameToFillPtr
|
||
XRA A
|
||
MOV M,A ;Turn off CompletionCode
|
||
STA SdlcFrameFlag
|
||
|
||
DB opMVIA ;A ¬ FlowControlFlag
|
||
FlowControlFlag:
|
||
DB 0
|
||
ORA A
|
||
CNZ SetLastBufferFlag
|
||
|
||
POP D ;Restore DE
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
StartFirstAsyncFrame:
|
||
{Come here to begin a new frame at the beginning of the Fifo. First, be sure we have room to start a new frame at the beginning of the Fifo. We calculate: CurrentFrameToSendPtr - (FirstFrameToFillPtr + MaxFrameSize). If this is negative, we have an overflow condition.}
|
||
LHLD CurrentFrameToSendPtr
|
||
DB opLXID ;DE ¬ FirstMaxFrameBoundary
|
||
FirstMaxFrameBoundary:
|
||
DW 0
|
||
MOV A,L
|
||
SBB E
|
||
MOV A,H
|
||
SBB D
|
||
JM FifoOverflow
|
||
|
||
{Continue if we have room to start a new frame. Now we can initialize the FifoState to Closed.}
|
||
MVI A,opJMP
|
||
STA FifoStateSwitch
|
||
STA RxFifoState
|
||
DB opLXIB ;BC ¬ FirstRxCharPtr
|
||
FirstRxCharPtr:
|
||
DW 0
|
||
DB opLXIH ;HL ¬ FirstFrameToFillPtr
|
||
FirstFrameToFillPtr:
|
||
DW 0
|
||
MVI M,FrameValid ;Set FrameValid
|
||
INX H
|
||
SHLD CurrentFrameToFillPtr
|
||
XRA A
|
||
MOV M,A ;Turn off CompletionCode
|
||
STA SdlcFrameFlag
|
||
|
||
LDA FlowControlFlag
|
||
ORA A
|
||
CNZ SetLastBufferFlag
|
||
|
||
POP D
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
|
||
FifoClosed:
|
||
{BC = NextFrameToFillPtr. Test to see that we do not overflow the Fifo. We calculate: CurrentFrameToSendPtr - (NextFrameToFillPtr + MaxFrameSize) If this is negative, we have an overflow condition. MaxFrameSize is the size specified in the client's IOCB + FrameData.}
|
||
DB opLXID ;DE ¬ CurrentFrameToSendPtr
|
||
CurrentFrameToSendPtr:
|
||
DW 0
|
||
DB opLXIH ;DE ¬ MaxFrameSize
|
||
MaxFrameSize:
|
||
DW 0
|
||
DAD B ;HL ¬ MaxFrameSize+NextFrameToFillPtr
|
||
MOV A,E
|
||
SUB L ;Subtract from CurrentFrameToSendPtr
|
||
MOV A,D
|
||
SBB H
|
||
JM FifoOverflow
|
||
|
||
{Continue if we have room to start a new frame. Now we can initialize CurrentFrameToFillPtr.}
|
||
MOV D,B
|
||
MOV E,C ;DE ¬ CurrentFrameToFillPtr
|
||
LXI H,FrameData
|
||
DAD D ;HL ¬ new NextRxCharPtr
|
||
XCHG ;HL ¬ CurrentFrameToFillPtr
|
||
MOV B,D
|
||
MOV C,E ;BC ¬ NextRxCharPtr
|
||
MVI M,FrameValid ;Set FrameValid
|
||
INX H
|
||
SHLD CurrentFrameToFillPtr
|
||
XRA A
|
||
MOV M,A ;Turn off CompletionCode
|
||
STA SdlcFrameFlag
|
||
|
||
LDA FlowControlFlag
|
||
ORA A
|
||
CNZ SetLastBufferFlag
|
||
|
||
POP D
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
;
|
||
FifoOverflow:
|
||
{We don't have room to start a new frame. We will store the next frame right over the current frame. Set CompletionCode back to empty so the GetLoop won't think this frame is ready. When the next frame completes, we will OR the CompletionCode with OverflowFlag to signal the loss of this frame to the GetLoop.}
|
||
MVI A,FifoOverflowed
|
||
STA OverflowFlag ;Note overflow for next time through EndOfFrame
|
||
LHLD CurrentFrameToFillPtr
|
||
{This is pre-Klamath 11.0g code
|
||
XRA A
|
||
MOV M,A ;Turn off CompletionCode
|
||
}
|
||
{Instead of simply clearing CompletionCode, which gets us into an infinite loop during aborts we will simply clear EndOfFrame and FifoOverflow. 4-Jan-84}
|
||
MOV A,M ;Load Old CompletionCode
|
||
ANI 1 ;Mask off all but abort
|
||
MOV M,A ;Restore CompletionCode
|
||
XRA A ;Clear the SdlcFrameFlag
|
||
|
||
STA SdlcFrameFlag
|
||
LXI D,FrameData-1
|
||
DAD D
|
||
MOV B,H
|
||
MOV C,L
|
||
POP D
|
||
POP H
|
||
POP PSW
|
||
EI ;Enable interrupts
|
||
RET
|
||
;
|
||
HandleTxDataInEOF:
|
||
{See if the last character has been sent. If the last byte has already been sent, we don't have to worry about clearing the interrupt.}
|
||
DB opMVIA ;A ¬ PutCompletedFlag
|
||
PutCompletedFlag:
|
||
DB 0FFH ;Initialized to TRUE since no PUTS in progress
|
||
ORA A
|
||
JNZ StoreFrameHeader
|
||
|
||
LHLD TxBufferPointer
|
||
MOV A,M ;Get character from buffer
|
||
OUT TxData ;send byte
|
||
DB opMVIA ;A ¬ LastTxBufferAddressLow
|
||
LastTxBufferAddressLow1:
|
||
DB 0
|
||
CMP L
|
||
JNZ UpdateTxBufferPointer
|
||
|
||
DB opMVIA ;A ¬ LastTxBufferAddressHigh
|
||
LastTxBufferAddressHigh1:
|
||
DB 0
|
||
CMP H
|
||
JNZ UpdateTxBufferPointer
|
||
|
||
{We have just sent the last byte. The next time we get a TxData interrupt, we will JMP to NoMoreBytesToSend.}
|
||
MVI A,opJMP
|
||
STA PutFinishedSwitch
|
||
STA PutCompletedFlag
|
||
JMP StoreFrameHeader
|
||
|
||
UpdateTxBufferPointer:
|
||
INX H ; increment buffer pointer
|
||
SHLD TxBufferPointer ; update buffer pointer
|
||
JMP StoreFrameHeader
|
||
|
||
;
|
||
SetLastBufferFlag:
|
||
{This subroutine which sets or clears the Last buffer flag assumes that the CurrentFrameToFillPtr (CFTF) is in the HL registers and the RxFifoState instruction has been set correctly for when the Fifo is open or Closed. (See description of the Get Fifo processing ). The routine implements the following algorithm for setting/clearing the LastBufferFlag.
|
||
|
||
IF (CurrentFrameToSendPtr<=(CurrentFrameToFillPtr+(2*MaxFrameSize)) AND fifoState = Closed)
|
||
OR (CurrentFrameToSendPtr<FirstFrameBoundary+138 AND
|
||
RxFifoEnd<=(CurrentFrameToFillPtr+(2*MaxFrameSize)) AND fifoState = Open)
|
||
THEN LastBufferFlag ¬ TRUE
|
||
ELSE LastBufferFlag ¬ FALSE;
|
||
|
||
}
|
||
XCHG
|
||
LHLD MaxFrameSize
|
||
DAD H
|
||
DAD D ;HL ¬ CFTF + 2*MaxFrameSize
|
||
XRA A
|
||
RxFifoState:
|
||
DB opJNZ ;determine if Open or Closed
|
||
DW CloseState
|
||
OpenState:
|
||
DB opLXID ;D ¬ RxFifoEnd
|
||
RxFifoEnd:
|
||
DW 0
|
||
MOV A,L ;If HL-RxfifoEnd<0 THEN clearFlag
|
||
SUB E
|
||
MOV A,H
|
||
SBB D
|
||
JM ClearFlag
|
||
LHLD FirstMaxFrameBoundary
|
||
LXI D,138 ;If (FirstMaxFrameBoundary+138
|
||
DAD D ; - CurrentFrameToSendPt) < 0
|
||
;THEN clear LastBufferFlag
|
||
|
||
CloseState:
|
||
XCHG
|
||
LHLD CurrentFrameToSendPtr
|
||
MOV A,E ;IF (DE-CurrentFrameToSendPtr)<0
|
||
SUB L
|
||
MOV A,D
|
||
SBB H
|
||
JM ClearFlag ;THEN clear LastBufferFlag
|
||
CMA ;ELSE set LastBufferFlag
|
||
STA LastBufferFlag
|
||
RET
|
||
|
||
ClearFlag:
|
||
XRA A
|
||
STA LastBufferFlag
|
||
RET
|
||
;
|
||
CheckFifoBoundary:
|
||
DB opMVIA ;A ¬ LastBufferFlag
|
||
LastBufferFlag:
|
||
DB 0 ;IF LastBufferFlag
|
||
ORA A
|
||
RZ
|
||
LDA FCState ;AND ~(sendingXoff | XoffSent)
|
||
ANI SendingXoff+XoffSent
|
||
RNZ
|
||
LHLD CurrentFrameToSendPtr ;THEN IF ( BC<cfts<=(BC+HWM) )
|
||
MOV A,L
|
||
SUB C
|
||
MOV L,A
|
||
MOV A,H
|
||
SBB B ;note effect below
|
||
MOV H,A
|
||
XCHG
|
||
LHLD HighWaterMark
|
||
JP ClosedFifoState ;From SBB instruction above
|
||
OpenFifoState: ;OR IF (BC<RXFIFOEnd<=(BC+HWM) )
|
||
DAD B
|
||
XCHG
|
||
LHLD RxFifoEnd
|
||
XCHG
|
||
|
||
ClosedFifoState:
|
||
MOV A,L
|
||
SUB E
|
||
MOV A,H
|
||
SBB D
|
||
RM ; THEN send XoffChar
|
||
|
||
{The following are the routines are called to send an Xon or Xoff char. Because they modify interrupt vector addresses and the FCState variable, interrupts must be disabled before calling these routines.
|
||
|
||
CAUTION: These routines make reference to absolute address 2060H, which is the address of the AsyncJumpTable defined in Common.asm. }
|
||
|
||
OutputXoff:
|
||
LDA PutCompletedFlag ;IF ~PutCompleted
|
||
ORA A
|
||
JNZ NoTxOut
|
||
LDA FCState
|
||
ANI StoppedTx ;AND ~TxStopped
|
||
LXI H,Xoff1 ;THEN set Interrupt handler to Xoff1
|
||
JZ SetXoffFlags
|
||
LDA FCState
|
||
ORI XoffSent
|
||
STA FCState
|
||
LDA XoffChar
|
||
OUT TxData
|
||
RET
|
||
|
||
NoTxOut:
|
||
LDA XoffChar
|
||
OUT TxData ;ELSE send Xoff Character
|
||
LXI H,Xoff2 ; set Interrupt handler to Xoff2
|
||
SetXoffFlags:
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
LDA FCState
|
||
ORI SendingXoff
|
||
STA FCState
|
||
RET
|
||
;
|
||
OutputXon:
|
||
LXI H,Xoff1
|
||
LDA PutCompletedFlag ;IF PutCompleted
|
||
ORA A
|
||
LDA FCState
|
||
MOV E,A
|
||
JZ PutinProgress ; -- (from ORA instruction above)
|
||
LXI H,Xoff2
|
||
ANI SendingXoff ; AND ~SendingXoff
|
||
JNZ XoffinProgress
|
||
LDA XonChar
|
||
OUT TxData ;THEN send Xon Character
|
||
MOV A,E
|
||
ANI -XoffSent-1 ; clear XoffSent Flag
|
||
;;;;; ORI SendingXon ; set SendingXon Flag
|
||
STA FCState
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
RET
|
||
PutinProgress:
|
||
MOV A,E
|
||
ANI StoppedTx ;IF Xoff received and TX has stopped
|
||
JNZ DoIt ;THEN output Xon anyway
|
||
XoffinProgress:
|
||
MOV A,E ;ELSE set SendXon flag
|
||
ORI SendXon
|
||
STA FCState ;set Interrupt handler
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
RET
|
||
DoIt:
|
||
LDA XonChar
|
||
OUT TxData ;THEN send Xon Character
|
||
MOV A,E
|
||
ANI -XoffSent-1 ; clear XoffSent Flag
|
||
STA FCState
|
||
RET
|
||
|
||
;
|
||
{The following routines are interrupt handlesrs for the flow control characters which have been or need to be sent. The routine Xoff1 will be invoked if a transmission is already in progress when an Xon/Xoff character needs to be sent. Xoff2 is used when no transmission is currently going on so that after transmitting the character, the TxAsyncData interrupt will be reset.}
|
||
Xoff1:
|
||
LDA FCState
|
||
MOV L,A
|
||
ANI SendingXoff+XoffSent ;IF SendingXoff AND ~XoffSent
|
||
CPI SendingXoff
|
||
JNZ TestforSendXon
|
||
LDA XoffChar ;THEN send Xoff and return
|
||
OUT TxData
|
||
MOV A,L
|
||
ORI XoffSent
|
||
STA FCState
|
||
JMP ReturnXoff1
|
||
TestforSendXon:
|
||
MOV A,L ;ELSE IF SendXon
|
||
ANI SendXon
|
||
JZ ResetFlags
|
||
LDA XonChar
|
||
OUT TxData ;THEN send Xon
|
||
MOV A,L
|
||
ANI -(SendXon+SendingXoff+XoffSent)-1
|
||
STA FCState
|
||
LXI H,TxAsyncDataInt ; set interrupt vector to normal
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
ReturnXoff1:
|
||
POP H
|
||
POP PSW
|
||
EI
|
||
RET
|
||
|
||
ResetFlags:
|
||
MOV A,L ;ELSE reset flags
|
||
ANI -SendingXoff-1
|
||
;;;;; ORI XoffSent
|
||
STA FCState ; set interrupt vector to normal
|
||
LXI H,TxAsyncDataInt
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
PCHL ; goto transmit next character
|
||
;
|
||
Xoff2:
|
||
DB opMVIA ;A ¬ FCState
|
||
FCState:
|
||
DB 0
|
||
MOV L,A
|
||
ANI SendXon ;IF SendXon
|
||
JZ CheckSendXoff
|
||
LDA XonChar
|
||
OUT TxData ;THEN send Xon
|
||
MOV A,L
|
||
ANI -(SendXon+SendingXoff+XoffSent)-1
|
||
;;;;; ORI SendingXon
|
||
STA FCState
|
||
JMP ReturnXoff2
|
||
CheckSendXoff:
|
||
MOV A,L ;ELSE IF SendingXoff
|
||
ANI SendingXoff
|
||
JZ Clear
|
||
MOV A,L
|
||
ANI -SendingXoff-1 ;THEN clear SendingXoff
|
||
ORI XoffSent
|
||
;;;;; JMP TestforPut
|
||
TestforPut:
|
||
STA FCState
|
||
Clear:
|
||
LXI H,TxAsyncDataInt;set interrupt vector to normal
|
||
SHLD 2060H+1 ;AsyncJumpTable+1
|
||
LDA PutCompletedFlag
|
||
ORA A ;IF ~PutCompleted THEN
|
||
JNZ ResetTx
|
||
PCHL ; goto transmit next character
|
||
ResetTx:
|
||
MVI A,ResetTxIntPending
|
||
OUT TxCont ;ELSE clear interrrupt pending
|
||
ReturnXoff2:
|
||
POP H
|
||
POP PSW
|
||
EI
|
||
RET
|
||
|
||
END
|
||
@
|
||
|
||
|
||
1.1.1.1
|
||
log
|
||
@first add
|
||
@
|
||
text
|
||
@@
|