~kris/9p

9hist

f9d03d2c24597487794512a96aabe3c77c2ad539 — David du Colombier 27 years ago 85db0cc
Plan 9 from Bell Labs 1999-05-08
6 files changed, 420 insertions(+), 193 deletions(-)

M mpc/devether.c
M mpc/etherscc.c
M mpc/main.c
M mpc/trap.c
M port/cache.c
M port/tod.c
M mpc/devether.c => mpc/devether.c +4 -1
@@ 304,7 304,7 @@ void
addethercard(char* t, int (*r)(Ether*))
{
	static int ncard;

print("addethercard\n");
	if(ncard == MaxEther)
		panic("too many ether cards");
	cards[ncard].type = t;


@@ 342,6 342,7 @@ etherreset(void)
	int i, n, ctlrno;
	char name[NAMELEN], buf[128];

print("etherreset\n");
	//ethermediumlink();
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)


@@ 352,7 353,9 @@ etherreset(void)
		ether->mbps = 10;
		if(isaconfig("ether", ctlrno, ether) == 0)
			continue;
print("after isaconfig %d\n", n);
		for(n = 0; cards[n].type; n++){
print("card %d\n", n);
			if(cistrcmp(cards[n].type, ether->type))
				continue;
			for(i = 0; i < ether->nopt; i++){

M mpc/etherscc.c => mpc/etherscc.c +99 -63
@@ 132,7 132,6 @@ attach(Ether *ether)
	ctlr->active = 1;
	ctlr->scc->gsmrl |= ENR|ENT;
	eieio();
//	m->bcsr[1] &= ~DisableEther;
}

static void


@@ 395,95 394,132 @@ sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
	Etherparam *p;
	IMM *io;

	io = ioplock();
	if(ctlr->port == 2){
		io->papar |= SIBIT(12)|SIBIT(13);	/* enable TXD2 and RXD2 pins */
		io->padir &= ~(SIBIT(12)|SIBIT(13));
		io->paodr &= ~SIBIT(12);

		io->pcpar &= ~(SIBIT(9)|SIBIT(8));	/* enable CLSN (CTS2) and RENA (CD2) */
		io->pcdir &= ~(SIBIT(9)|SIBIT(8));
		io->pcso |= SIBIT(9)|SIBIT(8);
print("sccsetup\n");

		io->papar |= SIBIT(6)|SIBIT(5);	/* enable CLK2 and CLK3 */
		io->padir &= ~(SIBIT(6)|SIBIT(5));
		eieio();
	io = ioplock();
	p = (Etherparam*)KADDR(SCC1P);

	if(ctlr->port != 1)
		panic("only do SCC1 at the momment");

	// step 1: enable TXD RXD ports
	io->papar |= SIBIT(14)|SIBIT(15);
	io->padir &= ~(SIBIT(14)|SIBIT(15));
	io->paodr &= ~SIBIT(14);
		
	// step 2: enable CLSN and RENA ports
	io->pcpar &= ~(SIBIT(11)|SIBIT(10));
	io->pcdir &= ~(SIBIT(11)|SIBIT(10));
	io->pcso |= SIBIT(11)|SIBIT(10);
	eieio();

		rcs = CLK2;
		tcs = CLK3;
	}else{
		io->papar |= SIBIT(14)|SIBIT(15);	/* enable TXD1 and RXD1 pins */
		io->padir &= ~(SIBIT(14)|SIBIT(15));
		io->paodr &= ~SIBIT(14);
	// setp 3
	io->pcpar &= ~SIBIT(15);		/* disble TENA pin */

		io->pcpar &= ~(SIBIT(10)|SIBIT(11));	/* enable CLSN (CTS1) and RENA (CD1) */
		io->pcdir &= ~(SIBIT(10)|SIBIT(11));
		io->pcso |= SIBIT(10)|SIBIT(11);
		eieio();
	// step 4: enable clocks
	io->papar |= SIBIT(6)|SIBIT(4);	/* enable CLK2 and CLK4 */
	io->padir &= ~(SIBIT(6)|SIBIT(4));
	eieio();

		io->papar |= SIBIT(6)|SIBIT(7);	/* enable CLK2 and CLK1 */
		io->padir &= ~(SIBIT(6)|SIBIT(7));
		eieio();
	// step 5/6: route clocks
	io->sicr = (7<<3) | (5);
	eieio();

		io->pcpar &= ~(SIBIT(4)|SIBIT(5)|SIBIT(6));	/* ETHLOOP, TPFULDL~, TPSQEL~ */
		io->pcdir |= SIBIT(4)|SIBIT(5)|SIBIT(6);
		io->pcdat &= ~SIBIT(4);
		io->pcdat |= SIBIT(5)|SIBIT(6);
		eieio();
	// step 7: set dma priority
	io->sdcr = 1;

		rcs = CLK2;
		tcs = CLK1;
	}
	iopunlock();

	sccnmsi(ctlr->port, rcs, tcs);	/* connect the clocks */
//	sccnmsi(ctlr->port, rcs, tcs);	/* connect the clocks */

	p = (Etherparam*)KADDR(ctlr->sccid==SCC1ID? SCC1P: SCC2P);
	memset(p, 0, sizeof(*p));
	p->rfcr = 0x18;
	p->tfcr = 0x18;
	p->mrblr = Bufsize;
	// step 8:
	p->rbase = PADDR(ctlr->rdr);
	p->tbase = PADDR(ctlr->tdr);

	cpmop(InitRxTx, ctlr->sccid, 0);
	// step 9:
	cpmop(InitRxTx, SCC1ID, 0);

	// step 10
	p->rfcr = 0x18;   // manuals say 0x10
	p->tfcr = 0x18;

	// step 11
	p->mrblr = Bufsize;

	// step 12:
	p->c_pres = ~0;

	// step 13:
	p->c_mask = 0xDEBB20E3;

	// step 14:
	p->crcec = 0;
	p->alec = 0;
	p->disfc = 0;

	// step 15:
	p->pads = 0x8888;
	
	// step 16:
	p->ret_lim = 0xF;

	// step 17:
	p->mflr = Rbsize;

	// step 18:
	p->minflr = ETHERMINTU+4;
	p->maxd1 = Bufsize;
	p->maxd2 = Bufsize;
	p->p_per = 0;	/* only moderate aggression */

	// step 19:
	p->maxd1 = Bufsize;	/* was 0x5F0 */
	p->maxd2 = Bufsize;	/* was 0x5F0 */

	// step 20:
	memset(p->gaddr, 0, sizeof(p->gaddr));

	// step 21:
	for(i=0; i<Eaddrlen; i+=2)
		p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];	/* it's not the obvious byte order */
		p->paddr[2-i/2] = (ea[i+1]<<8)|ea[i];

	scc->psmr = (2<<10)|(5<<1);	/* 32-bit CRC, ignore 22 bits before SFD */
	scc->dsr = 0xd555;
	scc->gsmrh = 0;	/* normal operation */
	scc->gsmrl = (1<<28)|(4<<21)|(1<<19)|0xC;	/* transmit clock invert, 48 bit preamble, repetitive 10 preamble, ethernet */
	eieio();
	// step 22
	p->p_per = 0;	/* only moderate aggression */

	// step 23:
	memset(p->iaddr, 0, sizeof(p->iaddr));

	// step 24:
	memset(p->taddr, 0, sizeof(p->taddr));

	// step 25:

	// step 26:

	// step 27:
	scc->scce = ~0;	/* clear all events */
	eieio();
	
	// step 28:
	scc->sccm = TXE | RXF | TXB;	/* enable interrupts */
	eieio();
	p->p_per = 0;	/* only moderate aggression */

	if(ctlr->sccid == SCC2ID){
		io->pbpar |= IBIT(18);	/* enable TENA pin (RTS2) */
		io->pbdir |= IBIT(18);
	}else{
		io->pbpar |= IBIT(19);	/* enable TENA pin (RTS1) */
		io->pbdir |= IBIT(19);
	}
	eieio();
	// step 29:
	// set by setvec

	// step 30:
	scc->gsmrh = 0;	/* normal operation */

	// step 31:
	scc->gsmrl = 0x1088000c;

	// step 32:
	scc->dsr = 0xd555;

	// step 33:
	scc->psmr = 0x080A;	/* 32-bit CRC, non-promiscuous */

	// step 34
	io->pcpar |= SIBIT(15);	/* enable TENA pin (RTS2) */
	io->pcdir &= ~SIBIT(15);

	/* enable is deferred until attach */
	// step 35: done at attach time
}

static int


@@ 499,7 535,7 @@ reset(Ether* ether)
	}

	if(!(ether->port >= 1 && ether->port <= 4)){
		print("%s ether: no SCC port %d\n", ether->type, ether->port);
		print("%s ether: no SCC port %ld\n", ether->type, ether->port);
		return -1;
	}



@@ 548,5 584,5 @@ void
etherscclink(void)
{
	addethercard("SCC", reset);
	addethercard("SCC2", reset);
//	addethercard("SCC2", reset);
}

M mpc/main.c => mpc/main.c +74 -2
@@ 7,7 7,7 @@
#include	"init.h"
#include	"pool.h"

#define MAXCONF 1000
#define MAXCONF 32

char *confname[MAXCONF];
char *confval[MAXCONF];


@@ 17,6 17,8 @@ int	predawn = 1;

Conf	conf;

static void options(void);

void
main(void)
{


@@ 40,9 42,11 @@ if(0) {
	pageinit();
	procinit0();
	initseg();
	options();
	links();
	chandevreset();
	swapinit();
print("usrinit\n");
	userinit();
predawn = 0;
	schedinit();


@@ 71,7 75,7 @@ machinit(void)
void
bootargs(ulong base)
{
print("bootargs = %ux\n", base);
print("bootargs = %ulx\n", base);
	USED(base);
}



@@ 269,6 273,74 @@ confinit(void)
	conf.copymode = 0;		/* copy on write */
}

static int
getcfields(char* lp, char** fields, int n, char* sep)
{
	int i;

	for(i = 0; lp && *lp && i < n; i++){
		while(*lp && strchr(sep, *lp) != 0)
			*lp++ = 0;
		if(*lp == 0)
			break;
		fields[i] = lp;
		while(*lp && strchr(sep, *lp) == 0){
			if(*lp == '\\' && *(lp+1) == '\n')
				*lp++ = ' ';
			lp++;
		}
	}

	return i;
}

static char BOOTARGS[] = 
		"ether0=type=SCC port=1 ea=08003e27df94\r\n"
		"vgasize=640x480x8\r\n"
		"kernelpercent=40\r\n"
		"console=0 lcd\r\nbaud=9600\r\n";

static void
options(void)
{
	long i, n;
	char *cp, *p, *q;
	char *line[MAXCONF];

	/*
	 *  parse configuration args from dos file plan9.ini
	 */
	cp = BOOTARGS;	/* where b.com leaves its config */

	/*
	 * Strip out '\r', change '\t' -> ' '.
	 */
	p = cp;
	for(q = cp; *q; q++){
		if(*q == '\r')
			continue;
		if(*q == '\t')
			*q = ' ';
		*p++ = *q;
	}
	*p = 0;

	n = getcfields(cp, line, MAXCONF, "\n");
	for(i = 0; i < n; i++){
		if(*line[i] == '#')
			continue;
		cp = strchr(line[i], '=');
		if(cp == 0)
			continue;
		*cp++ = 0;
		if(cp - line[i] >= NAMELEN+1)
			*(line[i]+NAMELEN-1) = 0;
		confname[nconf] = line[i];
		confval[nconf] = cp;
		nconf++;
	}
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{

M mpc/trap.c => mpc/trap.c +157 -11
@@ 34,6 34,7 @@ struct
void	faultpower(Ureg *ur, ulong addr, int read);
void	kernfault(Ureg*, int);
void	syscall(Ureg* ureg);
void	noted(Ureg*, ulong);

char *excname[] =
{


@@ 373,7 374,7 @@ intrstats(char *buf, int bsize)
	n = 0;
	for(i=0; i<nelem(halloc.ivec) && n < bsize; i++)
		if((h = halloc.ivec[i]) != nil && h->nintr)
			n += snprint(buf+n, bsize-n, "%3d %lud %lud %lud\n", i, h->nintr, h->ticks, h->maxtick);
			n += snprint(buf+n, bsize-n, "%3d %ud %uld %ud\n", i, h->nintr, h->ticks, h->maxtick);
	return n;
}



@@ 442,7 443,7 @@ dumpregs(Ureg *ur)
	int i;
	ulong *l;
	if(up) {
		print("registers for %s %d\n", up->text, up->pid);
		print("registers for %s %ld\n", up->text, up->pid);
		if(ur->srr1 & MSR_PR == 0)
		if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
			print("invalid stack ptr\n");


@@ 459,7 460,7 @@ dumpregs(Ureg *ur)
static void
linkproc(void)
{
print("linkproc %ux\n", up);
print("linkproc %ulx\n", up);
	spllo();
	(*up->kpfun)(up->kparg);
	pexit("", 0);


@@ 653,12 654,157 @@ syscall(Ureg* ureg)
	 *  the results register by caller of syscall.
	 */
	ureg->r3 = ret;
//print("ret = %d\n", ret);
//	if(scallnr == NOTED)
//		noted(ureg, *(ulong*)(sp+BY2WD));

//	if(scallnr!=RFORK && (up->procctl || up->nnote)){
//		splhi();
//		notify(ureg);
//	}

	if(scallnr == NOTED)
		noted(ureg, *(ulong*)(sp+BY2WD));

	if(scallnr!=RFORK && (up->procctl || up->nnote)){
		splhi();
		notify(ureg);
	}
}
/*
 *  Call user, if necessary, with note.
 *  Pass user the Ureg struct and the note on his stack.
 */
int
notify(Ureg* ur)
{
	int l;
	ulong s, sp;
	Note *n;

	if(up->procctl)
		procctl(up);
	if(up->nnote == 0)
		return 0;

	s = spllo();
	qlock(&up->debug);
	up->notepending = 0;
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0){
		l = strlen(n->msg);
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */
			l = ERRLEN-15;
		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
	}

	if(n->flag!=NUser && (up->notified || up->notify==0)){
		if(n->flag == NDebug)
			pprint("suicide: %s\n", n->msg);
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}

	if(up->notified) {
		qunlock(&up->debug);
		splhi();
		return 0;
	}

	if(!up->notify) {
		qunlock(&up->debug);
		pexit(n->msg, n->flag!=NDebug);
	}
	sp = ur->usp & ~(BY2V-1);
	sp -= sizeof(Ureg);

	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
	   !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)) {
		pprint("suicide: bad address or sp in notify\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	memmove((Ureg*)sp, ur, sizeof(Ureg));
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
	up->ureg = (void*)sp;
	sp -= BY2WD+ERRLEN;
	memmove((char*)sp, up->note[0].msg, ERRLEN);
	sp -= 3*BY2WD;
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
	ur->usp = sp;
	ur->pc = (ulong)up->notify;
	up->notified = 1;
	up->nnote--;
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));

	qunlock(&up->debug);
	splx(s);
	return 1;
}


/*
 *   Return user to state before notify()
 */
void
noted(Ureg* ureg, ulong arg0)
{
	Ureg *nureg;
	ulong oureg, sp;

	qlock(&up->debug);
	if(arg0!=NRSTR && !up->notified) {
		qunlock(&up->debug);
		pprint("call to noted() when not notified\n");
		pexit("Suicide", 0);
	}
	up->notified = 0;

	nureg = up->ureg;	/* pointer to user returned Ureg struct */

	/* sanity clause */
	oureg = (ulong)nureg;
	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
		pprint("bad ureg in noted or call to noted when not notified\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	memmove(ureg, nureg, sizeof(Ureg));

	switch(arg0){
	case NCONT:
	case NRSTR:
		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
			qunlock(&up->debug);
			pexit("Suicide", 0);
		}
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
		qunlock(&up->debug);
		break;

	case NSAVE:
		if(!okaddr(nureg->pc, BY2WD, 0)
		|| !okaddr(nureg->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
			qunlock(&up->debug);
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);
		sp = oureg-4*BY2WD-ERRLEN;
		splhi();
		ureg->sp = sp;
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
		break;

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		up->lastnote.flag = NDebug;
		/* fall through */
		
	case NDFLT:
		if(up->lastnote.flag == NDebug)
			pprint("suicide: %s\n", up->lastnote.msg);
		qunlock(&up->debug);
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
	}
}

M port/cache.c => port/cache.c +61 -9
@@ 5,13 5,12 @@
#include	"fns.h"
#include	"../port/error.h"

Image	fscache;

enum
{
	NHASH		= 128,
	MAXCACHE	= 1024*1024,
	NFILE		= 4096,
	NEXTENT		= 200,		/* extent allocation size */
};

typedef struct Extent Extent;


@@ 46,7 45,60 @@ struct Cache
	Mntcache	*tail;
	Mntcache	*hash[NHASH];
};
Cache cache;

typedef struct Ecache Ecache;
struct Ecache
{
	Lock;
	int	total;
	int	free;
	Extent*	head;
};

static Image fscache;
static Cache cache;
static Ecache ecache;

static void
extentfree(Extent* e)
{
	lock(&ecache);
	e->next = ecache.head;
	ecache.head = e;
	ecache.free++;
	unlock(&ecache);
}

static Extent*
extentalloc(void)
{
	Extent *e;
	int i;

	lock(&ecache);
	if(ecache.head == nil){
		e = xalloc(NEXTENT*sizeof(Extent));
		if(e == nil){
			unlock(&ecache);
			return nil;
		}
		for(i = 0; i < NEXTENT; i++){
			e->next = ecache.head;
			ecache.head = e;
			e++;
		}
		ecache.free += NEXTENT;
		ecache.total += NEXTENT;
	}

	e = ecache.head;
	ecache.head = e->next;
	memset(e, 0, sizeof(Extent));
	ecache.free--;
	unlock(&ecache);

	return e;
}

void
cinit(void)


@@ 120,7 172,7 @@ cnodata(Mntcache *m)
	 */
	for(e = m->list; e; e = n) {
		n = e->next;
		free(e);
		extentfree(e);
	}
	m->list = 0;
}


@@ 210,7 262,7 @@ copen(Chan *c)

	while(e) {
		next = e->next;
		free(e);
		extentfree(e);
		e = next;
	}
	qunlock(m);


@@ 271,7 323,7 @@ cread(Chan *c, uchar *buf, int len, vlong off)
		p = cpage(e);
		if(p == 0) {
			*t = e->next;
			free(e);
			extentfree(e);
			qunlock(m);
			return total;
		}


@@ 322,13 374,13 @@ cchain(uchar *buf, ulong offset, int len, Extent **tail)
	*tail = 0;
	t = &start;
	while(len) {
		e = malloc(sizeof(Extent));
		e = extentalloc();
		if(e == 0)
			break;

		p = auxpage();
		if(p == 0) {
			free(e);
			extentfree(e);
			break;
		}
		l = len;


@@ 583,7 635,7 @@ cwrite(Chan* c, uchar *buf, int len, vlong off)
	/* free the overlap - its a rare case */
	while(f && f->start < eblock) {
		e = f->next;
		free(f);
		extentfree(f);
		f = e;
	}


M port/tod.c => port/tod.c +25 -107
@@ 9,89 9,24 @@
// on the system.  converting the time to nanoseconds requires
// the following formula
//
//	t = (((1000000000<<s1)/f)*(ticks>>s2))>>(s1-s2)
//	t = (((1000000000<<31)/f)*ticks)>>31
//
//  where
//
//	'f'		is the clock frequency
//	'ticks'		are clock ticks
//	's1' and 's2'	are shift ammounts to avoid 64 bit
//			overflows in the calculations
//
//  to avoid too much calculation in gettod(), we calculate
//
//	mult = (1000000000<<s1)/f
//	mult = (1000000000<<31)/f
//
//  each time f is set.  f is normally set by a user level
//  program writing to /dev/fastclock.
//
//  To calculate s1 and s2, we have to avoid overflowing our
//  signed 64 bit calculations.  Also we wish to accomodate
//  15 minutes of ticks.  This gives us the following
//  constraints:
//
//	1) log2(1000000000<<s1) <= 63
//	   or s1 <= 32
//	2) accomodate 1 minute of ticks without overflow
//	   or log2(((1000000000<<s1)/f)*((60*f)>>s2)) <= 63
//	   or log2(mult) + 6 + log2(f) - s2 <= 63
//	   or log2(mult) + log2(f) - 57 <= s2
//
//  by definition
//
//	3) log2(mult) = log2(1000000000) + s1 - log2(f)
//	   or log2(mult) = 30 + s1 - log2(f)
//
//  To balance the accuracy of the multiplier and the sampled
//  ticks we set
//
//	4) log2(mult) = log2(f>>s2)
//	   or log2(mult) = log2(f) - s2
//
//  Combining 2) and 4) we get
//
//	5) log2(f) - s2 + log2(f) - 57 <= s2
//	   or 2*log2(f) - 57 <= 2*s2
//	   or log2(f) - 28 <= s2
//
//  Combining 3) and 4)
//
//	6) 30 + s1 - log2(f) = log2(f) - s2
//	   or s1 = 2*log2(f) - s2 - 30
//
//  Since shifting ticks left doesn't increase accuracy, and
//  shifting 1000000000 right loses accuracy
//
//	7) s2 >= 0
//	8) s1 >= 0
//
//  As an example, that gives us the following
//
//	for f = 100, log2(f) = 7
//
//		s2 = 0
//		s1 = 0
//
//	for f = 267000000, log2(f) = 28
//
//		s2 = 0
//		s1 = 26
//
//	for f = 2000000000, log2(f) = 31
//
//		s2 = 3
//		s1 = 29
//
//	for f = 8000000000, log2(f) = 33
//
//		s2 = 5
//		s1 = 31


// frequency of the tod clock
#define TODFREQ	1000000000LL

static vlong logtab[40];

struct {
	Lock;
	int	s1;		// time = ((ticks>>s2)*multiplier)>>(s1-s2)


@@ 106,56 41,38 @@ struct {
	ulong	send;		// ...
} tod;

int
log2(vlong x)
{
	int i;

	for(i = 0; i < nelem(logtab); i++){
		if(x < logtab[i])
			break;
	}
	return i+8;
}

void
todinit(void)
{
	vlong v;
	int i;

	v = 1LL<<8;
	for(i = 0; i < nelem(logtab); i++){
		logtab[i] = v;
		v <<= 1;
	}
	fastticks((uvlong*)&tod.hz);
	todsetfreq(tod.hz);
	addclock0link(todfix);
}

//
//  This routine makes sure that the multiplier has
//  at least Log2mult bits to guarantee that precision.
//  calculate multiplier
//
void
todsetfreq(vlong f)
{
	int lf;

	// this ensures that the multiplier has 22 bits
	// the shift is an attempt to maintain precision
	// during the caculations.  the number of bits in
	// the multiplier should be log(TODFREQ) + 31 - log(f).
	//
	//	Freq		bits
	//	167 MHZ		34
	//	267 MHZ		33
	//	500 MHZ		32
	//
	// in all cases, we need to call todget() at least once
	// a second to keep the subsequent calculations from
	// overflowing.

	ilock(&tod);
	tod.hz = f;
	lf = log2(f);
	tod.s2 = lf - 28;
	if(tod.s2 < 0)
		tod.s2 = 0;
	tod.s1 = 2*lf - tod.s2 - 30;
	if(tod.s1 < 0)
		tod.s1 = 0;
	if(tod.s1 > 32)
		tod.s1 = 32;
	tod.multiplier = (TODFREQ<<tod.s1)/f;
	tod.multiplier = (TODFREQ<<31)/f;
	iunlock(&tod);
}



@@ 193,7 110,8 @@ todset(vlong t, vlong delta, int n)
vlong
todget(void)
{
	vlong ticks, x, diff;
	uvlong x;
	vlong ticks, diff;
	ulong t;

	ilock(&tod);


@@ 213,15 131,15 @@ todget(void)
		tod.sstart = t;
	}

	// convert to epoch
	x = ((diff>>tod.s2)*tod.multiplier)>>(tod.s1-tod.s2);
	// convert to epoch, make sure calculation is unsigned
	x = (((uvlong)diff) * ((uvlong)tod.multiplier)) >> 31;
	x += tod.off;

	// protect against overflows (gettod is called at least once a second)
	tod.last = ticks;
	tod.off = x;

	/* time can't go backwards */
	// time can't go backwards
	if(x < tod.lasttime)
		x = tod.lasttime;
	tod.lasttime = x;


@@ 236,8 154,8 @@ todget(void)
void
todfix(void)
{
	// once a minute, make sure we don't overflow
	if((MACHP(0)->ticks % (60*HZ)) == 0)
	// once a second, make sure we don't overflow
	if((MACHP(0)->ticks % HZ) == 0)
		todget();
}