:IF[WithEIM]; ************************************** TITLE[EIM]; % Ed Fiala 23 April 1982, bum 2 mi at eimInt. Tom Rich April 23, 1982 merge EIMDefs and EIM into single module. Tom Rich April 22, 1982 make conditional on WithEIM. merge in EIMInit, move to first overlay. Tom Rich March 25, 1982 pNWW => IP[NWW]C, 342c => Stack&-1. rej April 27, 1981 2:36 PM add missing CR in eomWrap rej March 26, 1981 9:48 AM fix CSBquad4Offset to proper value rej March 13, 1981 4:42 PM notify at end of band in eomWrapMode rej March 4, 1981 5:05 PM change field sizes for input buffer parms rej March 4, 1981 4:48 PM new EOMwrap rej November 17, 1980 4:52 PM output gotcha 15, enableIO rej June 30, 1980 2:53 PM mod for amargosa rej May 8, 1980 10:10 PM fix process notify rej January 14, 1980 1:28 PM:dolang vers 5.0 rej November 19, 1979 12:45 PM process notify, temps shared with eom rej June 7, 1979 9:04 AM eop fix rej June 14, 1979 4:28 PM eop overrides parity/overflow rej June 18, 1979 1:17 PM init changed for 8G rej July 3, 1979 2:47 PM master enable, io enables,mesa requests,clears added for terminal conditions rej July 20, 1979 3:05 PM July 3 changes to 4c code included for 8g rej August 9, 1979 9:04 AM large house clean rej August 14, 1979 2:01 PM % SET[eimClearAddr,0]; *output register addresses SET[eimInputBufAddr,OR[lshift[eimTask,4],1]]; SET[eimEimModeAddr, 2]; SET[eimIITmodeAddr,3]; SET[eimNibPerScanAddr,4]; SET[eimIITcommandAddr,6]; SET[eimMaxNibRegAddr,7]; SET[eimDeviceIDaddr,0]; *input register addresses SET[eimOutputBufAddr,OR[lshift[eimTask,4],1]]; SET[eimMesaStatAddr,2]; SET[eimEimStatAddr,3]; SET[eimCompressStatAddr,4]; SET[eimEOMnextAddr,6];*INPUT is a command rather than a request for data SET[eimMesaDispLoc, OR [lshift[eimPage,10] , 20]]; *dispatch locations SET[eimEimDispLoc, OR [lshift[eimPage,10] , 40]]; SET[eim2to1LastLineLoc,OR [lshift[eimPage,10] , 60]]; SET[eim2to1ModeLoc,OR [lshift[eimPage,10] , 100]]; MC[eimoWUenable, 1]; *IO wakeup enable masks MC[eimiWUenable,2]; MC[eimioWUenable,3]; MC[eimPTeop,1]; *page terminating reasons MC[eimPTmesaOverflow, 2]; MC[eimPTeimOverflow, 4]; MC[eimPTparity, 10]; SET[eimCSBpage,377]; *CSB address SET[eimCSBbank,0]; MC[eimrhCSBbase, LSHIFT[eimTask,4]]; MC[eimlhCSBbase, LSHIFT[eimCSBpage,10]]; MC[eimlhCSBbase1, LSHIFT[eimCSBbank,10]]; MC[eimrhCSBbase1, ADD[eimCSBbank,1]]; SET[eimMesaInterruptMaskOffset, 0]; *CSB offsets SET[eimMesaLockOffset, 1]; SET[eimNemptyOffset, 2]; SET[eimiBufferParmOffset, 3]; SET[eimPTOffset, 4]; SET[eimEimModeOffset, 5]; SET[eimDataBaseOffset, 6]; SET[eimDataBaseOffset1, 7]; SET[eimOutputBaseOffset, 10]; SET[eimoBlockCntrOffset, 11]; SET[eimoBufferSelectOffset, 12]; SET[eimCSBquad4Offset, 14]; SET[eimSWmaxWordsOffset,0]; *pageDescriptor offsets SET[eimNibblesPerLineOffset,1]; SET[eimLinesPerPageOffset,2]; SET[eimLinesPerBandOffset,3]; SET[eimPBKtablePtrOffset,4]; SET[eimSWSoffset,5]; SET[eimRPTcountOffset,6]; MC[eimInputOffset,400]; *begin of input data buffer MC[eimLastLineInBand,177777]; *2to1 constants MC[eimRAW,1]; MC[eimNOR,1]; MC[eimSWTableOffset,20]; ******************************************************************************** * eim task registers ******************************************************************************** SETTASK[eimTask]; SET[eimRunO,LSHIFT[eimTask,4]]; SET[eimRbase, AND [60, eimRunO]]; RV[eimCSBbase, ADD[eimRbase,0]]; *long pointers RV[eimCSBbase1, ADD[eimRbase,1]]; RV[eimDataBase, ADD[eimRbase,2]]; RV[eimDataBase1, ADD[eimRbase,3]]; RV[eimiBuffPtr, ADD[eimRbase,4]]; RV[eimiBlockCntr, ADD[eimRbase,5]]; RV[eimiSectorCntr, ADD[eimRbase,6]]; RV[eimSWentryNum, ADD[eimRbase,7]]; RV[eimSWmaxWords, ADD[eimRbase,10]]; RV[eimNibblesPerLine, ADD[eimRbase,11]]; RV[eimLineInPage, ADD[eimRbase,12]]; RV[eimLineInBand, ADD[eimRbase,13]]; SET[eimtemp1, ADD[eimRbase, 14]]; SET[eimtemp2, ADD[eimRbase, 15]]; SET[eimtemp3, ADD[eimRbase, 16]]; SET[eimtemp4, ADD[eimRbase, 17]]; RV[eimTempReg1, eimtemp1]; *temporary registers RV[eimTempReg2, eimtemp2]; RV[eimTempReg3, eimtemp3]; RV[eimTempReg4, eimtemp4]; RV[eimNibblesInPage, ADD[eimRbase,30]]; *registers in bank shared with eom RV[eimNibblesInPage1, ADD[eimRbase,31]]; RV[eimoBuffPtr, ADD[eimRbase,32]]; RV[eimoBlockCntr, ADD[eimRbase,33]]; ******************************************************************************** *temporary registers ******************************************************************************** RV[eimDummyReg, ADD[eimRbase,37]]; *temp used by both EIM and EOM RV[eimTempReg5, ADD[eimRbase,36]]; *temp used by both EIM and EOM RV[eimTempReg6, ADD[eimRbase,37]]; *temp used by both EIM and EOM RV[eimClear, eimtemp1]; RV[eimMesaInterruptMask, eimtemp1]; RV[eimOutputBase, eimtemp1]; RV[eimOldSWentry, eimtemp1]; RV[eimEimMode, eimtemp2]; RV[eimMesaLock, eimtemp2]; RV[eimMesaStatus, eimtemp2]; RV[eimNewSWentry, eimtemp2]; RV[eimNsectorsEmpty, eimtemp3]; RV[eimMNR, eimtemp3]; RV[eimRPTcount, eimtemp3]; RV[eimPBKtablePtr, eimtemp3]; RV[eimPT, eimtemp3]; RV[eimEimStatus, eimtemp4]; RV[eimiBufferParm, eimtemp4]; RV[eimoBufferSelect, eimtemp4]; RV[eimCompressorStatus, eimtemp4]; ******************************************************************************** * initialization code ******************************************************************************** eimInit: eimCSBbase←eimrhCSBbase, At[eimInitLoc]; eimCSBbase←(eimCSBbase) OR (eimlhCSBbase); eimCSBbase1←eimrhCSBbase1; eimCSBbase1←(eimCSBbase1) OR (eimlhCSBbase1); LOADPAGE[eimPage] ; OUTPUT[eimClear,eimClearAddr], GotoP[eimSleep]; ONPAGE[eimPage]; eimNOPreturn: nop, RETURN; eimSleep: IOSTROBE, CALL[eimNOPreturn]; eimFirstInstruction: GOTO[eimRun]; ******************************************************************************** *why was I awakened? ******************************************************************************** eimRun: DBLGOTO[eimNonInputWU, eimInputWU, IOATTEN]; eimNonInputWU: INPUT[eimEimStatus,eimEimStatAddr]; *read eimstatus DISPATCH[eimEimStatus,15,3], LU←eimEimStatus; DISP[eimEimDisp]; ******************************************************************************** *subroutines ******************************************************************************** eimFetchIntMask: RETURN, PFETCH1[eimCSBbase, eimMesaInterruptMask, eimMesaInterruptMaskoffset]; eimFetchEIMmode: RETURN, PFETCH1[eimCSBbase, eimEimMode, eimEimModeOffset]; eimTerminalCondition: CALL[eimFetchIntMask]; OUTPUT[eimClear,eimClearAddr]; PSTORE1[eimCSBbase, eimPT, eimPToffset]; eimNotify: CALL[eimInt],IOSTROBE; GOTO[eimRun]; eimInt: eimTempReg5 ← IP[NWW]C; T ← (SStkP&NStkP) xor (377C); StkP ← eimTempReg5, eimTempReg5 ← T, NoRegILockOK; T ← eimMesaInterruptMask; Stack ← (Stack) or T, Skip[ALU#0]; StkP ← eimTempReg5, Return; Stack&-1; *Point StkP at RSImage T ← Stack ← (Stack) or (IntPendingBit); LU ← StkP ← eimTempReg5, RS232 ← T, RETURN; ******************************************************************************** * eimInputWU ******************************************************************************** ******************************************************************************** * transfer loop ******************************************************************************** eimInputWU: GOTO[eimiNewSector,R<0], eimiBlockCntr←(eimiBlockCntr)-(1c); eimiBlockTransfer: t←eimiBuffPtr; TASK,IOSTROBE,IOSTORE20[eimDataBase, eimOutputBufAddr]; eimiBuffPtr←(eimiBuffPtr)+(20c); GOTO[eimRun]; ******************************************************************************** * ring management ******************************************************************************** eimiNewSector: *fetch nsectorsempty , bufferparm, eimMesaInterruptMask CALL[eimNOPreturn], PFETCH4[eimCSBbase, eimMesaInterruptMask,0]; DBLGOTO[eimiHead, eimiBody, R<0], eimiSectorCntr←(eimiSectorCntr)-(1c); eimiHead: eimiBuffPtr←eimInputOffset; *set to start of ring t←(LDF[eimiBufferParm,0,7]); *reset sector count (new field size) eimiSectorCntr←t; eimiBody: t←(LDF[eimiBufferParm,7,11])-1; *minus one since a block will be delivered (new field size) eimNsectorsEmpty←(eimNsectorsEmpty)-(1c); GOTO[eimiBufferFull, ALU=0], eimiBlockCntr←t; CALL[eimNOPreturn]; *task before doing interrupt, ugh! CALL[eimInt], PSTORE4[eimCSBbase, eimMesaInterruptMask,0]; GOTO[eimiBlockTransfer]; eimiBufferFull: *Mesa fell behind GOTO[eimTerminalCondition], eimPT←eimPTmesaOverflow;*Nsectors will not be updated ******************************************************************************** *parity wakeup and Overflow wakeup ******************************************************************************** eimEimDisp: eimParity: AT[eimEimDispLoc,1], GOTO[eimTerminalCondition], eimPT←eimPTparity; eimOverflow: AT[eimEimDispLoc,2], GOTO[eimTerminalCondition], eimPT←eimPTeimOverflow; ******************************************************************************** *2to1 wakeup ******************************************************************************** ******************************************************************************** *end of page? *two extra RAW lines after last line? *normal 2to1 (including dummy at the beginning)? ******************************************************************************** eim2to1: AT[eimEimDispLoc,3], SKIP[R<0], eimSWentryNum←(eimSWentryNum)-1; PFETCH1[eimDataBase,eimSWentryNum,eimSWSoffset]; CALL[eimNOPreturn], INPUT[eimCompressorStatus, eimCompressStatAddr]; GOTO[eim2to1notForcedRAW,R>=0], eimLineInPage←(eimLineInPage)-1; t←(eimLineInPage)+(3c); GOTO[eim2to1setRAW, ALU>=0], t←zero; *force two RAW lines after last line ******************************************************************************** *End Of Page ******************************************************************************** eimEndOfPage: GOTO[eimTerminalCondition], eimPT←eimPTeop; ******************************************************************************** *fetch old SW entry ******************************************************************************** eim2to1notForcedRAW: eim2to1oldEntry: t←(eimSWentryNum)+(eimSWTableOffset); PFETCH1[eimDataBase,eimOldSWentry]; ******************************************************************************** *compute new entry: NOR←compressed nibbles, RAW←nibbles/line, RPT←2 ******************************************************************************** DISPATCH[eimCompressorStatus,3,2], LU←eimCompressorStatus; DISP[eim2to1LastLine], LU←ldf[eimCompressorStatus,0,1];*subtract one nibble?(last lineNOR) eim2to1LastLine: eim2to1LastLineNOR: AT[eim2to1LastLineLoc,0],*NOR GOTO[eim2to1NewEntry, ALU=0],t←ldf[eimCompressorStatus,5,13];*compressed nibbles GOTO[eim2to1NewEntry], t←(ldf[eimCompressorStatus,5,13] )-1;*subtract one nibble eim2to1LastLineRAW: AT[eim2to1LastLineLoc,1],*RAW GOTO[eim2to1NewEntry], t←eimNibblesPerLine; eim2to1LastLineRPT: AT[eim2to1LastLineLoc,2],*RPT TASK, t←(2c); PFETCH1[eimDataBase,eimRPTcount,eimRPTcountOffset]; eimRPTcount←(eimRPTcount)+1; PSTORE1[eimDataBase,eimRPTcount,eimRPTcountOffset]; eim2to1NewEntry: eimNewSWentry←t; CALL[eimNOPreturn], eimNewSWentry←rsh[eimNewSWentry,2];*nibbles to words eimNibblesInPage←(eimNibblesInPage)+t; GOTO[eim2to1Calculation, NOCARRY], eimNewSWentry←rsh[eimNewSWentry,2];*nibbles to words GOTO[eim2to1Calculation], eimNibblesInPage1←(eimNibblesInPage1)+1;*double precision add ******************************************************************************** *2to1 wakeup 2to1 calculations ******************************************************************************** *store eimNewSWentry, select mode and calculate new SWmaxWords ******************************************************************************** eim2to1Mode: DISP[eim2to1ModeDisp], PSTORE1[eimDataBase,eimNewSWentry]; eim2to1ModeDisp: eim2to1NormalModePos: AT[eim2to1ModeLoc,0], t←eimOldSWentry; eim2to1NormalModePos1: eimSWmaxWords←(eimSWmaxWords)+t; t←eimNewSWentry; RETURN, eimSWmaxWords←(eimSWmaxWords)-t; eim2to1NoRPTs: AT[eim2to1ModeLoc,1], RETURN; eim2to1AltRPTs: AT[eim2to1ModeLoc,2], RETURN; eim2to1NormalModeNeg: AT[eim2to1ModeLoc,3], GOTO[eim2to1NormalModePos1], t←eimOldSWentry; ******************************************************************************** *determine max nibbles per scan for next line ******************************************************************************** eim2to1Calculation: t←(eimSWentryNum)+(eimSWTableOffset); CALL[eim2to1Mode], DISPATCH[eimSWmaxWords,0,2]; eim2to1MaxNibbles: GOTO[.+2,r>=0], t←eimSWmaxWords; GOTO[eim2to1RAWRPT], t←2c; *eimSWmaxWords was negative LU←(RSH[eimNibblesPerLine,2])-t-1; *is eimSWmaxWords less than a RAW line? GOTO[eim2to1RAWRPT, ALU>=0], t←LSH[eimSWmaxWords,2]; GOTO[eim2to1setRAW], t←eimNibblesPerLine; ******************************************************************************** *determine RAW or RPT for next line RAW=1 RPT=0 ******************************************************************************** eim2to1RAWRPT: eimMNR←t; LU←ldf[eimCompressorStatus,3,1]; *was last line a repeat? GOTO[.+2, ALU=0] ,LU←(eimLineInBand); *no GOTO[eim2to1setRAW], t←eimNibblesPerLine; *yes, set RAW GOTO[eim2to1setRPT, ALU>=0]; *next line is not the beginning of a band GOTO[eim2to1setRAW], t←eimNibblesPerLine; *begin band must be RAW eim2to1setRPT: GOTO[eim2to1PBKNOR], eimMNR←LSH[eimMNR,1] ; eim2to1setRAW: eimMNR←t; eimMNR←(LSH[eimMNR,1] )+1; *shift and set RAW bit ******************************************************************************** *determine PBK or NOR next +1 line PBK=0 NOR=1 ******************************************************************************** eim2to1PBKNOR: LU←(eimLineInBand); *zero is next to last line in band;send PBK on next to last line GOTO[eim2to1outputMNR, ALU=0], eimMNR←LSH[eimMNR,1]; GOTO[eim2to1outputMNR], eimMNR←(eimMNR) OR (eimNOR); eim2to1outputMNR: eimMNR←LCY[eimMNR,16]; OUTPUT[eimMNR,eimMaxNibRegAddr]; CALL[eimNOPreturn]; ******************************************************************************** *2to1 wakeup PBKtable, eom wraparound ******************************************************************************** eim2to1EomWrap: LU←LDF[eimCompressorStatus,1,1]; *are we in EOMwrap mode? GOTO[eim2to1updateLineInBand, ALU=0]; GOTO[eim2to1EOMstart, R>=0], LU←eimLineInBand;*last line in band? nop; *placement CALL[eimFetchIntMask]; CALL[eimInt], PSTORE4[eimCSBbase,eimSWmaxWords,eimCSBquad4Offset]; *last word in quad is lineInBand which is -1; reason for notify; Mesa should reset GOTO[eim2to1updateLineInBand]; eim2to1EOMstart: INPUT[eimDummyReg,eimEOMnextAddr]; eim2to1updateLineInBand: SKIP[ R<0], eimLineInBand←(eimLineInBand)-1;*last line in band? GOTO[eimSleep]; NOP; *make sure write of eimLineInBand occurs before fetch PFETCH1[eimDataBase,eimLineInBand,eimLinesPerBandOffset]; CALL[eimNOPreturn], PFETCH1[eimDataBase,eimPBKtablePtr,eimPBKtablePtrOffset]; t←eimPBKtablePtr; TASK, PSTORE2[eimDataBase,eimNibblesInPage]; eimPBKtablePtr←(eimPBKtablePtr)+(2c); GOTO[eimSleep], PSTORE1[eimDataBase,eimPBKtablePtr,eimPBKtablePtrOffset]; ******************************************************************************** *eimMesaRequest ******************************************************************************** eimMesaRequest: AT[eimEimDispLoc,5], PFETCH4[eimCSBbase,eimMesaInterruptMask,0]; CALL[eimNOPreturn]; INPUT[eimMesaStatus,eimMesaStatAddr];*overwrites lock from PFETCH;will be reset later DISPATCH[eimMesaStatus,15,3], LU←eimMesaStatus;*lock untill it gets here DISP[eimMesaDisp]; eimMesaDisp: ******************************************************************************** *increment NsectorsEmpty ******************************************************************************** eimMesaNsectorsEmpty: AT[eimMesaDispLoc,0], GOTO[eimMesaClearMesaLock], eimNsectorsEmpty←(eimNsectorsEmpty) +(1c); ******************************************************************************** *disable eim wakeups ******************************************************************************** eimMesaDisableEimWakeups: AT[eimMesaDispLoc,1], GOTO[eimMesaClearMesaLock], OUTPUT[eimClear,eimClearAddr]; ******************************************************************************** *enable IO wakeups ******************************************************************************** eimMesaEnableInput: AT[eimMesaDispLoc,2], GOTO[.+2], t←eimiWUenable; *enable input wakeup only (IIT source) eimMesaEnableIO: AT[eimMesaDispLoc,3], t←eimioWUenable; *enable input and output (DO source) CALL[eimFetchEIMmode]; eimEimMode←(eimEimMode) OR (t); OUTPUT[eimEimMode,eimEimModeAddr]; NOP; *allow write of eimEIMMode GOTO[eimMesaClearMesaLock], PSTORE1[eimCSBbase, eimEimMode, eimEimModeOffset]; ******************************************************************************** *page init ******************************************************************************** eimMesapage init: AT[eimMesaDispLoc,4], PFETCH2[eimCSBbase, eimDataBase, eimDataBaseOffset]; eimiBuffPtr←eimInputOffset; *one page from start of DataBase t←(LDF[eimiBufferParm,0,7]); *reset sector count (new field size) eimiSectorCntr←t; PFETCH2[eimCSBbase, eimoBuffPtr, eimOutputBaseOffset]; t←(LDF[eimiBufferParm,7,11]); *reset block count (new field size) eimiBlockCntr←t; eimNibblesInPage←zero; TASK, PFETCH4[eimDataBase, eimSWmaxWords, eimSWmaxWordsOffset]; eimNibblesInPage1←zero; eimLineInBand←(zero)-1; *last line of imaginary 0th band GOTO[eimMesaClearMesaLock], eimSWentryNum←zero; ******************************************************************************** *start EOM data ******************************************************************************** eimMesaStartEOMdata: AT[eimMesaDispLoc,5], GOTO[eimMesaClearMesaLock], INPUT[eimDummyReg,eimEOMnextAddr]; ******************************************************************************** *clear lock ******************************************************************************** eimMesaClearMesaLock: eimMesaLock←0c; NOP; *make sure lock is written GOTO[eimSleep], PSTORE4[eimCSBbase, eimMesaInterruptMask,0]; ******************************************************************************** *eimOutWU ******************************************************************************** ******************************************************************************** * transfer loop ******************************************************************************** eimOutWU: AT[eimEimDispLoc,6], GOTO[eimoSectorEmpty,R<0], eimoBlockCntr←(eimoBlockCntr)-(1c); eimoBlockTransfer: t←eimoBuffPtr; TASK,IOSTROBE,IOFETCH20[eimDataBase, eimOutputBufAddr]; eimoBuffPtr←(eimoBuffPtr)+(20c); GOTO[eimRun]; ******************************************************************************** * buffer management ******************************************************************************** eimoSectorEmpty: CALL[eimFetchEIMmode]; eimEimMode←(eimEimMode) AND NOT (eimoWUenable); OUTPUT[eimEimMode,eimEimModeAddr]; *inhibit wakeups PFETCH1[eimCSBbase, eimoBufferSelect, eimoBufferSelectOffset]; TASK, t←eimoBuffPtr;*save buffPtr, it will be clobbered by PFETCH PSTORE1[eimCSBbase, eimEimMode, eimEimModeOffset]; PFETCH2[eimCSBbase, eimoBuffPtr, eimOutputBaseOffset];*reset BuffPtr CALL[eimFetchIntMask]; eimoBufferSelect←(eimoBufferSelect) XOR (1C); *flip sectors SKIP[ ALU=0], LU←eimoBuffPtr;*insure that fetch occurs first eimoBuffPtr←t; *restore BuffPtr GOTO[eimNotify], PSTORE1[eimCSBbase,eimoBufferSelect, eimoBufferSelectOffset]; END[EIM]; :ELSE; ********************************************* TITLE[No.EIM.microcode]; :ENDIF; ********************************************