{
 File name:  Raven.mc
 Description: Raven LSEP (Low Speed Electronic Printer) microcode
 Author: Pitts Jarvis,
 Created: March 14, 1980,
 Last Edited: 
	Jarvis, November 25, 1980  2:14 PM
	Olmstead, March 23, 1981  5:25 PM: Remove some unneeded CANCELBR's
	Garner, July 30, 1981  11:51 PM: added ClrDPRq & PCtl← after endBand
		so that hardware fix to allow slower LSEP's works.  (Note that the click
		at endBand can be eliminated if the click before uses nibCarry.)
	BJackson, 16-Nov-85 19:10:07: Cleanup tabs, etc.
	Fiala, 24-Jul-86 10:50:46 Initialize displayBase0 and displayBase2 from the
		constant cedarIOPageHigh instead of from the rh of uIOPage.  Also add 1
		to the values for WakeupMaskOffset here and PrinterOverrunOffsetM1 and
		PrinterRunOffset in NewDandelion.dfn because the value in uIOPage is
		1 less.
}

{
Printer Control register on X-Bus

~ClearLineActive	8	Inhibits data wakeups and forces video to all white until next line sync
ForceRequest		4	forces printer wakeups every round
VideoWhite		2	forces video to white
EnablePrinter		1	enables printer and memory refresh task wakeups
}

Set[EndActiveScanCtl,	1];
Set[EndBandScanCtl,	5];
Set[StartScanCtl,	9];
Set[StartActiveCtl,	0B];

{
Raven CSB  (read once per page, immediately after code detects run#0)

	run		non-zero=> index of 1st band record (displayBase0 relative), read then zeroed
	overrun		non-zero=> over ran band buffer
	interruptMask	Mesa process stuff
	bandSize	number of lines in a band
	active scan	number of words in line buffer actually sent to printer
	line size	number of words in line buffer
	tab		number of words skipped from line sync before sending image to printer
	scans		number of blank lines sent to printer at start of page
}

{
Raven band record

	pointer	real address of band (displayBase1 relative)
	next	index of next band record (displayBase0 relative)
	status	0=> empty, #0=> full, <0=> last band
}

SetTask[1]; StartAddress[PrinterInit];

PrinterInit:
	displayBase1 ← 0 {band buffer in first 64K}, CancelDisp[$]	,c1;
PrinterInitC2:
	displayBase0 ← cedarIOPageHigh,					c2;
	rD0 ← uIOPage,							c3;

pageGap:
	MAR← [displayBase0, rD0 + PrinterRunOffset]			,c1; {wait for non-zero run}
	MDR← 0, CancelPgCross[$, 0], LOOPHOLE[wok]			,c2; {. . . clear it immediately}
	rD1← MD								,c3;

	uThis← rD1, ZeroBr						,c1;
	rD1← 0A, BRANCH[startPage, $]					,c2; {rD1← AltUaddr index}
	PCtl← EndActiveScanCtl, GOTO[pageGap]				,c3;

startPage:
	Noop	,c3;

	rD0 ← MAR ← [displayBase0, rD0 + PrinterOverrunOffsetM1 + 1]	,c1; {clear overrun}
	MDR ← 0, CancelPgCross[$, 0], LOOPHOLE[wok]			,c2;
	Noop								,c3;

loadParam:
	MAR← [displayBase0, rD0+1], rD0← rD0+1				,c1; {load parameters}
	uScans← rD0, CancelPgCross[$]					,c2;
	rD0← MD								,c3;

	Ybus← rD1, rD1← rD1+1, NibCarryBr, AltUaddr			,c1;
	uyParamBase← rD0, BRANCH[$, skipLines]				,c2;
	rD0← uScans, GOTO[loadParam]					,c3;

skipLines:
	rD0← rD0-1, ZeroBr						,c3; {loaded uScans last}

	BRANCH[$, firstBand]						,c1;
	PCtl← EndActiveScanCtl, GOTO[skipLines]				,c2;

firstBand:
	rD0← uThis							,c2;
	rD1← 1								,c3; {not last band}

advanceBand:
	MAR← [displayBase0, rD0], rD0← rD0+1, ClrDPRq			,c1;
	[]← rD1, NegBr, CancelPgCross[$]				,c2; {test for last band}
	rD1← MD, BRANCH[$, lastBandDone]				,c3; {pointer to band}

	MAR← [displayBase0, rD0], rD0← rD0+1, ClrDPRq			,c1;
	uLineAddress← rD1, CancelPgCross[$]				,c2;
	rD1← MD								,c3; {next band}

	MAR← [displayBase0, rD0], uBandStatus← rD0, ClrDPRq		,c1; {save address for later}
	uThis← rD1, CancelPgCross[$]					,c2;
	rD1← MD								,c3; {status of this band}

	[]← rD1, ZeroBr							,c1;
	rD1← uLineAddress, BRANCH[$, RavenOverrun], ClrDPRq		,c2;
	rD0← uBandSize							,c3;

	uLineCount← rD0, ClrDPRq					,c1;
	rD0← uTabCnt							,c2;
	rD0← rD0-4, GOTO[startLine1]					,c3; {4 click band overhead}

startLine:
	PCtl← EndActiveScanCtl						,c1;
	rD0← uLineSize, ClrDPRq						,c2;
	rD1← uLineAddress						,c3;

	rD1← rD1+rD0, ClrDPRq						,c1; {line sync wakeup}
	PCtl← StartScanCtl						,c2;
	rD0← uTabCnt							,c3;

{Enter from advanceBand or startLine.  At this point rD0 has uTabCnt, rD1 has uLineAddress}

startLine1:
	uLineAddress← rD1, ClrDPRq					,c1;
	Noop								,c2;
	Noop								,c3;

idle:
	rD0← rD0-1, ZeroBr						,c1; {tab over to active area}
	BRANCH[$, startActive], ClrDPRq					,c2;
	GOTO[idle]							,c3;

startActive:
	PCtl← StartActiveCtl						,c3;

scan:
	MAR← [displayBase1, rD1+0], ClrDPRq				,c1;
	MDR← rD0{= zero}, rD1← rD1+1, PgCarryBr				,c2;
	POData← MD, BRANCH[scan, endLine]				,c3;

endLine:
	rD1← uLineCount, ClrDPRq					,c1; {play out last word}
	rD1← rD1-1, ZeroBr						,c2;
	uLineCount← rD1, BRANCH[startLine, endBand]			,c3;

endBand:
	ClrDPRq								,c1;
	PCtl← EndBandScanCtl						,c2;
	rD0← uBandStatus						,c3;

	MAR← [displayBase0, rD0+0]					,c1; {mark band empty}
	MDR← rD1							,c2; {. . . and get next band}
	rD1← MD								,c3; {negative=> last band}

{initiate band complete interrupt}

	rD0← uWP							,c1;
	rD0← uInterruptMask or rD0, MesaIntRq				,c2;
	uWP← rD0							,c3;

	rD0← uThis							,c1;
endBand1:
	Noop								,c2;
	PCtl← EndActiveScanCtl, GOTO[advanceBand]			,c3; {save old status for test}

lastBandDone:
	PCtl← EndActiveScanCtl, GOTO[PrinterInitC2]			,c1;

RavenOverrun:
	rD0 ← uIOPage							,c3;

	MAR← [displayBase0, rD0 + PrinterOverrunOffsetM1 + 1]		,c1; {set overrun}
	rD1 ← MDR ← 1, CancelPgCross[$, 0], LOOPHOLE[wok]		,c2; {. . . and not last band}
	rD0← uBandStatus						,c3;

	rD0← rD0-2, GOTO[endBand1]					,c1; {retry this band again}


{Memory Refresh Task}

SetTask[3]; StartAddress[RefreshGo];

	Set[WakeupMaskOffset, 0EB]; {added to uIOPage=(0)4000}
	Set[HalfFieldSize, 0E0];

RefreshGo:
	uClockBits ← 0, CancelDisp[$]					,c1;
	displayBase2 ← cedarIOPageHigh,					c2;
RefreshField:
	rD2 ← uIOPage,							c3;

	MAR ← [displayBase2, rD2 + WakeupMaskOffset]			,c1;
	Noop, CancelPgCross[$, 0]					,c2;
	rD2 ← MD							,c3;

	uPWakeup ← rD2							,c1;
{***Maybe bum 1 click here with:
	rD2 ← uWP or rD2, MesaIntRq,					c2;
	uWP ← rD2,							c3;
	}
	Noop								,c2;
	Noop								,c3;

{This code looks this way because uWP must be updated within one click.}

	rD2 ← uWP							,c1;
	rD2 ← uPWakeup or rD2, MesaIntRq				,c2;
	uWP ← rD2							,c3;

	rD2 ← LShift1 HalfFieldSize					,c1;
	uRefreshLine ← rD2						,c2;
	ClrRefRq							,c3;

Refresh:
	rD2 ← uClockLow, Refresh					,c1;
	rD2 ← rD2 + 1, CarryBr						,c2;
	uRefreshTemp ← rD2, BRANCH[$, RefreshCarry]			,c3;

	Refresh								,c1;
	Noop								,c2;
Refresh1:
	uClockLow ← rD2							,c3;

	rD2 ← uRefreshLine, ZeroBr					,c1;
	rD2 ← rD2 - 1, BRANCH[$, RefreshField]				,c2;
	uRefreshLine ← rD2, ClrRefRq, GOTO[Refresh]			,c3;

RefreshCarry:
	rD2 ← uClockHigh, Refresh					,c1;
	rD2 ← rD2 + 1							,c2;
	Noop								,c3;

	uClockHigh ← rD2						,c1;
	rD2 ← uRefreshTemp, GOTO[Refresh1]				,c2;