Charles.Forsyth20060303644188019 years agoHistory
318 lines · 5.7 KB · C
RawDownload
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" #include "ureg.h" static ulong timer_incr[4] = { 0, 0, 0, -1 }; typedef struct Clock0link Clock0link;typedef struct Clock0link {	void		(*clock)(void);	Clock0link*	link;} Clock0link; static Clock0link *clock0link;static Lock clock0lock;static void (*prof_fcn)(Ureg *, int); Timer*addclock0link(void (*clock)(void), int){	Clock0link *lp; 	if((lp = malloc(sizeof(Clock0link))) == 0){		print("addclock0link: too many links\n");		return nil;	}	ilock(&clock0lock);	lp->clock = clock;	lp->link = clock0link;	clock0link = lp;	iunlock(&clock0lock);	return nil;} static voidprofintr(Ureg *ur, void*){	OstmrReg *ost = OSTMRREG;	int t; 	if((ost->osmr[3] - ost->oscr) < 2*CLOCKFREQ) {		/* less than 2 seconds before reset, say something */		setpanic();		clockpoll();		dumpregs(ur);		panic("Watchdog timer will expire");	} 	/* advance the profile clock tick */	ost->osmr[2] += timer_incr[2];	ost->ossr = (1 << 2); 			/* Clear the SR */	t = 1;	while((ost->osmr[2] - ost->oscr) > 0x80000000) {		ost->osmr[2] += timer_incr[2];		t++;	}	if(prof_fcn)		prof_fcn(ur, t);} static voidclockintr(Ureg*, void*){	Clock0link *lp;	int losttick = 0;	OstmrReg *ost = OSTMRREG; {static int tag, led; if(++tag >= HZ){ledset(led ^= 1);tag=0;}}	m->ticks++;//	ost->osmr[3] = ost->oscr + timer_incr[3]; /* restart the watchdog */	ost->osmr[0] += timer_incr[0];		/* advance the clock tick */	ost->ossr = (1<<0); 			/* Clear the SR */ 	while((ost->osmr[0] - ost->oscr) >= 0x80000000) {		ost->osmr[0] += timer_incr[0]; 		losttick++;		m->ticks++;	} 	checkalarms(); 	if(canlock(&clock0lock)){		for(lp = clock0link; lp; lp = lp->link)			if(lp->clock)				lp->clock();		unlock(&clock0lock);	} 	/* round robin time slice is done by trap.c and proc.c */} voidtimerenable( int timer, int Hz, void (*f)(Ureg *, void*), void* a){	OstmrReg *ost = OSTMRREG;	char name[KNAMELEN]; 	if(timer < 0 || timer > 3)		return;	timer_incr[timer] = CLOCKFREQ/Hz;		/* set up freq */	ost->osmr[timer] = ost->oscr+timer_incr[timer];	snprint(name, sizeof(name), "timer%d", timer);	intrenable(IRQ, IRQtimer0+timer, f, a, name);	ost->ossr = (1 << timer);	/* clear any pending interrupt */	ost->oier |= (1 << timer);		/* enable interrupt */} voidtimerdisable( int timer ){	OstmrReg *ost = OSTMRREG; 	if(timer < 0 || timer > 3)		return;	ost->osmr[timer] = 0;				/* clear freq */	ost->oier &= ~(1 << timer);			/* disable interrupt */} voidinstallprof(void (*pf)(Ureg *, int)){	int s; 	s = splfhi();	prof_fcn = pf;	timerenable( 2, HZ+1, profintr, 0);	timer_incr[2] = timer_incr[0]+63;	/* fine tuning */	splx(s);} voidclockinit(void){	OstmrReg *ost = OSTMRREG;	m->ticks = 0;	/* Set up timer registers */	ost->ossr = 0xf;	/* clear all four OSSR trigger bits */	ost->oier = 0;	ost->osmr[0] = 0;	ost->osmr[1] = 0;	ost->osmr[2] = 0;	//	ost->osmr[3] = 0;	timerenable( 0, HZ, clockintr, 0);//	timer_incr[3] = CLOCKFREQ*10;	/* 10 second watchdog *///	timer_setwatchdog(timer_incr[3]);//	timerenable( 2, 1, profintr, 0);	/* watch the watchdog */} voidclockpoll(void){	OstmrReg *ost = OSTMRREG;//	ost->osmr[3] = ost->oscr + timer_incr[3];	/* restart the watchdog */} voidclockcheck(void){	OstmrReg *ost = OSTMRREG; 	if((ost->osmr[3] - ost->oscr) < CLOCKFREQ) {		setpanic();		clockpoll();		dumpstack();		panic("Watchdog timer will expire");	}} // macros for fixed-point math ulong _mularsv(ulong m0, ulong m1, ulong a, ulong s); /* truncated: */#define FXDPTDIV(a,b,n) ((ulong)(((uvlong)(a) << (n)) / (b)))#define MAXMUL(a,n)     ((ulong)((((uvlong)1<<(n))-1)/(a)))#define MULDIV(x,a,b,n) (((x)*FXDPTDIV(a,b,n)) >> (n)) #define MULDIV64(x,a,b,n) ((ulong)_mularsv(x, FXDPTDIV(a,b,n), 0, (n))) /* rounded: */#define FXDPTDIVR(a,b,n) ((ulong)((((uvlong)(a) << (n))+((b)/2)) / (b)))#define MAXMULR(a,n)     ((ulong)((((uvlong)1<<(n))-1)/(a)))#define MULDIVR(x,a,b,n) (((x)*FXDPTDIVR(a,b,n)+(1<<((n)-1))) >> (n)) #define MULDIVR64(x,a,b,n) ((ulong)_mularsv(x, FXDPTDIVR(a,b,n), 1<<((n)-1), (n)))  // these routines are all limited to a maximum of 1165 seconds,// due to the wrap-around of the OSTIMER ulongtimer_start(void){	return OSTMRREG->oscr;} ulongtimer_ticks(ulong t0){	return OSTMRREG->oscr - t0;} inttimer_devwait(ulong *adr, ulong mask, ulong val, int ost){	int i;	ulong t0 = timer_start();	while((*adr & mask) != val) 		if(timer_ticks(t0) > ost)			return ((*adr & mask) == val) ? 0 : -1;		else			for(i = 0; i < 10; i++);	/* don't pound OSCR too hard! (why not?) */	return 0;} voidtimer_setwatchdog(int t){	OstmrReg *ost = OSTMRREG;	ost->osmr[3] = ost->oscr + t;	if(t) {		ost->ossr = (1<<3);		ost->oier |= (1<<3);		ost->ower = 1;	} else 		ost->oier &= ~(1<<3);} voidtimer_delay(int t){		ulong t0 = timer_start();	while(timer_ticks(t0) < t)		;}  ulongus2tmr(int us){	return MULDIV64(us, CLOCKFREQ, 1000000, 24);} inttmr2us(ulong t){	return MULDIV64(t, 1000000, CLOCKFREQ, 24);} voidmicrodelay(int us){	ulong t0 = timer_start();	ulong t = us2tmr(us);	while(timer_ticks(t0) <= t)		;} ulongms2tmr(int ms){	return MULDIV64(ms, CLOCKFREQ, 1000, 20);} inttmr2ms(ulong t){	return MULDIV64(t, 1000, CLOCKFREQ, 32);} voiddelay(int ms){	ulong t0 = timer_start();	ulong t = ms2tmr(ms);	while(timer_ticks(t0) <= t)		clockpoll();} /* * for devbench.c */vlongarchrdtsc(void){	return OSTMRREG->oscr;} ulongarchrdtsc32(void){	return OSTMRREG->oscr;} /* * for devkprof.c */longarchkprofmicrosecondspertick(void){	return MS2HZ*1000;} voidarchkprofenable(int){	/* TO DO */} uvlongfastticks(uvlong *hz){	if(hz)		*hz = HZ;	return m->ticks;}