:TITLE[Jasmine]; %Last edited: 18 December 1980 by Fiala; 19 May 1980 by Maleson previously Normally used in conjunction with JasmineHalftone.Mc or JasmineHalftone4.Mc WARNING: LoadTimer/AddToTimer must be 14 cycles apart and an mi containing one of these must not have a branch condition. The storage refresh code in Timer.Mc controls the way the 14 cycle requirement is met. It has 6 cycles from its wakeup to its AddToTimer and 8 cycles after the AddToTimer until tasking--6 and 8 cycles are the minimums to meet here as well. 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 % SetTask[TTask]; *RM 343-56, 367-70 were available on 3 Dec 1980 RV2[ScanTime,ScanTimeHi,44]; *526 (contains wait count in ticks) RV2[ScanCBHead,ScanCBHeadHi,46]; *736; and 737 is StartCommand RV[TimerData,51]; *general temporary RV[PrinterControl,52]; *used in ScanStartTimer,PixelTimer RV[ScanWait,50]; *temporary used at top of ScanStartTimer RV[StatusReg,53]; *used in ScanCBTimer RV[ScanData,50]; *used in PixelTimer RV2[ScanBuffer,ScanBufferHi,54]; RV[StoreCount,56]; RV[StepperState,70]; RV[PixelTimerSet,67]; *used in PixelTimer, ScanCBTimer OnPage[JasPage]; *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: *58 cycles from Timer wakeup to return *load up ScanCBTimer with state: 5, data: 2, slot: 14B TimerData _ 50000C; *state=5, highdata=0 TimerData _ (TimerData) + (54C); *lowdata = 2, slot=14B LoadTimer[TimerData]; T _ ScanWait; ScanWait _ (LSh[ScanWait,1]) + T; *3*ScanWait T _ RSh[ScanWait,6]; ScanWait _ (LSh[ScanWait,1]) - T; *6*ScanWait - 3*ScanWait/64 *load slow timer with high 7 bits T _ 160400C; *slot=16B,state=1 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; TimerData _ T; TimerData _ LCy[TimerData,4]; *get into appropriate fields PrinterControl _ (PrinterControl) xor (177C); *invert command bits *12 cycles between PFetch1 and previous mi ensures 14 cycles between *previous LoadTimer and this AddToTimer. AddToTimer[TimerData]; *command output format: * 0:5 don't care, 6:6 command enable, 7:7 0, 8:8 don't care, 9:15 command. *Pulse start and finally TASK. T _ Printer _ PrinterControl; *<0> PrinterControl _ (PrinterControl) xor (1000C); *<1> PrinterControl _ T, Printer _ PrinterControl, NoRegILockOK; Nop; **Apparently spacing Printer_ by two mi is necessary PrgPrC: Printer _ PrinterControl, Return; *<0> *ScanCBTimer starts at haveCurrent or noCurrent * started by ScanStartTimer * started by PixelTimer when StoreCount goes to 0 *There is a current scan buffer: * assign status and dequeue * if DataLate, clear CB queue haveCurrent: *73 cycles from wakeup to return unless PixelTimerEntry jump *27 cycles from wakeup to already-idle return *74 cycles to noHead return *102 to 134 cycles to headCheck return PFetch1[ScanCBHead,ScanBuffer,0]; 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; *no error: pixel task has completed *if emulator has stored 0 into ScanCBHead, just return *21 cycles from wakeup to here pixelTimerEntry: Goto[NopReturn,ALU=0]; *already set to idle PStore1[ScanBuffer,StatusReg,2]; *StatusReg = StatusDONE PFetch1[ScanBuffer,ScanBuffer,0]; PStore1[ScanCBHead,ScanBuffer,0], Goto[headCheck]; *Check for input buffer (19 cycles to haveHead, 20 to noHead return). noCurrent: PFetch1[ScanCBHead,ScanBuffer,0], Goto[headCheck]; *ScanCB structure: * link * command (Read,Delay,Forward,Back) * status/count (negative = status, pos=count) * buffer headCheck: LU _ ScanBuffer; StoreCount _ 0C, Skip[ALU#0]; Return; *no head *64 cycles to here via haveCurrent; 23 cycles to here via noCurrent. *38 cycles here to return on READ, 68 or 70 on BACK/FORWARD, and 58 on DELAY PFetch1[ScanBuffer,TimerData,1]; LU _ Dispatch[TimerData,16,2]; LU _ Dispatch[StepperState,16,2], Disp[.+1]; PixelTimerSet _ 50000C, Goto[cREAD], DispTable[4]; *READ *take CB off queue, mark DONE *DELAY: wait until next start pulse (just throw command away) cDELAY: PStore1[ScanBuffer,StatusReg,2], Goto[cDELAY1]; *DELAY StepperState _ 55C, Disp[stepDone]; *FORWARD StepperState _ 56C, Disp[stepDone]; *BACK *Load PixelTimer with state: 5, data: 2, slot: 12B cREAD: PixelTimerSet _ (PixelTimerSet) + (52C); LoadTimer[PixelTimerSet]; PFetch1[ScanBuffer,StoreCount,2]; PFetch1[ScanBuffer,ScanBuffer,3]; PrinterControl _ 400C, Goto[PrgPrC]; *enable input *MOTORCTL=5 *<000000><00> *0101xxxx = disabled = 120 *BUT: we need to invert the low order 7 bits (ala Alto) *FIFOShft=0, Alto8=0, EnableInput=0 *For FORWARD: inverted sequence is: 0,1,3,2 (55,57,54,56) *For BACK: inverted sequence is: 2,3,1,0 (56,54,57,55) stepDone: *<0> T _ Printer _ StepperState, Goto[stepDone1], DispTable[4]; StepperState _ (StepperState) xor (2C), Goto[stepDone]; StepperState _ (StepperState) xor (1C), Goto[stepDone]; StepperState _ (StepperState) xor (3C), Goto[stepDone]; stepDone1: StepperState _ (StepperState) xor (1000C); *<1> StepperState _ T, Printer _ StepperState, NoRegILockOK; Nop; **Apparently spacing Printer_ by two mi is necessary Printer _ StepperState, Goto[cDELAY]; *<0> cDELAY1: PFetch1[ScanBuffer,TimerData,0]; *link ScanBuffer _ 0C; PStore1[ScanCBHead,TimerData,0], Return; JasmineInit: *set up ScanStartTimer to run TimerData _ (TimerData) + (56C); *lowdata=2,slot=16 LoadTimer[TimerData]; *first time initialization (min of 8 cycles) ScanTimeHi _ 0C; ScanTime _ 400C; ScanTime _ (ScanTime) + (126C); ScanCBHeadHi _ 0C; ScanCBHead _ 400C; ScanCBHead _ (ScanCBHead) + (336C); ScanBuffer _ 0C; StoreCount _ 0C, Return; %PixelTimer code: between shift out pulse and data read, leave a minimum of 850 nsecs. Printer input format is normally: 0:0 FIFOShift=0, 1:5 unused, 6:6 Alto8=0, 7:7 InputEnable=1, 8:15 FIFOData shift out by dropping FIFOShift to 0, and then back high % endCount: StatusReg _ (Zero) - 1, Goto[haveCurrent]; nextByte: PrinterControl _ 100400C, Skip[ALU<0]; done1: AddToTimer[PixelTimerSet], Goto[NNNopReturn]; Printer _ PrinterControl; PrinterControl _ 400C; Printer _ PrinterControl; StoreCount _ (StoreCount) - 1, Goto[oddByte,R Odd]; ScanData _ T, Skip[ALU#0]; ScanData _ LSh[ScanData,10], Goto[done1]; ScanData _ LSh[ScanData,10]; LU _ (StoreCount) - 1; T _ Printer, DblGoto[endCount,nextByte,ALU<0]; oddByte: AddToTimer[PixelTimerSet]; TimerData _ 377C; T _ (TimerData) and T; LU _ ScanBuffer; ScanData _ (ScanData) + T, Skip[ALU#0]; Return; ScanData _ (ScanData) xnor (0C); PStore1[ScanBuffer,ScanData,0]; ScanBuffer _ (ScanBuffer) + 1, Return; *catching the wakeup *slot 17 (At[x,0]) = refresh *slot 6 (At[x,11]) = ether *Slot 16 (TimerTable+1, ScanStartTimer), 14 (TimerTable+3, ScanCBTimer), *12 (TimerTable+7, PixelTimer), 10 (TimerTable+7, InitTimer) *are used below; TimerTable 20 and 21 and 6 (slot 11) are also used. LoadPage[JasPage], At[TimerTable,1]; PFetch1[ScanTime,ScanWait,0], GotoP[MRTloop], At[TimerTable,20]; LU _ ScanBuffer, LoadPage[JasPage], At[TimerTable,3]; StatusReg _ (Zero) - 1, DblGotoP[haveCurrent,noCurrent,ALU#0], At[TimerTable,21]; LU _ (StoreCount) - 1, LoadPage[JasPage], At[TimerTable,5]; T _ Printer, DblGotoP[endCount,nextByte,ALU<0], At[TimerTable,6]; LoadPage[JasPage], At[TimerTable,7]; TimerData _ 50000C, GotoP[JasmineInit], At[TimerTable,10]; *state=5, highdata=0 SetTask[0]; *EMULATOR LEVEL STUFF (can't use Timer registers!) *initialization: start up InitTimer, state: 5,data: 2, slot: 10B; xBuf _ 50000C, At[JasmineOn]; xBuf _ (xBuf) + (50C); LoadTimer[xBuf]; NNNopReturn: Nop; NNopReturn: Nop; NopReturn: Goto[Retn]; *shut down all timers xBuf _ 12C, At[JasmineOff]; JasmineOff2: Dispatch[xBuf,13,1]; xBuf _ (xBuf) or (40000C), Disp[.+1]; LoadTimer[xBuf], Skip, DispTable[2]; Retn: Return; Nop; Nop; Nop; Nop; xBuf _ (xBuf) + (2C), Goto[JasmineOff2]; Stack _ (Stack) xor (177C), At[JasminePulse]; **Apparently it is necessary to space Printer_ by two cycles.** Printer _ Stack; Stack _ (Stack) xor (1000C); Printer _ Stack; Stack _ (Stack) xor (1000C); Printer _ Stack&-1, Return; :END;(1792)