;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;
MAR ← 177740;--bank register for task 0 (emulator)
NOP;
L ← MD;
stk1 ← L; --savedbank
MAR←L←stk0+1;
stk0←L;
L←MD;
MAR ← 177740;
val ← L,TASK;
MD ← val; --bitmap bank
NOP;TASK RETURNS HERE: stk0 instruction uses ALU←SReg
MAR←L←stk0+1;
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;
XMAR←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;
XMAR←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;
XMAR←Screen+1;now, the previous value
TASK;
L←MD AND T;
XMAR←Screen+1;and store it back
T←CurrentBits;
L←LREG OR T;LREG has (prev contents)&mask
MD←LREG;
easyTimeTime: MAR ← 177740;
L←0;
stkp←L,SWMODE;
MD ← stk1,:romnextA; --saved bank reg
;---------------------------------------------------------------
;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;