; 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;