% File: MIOCBit.mc Edit by Danielson on March 19, 1981 1:25 PM: Fix base reg fixup code. Edit by Danielson on August 1, 1980 11:36 AM Always leave external status interrupts enabled. Edit by Danielson on July 25, 1980 1:38 PM Half-duplex -- interframe fill with FF. Edit by Danielson on June 5, 1980 3:29 PM Fix data lost code Edit by Danielson on April 18, 1980 3:40 PM Contains Bit RS232C code for MIOC board 1. IOCB type chaining 2. Single buffer/IOCB, single buffer/frame 3. BCC calculation done by SIO chip % insert[MIOCDefs]; Title [MIOCBit]; SET TASK [0]; ONPAGE [IOPage]; IMRESERVE[IOPage,260,120]; * Registers RV[IOBufBase,4]; RV[IOBufBaselo,5]; RV[IOMaxCount,6]; RV[IODataTemp,6]; RV[IOOffset,7]; RV[IONext,7]; RV[IODataByte,10]; RV[IOStart,10]; RV[IORegs,11]; RV[IOStatus,12]; MACRO[IOSizeDisp,DISPATCH[#1,10,2]]; * Character size dispatch MACRO[IOEOFDisp,DISPATCH[#1,5,3]]; * EOF dispatch SET [IOSizeLoc,ADD[LSHIFT[IOPage,10],220]]; * Char size SET [IOEOFLoc,ADD[LSHIFT[IOPage,10],200]]; * EOF * Channel B nop code * Satisfies interrupt on channel B if they occur * Interrupt vectors = 0 - 3 CALLEXTERNAL [IOWrRegBLoc], T _ (IOResetXmtr), AT [IOIntrLoc,0]; GOTOEXTERNAL [IOIntrDoneLoc]; CALLEXTERNAL [IOWrRegBLoc], T _ (IOResetExt), AT [IOIntrLoc,2]; GOTOEXTERNAL [IOIntrDoneLoc]; NOP, AT [IOIntrLoc,6]; CALLEXTERNAL [IORdDataBLoc], AT [IOIntrLoc,4]; GOTOEXTERNAL [IOIntrDoneLoc]; * Initialize overlay: Reset IOMisc bits GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ 0C, AT [IOInitOverlayLoc]; * Start transmitter: Treat as normal transmitter empty interrupt. * Also, reset Xmtr CRC generator. NOP, AT [IOStartXmtrLoc]; CALLEXTERNAL[IOWrRegALoc], T _ (IOResetXmtrCRC); GOTO [IONeedChar]; * Timeout occurred: Generate fake transmitter interrupt if needed. NOP, AT [IOTimeoutLoc]; * Bypass NOP LU _ (IOMisc) AND (IOMiscEOFTimeout); * Check for doing EOF. GOTO [IOFakeInterrupt, ALU#0]; * If so, fake an interrupt GOTOEXTERNAL [IOIntrDoneLoc]; * Else ignore IOFakeInterrupt: GOTO [IONeedChar]; * Interrupt vector = 4 (Transmitter has become empty). * 1. If no IOCB, satisfy interrupt by ResetXmtr command. * 2. If no more data to send in IOCB, satisfy interrupt by * ResetXmtr, issue ResetUnderrun * to force chip to send CRC, and set endOfFrame bit. * 3. If end of frame bit interrupt, complete the IOCB, and check for any more frames. IONeedChar: IOMisc _ (IOMisc) AND NOT (IOMiscInput), AT [IOIntrLoc,10]; GOTO [IOLoadIOCB], PFetch1[IOcsb, IOiocb, IOCSBOut!]; * Interrupt vector = 5 (External status change). Flag status * event in CSB and reset external status interrupts. PFetch1[IOcsb, IOStatus, IOcsbStat!], AT [IOIntrLoc,12]; CALLEXTERNAL[IORdRegALoc];(0,4032)(1,13760) LU _ (IOTemp0) AND (200C); * Check Break bit GOTO [IONotBreak, ALU=0], IOStatus _ (IOStatus) OR (IOStatEvent); PFetch1[IOcsb, IOiocb, IOCSBIn!], CALL [IODoTask]; LU _ IOiocb; GOTO [IONotBreak1,ALU=0]; PFetch1[IOiocb, IOStart, IOIOCBStart!], CALL [IODoTask]; LU _ IOStart; PStore1[IOiocb, IOStart, IOIOCBOffset!]; IONotBreak1: NOP; IONotBreak: NOP; CALL [IODoTask], PStore1[IOcsb, IOStatus, IOcsbStat!]; CALLEXTERNAL [IOWrRegALoc], T _ (IOResetExt); * Reset external interrupts IODoInt: CALLEXTERNAL [IODoNotifyLoc], PFetch1[IOcsb, IOInt1, IOcsbMask!]; * Do naked notify GOTOEXTERNAL [IOIntrDoneLoc]; * Interrupt vector = 7. (Special received condition). * 1. Save status for the Mesa face. * 2. Issue ResetError command to clear error. CALLEXTERNAL [IOWrRegALoc], T _ 1C, AT [IOIntrLoc,16]; NOP; CALLEXTERNAL [IORdRegALoc]; IOStatus _ T; CALLEXTERNAL [IOWrRegALoc], T _ (IOResetError); * Read in character IOInIntr: PFetch1[IOcsb, IODataTemp, IOcsbRegs!]; CALLEXTERNAL [IORdDataALoc], IOMisc _ (IOMisc) OR (IOMiscInput); IODataByte _ T; IOSizeDisp[IODataTemp]; DISP [.+1], PFetch1[IOcsb, IOiocb, IOcsbIn!]; IOSize5: GOTO [IOLoadIOCB], IODataByte _ (IODataByte) AND (37C), AT [IOSizeLoc,0]; IOSize7: GOTO [IOLoadIOCB], IODataByte _ (IODataByte) AND (177C), AT [IOSizeLoc,1]; IOSize6: GOTO [IOLoadIOCB], IODataByte _ (IODataByte) AND (77C), AT [IOSizeLoc,2]; IOSize8: GOTO [IOLoadIOCB], IODataByte _ (IODataByte) AND (377C), AT [IOSizeLoc,3]; * Interrupt vector = 6 (Receiver FIFO not empty). GOTO [IOInIntr], IOStatus _ 0C, AT [IOIntrLoc,14]; * 1. If no IOCB, then signal data lost * 2. If IOCB buffer full, then signal data lost * 3. Otherwise, store next character in buffer. IOLoadIOCB: LU _ IOiocb; GOTO [IONoIOCB,ALU=0]; PFetch4[IOiocb, IOBufBase, IOIOCBBuffer!], CALL[IODoTask]; T _ RHMASK[IOBufBaseLo]; IOBufBaseLo _ (LSH[IOBufBaseLo,10]) + T + 1; T _ IOMaxCount; LU _ (IOOffset) - T; DBLGOTO [IONoSpace, IOSpace, ALU=0], T _ RSH[IOOffSet, 1]; IOSpace: CALL [IODoTask], PFetch1[IOBufBase, IODataTemp]; DBLGOTO [IOISpace, IOOSpace, R ODD], LU _ IOMisc; * No IOCB condition: * On input, set data lost in CSB. * On output, issue ResetXmtr command to satisfy SIO transmitter interrupt. IONoIOCB: DBLGOTO[IOINoIOCB, IOONoIOCB, R ODD], LU _ IOMisc; IOINoIOCB: PFetch1[IOcsb, IORegs, IOcsbRegs!]; CALLEXTERNAL[IOWrRegALoc], T _ 3C; * Write register 3 CALLEXTERNAL[IOWrRegALoc], T _ RHMASK[IORegs]; * Set chip to look for SYN CALL [IODoTask], PFetch1[IOcsb, IOStatus, IOcsbStat!]; LU _ (IOStatus) AND (IOStatDataLost); GOTO [IOIDataLost, ALU#0], IOStatus _ (IOStatus) OR (IOStatDataLost); PStore1[IOcsb, IOStatus, IOcsbStat!]; GOTO [IODoInt]; IOIDataLost: GOTOEXTERNAL [IOIntrDoneLoc]; IOONoIOCB: PFetch1[IOcsb, IORegs, IOcsbRegs!]; CALLEXTERNAL [IOWrRegALoc], T _ OR[IOResetXmtr!,5]C; CALLEXTERNAL [IOWrRegALoc], T _ RSH[IORegs,10]; GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) AND NOT (IOMiscEnabled); * No space in IOCB condition: * On input, set data lost in IOCB by faking receiver overrun. * On output, process EOF. IONoSpace: DBLGOTO[IOINoSpace, IOONoSpace, R ODD], IOEOFDisp[IOMisc]; IOINoSpace: CALL [IOSaveIOCBStat], T _ 40C; * Rcvr overrun bit GOTO [IOCheckEnd]; IOONoSpace: DISP[IOEOFOut]; * Room in buffer (input case). * Stores a single byte in buffer. * IOOffset contains offset into buffer in bytes. IOISpace: GOTO [IOIEven, R EVEN], LU _ IOOffset; IOIOdd: T _ RHMASK[IODataByte]; GOTO [IOIBoth], IODataTemp _ (LHMASK[IODataTemp]) OR T; IOIEven: T _ LSH[IODataByte,10]; GOTO [IOIBoth], IODataTemp _ (RHMASK[IODataTemp]) OR T; IOIBoth: T _ RSH[IOOffset,1]; GOTO [IONewOffset], PStore1[IOBufBase, IODataTemp]; * Room in buffer (output case). * Enables transmitter. * Gets next byte from buffer. * IOOffset contains offset into buffer in bytes. IOOSpace: GOTO [IOOEven, R EVEN], LU _ IOOffset; IOOOdd: GOTO [IOOBoth], IODataTemp _ RHMASK[IODataTemp]; IOOEven: GOTO [IOOBoth], IODataTemp _ RSH[IODataTemp,10]; IOOBoth: PFetch1[IOcsb, IORegs, IOcsbRegs!]; CALLEXTERNAL[IOWrRegALoc], T _ 5C; T _ 10C; * Enable tranmitter CALLEXTERNAL[IOWrRegALoc], T _ (RSH[IORegs,10]) OR (T); IOMisc _ (IOMisc) OR (IOMiscEnabled); CALLEXTERNAL [IOWrDataALoc], T _ IODataTemp; IONewOffset: IOOffset _ (IOOffset) + 1; IOSaveOffset: CALL [IODoTask], PStore1[IOiocb, IOOffset, IOIOCBOffset!]; DBLGOTO [IOCheckEnd, .+1, R ODD], LU _ IOMisc; GOTOEXTERNAL [IOIntrDoneLoc]; * Check for end of input frame. * The SIO chip tells us when EOF occurs by setting the 200 bit in the status word. IOCheckEnd: LU _ (IOStatus) AND (200C); * Input end of file? GOTO [IOIDoneIOCB, ALU#0]; GOTOEXTERNAL [IOIntrDoneLoc]; * No IOIDoneIOCB: GOTO [IODoneIOCB], PStore1 [IOiocb, IOStatus, IOIOCBBCC!]; * Yes * Handle EOF on output * States are: * 0 -> Starting EOF. Reset chip to send CRC and increment state. * 2 -> Chip starting to send ending flag. If last IOCB in chain, * disable transmitter. Increment state to enable timeouts. * 4 -> First timeout, do nothing but increment state. * 6 -> Second timeout. End the frame. IOEOFOut: CALLEXTERNAL [IOWrRegALoc], T _ IOResetXmtr, AT [IOEOFLoc,0]; NOP; CALLEXTERNAL [IOWrRegALoc], T _ IOResetUnderrun; GOTOEXTERNAL [IOIntrDoneLoc], (IOMisc) _ (IOMisc) + (IOMiscEOFIncr); CALL [IODoTask], PFetch1[IOiocb, IONext, IOIOCBNext!], AT [IOEOFLoc,2]; LU _ IONext; GOTO [IOMoreToSend, ALU#0]; PFetch1[IOcsb, IORegs, IOcsbRegs!]; CALLEXTERNAL [IOWrRegALoc], T _ OR[IOResetXmtr!,5]C; CALLEXTERNAL [IOWrRegALoc], T _ RSH[IORegs,10]; IOMisc _ (IOMisc) AND NOT (IOMiscEnabled); IOMoreToSend: GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) + (IOMiscEOFIncr); GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) + (IOMiscEOFIncr), AT [IOEOFLoc,4]; GOTO [IODoneIOCB], IOMisc _ (IOMisc) AND NOT (IOMiscEOFBits), AT [IOEOFLoc,6]; * End of frame. * Chain to next IOCB and issue naked notify. IODoneIOCB: IOStatus _ (ZERO) - 1; CALL [IODoTask], PFetch1[IOiocb, IONext, IOIOCBNext!]; CALL [IODoTask], PFetch1[IOcsb, IOInt1, IOcsbMask!]; * Do naked notify CALL [IODoTask], LU _ IONext; * Get ptr to next IOCB DBLGOTO[IODoneIn,IODoneOut, R ODD], LU _ IOMisc; * Update CSB IODoneIn: Pstore1[IOcsb, IONext, IOcsbIn!]; CALLEXTERNAL [IODoNotifyLoc]; GOTOEXTERNAL [IOIntrDoneLoc], PStore1[IOiocb, IOStatus, IOIOCBState!]; IODoneOut: GOTO [.+1], Pstore1[IOcsb, IONext, IOcsbOut!]; CALLEXTERNAL [IODoNotifyLoc]; * Do naked notify CALLEXTERNAL[IOWrRegALoc], T _ (IOResetXmtrCRC); GOTO [IONeedChar], PStore1[IOiocb, IOStatus, IOIOCBState!]; IODoTask: RETURN; IOOutTask: NOP, GOTO [.-1]; IOSaveIOCBStat: GOTO [IODoTask, ALU=0]; PFetch1[IOiocb, IOTemp0, IOIOCBStat!]; IOTemp0 _ (IOTemp0) OR (T); RETURN, PStore1[IOiocb, IOTemp0, IOIOCBStat!]; :END[MIOCBit];