:TITLE[JasmineHalftone4];
*Last edited by Fiala 20 Nov 80, by Maleson 3 April 80

*Floyd-Steinberg error distribution halftoning, 4 bits/point
*	"REPLACE" mode,
*	doesn't work for all modes (save space)

*Available RM Temps: 44-53 56-57, 66-73; available Unused: 0
**These assignments require that the Mesa stack must not be allowed longer
**than 6 words when this code is run.
RV4[errorVec,errorVecHi,screenWord,screenWordHi,44];
RV4[bitCount,bitmapWidth,pixelArray,pixelArrayHi,50];
RV4[nInputPixels,blackVal,pixelVal,nOutputDots,10];

RV2[AddrTemp,AddrTempHi,14];

RV[CascadeRight,56];
RV[CascadeDiag,57];
RV[bitVal,66];
RV[jctr,67];
RV[x,70];
RV[val,71];
RV[errorTemp,72];
RV[returnLoc,73],

Set[HalftonePage,15];	*Presumably the software that uses this microcode
			*must be revised if this page assignment changes
			*(i.e., if the starting location changes).

PSet[PrintLine,HalftonePage,0];	*Starting location

SetTask[0];
OnPage[HalftonePage];

*halftone stuff
	AddrTempHi ← 0C, At[PrintLine];
	Stack&-1;
	T ← Stack;
	AddrTemp ← T, UseCTask;
	T ← APCTask&APC;
	returnLoc ← T;
	PFetch4[AddrTemp,errorVec,4];
	Stack&+1;
	PFetch4[AddrTemp,bitCount,10];
	T ← LSh[errorVecHi,10], Task;
	errorVecHi ← (errorVecHi) + T + 1;
	T ← LSh[screenWordHi,10];
	screenWordHi ← (screenWordHi) + T + 1;
	PFetch4[AddrTemp,nInputPixels,0], Task;
	T ← LSh[pixelArrayHi,10];
	Dispatch[bitCount,16,2];
	pixelArrayHi ← (pixelArrayHi) + T + 1, Disp[.+1]; 
*bit selection dispatch table
	bitVal ← 170000C, Goto[b20], DispTable[4];
	bitVal ← 7400C, Goto[b20];
	bitVal ← 360C, Goto[b20];
	bitVal ← 17C, Goto[b20];
b20:	T ← bitCount;
	PFetch1[errorVec,CascadeRight];
	bitCount ← LSh[bitCount,2];
	T ← Stack;
	AddrTemp ← T;
	T ← nOutputDots;
	jctr ← (Zero) - T;
	CascadeDiag ← Zero;
	CascadeRight ← (LSh[CascadeRight,2]) - 1;
	T ← nInputPixels;
	Stack4 ← T;
	T ← LdF[bitmapWidth,4,1];
	nInputPixels ← (nInputPixels) + T; 
	x ← T, Goto[forX0];

*subroutines: pieces used by all four modes
GetPixel:
	T ← RSh[x,1], Goto[xDone,ALU<0];
	PFetch1[pixelArray,pixelVal];
	LU ← x, Goto[xOdd,R Odd];
xEven:	pixelVal ← RSh[pixelVal,10], Return;
xOdd:	pixelVal ← RHMask[pixelVal], Return;

OrVal:	PFetch1[screenWord,Stack6];
	T ← bitVal;
	Dispatch[bitCount,14,2];
	Stack6 ← (Stack6) and not T, Disp[.+1];
	T ← LSh[val,14], Goto[or4], DispTable[4];
	T ← LSh[val,10], Goto[or4];
	T ← LSh[val,4], Goto[or4];
	T ← val;
or4:	Stack6 ← (Stack6) or T, Return;

StoreVal:
	PStore1[screenWord,Stack6], Return;

GetError: 
	CascadeRight ← (RSh[CascadeRight,1]) or T, Goto[a1,R Odd];
a0:	T ← (RSh[CascadeRight,1]) or T, Goto[a00,R Even];
a01:	CascadeRight ← (CascadeRight) + 1;
a00:	errorTemp ← T, Goto[haveError];

a1:	T ← (RSh[CascadeRight,1]) or T, Goto[a10,R Even];
a11:	errorTemp ← T ← (Zero) + T + 1, Goto[haveError];
a10:	CascadeRight ← (CascadeRight) + 1, Goto[a00];
haveError:
	CascadeDiag ← (CascadeDiag) + T;	
	T ← RSh[bitCount,2];
	PStore1[errorVec,CascadeDiag], Return;
GetNext:
	PFetch1[errorVec,Stack6];
	T ← errorTemp;
	CascadeDiag ← T;
	T ← Stack6;
	CascadeRight ← (CascadeRight) + T;
	T ← Stack4, Return;

xDone:	APCTask&APC ← returnLoc;
	Stack&-1, Return;

forX0:	LU ← (nInputPixels) - T - 1, Call[GetPixel]; *5 mi
	T ← jctr, Goto[jDone0,R>=0];
whileJ0: 
	T ← pixelVal;
	CascadeRight ← T ← (CascadeRight) + T;
	LU ← RSh[CascadeRight,10], Skip[ALU>=0];
	  val ← 0C, Goto[HaveVal];	*Neg. value
	PFetch1[AddrTemp,val], Goto[OverVal,ALU#0];	*Pos. value
	T ← val;
	T ← (LSh[val,4]) + T;
	CascadeRight ← (CascadeRight) - T, Goto[HaveVal];
OverVal:
	val ← 17C;
	CascadeRight ← (CascadeRight) - (377C);
HaveVal:
	T ← LdF[bitCount,0,14], Call[OrVal];
	T ← LdF[bitCount,0,14], Call[StoreVal];
EndDot0:
	T ← (CascadeRight) AND (100000C), Call[GetError];
	bitCount ← (bitCount) + (4C);
	T ← RSh[bitCount,2], Call[GetNext];
	jctr ← (jctr) + T;
	bitVal ← RCy[bitVal,4], Goto[whileJ0,ALU<0];
jDone0:	T ← nOutputDots;
	jctr ← (jctr) - T;
	x ← T ← (x) + 1, Goto[forX0]; *could save 7 mi if jctr still negative