;D0 parameter list
;Microcode for Floyd/Steinberg halftone algorithm

$10000
$10000;
$4000
$4000;
$s1
$R01;R register for ALU action after TASK: address of next word in s1
$val
$R02;R reg for shift: value of next data point stored here
$CascadeRight
$R03;error propogation to the right (R Reg for initial shift)
$error
$R05;R register for shift
$error1
$R07;R register for shift: error rshift 1

$xctr
$R41;loop counter across x for reading input points
$black
$R42;minimum value of data
$range
$R43;max-min
$CurrentBits
$R44;
$BitCount
$R45;
$byteptr
$R51;
$CascadeDiag
$R55;error propogation diagonally right
$GETS
$R56;address of next sample point in datavec

;stuff here that needs to stay around
$jctr
$R71;counter for repeating/deleting pts in x dir
$bitOffset
$R72; bit number of first output bit in first output word (0=leftmost)
$outpts
$R73;number of points to put out per line
$inpts
$R74;number of input points per line
$Screen
$R75;

;---------------------------------------------------------------
;first stuff appropriate S registers with input params
;---------------------------------------------------------------
;Print(inpts,black,range,outpts,s1,
s1bank,screen,screenbank,bitOffset,
;
[mode,xOdd,distance],pixelArray,pixelBank)
print: MAR←L←stk0;
L←stkp-1;reset stack pointer (1 element in, 0 out)
stkp ← L;
L←MD,TASK;
inpts←L;
NOP;TASK RETURNS HERE: stk0 instruction uses ALU←SReg

MAR←L←stk0+1;
stk0←L;
L←MD,TASK;
black←L;

NOP;TASK RETURNS HERE: stk0 instruction uses ALU←SReg
MAR←L←stk0+1;
stk0←L;
L←T←MD;
L ← LREG+T; range*2
range←L;
T←range;
L←range+T,TASK;range*4
range←L;

NOP;TASK RETURNS HERE: stk0 instruction uses ALU←SReg
MAR←L←stk0+1;
stk0←L;
L←MD,TASK;
outpts←L;

T←outpts;
L←0-T,TASK;
jctr←L;

NOP;TASK RETURNS HERE: stk0 instruction uses ALU←SReg
MAR←L←stk0+1;
stk0←L;
L←MD-1,TASK;we increment on the first store
s1←L;

T ← 2; skip bank (must be 0)
MAR←L←stk0+T;
stk0←L;
L←MD,TASK;
Screen←L;

T ← 2; skip bank (must be 0)
MAR←L←stk0+T;
stk0←L;
T ← 17;
L←MD,TASK;
val←L RSH 1;
L ← val,TASK;
val ← L RSH 1;
L ← val,TASK;
val ← L RSH 1;
L ← val,TASK;
val ← L RSH 1;
T ← val-1;
MAR←stk0;
L ← Screen+T;
Screen←L;
T ← 17;
L ← MD AND T,TASK;
bitOffset ← L;

;skip "distance"
T ← 2;
MAR←stk0+T;
L←inpts;
xctr←L;
L ← MD,TASK;
GETS ← L;

;---------------------------------------------------------------
;do the work
;---------------------------------------------------------------

!1,2,jdone,jloop;
!1,2,xloop,xdone;
!1,2,xloopL,xloopR;
!1,2,pos,neg;
!1,2,NoPut,PutWord;


;NOTE: error in from s1!0 is 1/4 range, so we multiply by 4 to keep the first line honest
;CascadeRight=(s1!0)*2
MAR←L←s1+1;
NOP;
L←MD,TASK;
CascadeRight←L LSH 1;
L←CascadeRight,TASK;
CascadeRight←L LSH 1;

L←0;
CurrentBits←L;
CascadeDiag←L,TASK;
byteptr←L;

;read the initial word, and mask out the bits from bitOffset on (unless bit Offset = 0)
!1,2,getPriorBits,noPriorBits;

L←T←bitOffset;
L←20-T,SH=0;
BitCount←L,:getPriorBits;1,2,getPriorBits,noPriorBits

getPriorBits:
L←BitCount-1;
T←LREG;
MAR←MASKTAB+T;
NOP;
L←MD;

MAR←Screen+1;
T←LREG;
L←MD AND NOT T,TASK;
CurrentBits←L;

noPriorBits:
L←T←0;

;for i=1 to x do
;let val=(GETS(picfile)-black) lshift 2
xloop: L←ONE XOR T;
byteptr←L,SH=0;
MAR←GETS,:xloopL;

xloopL: T←177400;
L←MD AND T;
temp←L LCY 8;
L←temp,:GETdone;

xloopR: L←GETS+1;
GETS←L;
T←377;
L←MD AND T;

GETdone:T←black;
L←LREG-T,TASK;

val←L LSH 1;
L←val,TASK;
val←L LSH 1;

!1,2,SetBit,NoSetBit;

;while jctr ls 0 do
L←jctr;
whilej:
T←val,SH<0;
L←CascadeRight-T,:jdone;

;test (CascadeRight-val) ls 0 then [ error=error+range] or SetBit()
jloop:
error←L,SH<0;
T←range,:SetBit;
NoSetBit:
L←error+T;

SetBitReturn:
T←0,SH<0;
error←L MRSH 1,:pos;do shift assuming positive (right half the time)
neg:
T←ONE;

;error=error rshift 1//arithmetic shift
error←L MRSH 1;

;error1=error rshift 1//arithmetic shift
pos:
L←error,TASK;************************************************************
error1←L MRSH 1;

;s1!index=CascadeDiag+error1
L←s1+1;
s1←L;
MAR←s1;
T←error1;
L←CascadeDiag+T,TASK;
MD←LREG;

;CascadeRight=s1!index+error
;CascadeDiag=error1
MAR←s1+1;
L←error1;
CascadeDiag←L;
T←error;TASK here bombs
L←MD+T;
CascadeRight←L;

L←BitCount-1;
BitCount←L,SH=0;
T←inpts,:NoPut;

PutWord:
L←Screen+1;
Screen ← L;
MAR←Screen;
L←20;
BitCount←L,TASK;
MD←CurrentBits;
L←0;
CurrentBits←L;
T←inpts;

NoPut:
L←jctr+T;no task here: SH not preserved
jctr←L,:whilej;

jdone: T←outpts;
L←jctr-T,TASK;
jctr←L;
NOP;TASK RETURNS HERE: next instruction uses ALU←SReg

L←xctr-1;
xctr←L,SH=0;
T←byteptr,:xloop;

;put out last word,reset Screen
;if BitCount=20 then done
;otherwise, read previous value of Screen!1
; mask out the first (20-BitCount) bits
; OR in CurrentBits
; write out

!1,2,workHard,easyTimeTime;
xdone: T←BitCount;
L←17-T;
L←BitCount-1,SH<0;
T←LREG,:workHard;!1,2,workHard,easyTimeTime;

workHard: MAR←MASKTAB+T;
first pick up the mask
NOP;
T←MD;

MAR←Screen+1;now, the previous value
TASK;
L←MD AND T;

MAR←Screen+1;and store it back
T←CurrentBits;
L←LREG OR T;LREG has (prev contents)&mask
MD←LREG;

easyTimeTime: L←0,SWMODE;
stkp←L,:romnextA;

;---------------------------------------------------------------
;setbit turns the bit (index) on.
;---------------------------------------------------------------
!37,40,GetBit,GetB1,GetB2,GetB3,GetB4,GetB5,GetB6,GetB7,GetB10,GetB11,GetB12,GetB13,GetB14,GetB15,GetB16,GetB17,GetB20;
;CurrentBits=CurrentBits % (#100000 rshift (index))

SetBit: SINK←BitCount,BUS;
BitCount is between 20 and 1
T←CurrentBits,:GetBit;
GetBit:
NOP;
GetB20: L←100000 OR T,TASK,:HaveBit;
GetB17: L←40000 OR T,TASK,:HaveBit;
GetB16: L←20000 OR T,TASK,:HaveBit;
GetB15: L←10000 OR T,TASK,:HaveBit;
GetB14: L←4000 OR T,TASK,:HaveBit;
GetB13: L←2000 OR T,TASK,:HaveBit;
GetB12: L←1000 OR T,TASK,:HaveBit;
GetB11: L←400 OR T,TASK,:HaveBit;
GetB10: L←200 OR T,TASK,:HaveBit;
GetB7: L←100 OR T,TASK,:HaveBit;
GetB6: L←40 OR T,TASK,:HaveBit;
GetB5: L←20 OR T,TASK,:HaveBit;
GetB4: L←10 OR T,TASK,:HaveBit;
GetB3: L←4 OR T,TASK,:HaveBit;
GetB2: L←2 OR T,TASK,:HaveBit;
GetB1: L←ONE OR T,TASK,:HaveBit;
HaveBit: CurrentBits←L;

L←error,:SetBitReturn;