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();
}