:IF[WithMIOC]; **************************************** INSERT[MIOCDefs]; TITLE[MIOC]; % Edit by Ed Fiala 17 March 1982: WithMIOC conditional; move IMReserve to Mesa1/2Occupied.Mc; absorb MIOCInit.Mc. Edit by Jim Frandeen September 2, 1980 2:27 PM: Change DoInt to NotifyInterrupt. Edit by July 24, 1980 1:26 PM: New poller command to handle reg 5 bit sharing. Edit by April 11, 1980 4:53 PM: Reorder commands and timeout code in poller. Edit by March 19, 1980 4:59 PM: New IMRESERVE for intraframe fill code. Edit by Danielson March 5, 1980 6:26 PM: Fix tty timeout code Edit by Danielson February 21, 1980 11:18 AM: Reduce display jitter with extra tasks Edit by Danielson January 25, 1980 1:44 PM: Added new status code Edit by Danielson January 16, 1980 1:34 PM: MIOC microcode Contains printer code, default RS232C and poller. % SetTask[0]; *MIOC initialization code *In Pilot mode, R0 contains CSB address. *In Alto mode, you figure it out yourself based on task. OnPage[IOInitPage]; :IF[AltoMode]; **************************************** NOP, At[IOInitLoc]; T _ CTask; *Get current task IOcsb _ T; T _ 177400C; *Get base of CSBs IOcsb _ (LSh[IOcsb,4]) + T; *Get actual CSB address :ELSE; ************************************************ T _ IOR0, At[IOInitLoc]; *Get CSB address IOcsb _ T; *Save CSB address :ENDIF; *********************************************** IOiocbHi _ T _ Zero; *IOCB base (hi half) LoadPage[IOPage], IOcsbHi _ T; *IOCB base (hi half) IOMisc _ T, GoToP[IOSetTPC]; *Set Misc bits *MIOC board needs servicing. *Read wake reason and dispatch to routine to handle wakeup. OnPage[IOPage]; IOSetTPC: Call[.+1], At[IOStartLoc]; *Set the TPC IOWaitWake: INPUT [IOTemp0,IOReadWakeup]; *Read interrupt vector IOWakeDisp[IOTemp0]; *Set up for dispatch Disp[IODoneInterrupt]; *Dispatch on wakeup GoTo[IODoneInterrupt], At[IOWakeupLoc,4]; * Plotter Data *Printer requested service. Load wakeup mask and issue naked *notify. NOP, At[IOWakeUpLoc,5]; *Issue naked notify NOP, At[IOWakeUpLoc,6]; PFetch1[IOcsb,IOInt1,IOCSBPrinterMask!], Call[IODoNotify]; GoTo[IODoneInterrupt]; *Now clear the wakeup, wait for the wakeup latency and TASK. IODoneInterrupt: IOStrobe, At[IOWakeupLoc,0]; NOP; * How many NOPs needed???? Call[IODoTask]; GOTO [IOWaitWake]; * Issue a naked notify by branching to code in main microcode. * When called from parts of the MIOC code, it expects thef * appropriate mask word in T. This code is at an absolute location so that the RS232 microcode can call it with a CALLEXTERNAL. IODoNotify: LoadPageExternal[NotifyInterruptPage], At[IODoNotifyLoc]; * Load correct page GoToExternal[NotifyInterruptLoc], T _ IOInt1; *Goto interrupt code. Mask in T. * Have gotten interrupt from SIO chip. Read interrupt vector and * dispatch. Since vector contains 0 in lowest bit, dispatch * addresses are at offset 0,2,4,6,10,12,14,16. IOGotInt: NOP, At[IOWakeupLoc,2]; Call[IOIntrAck]; IOIntDisp[IOTemp0]; Disp[.+1]; * Interrupt vector = 0 (Transmitter has become empty -- channel B). * Issue command to clear transmitter interrupt. CALL [IOWrRegB], T _ (IOResetXmtr), AT [IOIntrLoc,0]; GOTO [IODoReturn], AT [IOIntrLoc,1]; * Interrupt vector = 1 (External status change -- channel B). * Clear the interrupt. CALL [IOWrRegB], T _ (IOResetExt), AT [IOIntrLoc,2]; GOTO [IODoReturn], AT [IOIntrLoc,3]; * Interrupt vector = 3. (Special received condition -- channel B). * Just read character to clear interrupt. NOP, AT [IOIntrLoc,6]; * Interrupt vector = 2 (Receiver FIFO not empty). * Just read character to clear interrupt. CALL [IORdDataB], AT [IOIntrLoc,4]; GOTO [IODoReturn], AT [IOIntrLoc,5]; * Interrupt vector = 4 (Transmitter has become empty -- channel A). * Issue command to clear transmitter interrupt. IOWrStart: CALL [IOWrRegA], T _ (IOResetXmtr), AT [IOIntrLoc,10]; GOTO [IODoReturn], AT [IOIntrLoc,11]; * Interrupt vector = 5 (External status change -- channel A). * Clear the interrupt. IOStatStart: CALL [IOWrRegA], T _ (IOResetExt), AT [IOIntrLoc,12]; GOTO [IODoReturn], AT [IOIntrLoc,13]; * Interrupt vector = 7. (Special received condition -- channel A). * Just read character to clear interrupt. IOSpecStart: NOP, AT [IOIntrLoc,16]; * Interrupt vector = 6 (Receiver FIFO not empty). * Just read character to clear interrupt. IORdStart: CALL [IORdDataA], AT [IOIntrLoc,14]; GOTO [IODoReturn], AT [IOIntrLoc,15]; * Fill instructions. Unused at present. NOP, AT [IOIntrLoc,7]; NOP, AT [IOIntrLoc,17]; * Return from SIO interrupt. If not a fake wakeup, this is, one * generated by a poller command, issue the chip command to fake * a return from interrupt Z80 instruction. IODoReturn: LU _ (IOMisc) AND (IOMiscFake), AT [IOFixedLoc,10]; SKIP [ALU#0], IOMisc _ (IOMisc) AND NOT (IOMiscFake); CALL [IOWrRegA], T _ IOReturnIntr; * Return interrupt! GOTO [IODoneInterrupt]; * Issue commands to SIO chip. * For writes: T contains data to write. * For reads: Data returned in T and IOTemp0. IORdRegA: IOTemp0 _ OR[IOCmd,IORd,IOChanA]C, GOTO [IODoRd], AT [IORdRegALoc]; IORdRegB: IOTemp0 _ OR[IOCmd,IORd,IOChanB]C, GOTO [IODoRd], AT [IORdRegBLoc]; IOWrRegA: IOTemp0 _ (OR[IOCmd,IOWr,IOChanA]C), GOTO [IODoWr], AT [IOWrRegALoc]; IOWrRegB: IOTemp0 _ (OR[IOCmd,IOWr,IOChanB]C), GOTO [IODoWr], AT [IOWrRegBLoc]; IORdDataA: IOTemp0 _ OR[IOData,IORd,IOChanA]C, GOTO [IODoRd], AT [IORdDataALoc]; IORdDataB: IOTemp0 _ OR[IOData,IORd,IOChanB]C, GOTO [IODoRd], AT [IORdDataBLoc]; IOWrDataA: IOTemp0 _ OR[IOData,IOWr,IOChanA]C, GOTO [IODoWr], AT [IOWrDataALoc]; IOWrDataB: IOTemp0 _ OR[IOData,IOWr,IOChanB]C, GOTO [IODoWr], AT [IOWrDataBLoc]; IOIntrAck: IOTemp0 _ OR[IOCmd,IOWr,IOM1]C, GOTO [IODoRd]; * Issue chip commands. * First issue the appropriate OUTPUT instruction. Make sure the * OUTPUT is done by loading a zero into the register used for * the OUTPUT. Loop doing INPUTs until the CS line is no longer true (R >=0). IODoWr: IOTemp0 _ (IOTemp0) OR (T); * Or in data to write IODoRd:OUTPUT[IOTemp0, IOLoadRS232]; * Output command/data to chip UseCTask; T _ APC&APCTask; IOSave _ T; IOTemp0 _ 0C, CALL [IODoTask]; * Wait for OUTPUT to complete INPUT [IOTemp0, IOReadRS232]; SKIP [R>=0], T _ IOTemp0; * Wait for CS low (R>=0) IODoTask: RETURN; NOP; CALL [IODoTask]; GOTO [IODoTask], APC&APCTask _ IOSave; IOOutTask: GOTO [IODoTask]; * Poller. * Uses timer in mode 3 (square wave generator). By using this * mode, we don't have to reload the timer from microcode. CALL [IODOTask], PFetch4[IOcsb, IOPollCmd, IOcsbPoller!], AT [IOWakeupLoc,7]; * Process any poller command IOPollerDisp[IOPollCmd]; DISP [.+1], T _ (IOPollCmd) AND (100000C); * Command = 0. Do nothing * Command = 1. Start transmitter * Command = 2. Issue chip command (write chip) * Command = 3. Cannot be used * Command = 4. Nop * Command = 5. Initlaize overlay * Command = 6. Issue chip command (read chip) * Command = 7. Reset status bits * Command = 10. Set Reg 5. GOTO [IOCheckTimeout], AT [IOPollLoc,0]; GOTO [IOStartXmtr], IOMisc _ (IOMisc) OR (IOMiscFake), AT [IOPollLoc,1]; IOPollChipCmd: CALL [IOWrRegA], T _ (LDF[IOPollCmd,5,3]) OR (T), AT [IOPollLoc,2]; CALL [IOWrRegA], T _ (IOPollCmd) AND NOT (057400C), AT [IOPollLoc,3]; IOPollClr: GOTO [IOPollSet], IOPollCmd _ 0C, AT [IOPollLoc,4]; GOTO [IOInitOverlay], IOMisc _ (IOMisc) OR (IOMiscFake), AT [IOPollLoc,5]; GOTO [IOPollChipCmd], AT [IOPollLoc,6]; PFetch1[IOcsb, IOPollStat, IOcsbStat!], AT [IOPollLoc,7]; T _ RHMASK[IOPollCmd], CALL [IODoTask]; IOPollStat _ (IOPollStat) AND NOT (T); GOTO [IOPollClr], PStore1[IOcsb, IOPollStat, IOcsbStat!]; PFetch1[IOcsb, IOPollRegs, IOcsbRegs!], AT [IOPollLoc,10]; CALL [IOWrRegA], T _ 5C; T _ (IOMisc) AND (IOMiscEnabled);(0,4032)(1,11968) IOPollRegs _ (IOPollRegs) OR (T); CALL [IOWrRegA], T _ RSH[IOPollRegs,10]; GOTO [IOPollClr]; IOPollSet: IOResults _ T, CALL [IODoTask]; GOTO [IOCheckTimeout], PStore2[IOcsb, IOPollCmd, IOcsbPoller!]; * Check for timeout and if a timeout occurred branch to code in * overlay to handle it IOCheckTimeout: T _ (IOTimerInit), GOTO [IONoTimeout, R<0]; SKIP [R<0], IOTimer _ (IOTimer) - 1; GOTO [IONoTimeout], PStore1[IOcsb, IOTimer, IOcsbTimer!]; IOTimeout: IOTimer _ T; IOMisc _ (IOMisc) OR (IOMiscFake); GOTOEXTERNAL[IOTimeoutLoc], PStore1[IOcsb, IOTimer, IOcsbTimer!]; IONoTimeout: GOTO [IODoneInterrupt]; * Start transmitter requested. Save registers and branch to overlay code IOStartXmtr: IOPollCmd _ 0C; GOTOEXTERNAL[IOStartXmtrLoc], PStore2[IOcsb, IOPollCmd, IOcsbPoller!]; * Initialize overlay requested. Save registers and branch to overlay code IOInitOverlay: IOPOllCmd _ 0C; GOTOEXTERNAL[IOInitOverlayLoc], PStore2[IOcsb, IOPollCmd, IOcsbPoller!]; * Nop instructions for start transmitter, timeout, and initialize overlay GOTO [IODoneInterrupt], AT [IOStartXmtrLoc]; GOTO [IODoneInterrupt], AT [IOTimeoutLoc]; GOTO [IODoneInterrupt], IOMisc _ 0C, AT [IOInitOverlayLoc];  END[MIOC]; :ELSE; ************************************************ TITLE[No.MIOC.Microcode]; :ENDIF; *********************************************** e6