{File: [Iris]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