| plan 9 kernel history: overview | file list | diff list |
power/devhs.c (diff list | history)
| 1990/0227/sys/src/9/power/devhs.c:8,25 – 1990/0312/sys/src/9/power/devhs.c:8,62 (short | long) | ||
| 1990/0227 | #include "io.h" | |
| 1990/0312 | typedef struct Hsvme Hsvme; typedef struct Device Device; | |
| 1990/0227 | enum { | |
| 1990/0312 | Maxburst= 1023, /* maximum transmit burst size */ | |
| 1990/0227 | Vmevec= 0xd0, /* vme vector for interrupts */ Intlevel= 5, /* level to interrupt on */ | |
| 1990/0312 | Nhsvme= 1, | |
| 1990/0227 | }; | |
| 1990/0312 | /* * hsvme datakit board */ struct Device { ushort version; ushort pad0x02; ushort vector; ushort pad0x06; ushort csr; ushort pad0x0A; ushort data; }; #define HSVME VMEA24SUP(Device, 0xF90000) | |
| 1990/0227 | ||
| 1990/0312 | struct Hsvme { QLock; QLock xmit; Device *addr; int vec; /* interupt vector */ Rendez r; /* output process */ Rendez kr; /* input kernel process */ int chan; /* current input channel */ Queue *rq; /* read queue */ uchar buf[1024]; /* bytes being collected */ uchar *wptr; /* pointer into buf */ int kstarted; /* true if kernel process started */ /* statistics */ ulong parity; /* parity errors */ ulong rintr; /* rcv interrupts */ ulong tintr; /* transmit interrupts */ ulong in; /* bytes in */ ulong out; /* bytes out */ }; Hsvme hsvme[Nhsvme]; | |
| 1990/0227 | #define ALIVE 0x0001 #define IENABLE 0x0004 #define EXOFLOW 0x0008 | |
| 1990/0227/sys/src/9/power/devhs.c:42,62 – 1990/0312/sys/src/9/power/devhs.c:79,108 | ||
| 1990/0227 | #define TXEOD 0x0400 #define NND 0x8000 | |
| 1990/0312 | static void hsvmekproc(void*); | |
| 1990/0227 | ||
| 1990/0312 | /* * hsvme stream module definition */ static void hsvmeoput(Queue*, Block*); static void hsvmestopen(Queue*, Stream*); static void hsvmestclose(Queue*); Qinfo hsvmeinfo = { nullput, hsvmeoput, hsvmestopen, hsvmestclose, "hsvme" }; /* * restart a VME board */ | |
| 1990/0227 | void | |
| 1990/0312 | hsvmerestart(Hsvme *hp) | |
| 1990/0227 | { | |
| 1990/0312 | Device *addr; addr = hp->addr; | |
| 1990/0227 | addr->csr = RESET; wbflush(); | |
| 1990/0312 | delay(20); | |
| 1990/0227 | /* * set interrupt vector | |
| 1990/0227/sys/src/9/power/devhs.c:64,92 – 1990/0312/sys/src/9/power/devhs.c:110,141 | ||
| 1990/0227 | * set forcew to a known value * interrupt on level `Intlevel' */ | |
| 1990/0312 | addr->vector = hp->vec; | |
| 1990/0227 | addr->csr = NORESET|IPL(Intlevel)|IENABLE|ALIVE; wbflush(); | |
| 1990/0312 | delay(1); | |
| 1990/0227 | addr->csr = NORESET|IPL(Intlevel)|FORCEW|IENABLE|ALIVE; wbflush(); | |
| 1990/0312 | delay(1); | |
| 1990/0227 | } | |
| 1990/0312 | /* * reset all vme boards */ | |
| 1990/0227 | void hsvmereset(void) { | |
| 1990/0312 | int i; Hsvme *hp; | |
| 1990/0227 |
| |
| 1990/0312 | for(i=0; i<Nhsvme; i++){ hsvme[i].addr = HSVME+i; hsvme[i].vec = Vmevec+i; hsvme[i].addr->csr = RESET; setvmevec(hsvme[i].vec, hsvmeintr); } | |
| 1990/0227 | wbflush(); | |
| 1990/0312 | delay(20); | |
| 1990/0227 | } void | |
| 1990/0227/sys/src/9/power/devhs.c:95,117 – 1990/0312/sys/src/9/power/devhs.c:144,169 | ||
| 1990/0227 | } /* | |
| 1990/0312 | * enable the device for interrupts, spec is the device number | |
| 1990/0227 | */ | |
| 1990/0312 | Hsvme *hp; int i; Chan *c; | |
| 1990/0227 |
| |
| 1990/0312 | i = strtoul(spec, 0, 0); if(i >= Nhsvme) error(0, Ebadarg); hp = &hsvme[i]; hsvmerestart(hp); print("hsvme [%d] csr %ux\n", i, hp->addr->csr); | |
| 1990/0227 |
| |
| 1990/0312 | c = devattach('h', spec); c->dev = i; c->qid = CHDIR; return c; | |
| 1990/0227 | } Chan* | |
| 1990/0227/sys/src/9/power/devhs.c:123,147 – 1990/0312/sys/src/9/power/devhs.c:175,197 | ||
| 1990/0227 | int hsvmewalk(Chan *c, char *name) { | |
| 1990/0312 | return devwalk(c, name, 0, 0, streamgen); | |
| 1990/0227 | } void hsvmestat(Chan *c, char *dp) { | |
| 1990/0312 | devstat(c, dp, 0, 0, streamgen); | |
| 1990/0227 | } Chan* hsvmeopen(Chan *c, int omode) { | |
| 1990/0312 | if(c->qid == CHDIR){ if(omode != OREAD) error(0, Eperm); }else streamopen(c, &hsvmeinfo); | |
| 1990/0227 | c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; | |
| 1990/0227/sys/src/9/power/devhs.c:157,176 – 1990/0312/sys/src/9/power/devhs.c:207,226 | ||
| 1990/0227 | void hsvmeclose(Chan *c) { | |
| 1990/0312 | if(c->qid != CHDIR) streamclose(c); | |
| 1990/0227 | } long hsvmeread(Chan *c, void *buf, long n) { | |
| 1990/0312 | return streamread(c, buf, n); | |
| 1990/0227 | } long hsvmewrite(Chan *c, void *buf, long n) { | |
| 1990/0312 | return streamwrite(c, buf, n, 0); | |
| 1990/0227 | } void | |
| 1990/0227/sys/src/9/power/devhs.c:197,227 – 1990/0312/sys/src/9/power/devhs.c:247,562 | ||
| 1990/0227 | rooterrstr(e, buf); } | |
| 1990/0312 | /* * the stream routines */ /* * create the kernel process for input */ | |
| 1990/0227 | static void | |
| 1990/0312 | hsvmestopen(Queue *q, Stream *s) | |
| 1990/0227 | { | |
| 1990/0312 | Hsvme *hp; char name[32]; | |
| 1990/0227 |
| |
| 1990/0312 | hp = &hsvme[s->dev]; sprint(name, "**hsvme%d**", s->dev); q->ptr = q->other->ptr = hp; hp->rq = q; kproc(name, hsvmekproc, hp); } /* * kill off the kernel process */ static int kdead(void *arg) { Hsvme *hp; hp = (Hsvme *)arg; return hp->kstarted == 0; } static void hsvmestclose(Queue * q) { Hsvme *hp; hp = (Hsvme *)q->ptr; qlock(hp); hp->rq = 0; qunlock(hp); wakeup(&hp->kr); sleep(&hp->r, kdead, hp); } /* * free all blocks of a message in `q', `bp' is the first block * of the message */ static void freemsg(Queue *q, Block *bp) { for(; bp; bp = getq(q)){ if(bp->flags & S_DELIM){ freeb(bp); return; | |
| 1990/0227 | } | |
| 1990/0312 | freeb(bp); } } /* * return true if the output fifo is at least half empty. * the implication is that it can take at least another 1000 byte burst. */ static int halfempty(void *arg) { Device *addr; addr = (Device*)arg; return addr->csr & XHF; } /* * output a block * * the first 2 bytes of every message are the channel number, * low order byte first. the third is a possible trailing control * character. */ void hsvmeoput(Queue *q, Block *bp) { Device *addr; Hsvme *hp; int burst; int chan; int ctl; int n; if(bp->type != M_DATA){ freeb(bp); return; } /* * get a whole message before handing bytes to the device */ if(!putq(q, bp)) return; /* * one transmitter at a time */ hp = (Hsvme *)q->ptr; qlock(&hp->xmit); addr = hp->addr; /* * parse message */ bp = getq(q); if(bp->wptr - bp->rptr < 3){ freemsg(q, bp); qunlock(&hp->xmit); return; } chan = CHNO | *bp->rptr++ | (*bp->rptr++<<8); ctl = *bp->rptr++; /* * send the 8 bit data, burst are up to Maxburst (9-bit) bytes long */ if(!(addr->csr & XHF)) sleep(&hp->r, halfempty, addr); /* print("->%.2uo\n", CHNO|chan);/**/ addr->data = CHNO|chan; burst = Maxburst; while(bp){ if(burst == 0){ addr->data = TXEOD; /* print("->%.2uo\n", TXEOD); /**/ if(!(addr->csr & XHF)) sleep(&hp->r, halfempty, addr); /* print("->%.2uo\n", CHNO|chan); /**/ addr->data = CHNO|chan; burst = Maxburst; | |
| 1990/0227 | } | |
| 1990/0312 | n = bp->wptr - bp->rptr; if(n > burst) n = burst; burst -= n; while(n--){ /* print("->%.2uo\n", *bp->rptr); /**/ addr->data = *bp->rptr++; | |
| 1990/0227 | } | |
| 1990/0312 | if(bp->rptr >= bp->wptr){ if(bp->flags & S_DELIM){ freeb(bp); break; } freeb(bp); bp = getq(q); } } /* * send the control byte if there is one */ if(ctl){ /* print("->%.2uo\n", CTL|ctl); /**/ addr->data = CTL|ctl; } /* * start the fifo emptying */ /* print("->%.2uo\n", TXEOD); /**/ addr->data = TXEOD; qunlock(&hp->xmit); } /* * return true if the input fifo is non-empty */ static int notempty(void *arg) { Device *addr; addr = (Device *)arg; return addr->csr & REF; } /* * fill a block with what is currently buffered and send it upstream */ static void upstream(Hsvme *hp, unsigned int ctl) { int n; Block *bp; n = hp->wptr - hp->buf; bp = allocb(3 + n); bp->wptr[0] = hp->chan; bp->wptr[1] = hp->chan>>8; bp->wptr[2] = ctl; if(n) memcpy(&bp->wptr[3], hp->buf, n); bp->wptr += 3 + n; bp->flags |= S_DELIM; PUTNEXT(hp->rq, bp); hp->wptr = hp->buf; } /* * Read bytes from the input fifo. Since we take an interrupt every * time the fifo goes non-empty, we need to waste time to let the * fifo fill up. */ static void hsvmekproc(void *arg) { Hsvme *hp; Device *addr; unsigned int c; hp = (Hsvme *)arg; addr = hp->addr; hp->kstarted = 1; hp->wptr = hp->buf; for(;;){ /* * die if the device is closed */ qlock(hp); if(hp->rq == 0){ qunlock(hp); hp->kstarted = 0; wakeup(&hp->r); return; } /* * let the fifo fill a bit */ delay(1); /* * 0xFFFF means an empty fifo */ while ((c = addr->data) != 0xFFFF) { /* print(" %.2uo<-\n", c); /**/ if(c & CHNO){ c &= 0x1FF; if(hp->chan == c) continue; /* * new channel, put anything saved upstream */ if(hp->wptr - hp->buf != 0) upstream(hp, 0); hp->chan = c; } else if(c & NND){ /* * ctl byte, this ends a message */ upstream(hp, c); } else { /* * data byte, put in local buffer */ *hp->wptr++ = c; if(hp->wptr == &hp->buf[sizeof hp->buf]) upstream(hp, 0); } } qunlock(hp); /* * sleep if input fifo empty */ if(!notempty(addr)) sleep(&hp->kr, notempty, addr); } } /* * only one flavor interrupt. we have to use the less than half full * and not empty bits to figure out whom to wake. */ static void hsvmeintr(int vec) { ushort csr; Device *addr; Hsvme *hp; hp = &hsvme[vec - Vmevec]; if(hp < hsvme || hp > &hsvme[Nhsvme]){ print("bad hsvme vec\n"); return; } csr = hp->addr->csr; if (csr & REF) { hp->rintr++; wakeup(&hp->kr); } if (csr & XHF) { hp->tintr++; wakeup(&hp->r); } if ((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)) { hp->parity++; hsvmerestart(hp); print("hsvme %d: reset, csr = 0x%ux\n", HSVME, csr); } | |
| 1990/0227 | } | |
| 1990/0312/sys/src/9/power/devhs.c:364,371 – 1990/0315/sys/src/9/power/devhs.c:364,372 (short | long) | ||
| 1990/0312 | qunlock(&hp->xmit); return; } | |
| 1990/0315 | chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8); ctl = bp->rptr[2]; bp->rptr += 3; | |
| 1990/0312 | /* * send the 8 bit data, burst are up to Maxburst (9-bit) bytes long | |
| 1990/0315/sys/src/9/power/devhs.c:158,164 – 1990/0403/sys/src/9/power/devhs.c:158,163 (short | long) | ||
| 1990/0312 | error(0, Ebadarg); hp = &hsvme[i]; hsvmerestart(hp); | |
| 1990/0227 | ||
| 1990/0312 | c = devattach('h', spec); c->dev = i; | |
| 1990/0315/sys/src/9/power/devhs.c:466,471 – 1990/0403/sys/src/9/power/devhs.c:465,471 | ||
| 1990/0312 | Hsvme *hp; Device *addr; unsigned int c; | |
| 1990/0403 | int miss; | |
| 1990/0312 | hp = (Hsvme *)arg; addr = hp->addr; | |
| 1990/0315/sys/src/9/power/devhs.c:485,499 – 1990/0403/sys/src/9/power/devhs.c:485,498 | ||
| 1990/0312 | } /* | |
| 1990/0403 | * if we loop many times without finding a character, sleep | |
| 1990/0312 | */ | |
| 1990/0403 | for(miss = 0; miss < 10; miss++){ | |
| 1990/0312 | /* * 0xFFFF means an empty fifo */ while ((c = addr->data) != 0xFFFF) { | |
| 1990/0403 | miss = 0; | |
| 1990/0312 | if(c & CHNO){ c &= 0x1FF; if(hp->chan == c) | |
| 1990/0315/sys/src/9/power/devhs.c:517,522 – 1990/0403/sys/src/9/power/devhs.c:516,522 | ||
| 1990/0312 | if(hp->wptr == &hp->buf[sizeof hp->buf]) upstream(hp, 0); } | |
| 1990/0403 | } | |
| 1990/0312 | } qunlock(hp); | |
| 1990/0403/sys/src/9/power/devhs.c:260,266 – 1990/0722/sys/src/9/power/devhs.c:260,266 (short | long) | ||
| 1990/0312 | char name[32]; | |
| 1990/0227 | ||
| 1990/0312 | hp = &hsvme[s->dev]; | |
| 1990/0722 | sprint(name, "hsvme%d", s->dev); | |
| 1990/0312 | q->ptr = q->other->ptr = hp; hp->rq = q; kproc(name, hsvmekproc, hp); | |
| 1990/0722/sys/src/9/power/devhs.c:485,494 – 1990/0816/sys/src/9/power/devhs.c:485,490 (short | long) | ||
| 1990/0312 | } /* | |
| 1990/0403 |
| |
| 1990/0312 |
| |
| 1990/0403 |
| |
| 1990/0312 |
| |
| 1990/0722/sys/src/9/power/devhs.c:516,522 – 1990/0816/sys/src/9/power/devhs.c:512,517 | ||
| 1990/0312 | if(hp->wptr == &hp->buf[sizeof hp->buf]) upstream(hp, 0); } | |
| 1990/0403 |
| |
| 1990/0312 | } qunlock(hp); | |
| 1990/0816/sys/src/9/power/devhs.c:488,493 – 1990/0826/sys/src/9/power/devhs.c:488,494 (short | long) | ||
| 1990/0312 | * 0xFFFF means an empty fifo */ while ((c = addr->data) != 0xFFFF) { | |
| 1990/0826 | hp->in++; | |
| 1990/0403 | miss = 0; | |
| 1990/0312 | if(c & CHNO){ c &= 0x1FF; | |
| 1990/0826/sys/src/9/power/devhs.c:554,559 – 1990/0930/sys/src/9/power/devhs.c:554,559 (short | long) | ||
| 1990/0312 | hp->parity++; hsvmerestart(hp); print("hsvme %d: reset, csr = 0x%ux\n", | |
| 1990/0930 | vec - Vmevec, csr); | |
| 1990/0312 | } | |
| 1990/0227 | } | |
| 1990/0930/sys/src/9/power/devhs.c:466,471 – 1990/1101/sys/src/9/power/devhs.c:466,472 (short | long) | ||
| 1990/0312 | Device *addr; unsigned int c; | |
| 1990/0403 | int miss; | |
| 1990/1101 | int locked; | |
| 1990/0312 | hp = (Hsvme *)arg; addr = hp->addr; | |
| 1990/0930/sys/src/9/power/devhs.c:472,482 – 1990/1101/sys/src/9/power/devhs.c:473,493 | ||
| 1990/0312 | hp->kstarted = 1; hp->wptr = hp->buf; | |
| 1990/1101 | locked = 0; if(waserror()){ if(locked) qunlock(hp); hp->kstarted = 0; wakeup(&hp->r); return; } | |
| 1990/0312 | for(;;){ /* * die if the device is closed */ qlock(hp); | |
| 1990/1101 | locked = 1; | |
| 1990/0312 | if(hp->rq == 0){ qunlock(hp); hp->kstarted = 0; | |
| 1990/0930/sys/src/9/power/devhs.c:515,520 – 1990/1101/sys/src/9/power/devhs.c:526,532 | ||
| 1990/0312 | } } qunlock(hp); | |
| 1990/1101 | locked = 0; | |
| 1990/0312 | /* * sleep if input fifo empty | |
| 1990/1101/sys/src/9/power/devhs.c:88,94 – 1990/11151/sys/src/9/power/devhs.c:88,101 (short | long) | ||
| 1990/0312 | static void hsvmeoput(Queue*, Block*); static void hsvmestopen(Queue*, Stream*); static void hsvmestclose(Queue*); | |
| 1990/11151 | Qinfo hsvmeinfo = { nullput, hsvmeoput, hsvmestopen, hsvmestclose, "hsvme" }; | |
| 1990/0312 | /* * restart a VME board | |
| 1990/11151/sys/src/9/power/devhs.c:162,174 – 1990/11211/sys/src/9/power/devhs.c:162,174 (short | long) | ||
| 1990/0227 | ||
| 1990/0312 | i = strtoul(spec, 0, 0); if(i >= Nhsvme) | |
| 1990/11211 | error(Ebadarg); | |
| 1990/0312 | hp = &hsvme[i]; hsvmerestart(hp); | |
| 1990/0227 | ||
| 1990/0312 | c = devattach('h', spec); c->dev = i; | |
| 1990/11211 | c->qid.path = CHDIR; | |
| 1990/0312 | return c; | |
| 1990/0227 | } | |
| 1990/11151/sys/src/9/power/devhs.c:193,201 – 1990/11211/sys/src/9/power/devhs.c:193,201 | ||
| 1990/0227 | Chan* hsvmeopen(Chan *c, int omode) { | |
| 1990/0312 |
| |
| 1990/11211 | if(c->qid.path == CHDIR){ | |
| 1990/0312 | if(omode != OREAD) | |
| 1990/11211 | error(Eperm); | |
| 1990/0312 | }else streamopen(c, &hsvmeinfo); | |
| 1990/0227 | c->mode = openmode(omode); | |
| 1990/11151/sys/src/9/power/devhs.c:207,219 – 1990/11211/sys/src/9/power/devhs.c:207,219 | ||
| 1990/0227 | void hsvmecreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void hsvmeclose(Chan *c) { | |
| 1990/0312 |
| |
| 1990/11211 | if(c->qid.path != CHDIR) | |
| 1990/0312 | streamclose(c); | |
| 1990/0227 | } | |
| 1990/11151/sys/src/9/power/devhs.c:232,256 – 1990/11211/sys/src/9/power/devhs.c:232,244 | ||
| 1990/0227 | void hsvmeremove(Chan *c) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void hsvmewstat(Chan *c, char *dp) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1990/0312 | /* | |
| 1990/11211/sys/src/9/power/devhs.c:460,466 – 1990/1214/sys/src/9/power/devhs.c:460,465 (short | long) | ||
| 1990/0312 | Hsvme *hp; Device *addr; unsigned int c; | |
| 1990/0403 |
| |
| 1990/1101 | int locked; | |
| 1990/0312 | hp = (Hsvme *)arg; | |
| 1990/11211/sys/src/9/power/devhs.c:481,486 – 1990/1214/sys/src/9/power/devhs.c:480,486 | ||
| 1990/0312 | /* * die if the device is closed */ | |
| 1990/1214 | USED(locked); /* so locked = 0 and locked = 1 stay */ | |
| 1990/0312 | qlock(hp); | |
| 1990/1101 | locked = 1; | |
| 1990/0312 | if(hp->rq == 0){ | |
| 1990/11211/sys/src/9/power/devhs.c:487,492 – 1990/1214/sys/src/9/power/devhs.c:487,493 | ||
| 1990/0312 | qunlock(hp); hp->kstarted = 0; wakeup(&hp->r); | |
| 1990/1214 | poperror(); | |
| 1990/0312 | return; } | |
| 1990/11211/sys/src/9/power/devhs.c:495,501 – 1990/1214/sys/src/9/power/devhs.c:496,501 | ||
| 1990/0312 | */ while ((c = addr->data) != 0xFFFF) { | |
| 1990/0826 | hp->in++; | |
| 1990/0403 |
| |
| 1990/0312 | if(c & CHNO){ c &= 0x1FF; if(hp->chan == c) | |
| 1990/11211/sys/src/9/power/devhs.c:520,525 – 1990/1214/sys/src/9/power/devhs.c:520,526 | ||
| 1990/0312 | upstream(hp, 0); } } | |
| 1990/1214 | USED(locked); | |
| 1990/0312 | qunlock(hp); | |
| 1990/1101 | locked = 0; | |
| 1990/0312 | ||
| 1990/1214/sys/src/9/power/devhs.c:442,448 – 1991/0318/sys/src/9/power/devhs.c:442,448 (short | long) | ||
| 1990/0312 | bp->wptr[1] = hp->chan>>8; bp->wptr[2] = ctl; if(n) | |
| 1991/0318 | memmove(&bp->wptr[3], hp->buf, n); | |
| 1990/0312 | bp->wptr += 3 + n; bp->flags |= S_DELIM; PUTNEXT(hp->rq, bp); | |
| 1991/0318/sys/src/9/power/devhs.c:218,230 – 1991/0411/sys/src/9/power/devhs.c:218,230 (short | long) | ||
| 1990/0227 | } long | |
| 1991/0411 | hsvmeread(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1990/0312 | return streamread(c, buf, n); | |
| 1990/0227 | } long | |
| 1991/0411 | hsvmewrite(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1990/0312 | return streamwrite(c, buf, n, 0); | |
| 1990/0227 | } | |
| 1991/0411/sys/src/9/power/devhs.c:184,189 – 1991/0419/sys/src/9/power/devhs.c:184,195 (short | long) | ||
| 1990/0312 | return devwalk(c, name, 0, 0, streamgen); | |
| 1990/0227 | } | |
| 1991/0419 | Chan* hsvmeclwalk(Chan *c, char *name) { return devclwalk(c, name); } | |
| 1990/0227 | void hsvmestat(Chan *c, char *dp) { | |
| 1991/0419/sys/src/9/power/devhs.c:184,195 – 1991/0427/sys/src/9/power/devhs.c:184,189 (short | long) | ||
| 1990/0312 | return devwalk(c, name, 0, 0, streamgen); | |
| 1990/0227 | } | |
| 1991/0419 |
| |
| 1990/0227 | void hsvmestat(Chan *c, char *dp) { | |
| 1991/0427/sys/src/9/power/devhs.c:45,50 – 1991/0921/sys/src/9/power/devhs.c:45,51 (short | long) | ||
| 1990/0312 | uchar buf[1024]; /* bytes being collected */ uchar *wptr; /* pointer into buf */ int kstarted; /* true if kernel process started */ | |
| 1991/0921 | int started; | |
| 1990/0312 | /* statistics */ | |
| 1991/0427/sys/src/9/power/devhs.c:124,129 – 1991/0921/sys/src/9/power/devhs.c:125,131 | ||
| 1990/0227 | addr->csr = NORESET|IPL(Intlevel)|FORCEW|IENABLE|ALIVE; wbflush(); | |
| 1990/0312 | delay(1); | |
| 1991/0921 | hp->started = 1; | |
| 1990/0227 | } | |
| 1990/0312 | /* | |
| 1991/0427/sys/src/9/power/devhs.c:164,170 – 1991/0921/sys/src/9/power/devhs.c:166,173 | ||
| 1990/0312 | if(i >= Nhsvme) | |
| 1990/11211 | error(Ebadarg); | |
| 1990/0312 | hp = &hsvme[i]; | |
| 1991/0921 | if(!hp->started) hsvmerestart(hp); | |
| 1990/0227 | ||
| 1990/0312 | c = devattach('h', spec); c->dev = i; | |
| 1991/0921/sys/src/9/power/devhs.c:210,215 – 1991/1214/sys/src/9/power/devhs.c:210,216 (short | long) | ||
| 1990/0227 | void hsvmecreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1991/0921/sys/src/9/power/devhs.c:235,240 – 1991/1214/sys/src/9/power/devhs.c:236,242 | ||
| 1990/0227 | void hsvmeremove(Chan *c) { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1991/0921/sys/src/9/power/devhs.c:241,246 – 1991/1214/sys/src/9/power/devhs.c:243,249 | ||
| 1990/0227 | void hsvmewstat(Chan *c, char *dp) { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1991/1214/sys/src/9/power/devhs.c:3,9 – 1992/0111/sys/src/9/power/devhs.c:3,9 (short | long) | ||
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | #include "devtab.h" #include "io.h" | |
| 1992/0111/sys/src/9/power/devhs.c:352,357 – 1992/0117/sys/src/9/power/devhs.c:352,361 (short | long) | ||
| 1990/0312 | * one transmitter at a time */ hp = (Hsvme *)q->ptr; | |
| 1992/0117 | if(waserror()){ qunlock(&hp->xmit); nexterror(); } | |
| 1990/0312 | qlock(&hp->xmit); addr = hp->addr; | |
| 1992/0111/sys/src/9/power/devhs.c:419,424 – 1992/0117/sys/src/9/power/devhs.c:423,429 | ||
| 1990/0312 | addr->data = TXEOD; qunlock(&hp->xmit); | |
| 1992/0117 | poperror(); | |
| 1990/0312 | } /* | |
| 1992/0117/sys/src/9/power/devhs.c:18,23 – 1992/0123/sys/src/9/power/devhs.c:18,25 (short | long) | ||
| 1990/0312 | Nhsvme= 1, | |
| 1990/0227 | }; | |
| 1992/0123 | #define NOW (MACHP(0)->ticks*MS2HZ) | |
| 1990/0312 | /* * hsvme datakit board */ | |
| 1992/0117/sys/src/9/power/devhs.c:44,49 – 1992/0123/sys/src/9/power/devhs.c:46,52 | ||
| 1990/0312 | Queue *rq; /* read queue */ uchar buf[1024]; /* bytes being collected */ uchar *wptr; /* pointer into buf */ | |
| 1992/0123 | ulong time; /* time byte in buf[0] arrived */ | |
| 1990/0312 | int kstarted; /* true if kernel process started */ | |
| 1991/0921 | int started; | |
| 1990/0312 | ||
| 1992/0117/sys/src/9/power/devhs.c:458,463 – 1992/0123/sys/src/9/power/devhs.c:461,467 | ||
| 1990/0312 | bp->flags |= S_DELIM; PUTNEXT(hp->rq, bp); hp->wptr = hp->buf; | |
| 1992/0123 | hp->time = 0; | |
| 1990/0312 | } /* | |
| 1992/0117/sys/src/9/power/devhs.c:526,545 – 1992/0123/sys/src/9/power/devhs.c:530,558 | ||
| 1990/0312 | /* * data byte, put in local buffer */ | |
| 1992/0123 | if(hp->time == 0) hp->time = NOW + 100; | |
| 1990/0312 | *hp->wptr++ = c; if(hp->wptr == &hp->buf[sizeof hp->buf]) upstream(hp, 0); } } | |
| 1992/0123 | if(hp->time && NOW >= hp->time) upstream(hp, 0); | |
| 1990/1214 | USED(locked); | |
| 1990/0312 | qunlock(hp); | |
| 1990/1101 | locked = 0; | |
| 1990/0312 | /* | |
| 1992/0123 | * Sleep if input fifo empty. Make sure we don't hold onto * any byte for more tha 1/10 second. | |
| 1990/0312 | */ | |
| 1992/0123 | if(!(addr->csr & REF)){ if(hp->wptr == hp->buf) sleep(&hp->kr, notempty, addr); else tsleep(&hp->kr, notempty, addr, 100); } | |
| 1990/0312 | } } | |
| 1992/0123/sys/src/9/power/devhs.c:1,5 – 1992/0321/sys/src/9/power/devhs.c:1,5 (short | long) | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0321/sys/src/9/power/devhs.c:8,44 – 1992/0612/sys/src/9/power/devhs.c:8,60 (short | long) | ||
| 1990/0227 | #include "io.h" | |
| 1990/0312 |
| |
| 1992/0612 | typedef struct Hs Hs; | |
| 1990/0312 | ||
| 1990/0227 | enum { | |
| 1990/0312 | Maxburst= 1023, /* maximum transmit burst size */ | |
| 1990/0227 |
| |
| 1992/0612 | Intvec= 0xd0, /* vme vector for interrupts */ | |
| 1990/0227 | Intlevel= 5, /* level to interrupt on */ | |
| 1990/0312 |
| |
| 1990/0227 |
| |
| 1992/0612 | Nhs= 1, | |
| 1990/0227 | ||
| 1992/0123 |
| |
| 1992/0612 | /* * csr flags */ ALIVE = 0x0001, IENABLE = 0x0004, EXOFLOW = 0x0008, IRQ = 0x0010, EMUTE = 0x0020, EPARITY = 0x0040, EFRAME = 0x0080, EROFLOW = 0x0100, REF = 0x0800, XFF = 0x4000, XHF = 0x8000, | |
| 1992/0123 | ||
| 1990/0312 |
| |
| 1992/0612 | /* * csr reset flags */ FORCEW = 0x0008, NORESET = 0xFF00, RESET = 0x0000, /* * data flags */ CTL = 0x0100, CHNO = 0x0200, TXEOD = 0x0400, NND = 0x8000, | |
| 1990/0312 | }; | |
| 1990/0227 | ||
| 1990/0312 |
| |
| 1992/0612 | #define NOW (MACHP(0)->ticks*MS2HZ) #define IPL(x) ((x)<<5) struct Hs { | |
| 1990/0312 | QLock; QLock xmit; | |
| 1992/0612 | HSdev *addr; | |
| 1990/0312 | int vec; /* interupt vector */ Rendez r; /* output process */ Rendez kr; /* input kernel process */ | |
| 1992/0321/sys/src/9/power/devhs.c:59,113 – 1992/0612/sys/src/9/power/devhs.c:75,104 | ||
| 1990/0312 | ulong out; /* bytes out */ }; | |
| 1992/0612 | Hs hs[Nhs]; | |
| 1990/0312 | ||
| 1990/0227 |
| |
| 1992/0612 | static void hsintr(int); static void hskproc(void*); | |
| 1990/0227 |
| |
| 1990/0312 |
| |
| 1990/0227 | ||
| 1990/0312 | /* | |
| 1992/0612 | * hs stream module definition | |
| 1990/0312 | */ | |
| 1990/11151 |
| |
| 1992/0612 | static void hsoput(Queue*, Block*); static void hsstopen(Queue*, Stream*); static void hsstclose(Queue*); Qinfo hsinfo = | |
| 1990/11151 | { nullput, | |
| 1992/0612 | hsoput, hsstopen, hsstclose, "hs" | |
| 1990/11151 | }; | |
| 1990/0312 |
| |
| 1990/0227 | void | |
| 1990/0312 |
| |
| 1992/0612 | hsrestart(Hs *hp) | |
| 1990/0227 | { | |
| 1990/0312 |
| |
| 1992/0612 | HSdev *addr; | |
| 1990/0312 | addr = hp->addr; | |
| 1992/0321/sys/src/9/power/devhs.c:117,123 – 1992/0612/sys/src/9/power/devhs.c:108,114 | ||
| 1990/0227 | /* * set interrupt vector | |
| 1992/0612 | * turn on device | |
| 1990/0227 | * set forcew to a known value * interrupt on level `Intlevel' */ | |
| 1992/0321/sys/src/9/power/devhs.c:135,150 – 1992/0612/sys/src/9/power/devhs.c:126,142 | ||
| 1990/0312 | * reset all vme boards */ | |
| 1990/0227 | void | |
| 1992/0612 | hsreset(void) | |
| 1990/0227 | { | |
| 1990/0312 | int i; | |
| 1992/0612 | Hs *hp; | |
| 1990/0227 | ||
| 1990/0312 |
| |
| 1992/0612 | for(i=0; i<Nhs; i++){ hp = &hs[i]; hp->addr = HSDEV+i; hp->vec = Intvec+i; hp->addr->csr = RESET; setvmevec(hp->vec, hsintr); | |
| 1990/0312 | } | |
| 1990/0227 | wbflush(); | |
| 1990/0312 | delay(20); | |
| 1992/0321/sys/src/9/power/devhs.c:151,157 – 1992/0612/sys/src/9/power/devhs.c:143,149 | ||
| 1990/0227 | } void | |
| 1992/0612 | hsinit(void) | |
| 1990/0227 | { } | |
| 1992/0321/sys/src/9/power/devhs.c:159,176 – 1992/0612/sys/src/9/power/devhs.c:151,168 | ||
| 1990/0312 | * enable the device for interrupts, spec is the device number | |
| 1990/0227 | */ Chan* | |
| 1992/0612 | hsattach(char *spec) | |
| 1990/0227 | { | |
| 1990/0312 |
| |
| 1992/0612 | Hs *hp; | |
| 1990/0312 | int i; Chan *c; | |
| 1990/0227 | ||
| 1990/0312 | i = strtoul(spec, 0, 0); | |
| 1992/0612 | if(i >= Nhs) | |
| 1990/11211 | error(Ebadarg); | |
| 1990/0312 |
| |
| 1992/0612 | hp = &hs[i]; | |
| 1991/0921 | if(!hp->started) | |
| 1992/0612 | hsrestart(hp); | |
| 1990/0227 | ||
| 1990/0312 | c = devattach('h', spec); c->dev = i; | |
| 1992/0321/sys/src/9/power/devhs.c:179,209 – 1992/0612/sys/src/9/power/devhs.c:171,201 | ||
| 1990/0227 | } Chan* | |
| 1992/0612 | hsclone(Chan *c, Chan *nc) | |
| 1990/0227 | { return devclone(c, nc); } int | |
| 1992/0612 | hswalk(Chan *c, char *name) | |
| 1990/0227 | { | |
| 1990/0312 | return devwalk(c, name, 0, 0, streamgen); | |
| 1990/0227 | } void | |
| 1992/0612 | hsstat(Chan *c, char *dp) | |
| 1990/0227 | { | |
| 1990/0312 | devstat(c, dp, 0, 0, streamgen); | |
| 1990/0227 | } Chan* | |
| 1992/0612 | hsopen(Chan *c, int omode) | |
| 1990/0227 | { | |
| 1990/11211 | if(c->qid.path == CHDIR){ | |
| 1990/0312 | if(omode != OREAD) | |
| 1990/11211 | error(Eperm); | |
| 1990/0312 | }else | |
| 1992/0612 | streamopen(c, &hsinfo); | |
| 1990/0227 | c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; | |
| 1992/0321/sys/src/9/power/devhs.c:211,217 – 1992/0612/sys/src/9/power/devhs.c:203,209 | ||
| 1990/0227 | } void | |
| 1992/0612 | hscreate(Chan *c, char *name, int omode, ulong perm) | |
| 1990/0227 | { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1992/0321/sys/src/9/power/devhs.c:218,224 – 1992/0612/sys/src/9/power/devhs.c:210,216 | ||
| 1990/0227 | } void | |
| 1992/0612 | hsclose(Chan *c) | |
| 1990/0227 | { | |
| 1990/11211 | if(c->qid.path != CHDIR) | |
| 1990/0312 | streamclose(c); | |
| 1992/0321/sys/src/9/power/devhs.c:225,243 – 1992/0612/sys/src/9/power/devhs.c:217,235 | ||
| 1990/0227 | } long | |
| 1991/0411 |
| |
| 1992/0612 | hsread(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1990/0312 | return streamread(c, buf, n); | |
| 1990/0227 | } long | |
| 1991/0411 |
| |
| 1992/0612 | hswrite(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1990/0312 | return streamwrite(c, buf, n, 0); | |
| 1990/0227 | } void | |
| 1992/0612 | hsremove(Chan *c) | |
| 1990/0227 | { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1992/0321/sys/src/9/power/devhs.c:244,250 – 1992/0612/sys/src/9/power/devhs.c:236,242 | ||
| 1990/0227 | } void | |
| 1992/0612 | hswstat(Chan *c, char *dp) | |
| 1990/0227 | { | |
| 1991/1214 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1992/0321/sys/src/9/power/devhs.c:258,297 – 1992/0612/sys/src/9/power/devhs.c:250,294 | ||
| 1990/0312 | * create the kernel process for input */ | |
| 1990/0227 | static void | |
| 1990/0312 |
| |
| 1992/0612 | hsstopen(Queue *q, Stream *s) | |
| 1990/0227 | { | |
| 1990/0312 |
| |
| 1992/0612 | Hs *hp; | |
| 1990/0312 | char name[32]; | |
| 1990/0227 | ||
| 1990/0312 |
| |
| 1990/0722 |
| |
| 1992/0612 | hp = &hs[s->dev]; sprint(name, "hs%d", s->dev); | |
| 1990/0312 | q->ptr = q->other->ptr = hp; hp->rq = q; | |
| 1992/0612 | kproc(name, hskproc, hp); | |
| 1990/0312 | } /* | |
| 1992/0612 | * ask kproc to die and wait till it happens | |
| 1990/0312 | */ static int kdead(void *arg) { | |
| 1992/0612 | Hs *hp; | |
| 1990/0312 |
| |
| 1992/0612 | hp = (Hs *)arg; | |
| 1990/0312 | return hp->kstarted == 0; } static void | |
| 1992/0612 | hsstclose(Queue * q) | |
| 1990/0312 | { | |
| 1992/0612 | Hs *hp; | |
| 1990/0312 |
| |
| 1992/0612 | hp = (Hs *)q->ptr; | |
| 1990/0312 | qlock(hp); hp->rq = 0; qunlock(hp); | |
| 1992/0612 | while(waserror()) ; while(hp->kstarted){ wakeup(&hp->kr); sleep(&hp->r, kdead, hp); } poperror(); | |
| 1990/0312 | } /* | |
| 1992/0321/sys/src/9/power/devhs.c:317,325 – 1992/0612/sys/src/9/power/devhs.c:314,322 | ||
| 1990/0312 | static int halfempty(void *arg) { | |
| 1992/0612 | HSdev *addr; | |
| 1990/0312 |
| |
| 1992/0612 | addr = (HSdev*)arg; | |
| 1990/0312 | return addr->csr & XHF; } | |
| 1992/0321/sys/src/9/power/devhs.c:331,340 – 1992/0612/sys/src/9/power/devhs.c:328,337 | ||
| 1990/0312 | * character. */ void | |
| 1992/0612 | hsoput(Queue *q, Block *bp) | |
| 1990/0312 | { | |
| 1992/0612 | HSdev *addr; Hs *hp; | |
| 1990/0312 | int burst; int chan; int ctl; | |
| 1992/0321/sys/src/9/power/devhs.c:354,365 – 1992/0612/sys/src/9/power/devhs.c:351,362 | ||
| 1990/0312 | /* * one transmitter at a time */ | |
| 1992/0612 | hp = (Hs *)q->ptr; qlock(&hp->xmit); | |
| 1992/0117 | if(waserror()){ qunlock(&hp->xmit); nexterror(); } | |
| 1990/0312 |
| |
| 1992/0321/sys/src/9/power/devhs.c:369,374 – 1992/0612/sys/src/9/power/devhs.c:366,372 | ||
| 1990/0312 | if(bp->wptr - bp->rptr < 3){ freemsg(q, bp); qunlock(&hp->xmit); | |
| 1992/0612 | poperror(); | |
| 1990/0312 | return; } | |
| 1990/0315 | chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8); | |
| 1992/0321/sys/src/9/power/devhs.c:435,443 – 1992/0612/sys/src/9/power/devhs.c:433,441 | ||
| 1990/0312 | static int notempty(void *arg) { | |
| 1992/0612 | HSdev *addr; | |
| 1990/0312 |
| |
| 1992/0612 | addr = (HSdev *)arg; | |
| 1990/0312 | return addr->csr & REF; } | |
| 1992/0321/sys/src/9/power/devhs.c:445,451 – 1992/0612/sys/src/9/power/devhs.c:443,449 | ||
| 1990/0312 | * fill a block with what is currently buffered and send it upstream */ static void | |
| 1992/0612 | upstream(Hs *hp, unsigned int ctl) | |
| 1990/0312 | { int n; Block *bp; | |
| 1992/0321/sys/src/9/power/devhs.c:470,483 – 1992/0612/sys/src/9/power/devhs.c:468,481 | ||
| 1990/0312 | * fifo fill up. */ static void | |
| 1992/0612 | hskproc(void *arg) | |
| 1990/0312 | { | |
| 1992/0612 | Hs *hp; HSdev *addr; | |
| 1990/0312 | unsigned int c; | |
| 1990/1101 | int locked; | |
| 1990/0312 |
| |
| 1992/0612 | hp = (Hs *)arg; | |
| 1990/0312 | addr = hp->addr; hp->kstarted = 1; hp->wptr = hp->buf; | |
| 1992/0321/sys/src/9/power/devhs.c:509,515 – 1992/0612/sys/src/9/power/devhs.c:507,513 | ||
| 1990/0312 | /* * 0xFFFF means an empty fifo */ | |
| 1992/0612 | while((c = addr->data) != 0xFFFF){ | |
| 1990/0826 | hp->in++; | |
| 1990/0312 | if(c & CHNO){ c &= 0x1FF; | |
| 1992/0321/sys/src/9/power/devhs.c:561,591 – 1992/0612/sys/src/9/power/devhs.c:559,589 | ||
| 1990/0312 | * and not empty bits to figure out whom to wake. */ static void | |
| 1992/0612 | hsintr(int vec) | |
| 1990/0312 | { ushort csr; | |
| 1992/0612 | HSdev *addr; Hs *hp; | |
| 1990/0312 |
| |
| 1992/0612 | hp = &hs[vec - Intvec]; if(hp < hs || hp > &hs[Nhs]){ print("bad hs vec\n"); | |
| 1990/0312 | return; } csr = hp->addr->csr; | |
| 1992/0612 | if(csr & REF){ | |
| 1990/0312 | hp->rintr++; wakeup(&hp->kr); } | |
| 1992/0612 | if(csr & XHF){ | |
| 1990/0312 | hp->tintr++; wakeup(&hp->r); } | |
| 1992/0612 | if((csr^XFF) & (XFF|EROFLOW|EFRAME|EPARITY|EXOFLOW)){ | |
| 1990/0312 | hp->parity++; | |
| 1990/0930 |
| |
| 1992/0612 | hsrestart(hp); print("hs %d: reset, csr = 0x%ux\n", vec - Intvec, csr); | |
| 1990/0312 | } | |
| 1990/0227 | } | |
| 1992/0612/sys/src/9/power/devhs.c:341,346 – 1992/0623/sys/src/9/power/devhs.c:341,353 (short | long) | ||
| 1990/0312 | freeb(bp); return; } | |
| 1992/0623 | if(BLEN(bp) < 3){ bp = pullup(bp, 3); if(bp == 0){ print("hsoput pullup failed\n"); return; } } | |
| 1990/0312 | /* * get a whole message before handing bytes to the device | |
| 1992/0612/sys/src/9/power/devhs.c:363,374 – 1992/0623/sys/src/9/power/devhs.c:370,375 | ||
| 1990/0312 | * parse message */ bp = getq(q); | |
| 1992/0612 |
| |
| 1990/0312 |
| |
| 1990/0315 | chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8); ctl = bp->rptr[2]; bp->rptr += 3; | |
| 1992/0623/sys/src/9/power/devhs.c:544,554 – 1992/0703/sys/src/9/power/devhs.c:544,554 (short | long) | ||
| 1990/0312 | /* | |
| 1992/0123 | * Sleep if input fifo empty. Make sure we don't hold onto | |
| 1992/0703 | * any byte for more than 1/10 second. | |
| 1990/0312 | */ | |
| 1992/0123 | if(!(addr->csr & REF)){ if(hp->wptr == hp->buf) | |
| 1992/0703 | tsleep(&hp->kr, notempty, addr, 2000); | |
| 1992/0123 | else tsleep(&hp->kr, notempty, addr, 100); } | |
| 1992/0703/sys/src/9/power/devhs.c:206,211 – 1992/0711/sys/src/9/power/devhs.c:206,214 (short | long) | ||
| 1992/0612 | hscreate(Chan *c, char *name, int omode, ulong perm) | |
| 1990/0227 | { | |
| 1991/1214 | USED(c); | |
| 1992/0711 | USED(name); USED(omode); USED(perm); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1992/0703/sys/src/9/power/devhs.c:219,224 – 1992/0711/sys/src/9/power/devhs.c:222,228 | ||
| 1990/0227 | long | |
| 1992/0612 | hsread(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1992/0711 | USED(offset); | |
| 1990/0312 | return streamread(c, buf, n); | |
| 1990/0227 | } | |
| 1992/0703/sys/src/9/power/devhs.c:225,230 – 1992/0711/sys/src/9/power/devhs.c:229,235 | ||
| 1990/0227 | long | |
| 1992/0612 | hswrite(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1992/0711 | USED(offset); | |
| 1990/0312 | return streamwrite(c, buf, n, 0); | |
| 1990/0227 | } | |
| 1992/0703/sys/src/9/power/devhs.c:239,244 – 1992/0711/sys/src/9/power/devhs.c:244,250 | ||
| 1992/0612 | hswstat(Chan *c, char *dp) | |
| 1990/0227 | { | |
| 1991/1214 | USED(c); | |
| 1992/0711 | USED(dp); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } | |
| 1992/0703/sys/src/9/power/devhs.c:563,569 – 1992/0711/sys/src/9/power/devhs.c:569,574 | ||
| 1992/0612 | hsintr(int vec) | |
| 1990/0312 | { ushort csr; | |
| 1992/0612 |
| |
| 1990/0312 | ||
| 1992/0612 | hp = &hs[vec - Intvec]; | |
| Too many diffs (26 > 25). Stopping. | ||