% File: MIOCTTY.mc Edit by Danielson on March 19, 1981 1:25 PM: Fix base reg fixup code. Edit by Danielson on August 1, 1980 11:38 AM Always leave status interrupts enabled. Edit by Danielson on July 24, 1980 1:40 PM Enabling/disabling transmitter. Edit by Danielson on June 5, 1980 3:34 PM Fix data lost code Edit by Danielson on May 21, 1980 4:09 PM Contains Async character at a time RS232C code for MIOC board IOCB type chaining, input frame timeout, single buffer/IOCB, single buffer/frame % insert[MIOCDefs]; Title [MIOCTTY]; SET TASK [0]; ONPAGE [IOPage]; IMRESERVE[IOPage,260,120]; * Registers RV[IOState,1]; RV[IONext,3]; RV[IODataTemp,3]; RV[IOBufBase,4]; RV[IOBufBaselo,5]; RV[IOMaxCount,6]; RV[IOOffset,7]; RV[IODataByte,10]; RV[IORegs,11]; RV[IOStatus,12]; M@[IOSizeDisp,DISPATCH[#1,10,2]]; * Character size dispatch SET [IOSizeLoc,ADD[LSHIFT[IOPage,10],220]]; * Char size * 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]; * Initialization code GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ 0C, AT [IOInitOverlayLoc]; * Start transmitter: Treat as transmitter empty interrupt GOTO [IONeedChar], AT [IOStartXmtrLoc]; * Timeout occurred: * If no input data, clear timeout flag. * If input data, check timeout flag. * If timeout flag cleared, set it. * If timeout flag set, force from to end and clear timeout flag. NOP, AT [IOTimeoutLoc]; * Memory bypass NOP!! LU _ (IOMisc) AND (IOMiscTTYChars); SKIP [ALU#0], LU _ (IOMisc) AND (IOMiscTTYTimeout); GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) AND NOT (IOMiscTTYTimeout); SKIP [ALU#0], IOMisc _ (IOMisc) AND NOT (IOMiscTTYTimeout); GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) OR (IOMiscTTYTimeout); CALL [IODoTask], PFetch1 [IOcsb, IOiocb, IOcsbIn!];(0,4032)(1,13760) GOTO [IODoneIOCB], IOMisc _ (IOMisc) OR (IOMiscInput); * 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, complete the IOCB, and check for any more frames. IONeedChar: IOMisc _ (IOMisc) AND NOT (IOMiscInput), AT [IOIntrLoc,10]; IOStatus _ 0C; GOTO [IOLoadIOCB], PFetch1[IOcsb, IOiocb, IOCSBOut!]; * Interrupt vector = 5 (External status change). Flag status * event in CSB and disable status interrupts. CALL [IODoTask], PFetch1[IOcsb, IOStatus, IOcsbStat!], AT [IOIntrLoc,12]; IOStatus _ (IOStatus) OR (IOStatEvent); 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: PFetch1[IOBufBase, IODataTemp], CALL [IODoTask]; DBLGOTO [IOISpace, IOOSpace, R ODD], LU _ IOMisc; * No IOCB condition: * On input, set data lost in CSB. * On output, satisfy xmtr interrupt and disable transmitter. IONoIOCB: DBLGOTO[IOINoIOCB, IOONoIOCB, R ODD], LU _ IOMisc; IOINoIOCB: 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: End the IOCB IONoSpace: GOTO [IODoneIOCB]; * Room in buffer (input case). * Stores a single byte in buffer. * IOOffset contains offset into buffer in bytes. * Also sets flags indicating the IOCB has characters * and clears timeout. IOISpace: IOMisc _ (IOMisc) OR (IOMiscTTYChars); IOMisc _ (IOMisc) AND NOT (IOMiscTTYTimeout); 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). * 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 tranmsitter CALLEXTERNAL [IOWrRegALoc], T _ (RSH[IORegs,10]) OR (T); CALLEXTERNAL [IOWrDataALoc], T _ IODataTemp; IOMisc _ (IOMisc) OR (IOMiscEnabled); IONewOffset: IOOffset _ (IOOffset) + 1; IOSaveOffset: PStore1[IOiocb, IOOffset, IOIOCBOffset!]; LU _ (IOStatus) AND (IOTTYBadStatus); SKIP [ALU#0], IOMisc _ (IOMisc) OR (IOMiscTTYStatEnd); GOTOEXTERNAL [IOIntrDoneLoc], IOMisc _ (IOMisc) AND NOT (IOMiscTTYStatEnd); GOTO [IODoneIOCB], PStore1[IOiocb, IOStatus, IOIOCBStat!]; * End of frame. * Chain to next IOCB and issue naked notify. IODoneIOCB: PFetch1[IOiocb, IONext, IOIOCBNext!]; LU _ IONext; * Get ptr to next IOCB DBLGOTO[.+1,.+2, R ODD], LU _ IOMisc; * Update CSB GOTO [.+2], Pstore1[IOcsb, IONext, IOcsbIn!]; GOTO [.+1], Pstore1[IOcsb, IONext, IOcsbOut!]; CALLEXTERNAL [IODoNotifyLoc], PFetch1[IOcsb, IOInt1, IOcsbMask!]; * Do naked notify IOState _ (ZERO) - 1; * Set processed DBLGOTO [IODoneIn, IODoneOut, R ODD] , LU _ (IOMisc) AND (OR[IOMiscFake!, IOMiscTTYStatEnd!]C); * Output done. Set State to completed and return to main microcode IODoneOut: PStore1[IOiocb, IOState, IOIOCBState!]; CALL [IODoTask]; GOTOEXTERNAL [IOIntrDoneLoc]; * Input end..check if real or fake interrupt. * If fake interrupt, it was caused by timeout, so branch to * Interrupt Done code. If not fake interrupt, it was caused by * input buffer filling up. Therefore, we still have to try and * store the input character, so load up new IOCB address and * branch back up into code to look for more buffer space. IODoneIn: DBLGOTO [IOInFake, IOInReal, ALU#0], IOMisc _ (IOMisc) AND NOT (IOMiscTTYChars); IOInFake: GOTO [IODoneOut], IOMisc _ (IOMisc) AND NOT (IOMiscTTYStatEnd); IOInReal: T _ IONext; CALL [IODoTask], PStore1[IOiocb, IOState, IOIOCBState!]; GOTO [IOLoadIOCB], IOiocb _ T; IODoTask: RETURN; IOOutTask: NOP, GOTO [.-1]; :END[MIOCTTY];