; DDTapeWriteTask.mu  -- Tape Microcode for the Alto Double Density Tape Controller
; Copyright Xerox Corporation 1980

; Body of Tape Controller write task microcode -- requires definitions in DDTapeDefs.mu
;
; Last modified by Tim Diebert, March 4, 1981  11:32 AM
; 
; Branch Conditionals
!1, 2, EraseDataOp, WriteData;
!1, 2, WriteByte, WriteAlmostLastByte;
!1, 2, WriteTwo, WriteOne;
!1, 2, EraseData, EraseDone;
!1, 2, Write, Write1;

; Write loop
;     Task 5
;
; Write expects the following registers to be loaded.
; ByteCnt should contain the number of bytes to be written.
; WordCnt must not contain any usefull data.
; WrtPtr points to the first word to be transfered - 1.

WriteTask:
	NOP;

Write:
	GoCmd← ZeroCmd;	Tell the read task we understand and are reset.
	TASK;
	NOP;	THIS IS WHERE THE WRITE TASK SHOULD BE AFTER THE RESET.

	T← ResetWriteTask;	Wait for write task to reset.
	L← TStatus AND T;
	TASK, SH=0;
	:Write;	[Write, Write1]

Write1:
	T← IErase;
	L← Command AND T;
	L← WriteByteCnt, SH=0;	Build the word count and the low order bit of the byte count.
	WriteWordCnt← LRSH1, :EraseDataOp;	[EraseDataOp, WriteData]

WriteData:
	T← ByteCountOffset;
	MAR← TCBBase + T;
	TASK;
	MD← WriteByteCnt;

	T← WriteByteCnt;
	L← WriteWordCnt - 1; Decrement the word count by 1.
	WriteWordCnt← L;
	L← 1 AND T;
	WriteByteCnt← L;

; The write loop works as follows. The main loop is executed until 4 or 5 bytes
; remain. Then WriteAlmostLastByte is entered. The last word known not to contain the 
; last byte is written. The first byte of the word that may contain the last byte is written
; while a check for odd byte is done. At this point the last byte is written or the last 2
; bytes are written so the hardware can be told when to send LastWord to the formatter.
WriteLoop:
	T← MAR← WritePtr + 1;	Start memory reference
	L← WriteWordCnt - 1;	Decrement the byte count
	WriteWordCnt← L, L← T, SH=0;
	WritePtr← L, :WriteByte;	[WriteByte, WriteAlmostLastByte]
WriteByte:
	L← TWrite← MD, TASK;
	WriteTapeData← LLCY8;
	TWrite← WriteTapeData, TASK;
	:WriteLoop;

WriteAlmostLastByte:
	L← TWrite← MD, TASK;	Write byte n-4 or n-3
	WriteTapeData← LLCY8;
	TWrite← WriteTapeData, TASK;	
	NOP;
	L← MAR← WritePtr + 1;	Start memory reference
	WritePtr← L;
	SINK← WriteByteCnt, BUS=0;
	L← TWrite← MD, :WriteTwo;	[WriteTwo, WriteOne] Write byte n-2 or n-1
WriteOne:
	TASK;
	WriteTapeData← LLCY8;
	TLastByte← WriteTapeData;	Write byte n.
	:WriteDone;

WriteTwo:
	TASK;
	WriteTapeData← LLCY8;
	TWrite← WriteTapeData, TASK;
	NOP;
	L← MAR← WritePtr + 1;	Start memory reference
	NOP;
	TLastByte← MD;	Write byte n.

	L← ALLONES;
	MAR← TCBBase;
	TASK;
	MD← M, :WriteDone;

EraseDataOp:
	WriteTapeData← 0;
EraseData:
	TASK;
	NOP;
	L← WriteByteCnt - 1;
	WriteByteCnt← L, SH=0;
	TWrite← WriteTapeData, :EraseData;	[EraseData, EraseDone]

EraseDone:
	TASK;
	NOP;
	TLastByte← WriteTapeData;
	:WriteDone;

WriteDone:
	:Write;