; DDTapeReadTask.mu -- Tape Microcode for the Alto Double Density Tape Controller ; Copyright Xerox Corporation 1980 ; Body of Tape Controller microcode -- requires definitions in DDTapeDefs.mu ; ; Last modified by Tim Diebert, March 4, 1981 10:28 AM ; ; Branch Conditionals !1, 2, Tape2, CommandDcd; !1, 2, DriveNotRdy, DriveRdy; !1, 2, BadCmd, DRNoOp; !1, 2, ReadLoop, NoBufLoop; !3, 4, BytesLeft, , BytesGoneEven, ; !3, 4, BytesLeft1, BytesLeftBufGone, BytesGoneOdd, BytesGoneOddBufGone; !3, 4, BytesLeftBufGoneLoop, , AdjustByteCnt, ; !1, 2, OpEnd, HardWareError; !1, 2, ReadDataFwd1, HardWareError1; !1, 2, ReadDataRev1, HardWareError2; !1, 2, ReadRevLoop, ReadRevNoBufLoop; !3, 4, ReadRevBytesLeft, , ReadRevBytesGoneEven, ; !3, 4, ReadRevBytesLeft1, ReadRevBufGoneBytesLeft, ReadRevBytesGoneOdd, ReadRevBytesGoneOddBufGone; !3, 4, ReadRevBufGoneBytesLeftLoop, , ReadRevAdjustByteCnt, ; !1, 2, WriteError3, WriteEof1; !1, 2, WriteError, WriteOp1; !1, 2, ReadDataFwd2, NoReadAfter; !1, 2, WriteError1, Erase1; !1, 2, WriteError2, EraseVar1; !1, 2, WriteOp2, HardWareError5; !1, 2, EraseVar2, HardWareError4; !1, 2, OpEnd3, OpEnd4; !1, 2, Tape3, Tape4; !1, 2, BytesLeftBufGoneLoop1, BailOut; !37, 40, ReadFwd, FwdSpaceRec, BadCmd02, BadCmd03, BadCmd04, FwdSpaceFile, BadCmd06, BadCmd07, WriteFwd, EraseVar, WriteEdit, BadCmd13, WriteEof, Erase, BadCmd16, BadCmd17, ReadRev, BackSpaceRec, ReadRevEdit, BadCmd23, BadCmd24, BackSpaceFile, BadCmd26, BadCmd27, BadCmd30, BadCmd31, BadCmd32, BadCmd33, BadCmd34, Rewind, Unload, NoOp; ; ; Top of loop ; Tape: NOP; Reset; Reset the tape controller hardware. T← 2; WriteWordCnt← T; WriteByteCnt← T; GoCmd← SetResetWriteTask; Wakeup the write task to start reset. TASK; NOP; T← 20; Set up to read TStart. MAR← 602 OR T; NOP; L← MD; TCBBase← L; Save the Pointer to the TCB. Tape3: T← ResetWriteTask; Wait for write task to reset. L← TStatus AND T; TASK, SH=0; :Tape3; [Tape3, Tape4] Tape4: Reset; Reset the tape controller hardware. T← ForcedReset; Check to see if we got here by a forced reset. L← TStatus AND T; L← StatusMask, SH=0; T← StatusOffset, :Tape2; [Tape2, CommandDcd] Tape2: GoCmd← ResetFMTEnbl; Disable the formatter. NOP; TASK; GoCmd← SetFMTEnbl, :OpEnd1; Enable the formatter. CommandDcd: MAR← TCBBase + 1; Get the command word. NOP; L← FmtCmd← MD; Load up the command so we get the unit adressed. Command← L; T← ReadOffset; Build read stuff for later. MAR← TCBBase + T; NOP; L← MD - 1; T← MD; ReadPtr← L, L← T, TASK; ReadBufSize← L; T← WriteOffset; Build write stuff for later. MAR← TCBBase + T; NOP; L← MD - 1; T← MD; WritePtr← L, L← T, TASK; WriteByteCnt← L; T← RdyOnl; Check for online and ready and save for later. T← TStatus . T; L← RdyOnl XOR T; SH=0; T← NoOpCmd, :DriveNotRdy; [DriveNotRdy, DriveRdy] DriveNotRdy: T← Command . T; L← NoOpCmd XOR T; SH=0; :BadCmd; [BadCmd, DRNoOp] DriveRdy: T← 37; Prepare for dispatch. L← Command AND T; SINK← M, BUS, TASK; Dispatch. :ReadFwd; ; ; Bad or unkown command processing ; BadCmd02: :BadCmd; BadCmd03: :BadCmd; BadCmd04: :BadCmd; BadCmd06: :BadCmd; BadCmd07: :BadCmd; BadCmd13: :BadCmd; BadCmd16: :BadCmd; BadCmd17: :BadCmd; BadCmd23: :BadCmd; BadCmd24: :BadCmd; BadCmd26: :BadCmd; BadCmd27: :BadCmd; BadCmd30: :BadCmd; BadCmd31: :BadCmd; BadCmd32: :BadCmd; BadCmd33: :BadCmd; BadCmd34: :BadCmd; BadCmd: T← StatusMask; Build Status. L← TStatus . T; T← StatusOffset; MAR← TCBBase + T; T← M, BLOCK; L← 1 OR T, TASK; Set the CmdErr bit MD← M, :Tape; ; ; Direct to drive commands ; Rewind: GoCmd← RewindCmd, :WaitABit; Unload: GoCmd← UnloadCmd, :WaitABit; WaitABit: NOP; NOP; NOP; NOP; NOP; NOP, TASK; GoCmd← ZeroCmd, :NoFmtGoOpEnd; DRNoOp: :NoFmtGoOpEnd; NoOp: :NoFmtGoOpEnd; ; ; End of operation stuff ; OpEnd: TASK; NOP; OpEnd1: T← 14; Set up to see if the formatter busy and data busy have gone L← TStatus . T; SH=0; :OpEnd3; [OpEnd3, OpEnd4] OpEnd3: BLOCK; This is to remove initail wakeup or Data Busy wakeup. TASK; NOP; OpEnd4: L← StatusMask; Build Status. T← StatusOffset; MAR← TCBBase + T; T← M; L← TStatus . T, TASK; MD← M; SIO9Reset, BLOCK; This is for the wait for FormatterBusy to go away. TASK; :Tape; ; ; End of operation where formatter busy will not give a final wakeup. ; NoFmtGoOpEnd: L← StatusMask; Build Status. T← StatusOffset; MAR← TCBBase + T; T← M, BLOCK; This is to remove initail wakeup. L← TStatus . T, TASK; MD← M; SIO9Reset; TASK; :Tape; ; ; Skip type operations ; FwdSpaceRec: BLOCK, :NoDataOP; FwdSpaceFile: BLOCK, :NoDataOP; BackSpaceRec: BLOCK, :NoDataOP; BackSpaceFile: BLOCK, :NoDataOP; NoDataOP: GoCmd← GO; Set the go flag bit and wait for at least 1 microsecond NOP; to turn it off. NOP; NOP; NOP; NOP; NOP; GoCmd← ZeroCmd; NOP; Check for formatter busy. T← FmtBusy; L← TStatus AND T; SH=0; :OpEnd; [OpEnd, HardWareError] ; ; Read operations ; ; ; Read assumes that ReadPtr contains the starting address of the read buffer - 1 ; and that RdBufSize contains the number of WORDS in the read buffer. ; ; The hardware provides a force of NEXT8 when a ←TReadF1 or ←TReadF2 encounters ; no more data to be transfered. ; Thus every instruction that executes a ←TReadF1 or ←TReadF2 must have a branch ; in the instruction following that goes to the end of data routine. ReadFwd: GoCmd← GO; start the ball rolling. NOP; NOP; NOP; NOP; NOP; GoCmd← ZeroCmd; Remove IGO after about 1 microsecond. NOP; Check for formatter busy. T← FmtBusy; L← TStatus AND T; SH=0; TASK, :ReadDataFwd1; [ReadDataFwd1, HardWareError1] ReadDataFwd2: EnRead, TASK; :ReadDataFwd3; This NOP is to make the tasking work ; for read after write. ReadDataFwd1: EnRead; BLOCK; TASK; :ReadDataFwd3; ReadDataFwd3: L← T← ReadBufSize; Build ReadBufBytes, & EndReadBuf values. ByteCnt← LLSH1; L← ReadPtr + T; EndReadBuf← L; L← ReadPtr; ReadBufStart← L; SINK← ByteCnt, BUS=0; Check for no read buffer. :ReadLoop; [ReadLoop, NoBufLoop] ReadLoop: L←TReadF2, TASK; Read the first byte of this word ReadTapeData← LLCY8, :BytesLeft; and move it to the top half of the word. ; [BytesLeft, , BytesGoneEven, ] BytesLeft: T← MAR← ReadPtr + 1; Start memory operation at ReadPtr+1. L← EndReadBuf - T; Check to see if this is the last word ; we can put in core. L← ReadTapeData, TReadF1, SH=0; Read the data & AND it with previous byte. MD← M, L← T, TASK, :BytesLeft1; Put it in memeory. ; [BytesLeft1, BytesLeftBufGone, BytesGoneOdd, BytesGoneOddBufGone] BytesLeft1: ReadPtr← L, :ReadLoop; Save the new read pointer. BytesLeftBufGone: ReadPtr← L, :NoBufLoop; Save the pointer for last byte computation. NoBufLoop: NOP; BytesLeftBufGoneLoop: T← 4; Set up to see if data busy has gone L← TStatus . T; T← ByteCnt + 1, SH=0; Increment the byte count. SINK← TReadF2, L← T, TASK, :BytesLeftBufGoneLoop1; [BytesLeftBufGoneLoop1, BailOut] BytesLeftBufGoneLoop1: ByteCnt← L, :BytesLeftBufGoneLoop ; [BytesLeftBufGoneLoop, , AdjustByteCnt, ] BytesGoneEven: T← ReadBufStart; Calculate number of bytes transfered. L← ReadPtr - T; ByteCnt← LLSH1, :ReadDone; BytesGoneOddBufGone: ReadPtr← L, :BytesGoneOdd1; BytesGoneOdd: ReadPtr← L, :BytesGoneOdd1; BytesGoneOdd1: T← ReadBufStart; Calculate number of bytes transfered. L← ReadPtr - T; ByteCnt← LLSH1, :AdjustByteCnt; BailOut: ByteCnt← L; AdjustByteCnt: L← ByteCnt - 1; ByteCnt← L, :ReadDone; ReadDone: T← ByteCountOffset; Prepare to store the byte count. MAR← TCBBase + T; TASK; MD← ByteCnt, :OpEnd; ; ; Read Reverse Data operation. ; ; ; ReadRev assumes that ReadPtr contains the starting address of the read buffer - 1 ; and that RdBufSize contains the number of WORDS in the read buffer. ; ; The hardware provides a force of NEXT8 when a ←TReadF1 or ←TReadF2 encounters ; no more data to be transfered. ; Thus every instruction that executes a ←TReadF1 or ←TReadF2 must have a branch ; in the instruction following that goes to the end of data routine. ReadRev: :BadCmd; ReadRevEdit: :BadCmd; ; ; Write type Operations ; WriteEof: T← FileProtectBit; L← TStatus AND T; SH=0; :WriteError3; [WriteError3, WriteEof1] WriteEof1: BLOCK, :NoDataOP; WriteFwd: :WriteOp; WriteEdit: :WriteOp; WriteOp: T← FileProtectBit; L← TStatus AND T; SH=0; :WriteError; [WriteError, WriteOp1] WriteOp1: EnWrite, TASK; NOP; GoCmd← GO; NOP; NOP; NOP; NOP; NOP; GoCmd← ZeroCmd; NOP; Check for formatter busy. T← FmtBusy; L← TStatus AND T; SH=0; :WriteOp2; [WriteOp2, HardWareError5] WriteOp2: T← ReadAfterWriteBit, BLOCK; Check for read after write. L← Command AND T; SH=0; :ReadDataFwd2; [ReadDataFwd2, NoReadAfter] NoReadAfter: TASK; :OpEnd; Erase: T← FileProtectBit; L← TStatus AND T; SH=0; :WriteError1; [WriteError1, Erase1] Erase1: BLOCK, :NoDataOP; EraseVar: T← FileProtectBit; L← TStatus AND T; SH=0; :WriteError2; [WriteError2, EraseVar1] EraseVar1: GoCmd← GO; NOP; NOP; NOP; NOP; NOP; GoCmd← ZeroCmd; NOP; Check for formatter busy. T← FmtBusy; L← TStatus AND T; SH=0; :EraseVar2; [EraseVar2, HardWareError4] EraseVar2: BLOCK; EnWrite, TASK; :OpEnd; WriteError: :WriteError2; WriteError1: :WriteError2; WriteError3: :WriteError2; WriteError2: T← StatusMask; Build Status. L← TStatus . T; T← StatusOffset; MAR← TCBBase + T; T← M, BLOCK; L← 2 OR T, TASK; Set the Write Error bit MD← M, :Tape; ; ; Errors ; HardWareError: :HardWareError2; HardWareError1: :HardWareError2; HardWareError4: :HardWareError2; HardWareError5: :HardWareError2; HardWareError2: T← StatusMask; Build Status. L← TStatus . T; T← StatusOffset; MAR← TCBBase + T; T← M, BLOCK; L← 4 OR T; Set the Hardware Error bit MD← M; TASK; :Tape;