{ IOCopy.mc, HGM, 4-Nov-84 2:58:57 This module implements a clump of opcodes used to copy data from/to main memory to/from Multibus IO addresses. The extra set of opcodes is because some devices (DES chip, SUN 3mb board) stuff all the data through 1 address, and others (3Com 10mb board) use a range of addresses. "Read" means Read from IO device and write into memory. "Write" means Write to IO device and read from memory. IO Mapping can't cross 64K word boundries. (Something is probably wrong if they cross 64K byte boundries.) Main memory address must be valid if word count is 0. Register usage: rhRio, Rio Used to address IO device T Holds data word rhTT, TT/Q Hold Virtual address rhRx, Rx Hold Real address TOS Has count of words left to transfer All 8 operations are minimal stack. Thus: TOS Count of words to transfer uStack5 STK High word of IO address uStack4 STK-1 Low word of IO address uStack3 STK-2 High word of main memory address uStack2 STK-3 Low word of main memory address Except for uStack2, the info on the stack is kept up to date. L0, L1, and L3 used for Map Fixup L2 used for mode dispatching Beware: IO Addresses are WORD addresses rather than byte addresses. Most boards will ignore the high bit in Rio and all of rhRio. rhRio is there because the 3Com Ethernet boards eat up a lot of address space. Fortunately, they respond to 24 bit addresses. IO addresses can't cross 64K boundries. Note that main memory address is on the bottom of the stack for both Reading and Writing. This makes the microcode simpler, but adds an opportunity to get things mixed up if you expect the dest to be on the bottom. } Set[L2.ReadHole, 0]; Set[L2.ReadBlock, 1]; Set[L2.ReadHyper, 2]; Set[L2.WriteHole, 3]; Set[L2.WriteBlock, 4]; Set[L2.WriteHyper, 5]; Set[L2.ReadHoleSlow, 6]; Set[L2.WriteHoleSlow, 7]; ESC9n: {L2 loaded on the DISP4 to get here} ReadHole: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.ReadHole,10,ESC9n]; ReadBlock: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.ReadBlock,10,ESC9n]; ReadHyper: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.ReadHyper,10,ESC9n]; WriteHole: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.WriteHole,10,ESC9n]; WriteBlock: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.WriteBlock,10,ESC9n]; WriteHyper: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.WriteHyper,10,ESC9n]; ReadHoleSlow: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.ReadHoleSlow,10,ESC9n]; WriteHoleSlow: TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1, at[L2.WriteHoleSlow,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[08,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[09,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0A,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0B,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0C,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0D,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0E,10,ESC9n]; PC ← PC - 1, GOTO[ESCb], c1, at[0F,10,ESC9n]; IOCopyRestart: rhTT ← uStack3{MemHi}, c2; L0 ← L0.IOCopy, GOTO[IOMap], c3; IONewPage: [] ← TT, ZeroBr, CANCELBR[$, 1], c2; uStack2 ← TT, BRANCH[IOMap, IONewBank], c3; IONewBank: Q ← rhTT + 1, LOOPHOLE[byteTiming], c1; rhTT ← Q LRot0, c2; uStack3 ← Q, c3; IOMap: Map ← Q ← [rhTT, TT], L1 ← L1.None, c1; rhRio ← uStack5{IOHi}, c2; Rx ← rhRx ← MD, XDirtyDisp, c3; BRANCH[IOMud, $, 1] c1, WLMFRet[L0.IOCopy]; [] ← TOS, ZeroBr, c2; BRANCH[IOCopy, IOCopyDone], c3; IOCopy: Rio ← uStack4, MesaIntBr, BRANCH[$, IONewPage], c1; Q ← Rio + 1, L2Disp, BRANCH[$, IOCopyInt], c2; DISP3[IOLoad], c3; IOLoadWord: IO ← [rhRio, Rio + 0], GOTO[IORdHole], c1, at[L2.ReadHole, 8, IOLoad]; IO ← [rhRio, Rio + 0], GOTO[IORd], c1, at[L2.ReadBlock, 8, IOLoad]; MAR ← [rhRio, Rio + 0], RawRef, GOTO[IORd], c1, at[L2.ReadHyper, 8, IOLoad]; MAR ← [rhRx, TT + 0], GOTO[IORdHole], c1, at[L2.WriteHole, 8, IOLoad]; MAR ← [rhRx, TT + 0], GOTO[IORd], c1, at[L2.WriteBlock, 8, IOLoad]; MAR ← [rhRx, TT + 0], GOTO[IORd], c1, at[L2.WriteHyper, 8, IOLoad]; IO ← [rhRio, Rio + 0], GOTO[IORdHole], c1, at[L2.ReadHoleSlow, 8, IOLoad]; MAR ← [rhRx, TT + 0], GOTO[IORdHole], c1, at[L2.WriteHoleSlow, 8, IOLoad]; IORdHole: L2Disp, GOTO[IORda], c2; IORd: uStack4 ← Q, L2Disp, c2; IORda: T ← MD, DISP3[IOStore], c3; IOStoreWord: MAR ← [rhRx, TT + 0], GOTO[IOWr], c1, at[L2.ReadHole, 8, IOStore]; MAR ← [rhRx, TT + 0], GOTO[IOWr], c1, at[L2.ReadBlock, 8, IOStore]; MAR ← [rhRx, TT + 0], GOTO[IOWr], c1, at[L2.ReadHyper, 8, IOStore]; IO ← [rhRio, Rio + 0], GOTO[IOWr], c1, at[L2.WriteHole, 8, IOStore]; IO ← [rhRio, Rio + 0], GOTO[IOWr], c1, at[L2.WriteBlock, 8, IOStore]; MAR ← [rhRio, Rio + 0], RawRef, GOTO[IOWr], c1, at[L2.WriteHyper, 8, IOStore]; MAR ← [rhRx, TT + 0], GOTO[IOWr], c1, at[L2.ReadHoleSlow, 8, IOStore]; IO ← [rhRio, Rio + 0], GOTO[IOWr], c1, at[L2.WriteHoleSlow, 8, IOStore]; IOWr: MDR ← T, TOS ← TOS - 1, ZeroBr, c2; TT ← TT + 1, PgCarryBr, BRANCH[IOCopy, IOCopyDone], c3; {-------------------------------------------------------------------------} {Don't bother to remember if we are reading or writing} {Map Update smashes L3.} IOMud: CALL[WLMapFix], c2; {-------------------------------------------------------------------------} IOCopyInt: [] ← uWDC, NZeroBr, CANCELBR[$, 0F], c3; uStack2 ← TT, BRANCH[$, IOCopyIgnoreInt], c1; PC ← PC - 1, GOTO[IOCopyDoInt], c2; IOCopyFalseInt: {Lots of registers have been smashed, but not L2} TT ← uStack2{MemLo}, GOTO[IOCopyRestart], c1; IOCopyIgnoreInt: Noop, c2; ClrIntErr, GOTO[IOCopy], c3; {-------------------------------------------------------------------------} IOCopyDone: stackP ← 0, CANCELBR[$, 1], c1; Noop, c2; Xbus ← uPCCross, XRefBr, c3; PC ← PC - PC16, BRANCH[blNoInt, blSetInt {Block.mc}], c1; {-------------------------------------------------------------------------}