* WARNING:
*
LOADTIMERs must be 7 instructions apart
insert[JasHalftone]; *which inserts d0lang and GlobalDefs

TITLE [JasMC -- May 19, 1980 10:07 AM];
* NOTE: labels are named to match Alto microcode labels

* Three timers are used:
*
ScanStartTimer: ticks once per scanline, STARTs ScanCBTimer
*
ScanCBTimer: processes a control block, STARTs PixelTimer
*
PixelTimer: reads in bytes, STARTs ScanCBTimer
SET TASK[TTask];

* Registers in Timer Task
* 44-56,67-70 available
RV[ScanTime,44]; *526 (contains wait count in ticks)
RV[ScanTimeHi,45]; *0
RV[ScanCBHead,46]; *736; and 737 is StartCommand
RV[ScanCBHeadHi,47];

RV[TimerData,51]; *general temporary
RV[PrinterControl,52]; *used in ScanStartTimer,PixelTimer

*ScanStartTimer names
RV[ScanWait,50]; *temporary used at top of ScanStartTimer
RV[StatusReg,53]; *used in ScanCBTimer
*PixelTimer names
RV[ScanData,50]; *used in PixelTimer

RV[ScanBuffer,54];
RV[ScanBufferHi,55];
RV[StoreCount,56];
RV[StepperState,70];
RV[PixelTimerSet,67]; *used in PixelTimer,ScanCBTimer

* At locations
SET [JasmineOn,ADD[LSHIFT[InitPage,10],010]];
* Starting location
SET [
JasmineOff,ADD[LSHIFT[InitPage,10],011]];* Starting location
SET [
JasminePulse,ADD[LSHIFT[InitPage,10],012]];* Starting location
SET [
StorePrinter,ADD[LSHIFT[InitPage,10],013]];* Starting location
SET [
ReadPrinter,ADD[LSHIFT[InitPage,10],014]];* Starting location
SET [bLoc,ADD[LSHIFT[InitPage,10],200]];
SET [cLoc,ADD[LSHIFT[InitPage,10],220]];
SET [fLoc,ADD[LSHIFT[InitPage,10],240]];
SET [tLoc,ADD[LSHIFT[InitPage,10],260]];

ONPAGE[InitPage];
* EMULATOR LEVEL STUFF (
can’t use Timer registers!!!!)
RV[EmulatorTemp,40];
*initialization: start up InitTimer, state: 5,data: 2, slot: 10B;
AT[JasmineOn], EmulatorTemp ← (50000C);
EmulatorTemp ← (EmulatorTemp) + (50C);
LOADTIMER[EmulatorTemp];
NNNopReturn: NOP;
NNopReturn: NOP;
NopReturn: NOP;
RETURN;
*shut down all timers
AT[JasmineOff],EmulatorTemp ← (12C),GOTOP[JasmineOff2];
JasmineOff2:
DISPATCH[EmulatorTemp,13,1];
EmulatorTemp ← (EmulatorTemp) OR (40000C),DISP[timer0];
timer0: LOADTIMER[EmulatorTemp],GOTO[TurnOff],AT[tLoc,0];
timer1: RETURN,AT[tLoc,1];
TurnOff: EmulatorTemp ← (EmulatorTemp) + (2C);
NOP;
NOP;
NOP;
GOTO[JasmineOff2];
AT[JasminePulse],Stack ← (Stack) XOR (177C);
PRINTER ← Stack;
Stack ← (Stack) XOR (1000C);
PRINTER ← Stack;
Stack ← (Stack) XOR (1000C);
AT[
StorePrinter],PRINTER ← Stack&-1,RETURN;
AT[
ReadPrinter],T←PRINTER;
Stack&+1 ← T,RETURN;

* 1 alto tick = 38.08 usec
* 1 D0 tick = 6.4 usec
* approx conversion: D0Ticks = 6*AltoTicks - (3*AltoTicks)/64
* timer format: state: 0-3, data: 4-11, slot: 12-15
MRTloop: PFetch1[ScanTime,ScanWait,0];
*this runs 25 instrs = 5 usecs
*load up ScanCBTimer with state: 5,data: 2,slot: 14B
TimerData ← 50000C; *state=5, highdata=0
TimerData ← (TimerData)+(54C); *lowdata = 2,slot=14B5 instrs
T ← ScanWait;
LOADTIMER[TimerData];
ScanWait ← (LSH[ScanWait,1])+T; *3
T ← (RSH[ScanWait,6]);
ScanWait ← (LSH[ScanWait,1])-T;
* load slow timer with high 7 bits
T ← (160400C); *slot=16B,state=1 15 instrs
T ← (LDF[ScanWait,1,7]) + T;
TimerData ← T;
TimerData ← (LCY[TimerData,4]); *get into appropriate fields
LOADTIMER[TimerData];
PFetch1[ScanCBHead,PrinterControl,1]; *read PrinterControl;
* load fast timer with low 8 bits
T ← (154400C); *slot=15B,state=11B
T ← (LDF[ScanWait,10,10]) + T;*10 instrs
TimerData ← T;
TimerData ← (LCY[TimerData,4]); *get into appropriate fields
PrinterControl ← (PrinterControl) XOR (177C); *invert command bits
PRINTER ← PrinterControl; *<0><START><SkipCount> 20 instrs
ADDTOTIMER[TimerData];

*command output format:
* 0-5) don’t care, 6) command enable, 7) 0, 8) don’t care, 9-15) command
startScan:
*quick like a bunny pulse start, then (whew!) you can TASK
PrinterControl ← (PrinterControl) XOR (1000C);
PRINTER ← PrinterControl; *<1><START><SkipCount>
PrinterControl ← (PrinterControl) XOR (1000C);
PRINTER ← PrinterControl,RETURN; *<0><START><SkipCount> 25 instrs
*PrinterControl ← (400C); *FIFOShift=0,Alto8=0,EnableInput=1
*
PRINTER ← PrinterControl,RETURN;

*ScanCBTimer starts here
* started by ScanStartTimer
* started by PixelTimer when StoreCount goes to 0
ScanCBLoop:
LU ← ScanBuffer;
StatusReg ← (zero) - 1,GOTO[noCurrent,ALU=0];

*there is a current scan buffer:
*
assign status and dequeue
*
if DataLate, clear CB queue
haveCurrent:
PFetch1[ScanCBHead,ScanBuffer,0];* 5 instrs
LU ← StoreCount;
LU ← ScanBuffer,GOTO[pixelTimerEntry,ALU=0]; *interlock
PStore1[ScanBuffer,StoreCount,1];
StatusReg ← (StatusReg)-1; *StatusDATALATE;
*smash PixelTimer, so it won’t run
PixelTimerSet ← 40000C; *state=4(idle),highdata=0
PixelTimerSet ← (PixelTimerSet)+(12C); *lowdata = 0,slot=12B
LOADTIMER[PixelTimerSet];
PStore1[ScanBuffer,StatusReg,2];
ScanBuffer ← (0C);
StoreCount ← (0C);
PStore1[ScanCBHead,ScanBuffer,0],RETURN;
pixelTimerEntry: *no error: pixel task has completed
*if emulator has stored 0 into ScanCBHead, just return
GOTO[NNNopReturn,ALU=0]; *already set to idle
PStore1[ScanBuffer,StatusReg,2]; *StatusReg = StatusDONE
PFetch1[ScanBuffer,ScanBuffer,0];
LU ← ScanBuffer;
PStore1[ScanCBHead,ScanBuffer,0],DBLGOTO[haveHead,noHead,ALU#0];

*check for available input buffer
noCurrent: PFetch1[ScanCBHead,ScanBuffer,0];
LU ← ScanBuffer;
StoreCount ← 0C,DBLGOTO[haveHead,noHead,ALU#0]; * 10 instrs
noHead: RETURN;

%dummy code for recording PC value when ScanCBHead↑=0
LOADPAGE[TimerInitPage];
T ← STKP,GOTOP[noHeadFinish];
ONPAGE[TimerInitPage];
noHeadFinish:

*store mesa PC in bank 4
TimerData ← T; *T has STKP
ScanBuffer ← (30C); *mesa PC
STKP ← ScanBuffer;
ScanTimeHi ← T ← (4C);
ScanTimeHi ← (LSH[ScanTimeHi,10]) + T;
T ← Stack&+1;
ScanBuffer ← T;
PFetch1[ScanTimeHi,ScanWait,0];
T ← Stack;
ScanBufferHi ← T;
ScanWait ← T ← (ScanWait) + (2C);
PStore1[ScanTimeHi,ScanWait,0];
NOP;
PStore2[ScanTimeHi,ScanBuffer];
TimerData ← (TimerData) XOR (377C);
STKP ← TimerData;
ScanBuffer ← (0C);
ScanBufferHi ← (0C);
ScanTimeHi ← (0C);

TimerData ← (24C);
T ← (TimerData)+(400C);
PFetch1[ScanBuffer,TimerData];
TimerData ← (TimerData) XOR (10C);
PStore1[ScanBuffer,TimerData],RETURN;
*won’t always work, but who cares?
ONPAGE[InitPage];
%

*ScanCB structure:
*
link
*
command (Read,Delay,Forward,Back)
*
status/count (negative = status, pos=count)
*
buffer
haveHead: LU ← ScanBuffer;*prev may have been PStore1[ScanCBHead,ScanBuffer,0]
PFetch1[ScanBuffer,TimerData,1];
LU ← DISPATCH[TimerData,16,2];
DISP[CommandREAD];
CommandREAD: *load PixelTimer with state: 5,data:
2, slot: 12B
PixelTimerSet ← 50000C,AT[cLoc,0]; *state=5 highdata = 0; *15 instrs
PixelTimerSet ← (PixelTimerSet)+(52C); *lowdata=2,slot=12;
LOADTIMER[PixelTimerSet];
PFetch1[ScanBuffer,StoreCount,2];
PFetch1[ScanBuffer,ScanBuffer,3];
PrinterControl ← (400C); *enable input
PRINTER ← PrinterControl,RETURN;

*
MOTORCTL=5
*<000000><ENABLE><00><MOTORCTL><xxxx>

*0101xxxx = disabled = 120
*BUT: we need to invert the low order 7 bits (a la Alto)
CommandBACK:
DISPATCH[StepperState,16,2],AT[cLoc,3]; *15 instrs
DISP[bstep0];*FIFOShft=0,Alto8=0,EnableInput=0
*inverted sequence is: 2,3,1,0
bstep0: StepperState ← (56C),GOTO[stepDone],AT[bLoc,0];
bstep1: StepperState ← (54C),GOTO[stepDone],AT[bLoc,1];
bstep2: StepperState ← (57C),GOTO[stepDone],AT[bLoc,2];
bstep3: StepperState ← (55C),GOTO[stepDone],AT[bLoc,3];

CommandFORWARD:
DISPATCH[StepperState,16,2],AT[cLoc,2]; *15 instrs
DISP[fstep0];*FIFOShft=0,Alto8=0,EnableInput=0
*inverted sequence is: 0,1,3,2
fstep0: StepperState ← (55C),GOTO[stepDone],AT[fLoc,0];
fstep1: StepperState ← (57C),GOTO[stepDone],AT[fLoc,1];
fstep2: StepperState ← (54C),GOTO[stepDone],AT[fLoc,2];
fstep3: StepperState ← (56C),GOTO[stepDone],AT[fLoc,3];

stepDone: PRINTER ← StepperState;
*<0><MOTORCTL><StepState>
StepperState ← (StepperState) XOR (1000C);
PRINTER ← StepperState;*<1><MOTORCTL><StepState> 20 instrs
StepperState ← (StepperState) XOR (1000C);
PRINTER ← StepperState;*<0><MOTORCTL><StepState>
*PRINTER ← PrinterControl;*EnableInput=1

*take CB off queue, mark DONE
*DELAY: wait until next start pulse (just throw command away)
CommandDELAY:
AT[cLoc,1],PStore1[ScanBuffer,StatusReg,2];*StatusReg=StatusDONE
PFetch1[ScanBuffer,TimerData,0]; *link
ScanBuffer ← 0C;
LU ← TimerData;
PStore1[ScanCBHead,TimerData,0],RETURN; *25 instrs

JasmineInit:
*set up ScanStartTimer to run
TimerData ← (50000C); *state=5, highdata=0
TimerData ← (TimerData) + (56C); *lowdata=2,slot=16
LOADTIMER[TimerData];
*first time initialization (min of 4 instructions)
T ← (10000C);
FFault ← (FFault) AND NOT T;
ScanTimeHi ← (0C);
ScanTime ← 400C;
ScanTime ← (ScanTime) + (126C);
ScanCBHeadHi ← 0C;
ScanCBHead ← 400C;
ScanCBHead ← (ScanCBHead) + (336C);
ScanBuffer ← (0C);
StoreCount ← (0C),RETURN;

*PixelTimer starts here
*between shift out pulse and data read, leave a minimum of 850 nsecs
* PRINTER input format is normally:
* 0) FIFOShift=0, 1-5)unused, 6)Alto8=0, 7)InputEnable=1, 8-15) FIFOData
* shift out by dropping FIFOShift to 0, and then back high
checkInput: LU ← (StoreCount)-1,DBLGOTO[oddByte,evenByte,R ODD];


evenByte: T ← PRINTER,GOTO[noCount,ALU<0];*really StoreCount<=0
PrinterControl ← (100400C),GOTO[doWord,ALU<0];
noWord:
ADDTOTIMER[PixelTimerSet],GOTO[NNNopReturn];
doWord: PRINTER ← PrinterControl;
*5 instrs
PrinterControl ← (400C);
PRINTER ← PrinterControl;
ScanData ← T;
StoreCount ← (StoreCount)-1;
ScanData ← LSH[ScanData,10],GOTO[read1,ALU#0];*10 instrs
done1:
ADDTOTIMER[PixelTimerSet],GOTO[NNNopReturn];

oddByte: NOP;
read1: T ← PRINTER;

PrinterControl ← (100400C),GOTO[doWord1,ALU<0];
noWord1:
ADDTOTIMER[PixelTimerSet],GOTO[NNNopReturn];
doWord1: PRINTER ← PrinterControl;
PrinterControl ← (400C);
PRINTER ← PrinterControl;
TimerData ← (377C);
T ← (TimerData) AND T;*15 instrs
ADDTOTIMER[PixelTimerSet];
LU ← ScanBuffer;
ScanData ← (ScanData) + T,GOTO[noBuffer1,ALU=0];
T ← (zero) - 1;
ScanData ← (ScanData) XOR T;
PStore1[ScanBuffer,ScanData,0];*20 instrs
ScanBuffer ← (ScanBuffer) + 1;
noBuffer1: StoreCount ← (StoreCount)-1,
RETURN;

*come here when storecount is exhausted:
*
process next CB
*need to do something if requested read was odd number of bytes
noCount: StatusReg ← (zero)-1,GOTOP[haveCurrent];

* catching the wakeup
* slot 17 (AT[x,0]) = refresh
* slot 6 (AT[x,11]) = ether
LOADPAGE[InitPage], AT[TimerTable,01]; *slot 16=ScanStartTimer
GOTOP[MRTloop], AT[TimerTable,12]; *slot 5 (unused)
LOADPAGE[InitPage], AT[TimerTable,03]; *slot 14=ScanCBTimer
GOTOP[ScanCBloop], AT[TimerTable,04]; *slot 13 (unused)
LOADPAGE[InitPage], AT[TimerTable,05]; *slot 12=PixelTimer
GOTOP[checkInput], AT[TimerTable,06]; *slot 11 (unused)
LOADPAGE[InitPage], AT[TimerTable,07]; *slot 10=InitTimer
GOTOP[JasmineInit], AT[TimerTable,10]; *slot 7 (unused)

END;