:TITLE[Timer]; *Last edited: 30 April 1981 by Fiala %Occurrences of LoadTimer and AddToTimer must be separated by 7 mi, and branch conditions are illegal with LoadToTimer and AddToTimer. Here the 7 mi requirement is fulfilled with 3 mi before LoadTimer/AddToTimer and 4 mi after. OTHER MODULES MUST GUARANTEE 3 MI FROM WAKEUP TO LOADTIMER/ADDTOTIMER AND 4 MI AFTER LOADTIMER/ADDTOTIMER BEFORE TASKING TO BE CONSISTENT. Refresh must cycle fast enough to maintain storage. 16k ic's specification is a refresh period of 2 ms at maximum operating temperature (80 deg C). The leakage phenomenon which necessitates refresh is exponential in absolute temperature, about exp(-44*(300/T)) so required refresh rate goes up by a factor of 2 for every increase of 5 degrees C. Refresh at a 2 ms period is undesirable because about 4 percent of all cycles would be consumed by the timer task; the code below presently implements a refresh period of 8 ms, which gives up about 10 degrees in temperature margin, possibly requiring a few more marginal ic's to be replaced. In LoadTimer/AddToTimer, 0:3 are the new state, 4:11 new data, and 12:15 are the slot number. Slot 17b is used for refresh and realtime clock update. The clock constant ideally has a value such that carries out of RTCLOW will occur at the same rate as the Alto clock. To achieve this, the clock constant should have a value for a 64 us clock period of (65536*64)/39009.5 = 107.52d. Also, the implementation below requires the clock constant to be even. The table below shows values for a 40 mhz (100 ns cycle) main system clock; constants are also given for 44.5 mhz (89.886 ns cycle) and 50 mhz (80 ns cycle) clocks. Since timers run off the system clock, both refresh and clock periods scale with the main system clock. Note that clock periods larger than 512 us would require a double timer. Equivalent numbers for the three frequencies are 107.52d (40 mhz), 96.645d (44.5 mhz), and 86.016d (50 mhz). Refresh Clock RTimer 40 mhz 44.5 mhz 50 mhz Period Period Value Constant Constant Constant 2 ms 64 us 50257b 154b 141b 126b 4 ms 128 us 50517b 327b 301b 254b 8 ms 256 us 51217b 656b 603b 530b 16 ms 512 us 52417b 1534b 1405b 1260b % SetTask[0]; OnPage[XMiscPage]; *Common subroutine for Mesa/Alto ReadClock. Takes 430b in T, returns *(VM 430) in RTemp, RTCLOW in T. MXRClk: PFetch1[MDS,RTemp]; RTemp1 _ IP[RTCLOW]C; T _ (SStkP&NStkP) xor (377C); StkP _ RTemp1, RTemp1 _ T, NoRegILockOK; T _ (Stack) and not (77C); *Return Most Significant 10d bits RestSP: StkP _ RTemp1, Return; *Restore StkP SetTask[TTask]; *Initialize Notifies here to set up timers (this is throwaway code) InitTimers: TimerTemp _ 100000C, At[TimerInitLoc]; ClrTimers: TimerTemp _ (LoadTimer[TimerTemp]) + 1; RSImage _ T _ 0C; REFR _ RS232 _ T; *Zap RS232, setup refresh pointer TimerBasehi _ T, ResetMemErrs; *Clear any pending memory errors *initialize high base register ***Might be better to eliminate the RTCLOW even/odd kludge, which halves the ***clock preceision, and instead zero RConstant here, then correct its ***value after storage is initialized. RTCLOW _ 1C; *Make RTCLOW odd so that clock updating won't *start until after memory initialization. *Clock error is about .00019 or 16.2 sec/day for this 40 mhz value. RConstant _ 256C; RConstant _ (RConstant) or (400C); RTimer _ 51000C; *Set up the Refresh time LU _ (TimerTemp) and (17C); *clear 20b timers RTimer _ (RTimer) or (217C), GoTo[ClrTimers,ALU#0]; LU _ Timer, LoadPage[TimerPage]; *read to clear pending wakeups LoadTimer[RTimer], GoToP[TimerSetTPC]; *load refresh timer OnPage[TimerPage]; TimerSetTPC: TimerBase _ 400C, Call[TimerRet]; *initialize low base register TimerWakeup: *Timer wakeups come here Dispatch[Timer,14,4]; *Since Refresh timer has the greatest effect on performance, do something *useful for it in this mi. T _ RConstant, Disp[.+1]; *Timer dispatch table for task 16 (not all entries are used) Refresh[REFR], GoTo[RefreshNext], At[TimerTable,0]; *slot 17 **NOTE: TimerTable 1, 3, 5, 6, 7, 10, 20, and 21 are overwritten by **Jasmine.Mc, 15 is Audio.Mc timer, 16 and 17 overwritten by Audio.Mc SetFault, GoTo[.], At[TimerTable,1]; *slot 16 Jasmine SetFault, GoTo[.], At[TimerTable,2]; *slot 15 Jasmine SetFault, GoTo[.], At[TimerTable,3]; *slot 14 Jasmine SetFault, GoTo[.], At[TimerTable,4]; *slot 13 Jasmine SetFault, GoTo[.], At[TimerTable,5]; *slot 12 SetFault, GoTo[.], At[TimerTable,6]; *slot 11 SetFault, GoTo[.], At[TimerTable,7]; *slot 10 SetFault, GoTo[.], At[TimerTable,10]; *slot 7 *Ethernet Output Notify slot (Add copies with EOTask1, EOTask2 ... if *multiple controllers). TimerTemp _ HiA[EOTimerDoneLoc,EOTask], GoTo[TEONotify], At[TimerTable,11]; SetFault, GoTo[.], At[TimerTable,12]; *slot 5 SetFault, GoTo[.], At[TimerTable,13]; *slot 4 SetFault, GoTo[.], At[TimerTable,14]; *slot 3 **Temporarily commented out for Audio.Mc * SetFault, GoTo[.], At[TimerTable,15]; *slot 2 Audio * SetFault, GoTo[.], At[TimerTable,16]; *slot 1 * SetFault, GoTo[.], At[TimerTable,17]; *slot 0 *Reserve locations that can be overwritten by non-resident overlays which *use timers (reserve TimerTable 20 and 21 here; since 22 to 24 are used, *25 is the next one available if more are needed). IMReserve[0,Add[TimerTable,20],2]; *Notify for Ethernet output (Only one copy required) TEONotify: *Notify Ethernet output task, don't restart timer TimerTemp _ (TimerTemp) or (LoA[EOTimerDoneLoc]); APCTask&APC _ TimerTemp; TimerRet: Return, At[TimerTable,24]; *Must be MouseHalt+1 for proper restarting. RefreshNext: AddToTimer[RTimer]; RTCLOW _ (RTCLOW) + T, Skip[R Even]; RTCLOW _ (Zero) + 1; *RTC has not been started yet. :IF[WithMidas]; ******************************* T _ (FFault) and (10000C), GoTo[RTCUpd,Carry]; LU _ (Printer) and T; Skip[ALU#0]; *Skip if Midas present & mouse halt RTCRet: REFR _ (REFR) + (20C), Return; *increment the refresh address *Midas mouse halt is a task 16 breakpoint that was not set by the user. *Midas continues by going to location 7004 (which contains a return). MouseHalt: SetFault, GoTo[.], At[TimerTable,23]; *Note: MC1 is busy for 20 cycles after Refresh, so the PFetch1 below will be *held for 11 cycles; when we take this path, we postpone checking for *Midas present and mouse halt until the next iteration. RTCUpd: T _ 30C; :ELSE; **************************************** T _ 30C, GoTo[.+3,Carry]; Nop; *Ensure 4 mi after AddToTimer RTCRet: REFR _ (REFR) + (20C), Return; :ENDIF; *************************************** PFetch1[TimerBase,TimerTemp]; *Increment VM 430 TimerTemp _ (TimerTemp) + 1; PStore1[TimerBase,TimerTemp], GoTo[RTCRet]; :END[Timer];(1795)\4753f1 26f0 671f1 127f0