{File: [Iris]<WMicro>DLion>RS232CPut.asm
Modification History:
Dennis Grundler: 1-Sep-84 17:14:26: Added copyright notice
Mike Thatcher: 27-Mar-84 9:41:24: Corrected minor glitch with flow control
Mike Thatcher: 22-Dec-83 15:55:11: added Async Flow Control
Dennis Grundler: 9-Oct-83 16:28:53: fix problem with sending character before TxBufferEmpty.
Dennis Grundler: 3-Oct-83 10:13:28: fix abort for bisync and async modes.
Jim Frandeen : September 8, 1982 3:08 PM: Zero Success bit in case or error. Change handling of Abort.
Jim Frandeen : July 30, 1982 1:33 PM: new IO Page Format
Created by Jim Frandeen : March 26, 1982 8:23 AM
}
{ Copyright (C) 1982, 1983 by Xerox Corporation. All rights reserved.}
Get "SysDefs"
Get "CommonDefs"
Get "RS232CDefs"
IMP CheckCPDmaComplete ;From CPSubs
IMP CurrentSyncCount ;From RS232CMisc
IMP DisableTxCRC1 ;From BisyncInterrupts
IMP DoNakedNotify ;From MultiTask
IMP FlowControlFlag
IMP FCState
IMP LastTxBufferAddressHigh ;From RS232CInterrupts
IMP LastTxBufferAddressHigh1 ;From RS232CInterrupts
IMP LastTxBufferAddressLow ;From RS232CInterrupts
IMP LastTxBufferAddressLow1 ;From RS232CInterrupts
IMP PortBusyFlag ;From CPSubs
IMP PutCompletedFlag ;From RS232CInterrupts
IMP PutFinishedSwitch ;From RS232CInterrupts
IMP ReadCPBuffer ;From CPSubs
IMP RS232CMode ;From RS232CMisc
IMP RS232CPutFlag ;From BookKeepingTask
IMP RS232CTaskWakeMask ;From RS232CMisc
IMP StartCPReadDma ;From CPSubs
IMP SyncCharacterCount ;From BisyncInterrupts
IMP TxBisyncInitial ;From BisyncInterrupts
IMP TxBuffer ;From Buffer
IMP TxBufferPointer ;From RS232CInterrupts
IMP TxBisyncStateSwitch ;From BisyncInterrupts
IMP TxWR1 ;From RS232CMisc
IMP TxWR5 ;From RS232CMisc
IMP WriteCPBuffer ;From CPSubs
IMP XoffReceivedFlag
IMP ZeroCommand ;From CPSubs
EXP AbortPutFlag
EXP IllegalBisyncCharacterFlag
EXP PutAsyncMode
EXP PutBisyncMode
EXP PutSdlcMode
EXP PutModeSwitch
EXP PutTaskResumeAddress
EXP PutTaskQuiet
EXP RestartSIOCharacter
EXP StartPutTask
EXP TxUnderrunDetectedFlag
;
RS232CPutTask:
DB opJMP ;JMP PutTaskYield
PutTaskResumeAddress:
DW PutTaskQuiet ;Set by Misc Off Command
; JMP StartPutTask ;Set by Misc SetParameters Command
; JMP FetchPutIocb
; JMP WaitForPutBlock
; JMP WaitForAsyncPut
; JMP WaitForSdlcPut
; JMP WaitForBisyncPut
; JMP TerminateTransmit
RS232CPutCSB:
PutIOCBAddressPointerLo:
DS 2 ;14031
PutIOCBAddressPointerHi:
DS 2 ;14032
{Put IOCB: this IOCB is copied from the CP into this buffer. When the IOCB has been processed, it is sent back to the CP.}
PutIocbBuffer:
PutBufferAddressLo:
DW 0 ; Virtual Address of Put Buffer
PutBufferAddressHi:
DW 0
PutByteCount:
DW 0 ; Size of Data in bytes
PutDataByteCount:
DW 0 ; Number of bytes actually sent.
PutTransferStatus:
DB 0
PutTransferStatusHi:
DB 0
PutIocbSize EQU 10
{Port Control Block to read and write the above IOCB}
PutIocbPCB:
PutPCBAddressLo:
DW 0 ; Address of IOCB in CP memory
PutPCBAddressHi:
DW 0
DW PutIocbSize ;Size of IOCB in bytes
DW PutIocbBuffer ; points to IOCB above
{Port Control Block to send CSB back to CP}
ReadPutPCB:
DW RS232CPutCSBLoc ; Address in IO Page
DW CPIOPageHi
DW RS232CPutCSBSize ; Size of CSB (in bytes)
DW RS232CPutCSB ; Pointer to IOP Buffer
{Port Control Block to Zero Put Flag}
ZeroPutFlag:
DW RS232CPutFlagLoc; Address in IO Page
DW CPIOPageHi
DW 2 ; Size of CSB (in bytes)
DW ZeroCommand ; Pointer to IOP Buffer
{PortControlBlock to read block of data from the CP.}
TxBlockPCB:
TxBlockAddressLo:
DW 0 ;Address Of Buffer in Main Memory
TxBlockAddressHi:
DW 0
TxBlockByteCount:
DW 0 ;Transfer data Count (in bytes)
DW TxBuffer ;Read into TxBuffer
;
StartPutTask:
{Come here when the Misc On Command sets the resume address to start this task.}
FetchPutIocb:
LDA RS232CPutFlag ; Check if bit 0 #0 (full)
ORA A ; Set Flags
JNZ ReadPutCSB
{Nothing to do since the Put Flag is not on. Turn off AbortPutFlag in case Misc is waiting for it.}
PutTaskQuiet:
XRA A
STA AbortPutFlag
JMP PutTaskYield
ReadPutCSB:
LDA PortBusyFlag
ORA A
JNZ PutTaskYield
LXI H,ReadPutPCB
CALL ReadCPBuffer ;Read CSB
{Move the IOCB address from the IOPage into the ReadBlock command.}
LHLD PutIocbAddressPointerLo
SHLD PutPCBAddressLo
LHLD PutIocbAddressPointerHi
SHLD PutPCBAddressHi
{Copy IOCB from main memory into IOP memory defined above.}
{NOTE: The IOCB should be in the IOPage. Then we won't have to copy it.}
LXI H,PutIocbPCB
CALL ReadCPBuffer
{Prepare to fetch the block of data from the CP. Copy the address of the data and the byte count from the IOCB into the Transfer ControlBlock.}
{NOTE: the IOCB should be in the format of a DmaControlBlock.}
LHLD PutBufferAddressLo
SHLD TxBlockAddressLo
LHLD PutBufferAddressHi
SHLD TxBlockAddressHi
LHLD PutByteCount ; H,L contains number of bytes in block
SHLD PutDataByteCount ; Assume we will put that many bytes
{Check to see if the data will fit in the TxBuffer.}
{NOTE: The head should do this.}
LXI D,TxBufferSize
MOV A,E
SUB L
MOV A,D
SBB H
JM PutBlockTooBig ; Jump if block is too big
{Calculate the address of the last character so the interrupt routine will know when it is finished.}
LXI D,TxBuffer
DAD D
DCX H ;HL = last address
MOV A,L
STA LastTxBufferAddressLow
STA LastTxBufferAddressLow1
MOV A,H
STA LastTxBufferAddressHigh
STA LastTxBufferAddressHigh1
{Initialize the instruction at PutFinishedSwitch. This gets modified by the interrupt routine when it sends the last byte.}
MVI A,opJNZ
STA PutFinishedSwitch
{Make sure the number of bytes is even.}
LHLD PutByteCount
INX H
MOV A,L
ANI 0FEH
MOV L,A
SHLD TxBlockByteCount
{Start the command to read the block from the CP.}
LXI H,TxBlockPCB
CALL StartCPReadDma
LXI H,WaitForPutBlock
JMP SavePutTaskResumeAddressAndYield
WaitForPutBlock:
CALL CheckCPDmaComplete
JZ PutTaskYield
{Now we have the data in memory. Perform initialization common to Async, Bisync, and Sdlc.}
XRA A
STA TxUnderrunDetectedFlag
LXI H,XferSuccess ;Assume successful transfer
SHLD PutTransferStatus
MVI A,ResetTxCRCGenerator
OUT TxCont
{Jump to the appropriate routine. The following JMP address is modified by Misc when it processes a SetParameters command.}
DB opJMP ;JMP PutAsyncMode
PutModeSwitch:
DW PutAsyncMode
; JMP PutAsyncMode
; JMP PutBisyncMode
; JMP PutSdlcMode}
;
PutBisyncMode:
XRA A
STA IllegalBisyncCharacterFlag
STA RestartSIOCharacter
DI
STA PutCompletedFlag
LXI H,TxBisyncInitial
SHLD TxBisyncStateSwitch
EI
LXI H,TxBuffer ;Initialize TxBufferPointer
SHLD TxBufferPointer
LDA CurrentSyncCount
STA SyncCharacterCount
LXI H,8000H+TxCont
LDA DisableTxCRC1
DI
MVI M,PointToWR5
MOV M,A ;Disable CRC generator
EI
MVI A,ModemSYN
OUT TxData ; send the first byte to the chip
LXI H,WaitForBisyncPut
JMP SavePutTaskResumeAddressAndYield
WaitForBisyncPut:
{We won't get the first interrupt for TxBufferEmpty until we have sent one character. Wait for the interrupt routine to send all the rest of the characters. }
LDA AbortPutFlag
ORA A
JNZ AbortPut
DB opMVIA ;A ← RestartSIOCharacter
RestartSIOCharacter:
DB 0
ORA A
JNZ PrimeSIO
LDA PutCompletedFlag
ORA A
JZ PutTaskYield
DB opMVIA ;A ← IllegalBisyncCharacterFlag
IllegalBisyncCharacterFlag:
DB 0
ORA A
JZ TerminateTransmit
MVI L,InvalidCharacter
JMP StoreErrorStatus
PrimeSIO:
{The interrupt routine wants us to prime the chip by sending a character. See if this is the filler character for end of frame.}
CPI Filler
JNZ RestartSIO
{If this is a filler character, wait until we get underrun. This means the CRC has been sent. We must not restart the chip until the CRC has been sent.}
LDA TxUnderrunDetectedFlag
ORA A
JZ PutTaskYield
MVI A,Filler
RestartSIO:
MOV D,A ;temporarily save value
LXI H,8000H+TxCont ;set up to read SIO register 0
MVI M,PointToWR0
MOV A,M ;Read SIO register 0.
ANI TxBufferEmpty ;check for Tx buffer empty.
MOV A,D ;restore value to send without disturbing the flags.
JZ PutTaskYield
OUT TxData ; send the first byte to the chip
XRA A
STA RestartSIOCharacter
JMP PutTaskYield
;
PutSdlcMode:
XRA A
STA PutCompletedFlag
LXI H,TxBuffer
MOV A,M ; get the first character
INX H ; point to next byte
SHLD TxBufferPointer
OUT TxData ; send the first byte to the chip
{When in Sdlc mode, we must reset the TxUnderRun/EOM flag after sending the first byte of message. This causes the CRC to be sent at the end of the frame.}
MVI A,ResetTxEOM
OUT TxCont
LXI H,WaitForSdlcPut
JMP SavePutTaskResumeAddressAndYield
{Wait for the interrupt routine to send all the rest of the characters.}
WaitForSdlcPut:
DB opMVIA ;A ← AbortPutFlag
AbortPutFlag:
DB 0
ORA A
JNZ AbortPut
DB opORI ;A ← TxUnderrunDetectedFlag
TxUnderrunDetectedFlag:
DB 0
JZ PutTaskYield
{Continue if underrun has been detected. See if all the data has been transferred. If the Put did not complete, and we got an illegal transmit underrun, abort this frame.}
LDA PutCompletedFlag
ORA A
JNZ TestBufferEmpty
AbortPut:
MVI A,SendAbort
OUT TxCont
MVI L,Aborted
JMP StoreErrorStatus
PutBlockTooBig:
MVI L,DeviceError
StoreErrorStatus:
MVI H,0 ;Zero success bit
SHLD PutTransferStatus
{Compute number of bytes actually sent: TxBufferPointer - TxBuffer.}
LHLD TxBufferPointer
XCHG ;DE ← TxBufferPointer
LXI H,TxBuffer
MOV A,D
SUB L ;Subtract TxBuffer
MOV L,A
MOV A,E
SBB H
MOV H,A
SHLD PutDataByteCount
JMP TerminateTransmit
;
PutAsyncMode:
LDA FlowControlFlag
ORA A
JZ SendFirstCharacter
DI
LDA XoffReceivedFlag
ORA A
JNZ Wait
LDA FCState
ANI SendXon+SendingXoff
JNZ Wait
EI
SendFirstCharacter:
STA PutCompletedFlag
LXI H,TxBuffer
MOV A,M ; get the first character
INX H ; point to next byte
SHLD TxBufferPointer
OUT TxData ; send the first byte to the chip
LXI H,WaitForAsyncPut
JMP SavePutTaskResumeAddressAndYield
Wait:
XRA A
STA PutCompletedFlag
LXI H,TxBuffer
SHLD TxBufferPointer
EI
LXI H,WaitForAsyncPut
JMP SavePutTaskResumeAddressAndYield
WaitForAsyncPut:
{We won't get the first interrupt for TxBufferEmpty until we have sent one character. Wait for the interrupt routine to send all the rest of the characters. It must be the case that we have sent all of the characters AND we have received the last interrupt from the chip. If we haven't received the last interrupt from the chip, there will still be a character in the transmit buffer, and it will not get sent until the next frame.}
LDA AbortPutFlag
ORA A
JNZ AbortPut
LDA PutCompletedFlag
ORA A
JZ PutTaskYield ; if not done
TestBufferEmpty:
IN TxCont ; Check to see if the buffer is empty
ANI TxBufferEmpty
JZ PutTaskYield
TerminateTransmit:
{Send the processed IOCB back to the CP.}
LDA PortBusyFlag
ORA A
JZ ReturnPutIocb
LXI H,TerminateTransmit
JMP SavePutTaskResumeAddressAndYield
ReturnPutIocb:
{Clear Put Abort flag in case it was set. This is used to signal the AbortOutput command in RS232CMisc that the task has completed.}
STA AbortPutFlag
LXI H,PutIocbPCB
CALL WriteCPBuffer
{Zero the PutFlag to indicate that the IOCB has been processed, and we are ready for another.}
LXI H,ZeroPutFlag
CALL WriteCPBuffer
LHLD RS232CTaskWakeMask
CALL DoNakedNotify
LXI H,FetchPutIocb
SavePutTaskResumeAddressAndYield:
SHLD PutTaskResumeAddress
PutTaskYield:
{Pass control to the next task specified in Domino.cfg}
DS 0
END