:TITLE[Jasmine]; %Edit by Fiala 5 October 1981: Parameterize values put in ScanTime and ScanCBHead base registers; relocate registers for AMesa system; add WithMidas warning. Edit by Fiala 6 May 1981: Harmonize with Pilot; eliminate initialization timer (saved 4 mi); change pixel timer from slot 12b to 13b to avoid conflict with 10 mb Ethernet timer and fixup JasmineOff for this change; avoid overwriting TimerTable slots except ones used; JasmineOn must now have 160000b+JasmineOn as JRam argument. Edit by Fiala 18 December 1980: Harmonize with Alto microcode; improve bad timing cases, bum many mi. Created 19 May 1980 by Joe Maleson Normally used in conjunction with JasmineHalftone.Mc or JasmineHalftone4.Mc WARNING: LoadTimer/AddToTimer must be 7 mi 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 7 mi requirement is met. For both Alto and Cedar, 3 mi from wakeup to AddToTimer and 4 mi after AddToTimer until tasking are minimum requirements. WARNING: Printer_ must apparently be spaced by two mi (i.e., not in two consecutive mi). Three timers are used: ScanStartTimer: ticks once per scanline, STARTs ScanCBTimer ScanCBTimer (two-stage): processes a control block, STARTs PixelTimer PixelTimer: reads in bytes, STARTs ScanCBTimer Timer dispatch entries replace entries in Timer.Mc slot 17b (At[TimerTable,0]) = refresh slot 16b (At[TimerTable,1]) = slow stage of ScanStartTimer here slot 15b = fast stage of ScanStartTimer here slot 14b (At[TimerTable,3]) = ScanCBTimer here slot 13b (At[TimerTable,4]) = PixelTimer here slot 12b (At[TimerTable,5]) = 10 mb ethernet slot 06b (At[TimerTable,11]) = 3 mb ethernet slot 04b (At[TimerTable,13]) = 2nd ethernet (3 mb or 10 mb) slot 02b (At[TimerTable,15]) = audio PROBLEMS: 1) ScanTimeLoc and ScanCBHeadLoc should be made adjacent to eliminate one base register and save 3 mi; these locations need to be specified for Cedar, probably at 177400 + 20*16. 2) Save the final NOP in MRTloop by advancing the Printer_ stuff. 3) Change the "Alto ticks" stuff which must be converted for LoadTimer to appropriate Dolphin units. 4) ScanBufferHi is not initialized. 5) Quadalign the buffer headers; possibly eliminate the pointer to the buffer by uniting the buffer header and the buffer; possibly arrange the store count and status to be in words 0 and 1 of the header to allow a PStore2 in haveCurrent. 6) Find out why ScanCBHead has to be updated for each buffer. 7) Why is jStoreCount stored at jScanBuffer+1 in haveCurrent? % IFE[WithMidas,1,ER[WARNING.Jasmine.can't.be.used.with.Midas]]; SetTask[TTask]; :IF[AltoMode]; ******************************** *These registers are targets for PFetch/PStore, so they must be RM 340-357. RV[jTimerData,43]; *general temporary RV[jScanWait,44]; *temporary used at top of ScanStartTimer RV[jScanData,44]; *used in PixelTimer RV[jStoreCount,45]; RV[jPrinterControl,46]; *used in ScanStartTimer, PixelTimer RV[jStatusReg,47]; *used in ScanCBTimer RV2[jScanBuffer,jScanBufferHi,50]; *These registers may be RM 320-377b. RV2[jScanTime,jScanTimeHi,30]; *contains wait count in ticks Set[ScanTimeLoc,526]; RV2[jScanCBHead,jScanCBHeadHi,32]; *ScanCBHeadLoc+1 is StartCommand Set[ScanCBHeadLoc,736]; RV[jStepperState,34]; RV[jPixelTimerSet,35]; *used in PixelTimer, ScanCBTimer :ELSE; **************************************** Set[tRB,LShift[And[TTask,3],4]]; *These registers are targets for PFetch/PStore, so they must be RM 340-357. RV[jScanWait,Add[tRB,0]]; *temporary used at top of ScanStartTimer RV[jScanData,Add[tRB,0]]; *used in PixelTimer RV[jTimerData,Add[tRB,1]]; *general temporary RV[jPrinterControl,Add[tRB,2]]; *used in ScanStartTimer,PixelTimer RV[jStatusReg,Add[tRB,3]]; *used in ScanCBTimer RV2[jScanBuffer,jScanBufferHi,Add[tRB,4]]; RV[jStoreCount,Add[tRB,6]]; *These registers may be in RM 320-377b. RV2[jScanTime,jScanTimeHi,34]; *contains wait count in ticks Set[ScanTimeLoc,526]; RV2[jScanCBHead,jScanCBHeadHi,36]; *ScanCBHeadLoc+1 is StartCommand Set[ScanCBHeadLoc,736]; RV[jStepperState,Add[tRB,7]]; RV[jPixelTimerSet,Add[tRB,10]]; *used in PixelTimer, ScanCBTimer :ENDIF; *************************************** *ScanStartTimer (slot 16b is slow stage; slot 15b is fast stage). PFetch1[jScanTime,jScanWait,0], At[TimerTable,1]; LoadPage[JasPage]; **Cannot have LoadPage in previous mi jTimerData _ HiA[50054]; 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 *64 cycles from Timer wakeup to return *load ScanCBTimer with state: 5, data: 2, slot: 14B *SCanCBTimer is a simple timer; load it with state 5, data 2, slot 14b. jTimerData _ (jTimerData) + (LoA[50054]); LoadTimer[jTimerData]; T _ jScanWait; jScanWait _ (LSh[jScanWait,1]) + T; *3*jScanWait T _ RSh[jScanWait,6]; jScanWait _ (LSh[jScanWait,1]) - T; *6*jScanWait - 3*jScanWait/64 *Slots 15b and 16b are two-stage timer. *Load slow timer with high 7 bits T _ 160400C; *(slot=16B,state=1) RCy 4 T _ (LdF[jScanWait,1,7]) + T; jTimerData _ T; jTimerData _ LCy[jTimerData,4]; *get into appropriate fields LoadTimer[jTimerData]; PFetch1[jScanCBHead,jPrinterControl,1]; *read PrinterControl; *Load fast timer with low 8 bits T _ 154400C; *(slot=15B,state=11B) RCy 4 T _ (LdF[jScanWait,10,10]) + T; jTimerData _ T; jTimerData _ LCy[jTimerData,4]; *get into appropriate fields jPrinterControl _ (jPrinterControl) xor (177C); *invert command bits *12 cycles between PFetch1 and previous mi ensures 14 cycles between *previous LoadTimer and this AddToTimer. AddToTimer[jTimerData]; *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 _ jPrinterControl; *<0> jPrinterControl _ (jPrinterControl) xor (1000C); *<1> jPrinterControl _ T, Printer _ jPrinterControl, NoRegILockOK; Nop; PrgPrC: Printer _ jPrinterControl, Return; *<0> %ScanCBTimer (slot 14b) starts at haveCurrent or headCheck started by ScanStartTimer started by PixelTimer when jStoreCount goes to 0 There is a current scan buffer: assign status and dequeue if DataLate, clear CB queue % jStatusReg _ (Zero) - 1, At[TimerTable,3]; **Cannot have LoadPage in previous mi since only 2nd after wakeup and might **page fault. LU _ jScanBuffer, LoadPage[JasPage]; PFetch1[jScanCBHead,jScanBuffer,0], DblGoToP[haveCurrent,headCheck,ALU#0]; *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 OnPage[JasPage]; haveCurrent: LU _ jStoreCount; LU _ jScanBuffer, GoTo[pixelTimerEntry,ALU=0]; *interlock PStore1[jScanBuffer,jStoreCount,1]; jStatusReg _ (jStatusReg) - 1; *StatusDATALATE; *Smash PixelTimer, so it won't run, to state 4 (idle), data 0, slot 13b jPixelTimerSet _ HiA[40013]; jPixelTimerSet _ (jPixelTimerSet) + (LoA[40013]); LoadTimer[jPixelTimerSet]; PStore1[jScanBuffer,jStatusReg,2]; jScanBuffer _ 0C; jStoreCount _ 0C; PStore1[jScanCBHead,jScanBuffer,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[jScanBuffer,jStatusReg,2]; *jStatusReg = StatusDONE PFetch1[jScanBuffer,jScanBuffer,0]; PStore1[jScanCBHead,jScanBuffer,0], GoTo[headCheck]; *Check for input buffer (19 cycles to haveHead, 20 to noHead return). *ScanCB structure: * link * command (Read,Delay,Forward,Back) * status/count (negative = status, pos=count) * buffer headCheck: LU _ jScanBuffer; jStoreCount _ 0C, Skip[ALU#0]; Return; *no head *64 cycles to here via haveCurrent; 23 cycles to here via headCheck. *38 cycles here to return on READ, 68 or 70 on BACK/FORWARD, and 58 on DELAY PFetch1[jScanBuffer,jTimerData,1]; LU _ Dispatch[jTimerData,16,2]; LU _ Dispatch[jStepperState,16,2], Disp[.+1]; jPixelTimerSet _ HiA[50053], GoTo[cREAD], DispTable[4]; *READ *take CB off queue, mark DONE *DELAY: wait until next start pulse (just throw command away) cDELAY: PStore1[jScanBuffer,jStatusReg,2], GoTo[cDELAY1]; *DELAY jStepperState _ 55C, Disp[stepDone]; *FORWARD jStepperState _ 56C, Disp[stepDone]; *BACK *Load PixelTimer with state 5, data 2, slot 13b cREAD: jPixelTimerSet _ (jPixelTimerSet) + (LoA[50053]); LoadTimer[jPixelTimerSet]; PFetch1[jScanBuffer,jStoreCount,2]; PFetch1[jScanBuffer,jScanBuffer,3]; jPrinterControl _ 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 _ jStepperState, GoTo[stepDone1], DispTable[4]; jStepperState _ (jStepperState) xor (2C), GoTo[stepDone]; jStepperState _ (jStepperState) xor (1C), GoTo[stepDone]; jStepperState _ (jStepperState) xor (3C), GoTo[stepDone]; stepDone1: jStepperState _ (jStepperState) xor (1000C); *<1> jStepperState _ T, Printer _ jStepperState, NoRegILockOK; Nop; Printer _ jStepperState, GoTo[cDELAY]; *<0> cDELAY1: PFetch1[jScanBuffer,jTimerData,0]; *link jScanBuffer _ 0C; PStore1[jScanCBHead,jTimerData,0], Return; %PixelTimer code (slot 13b): 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 % Nop, At[TimerTable,4]; *These two mi duplicate those at done1; cannot have LoadPage in previous mi. LU _ (jStoreCount) - 1, LoadPage[JasPage]; T _ Printer, DblGoToP[endCount,nextByte,ALU<0]; OnPage[JasPage]; endCount: jStatusReg _ (Zero) - 1, GoTo[haveCurrent]; nextByte: jPrinterControl _ 100400C, Skip[ALU<0]; done1: AddToTimer[jPixelTimerSet], GoTo[NNNopReturn]; Printer _ jPrinterControl; jPrinterControl _ 400C; Printer _ jPrinterControl; jStoreCount _ (jStoreCount) - 1, GoTo[oddByte,R Odd]; jScanData _ T, Skip[ALU#0]; jScanData _ LSh[jScanData,10], GoTo[done1]; jScanData _ LSh[jScanData,10]; LU _ (jStoreCount) - 1; T _ Printer, DblGoTo[endCount,nextByte,ALU<0]; oddByte: AddToTimer[jPixelTimerSet]; jTimerData _ 377C; T _ (jTimerData) and T; LU _ jScanBuffer; jScanData _ (jScanData) + T, Skip[ALU#0]; Return; jScanData _ (jScanData) xnor (0C); PStore1[jScanBuffer,jScanData,0]; jScanBuffer _ (jScanBuffer) + 1, Return; *Initialization: enter here with Mesa JRam 160000b+JasimineOn jTimerData _ HiA[50056], At[JasmineOn]; *State 5, data 2, slot 16b jTimerData _ (jTimerData) + (LoA[50056]); LoadTimer[jTimerData]; jScanTimeHi _ 0C; *Only word 0 used at ScanTimeLoc jScanTime _ HiA[ScanTimeLoc]; jScanTime _ (jScanTime) + (LoA[ScanTimeLoc]); jScanCBHeadHi _ 0C; *Two words used at ScanCBHeadLoc jScanCBHead _ HiA[ScanCBHeadLoc]; jScanCBHead _ (jScanCBHead) + (LoA[ScanCBHeadLoc]); jScanBuffer _ 0C; jStoreCount _ 0C, Return; SetTask[0]; *EMULATOR LEVEL STUFF (can't use Timer registers!) NNNopReturn: Nop; NNopReturn: Nop; NopReturn: Nop; Retn: Return; *Shut down timers 13b to 16b xBuf _ LoA[40013], At[JasmineOff]; xBuf1 _ 2C; JasmineOff2: xBuf _ (xBuf) or (HiA[40013]); LoadTimer[xBuf]; xBuf1 _ (xBuf1) - 1, Skip[R>=0]; GoTo[NNopReturn]; Nop; Nop; Nop; Nop; xBuf _ (xBuf) + 1, GoTo[JasmineOff2]; Stack _ (Stack) xor (177C), At[JasminePulse]; Printer _ Stack; Stack _ (Stack) xor (1000C); Printer _ Stack; Stack _ (Stack) xor (1000C); Printer _ Stack&-1, Return; :END[Jasmine];(1792)\f5