:TITLE[JasmineHalftone];

%Edit by Fiala 16 July 1981: Harmonize with Pilot; change register assignments
to use more of available Stack registers; eliminate returnLoc register; add
prefix jh to register names.
Edit by Fiala 7 January 1981: Harmonize with Alto system; bum many mi.
Created by Maleson 3 April 1980.

Floyd-Steinberg error distribution halftoning,
"REPLACE" mode doesn’t work for all modes (save space)
%
SetTask[0];

*jhTemp1 (RM 5) and jhTemp2 (RM 7) are also used.
:IF[AltoMode]; **********************************
RV4[jhErrorVec,jhErrorVecHi,jhScreenWord,jhScreenWordHi,44];
RV4[jhBitCount,jhBitmapWidth,jhPixelArray,jhPixelArrayHi,50];
RV4[jhNInputPixels,jhBlackVal,jhRange,jhNOutputDots,10];

RV2[jhAddrTemp,jhAddrTempHi,14];

RV[jhCascadeRight,56];
RV[jhCascadeDiag,57];
RV[jhBitVal,66];
RV[jhJCtr,67];
RV[jhX,2];
RV[jhVal,3];
RV[jhErrorTemp,4];
RV[jhTemp1,5];
RV[jhTemp2,7];
:ELSE; ******************************************
*It seems that RM 6, 16-17 and 70-73 are available temporaries.
RV4[jhErrorVec,jhErrorVecHi,jhScreenWord,jhScreenWordHi,44];
RV4[jhBitCount,jhBitmapWidth,jhPixelArray,jhPixelArrayHi,50];
RV4[jhNInputPixels,jhBlackVal,jhRange,jhNOutputDots,10];

RV2[jhAddrTemp,jhAddrTempHi,14];

RV[jhCascadeRight,56];
RV[jhCascadeDiag,57];
RV[jhBitVal,66];
RV[jhJCtr,67];
RV[jhX,2];
RV[jhVal,3];
RV[jhErrorTemp,4];
RV[jhTemp1,5];
RV[jhTemp2,7];
:ENDIF; *****************************************

OnPage[HalftonePage];

***Find out whether MDShi should be used here and/or in Jasmine.Mc instead of
***0C for the high base register value.
@JHalfTone:
jhAddrTempHi ← 0C, At[PrintLine];
T ← Stack;
jhAddrTemp ← T;
PFetch4[jhAddrTemp,jhErrorVec,4];
PFetch4[jhAddrTemp,jhBitCount,10];
T ← LSh[jhErrorVecHi,10], Task;
jhErrorVecHi ← (jhErrorVecHi) + T + 1;
T ← LSh[jhScreenWordHi,10];
jhScreenWordHi ← (jhScreenWordHi) + T;*no +1, for negative adds;
PFetch4[jhAddrTemp,jhNInputPixels,0], Task;
T ← LSh[jhPixelArrayHi,10];
jhPixelArrayHi ← (jhPixelArrayHi) + T + 1;
T ← LdF[jhBitCount,14,4];
jhBitVal ← 17C;
jhBitVal ← (jhBitVal) - T;
CycleControl ← jhBitVal;
jhBitVal ← 100000C;
*jhBitVal ← 100000b rsh (jhBitCount[12d:15d])
jhBitVal ← WFA[jhBitVal];
T ← jhBitCount;
PFetch1[jhErrorVec,jhCascadeRight];
T ← jhNOutputDots;
jhJCtr ← (Zero) - T;
jhCascadeDiag ← Zero;
jhCascadeRight ← (LSh[jhCascadeRight,2]) - 1;
T ← jhNInputPixels;
jhTemp1 ← T;
T ← LdF[jhBitmapWidth,4,1];
jhNInputPixels ← (jhNInputPixels) + T;
jhX ← T, GoTo[forX0];

*subroutines: pieces used by all four modes
GetPixel:
T ← RSh[jhX,1], GoTo[xDone,ALU<0];
PFetch1[jhPixelArray,jhVal];
T ← jhBlackVal;
LU ← jhX, GoTo[xOdd,R Odd];
xEven:
jhVal ← T ← (RSh[jhVal,10]) - T, GoTo[blackCheck];
xOdd:
jhVal ← T ← (RHMask[jhVal]) - T, GoTo[blackCheck];
blackCheck:
LU ← (jhRange) - T, GoTo[blackOK,ALU>=0];
jhVal ← Zero, Return;
blackOK:
T ← jhRange, GoTo[whiteOK,ALU>=0];
jhVal ← T, Return;
whiteOK:
Return;

OrBlack:
PFetch1[jhScreenWord,jhTemp2];
T ← jhBitVal;
jhTemp2 ← (jhTemp2) or T, Return;

NotWhite:
PFetch1[jhScreenWord,jhTemp2];
T ← jhBitVal;
jhTemp2 ← (jhTemp2) and not T, Return;

StoreVal:
PStore1[jhScreenWord,jhTemp2], Return;

GetError:
jhCascadeRight ← (RSh[jhCascadeRight,1]) or T, GoTo[a1,R Odd];
a0:
T ← (RSh[jhCascadeRight,1]) or T, GoTo[a00,R Even];
a01:
jhCascadeRight ← (jhCascadeRight) + 1;
a00:
jhErrorTemp ← T, GoTo[haveError];

a1:
T ← (RSh[jhCascadeRight,1]) or T, GoTo[a10,R Even];
a11:
jhErrorTemp ← T ← (Zero) + T + 1, GoTo[haveError];
a10:
jhCascadeRight ← (jhCascadeRight) + 1, GoTo[a00];
haveError:
jhCascadeDiag ← (jhCascadeDiag) + T;
T ← jhBitCount;
PStore1[jhErrorVec,jhCascadeDiag], Return;
GetNext:
PFetch1[jhErrorVec,jhTemp2];
T ← jhErrorTemp;
jhCascadeDiag ← T;
T ← jhTemp2;
jhCascadeRight ← (jhCascadeRight) + T;
T ← jhTemp1, Return;

xDone:
LoadPageExternal[opPage3];
GoToExternal[P7TailLoc];

forX0:
LU ← (jhNInputPixels) - T - 1, Call[GetPixel];
T ← jhJCtr, GoTo[jDone0,R>=0];
whileJ0:
T ← jhVal;
jhCascadeRight ← (jhCascadeRight) + T;
T ← jhRange, GoTo[White0,ALU>=0];
Black0: T ← LdF[jhBitCount,0,14], Call[OrBlack];
T ← LdF[jhBitCount,0,14], Call[StoreVal];
EndDot0:
T ← (jhCascadeRight) and (100000C), Call[GetError];
jhBitCount ← T ← (jhBitCount) + 1, Call[GetNext];
jhJCtr ← (jhJCtr) + T;
jhBitVal ← RCy[jhBitVal,1], GoTo[whileJ0,ALU<0];
jDone0:
T ← jhNOutputDots;
jhJCtr ← (jhJCtr) - T;
jhX ← T ← (jhX) + 1, GoTo[forX0]; *could save 7 mi if jhJCtr still negative

White0: jhCascadeRight ← (jhCascadeRight) - T;
T ← LdF[jhBitCount,0,14], Call[NotWhite];
T ← LdF[jhBitCount,0,14];
PStore1[jhScreenWord,jhTemp2], GoTo[EndDot0];

:END[JasmineHalftone];