/* * kirkwood clock */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #define TIMERREG ((TimerReg*)AddrTimer) enum { Tcycles = CLOCKFREQ / HZ, /* cycles per clock tick */ <<<<<<< /sys/src/9/kw/clock.c /* timer ctl bits */ Tmr0enable = 1<<0, Tmr0periodic = 1<<1, Tmr1enable = 1<<2, Tmr1periodic = 1<<3, TmrWDenable = 1<<4, TmrWDperiodic = 1<<5, }; typedef struct TimerReg TimerReg; struct TimerReg { ulong ctl; ulong pad[3]; ulong reload0; ulong timer0; ulong reload1; ulong timer1; ulong reloadwd; ulong timerwd; ||||||| clock.c.orig ======= MaxPeriod = Tcycles, MinPeriod = MaxPeriod / 100, >>>>>>> clock.c }; static void clockintr(Ureg *ureg, void*) { TIMERREG->timerwd = CLOCKFREQ; /* reassure the watchdog */ coherence(); timerintr(ureg, 0); intrclear(Irqbridge, IRQcputimer0); } /* stop clock interrupts and disable the watchdog timer */ void clockshutdown(void) { TIMERREG->ctl = 0; coherence(); } void clockinit(void) { int s; long cyc; TimerReg *tmr = TIMERREG; clockshutdown(); intrenable(Irqbridge, IRQcputimer0, clockintr, nil, "clock"); s = spllo(); /* risky */ /* take any deferred clock (& other) interrupts here */ splx(s); /* adjust m->bootdelay, used by delay()? */ m->ticks = 0; m->fastclock = 0; tmr->timer0 = Tcycles; tmr->ctl = Tmr0enable; /* just once */ coherence(); s = spllo(); /* risky */ /* one iteration seems to take about 40 ns. */ for (cyc = Tcycles; cyc > 0 && m->fastclock == 0; cyc--) ; splx(s); if (m->fastclock == 0) { serialputc('?'); if (tmr->timer0 == 0) panic("clock not interrupting"); else if (tmr->timer0 == tmr->reload0) panic("clock not ticking"); else panic("clock running very slowly"); } clockshutdown(); tmr->timer0 = Tcycles; tmr->timer1 = ~0; tmr->reload1 = ~0; tmr->timerwd = CLOCKFREQ; coherence(); tmr->ctl = Tmr0enable | Tmr1enable | Tmr1periodic | TmrWDenable; CPUCSREG->rstout |= RstoutWatchdog; coherence(); } void timerset(Tval next) { <<<<<<< /sys/src/9/kw/clock.c #ifdef FANCYTIMERS Tn *tn; Tval offset; ilock(&timers.tn1lock); tn = (Tn*)Tn1; tn->cr = Tm; offset = next + tn->cv; if(offset < timers.tn1minperiod) offset = timers.tn1minperiod; else if(offset > timers.tn1maxperiod) offset = timers.tn1maxperiod; tn->lc = offset; tn->cr = Tm|Te; iunlock(&timers.tn1lock); #else USED(next); #endif } /* * shift by 8 to provide enough resolution that dropping the tick rate * won't mess up TOD calculation and cause infrequent clock interrupts. */ ||||||| clock.c.orig #ifdef FANCYTIMERS Tn *tn; Tval offset; ilock(&timers.tn1lock); tn = (Tn*)Tn1; tn->cr = Tm; offset = next + tn->cv; if(offset < timers.tn1minperiod) offset = timers.tn1minperiod; else if(offset > timers.tn1maxperiod) offset = timers.tn1maxperiod; tn->lc = offset; tn->cr = Tm|Te; iunlock(&timers.tn1lock); #else USED(next); #endif } ======= TimerReg *tmr = TIMERREG; int offset; offset = next - fastticks(nil); if(offset < MinPeriod) offset = MinPeriod; else if(offset > MaxPeriod) offset = MaxPeriod; tmr->timer0 = offset; coherence(); } >>>>>>> clock.c uvlong fastticks(uvlong *hz) { uvlong now; int s; if(hz) <<<<<<< /sys/src/9/kw/clock.c *hz = HZ << 8; return m->fastclock << 8; ||||||| clock.c.orig *hz = HZ; return m->fastclock; ======= *hz = CLOCKFREQ; s = splhi(); now = (m->fastclock&0xFFFFFFFF00000000LL) | ~TIMERREG->timer1; if(now < m->fastclock) now += 0x100000000LL; m->fastclock = now; splx(s); return now; >>>>>>> clock.c } ulong µs(void) { return fastticks2us(fastticks(nil)); } void microdelay(int l) { int i; l *= m->delayloop; l /= 1000; if(l <= 0) l = 1; for(i = 0; i < l; i++) ; } void delay(int l) { ulong i, j; j = m->delayloop; while(l-- > 0) for(i=0; i < j; i++) ; } ulong perfticks(void) { return ~TIMERREG->timer1; }