~kris/9p

9hist

9fe2b517e9769fa149754efe5fddee414ea24bf5 — David du Colombier 26 years ago 28ad387
Plan 9 from Bell Labs 2000-05-16
M mpc/clock.c => mpc/clock.c +48 -0
@@ 67,6 67,41 @@ enum {

static	ulong	clkreload;

#ifdef XXX
ulong
millisec(void)
{
	ulong tbu, tbl, x;
	vlong t;

	do {
		tbu = gettbu();
		tbl = gettbl();
	} while (gettbu() != tbu);
	t = (((vlong)tbu)<<32) + tbl;

	t <<= 4;
	t /= m->oscclk * 1000;

	x = t;
	if((long)(ledtime-x) < 0)
		powerdownled();

	return (ulong)t;
}

#endif
ulong
millisec(void)
{
	ulong tbl, x;

	tbl = gettbl();
	x = tbl/((m->oscclk * 1000)/16);

	return x;
}

void
delayloopinit(void)
{


@@ 118,6 153,13 @@ clockintr(Ureg *ur)
	m->iomem->swsr = 0xaa39;
	
	m->ticks++;

	if((m->iomem->pddat & SIBIT(15)) == 0) {
		print("button pressed\n");
		delay(200);
		reset();
	}

	if(m->proc)
		m->proc->pc = ur->pc;



@@ 134,6 176,12 @@ clockintr(Ureg *ur)
		unlock(&clock0lock);
	}

	if(m->flushmmu){
		if(up)
			flushmmu();
		m->flushmmu = 0;
	}

	if(up == 0 || up->state != Running)
		return;


A mpc/cmmu.c => mpc/cmmu.c +391 -0
@@ 0,0 1,391 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

/*
 *  tlb entry 0 is used only by mmuswitch() to set the current tlb pid.
 */

/*
 *  Kmap entries start at tlb index 1 and work their way up until
 *  kmapinval() removes them.  They then restart at 1.  As long as there
 *  are few kmap entries they will not pass TLBROFF (the WIRED tlb entry
 *  limit) and interfere with user tlb entries.
 */

/*
 *  All invalidations of the tlb are via indexed entries.  The virtual
 *  address used is always 'KZERO | (x<<(PGSHIFT+1) | currentpid' where
 *  'x' is the index into the tlb.  This ensures that the current pid doesn't
 *  change and that no two invalidated entries have matching virtual
 *  addresses just in case SGI/MIPS ever makes a chip that cares (as
 *  they keep threatening).  These entries should never be used in
 *  lookups since accesses to KZERO addresses don't go through the tlb.
 */

#define TLBINVAL(x, pid) puttlbx(x, KZERO|((x)<<(PGSHIFT+1))|(pid), 0, 0, PGSZ4K)

void
tlbinit(void)
{
	int i;

	for(i=0; i<NTLB; i++)
		TLBINVAL(i, 0);
}

Lock	kmaplock;
KMap	kpte[KPTESIZE];
KMap*	kmapfree;

void
kmapinit(void)
{
	KMap *k, *klast;

	kmapfree = kpte;
	klast = &kpte[KPTESIZE-1];
	for(k=kpte; k<klast; k++)
		k->next = k+1;
	k->next = 0;

	m->ktlbnext = TLBROFF;
}

/*
 *  Arrange that the KMap'd virtual address will hit the same
 *  primary cache line as pg->va by making bits 14...12 of the
 *  tag the same as virtual address.  These bits are the index
 *  into the primary cache and are checked whenever accessing
 *  the secondary cache through the primary.  Violation causes
 *  a VCE trap.
 */
KMap *
kmap(Page *pg)
{
	int s;
	KMap *k;
	ulong pte;
	ulong x, virt;

	s = splhi();
	lock(&kmaplock);

	if(kmapfree == 0) {
		unlock(&kmaplock);
		kmapinval();		/* try and free some */
		lock(&kmaplock);
		if(kmapfree == 0)
			panic("out of kmap");
	}

	k = kmapfree;
	kmapfree = k->next;

	k->pg = pg;
	/* One for the allocation,
	 * One for kactive
	 */
	k->ref = 2;
	k->konmach[m->machno] = m->kactive;
	m->kactive = k;

	virt = pg->va;
	/* bits 14..12 form the secondary-cache virtual index */
	virt &= PIDX;	
	virt |= KMAPADDR | ((k-kpte)<<KMAPSHIFT);

	k->virt = virt;
	pte = PPN(pg->pa)|PTECOHERXCLW|PTEGLOBL|PTEWRITE|PTEVALID;
	if(virt & BY2PG) {
		k->phys0 = PTEGLOBL|PTECOHERXCLW;
		k->phys1 = pte;
	}
	else {
		k->phys0 = pte;
		k->phys1 = PTEGLOBL|PTECOHERXCLW;
	}

	x = m->ktlbnext;
	k->tlbi[m->machno] = x;
	puttlbx(x, (virt&~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	if(++x >= NTLB)
		m->ktlbnext = TLBROFF;
	else
		m->ktlbnext = x;

	unlock(&kmaplock);

	splx(s);
	return k;
}

void
kunmap(KMap *k)
{
	int s;

	s = splhi();
	if(decref(k) == 0) {
		k->virt = 0;
		k->phys0 = 0;
		k->phys1 = 0;
		k->pg = 0;

		lock(&kmaplock);
		k->next = kmapfree;
		kmapfree = k;
		unlock(&kmaplock);
	}
	splx(s);
}

void
kfault(Ureg *ur)
{
	int mno;
	KMap *k, *f;
	ulong x, index, virt, addr;

	mno = m->machno;
	addr = ur->badvaddr;
	index = (addr & ~KMAPADDR) >> KMAPSHIFT;

	if(index >= KPTESIZE)
		panic("kmapfault: %lux", addr);

	k = &kpte[index];
	if(k->virt == 0 || k->ref < 1)
		panic("kmapfault: unmapped %lux", addr);

	for(f = m->kactive; f; f = f->konmach[mno])
		if(f == k)
			break;

	if(f == 0) {
		incref(k);
		k->konmach[mno] = m->kactive;
		m->kactive = k;
	}

	x = m->ktlbnext;
	virt = (k->virt&~BY2PG)|TLBPID(tlbvirt());
	puttlbx(x, virt, k->phys0, k->phys1, PGSZ4K);
	k->tlbi[mno] = x;

	if(++x >= NTLB)
		m->ktlbnext = TLBROFF;
	else
		m->ktlbnext = x;
}

void
kmapinval()
{
	int mno, curpid;
	KMap *k, *next;

	if(m->kactive == 0)
		return;

	curpid = PTEPID(TLBPID(tlbvirt()));
	mno = m->machno;
	for(k = m->kactive; k; k = next) {
		next = k->konmach[mno];
		TLBINVAL(k->tlbi[mno], curpid);
		kunmap(k);
	}
	m->kactive = 0;
}

void
mmuswitch(Proc *p)
{
	int tp;

	if(p->newtlb) {
		memset(p->pidonmach, 0, sizeof p->pidonmach);
		p->newtlb = 0;
	}
	tp = p->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(p);

	puttlbx(0, KZERO|PTEPID(tp), 0, 0, PGSZ4K);
}

void
mmurelease(Proc *p)
{
	memset(p->pidonmach, 0, sizeof p->pidonmach);
}

/*
 * Process must be splhi
 */
int
newtlbpid(Proc *p)
{
	int i, s;
	Proc **h;

	i = m->lastpid;
	h = m->pidproc;
	for(s = 0; s < NTLBPID; s++) {
		i++;
		if(i >= NTLBPID)
			i = 1;
		if(h[i] == 0)
			break;
	}

	if(h[i])
		purgetlb(i);
	if(h[i] != 0)
		panic("newtlb");

	m->pidproc[i] = p;
	p->pidonmach[m->machno] = i;
	m->lastpid = i;

	return i;
}

void
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
{
	int s;
	short tp;
	char *ctl;
	Softtlb *entry;

	s = splhi();
	tp = up->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(up);

	/*
	 * Fix up EISA memory address which are greater
	 * than 32 bits physical: 0x100000000
	 */
	if((tlbphys&0xffff0000) == PPN(Eisamphys)) {
		tlbphys &= ~PPN(Eisamphys);
		tlbphys |= 0x04000000;
	}
	tlbvirt |= PTEPID(tp);
	if((tlbphys & PTEALGMASK) != PTEUNCACHED) {
		tlbphys &= ~PTEALGMASK;
		tlbphys |= PTECOHERXCLW;
	}

	entry = putstlb(tlbvirt, tlbphys);
	puttlb(entry->virt, entry->phys0, entry->phys1);

	ctl = &pg->cachectl[m->machno];
	switch(*ctl) {
	case PG_TXTFLUSH:
		icflush((void*)pg->va, BY2PG);
		*ctl = PG_NOFLUSH;
		break;
	case PG_DATFLUSH:
		dcflush((void*)pg->va, BY2PG);
		*ctl = PG_NOFLUSH;
		break;
	case PG_NEWCOL:
		cleancache();		/* Too expensive */
		*ctl = PG_NOFLUSH;
		break;
	}
	splx(s);
}

void
purgetlb(int pid)
{
	int i, mno;
	Proc *sp, **pidproc;
	Softtlb *entry, *etab;

	m->tlbpurge++;

	/*
	 * find all pid entries that are no longer used by processes
	 */
	mno = m->machno;
	pidproc = m->pidproc;
	for(i=1; i<NTLBPID; i++) {
		sp = pidproc[i];
		if(sp && sp->pidonmach[mno] != i)
			pidproc[i] = 0;
	}

	/*
	 * shoot down the one we want
	 */
	sp = pidproc[pid];
	if(sp != 0)
		sp->pidonmach[mno] = 0;
	pidproc[pid] = 0;

	/*
	 * clean out all dead pids from the stlb;
	 */
	entry = m->stb;
	for(etab = &entry[STLBSIZE]; entry < etab; entry++)
		if(pidproc[TLBPID(entry->virt)] == 0)
			entry->virt = 0;

	/*
	 * clean up the hardware
	 */
	for(i=TLBROFF; i<NTLB; i++)
		if(pidproc[TLBPID(gettlbvirt(i))] == 0)
			TLBINVAL(i, pid);
}

void
flushmmu(void)
{
	int s;

	s = splhi();
	up->newtlb = 1;
	mmuswitch(up);
	splx(s);
}

void
clearmmucache(void)
{
}

Softtlb*
putstlb(ulong tlbvirt, ulong tlbphys)
{
	int k;
	Softtlb *entry;

	k = tlbvirt & BY2PG;
	tlbvirt &= ~BY2PG;

	entry = &m->stb[(tlbvirt ^ (tlbvirt>>13)) & (STLBSIZE-1)];
	if(entry->virt != tlbvirt) {
		entry->virt = tlbvirt;
		entry->phys0 = 0;
		entry->phys1 = 0;
	}

	if(k)
		entry->phys1 = tlbphys;
	else
		entry->phys0 = tlbphys;

	if(entry->phys0 == 0 && entry->phys1 == 0)
		entry->virt = 0;

	return entry;
}

A mpc/conf.c => mpc/conf.c +74 -0
@@ 0,0 1,74 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"init.h"

char*
getconf(char *name)
{
	char **p;
	int n;

	n = strlen(name);

	for(p = conf; *p; p++) {
		if(strncmp(*p, name, n) == 0 && (*p)[n] == '=')
			return *p+n+1;
	}
	return 0;
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	char cc[NAMELEN], *p, *q, *r;

	strcpy(cc, class);
	p = cc + strlen(cc);
	*p++ = ctlrno + '0';
	*p = 0;

	p = getconf(cc);
	if(p == 0)
		return 0;

	while(*p){
		while(*p == ' ' || *p == '\t')
			p++;
		if(*p == '\0')
			break;
		if(strncmp(p, "type=", 5) == 0){
			p += 5;
			for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
				if(*p == '\0' || *p == ' ' || *p == '\t')
					break;
				*q = *p++;
			}
			*q = '\0';
		}
		else if(strncmp(p, "port=", 5) == 0)
			isa->port = strtoul(p+5, &p, 0);
		else if(strncmp(p, "irq=", 4) == 0)
			isa->irq = strtoul(p+4, &p, 0);
		else if(strncmp(p, "mem=", 4) == 0)
			isa->mem = strtoul(p+4, &p, 0);
		else if(strncmp(p, "size=", 5) == 0)
			isa->size = strtoul(p+5, &p, 0);
		else if(isa->nopt < NISAOPT){
			r = isa->opt[isa->nopt];
			while(*p && *p != ' ' && *p != '\t'){
				*r++ = *p++;
				if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
					break;
			}
			*r = '\0';
			isa->nopt++;
		}
		while(*p && *p != ' ' && *p != '\t')
			p++;
	}
	return 1;
}

M mpc/cpm.c => mpc/cpm.c +152 -149
@@ 365,11 365,11 @@ cpmparam(ulong olda, int nb)
	if(olda < INTMEM)
		olda += INTMEM;
	if(olda != SPIP && olda != I2CP)
		return KADDR(olda);
		return (void*)(olda);
	p = cpmalloc(nb, 32);	/* ``RPBASE must be multiple of 32'' */
	if(p == nil)
		return p;
	*(ushort*)KADDR(olda+0x2C) = PADDR(p);	/* set RPBASE */
	*(ushort*)(olda+0x2C) = PADDR(p);	/* set RPBASE */
	eieio();
	return p;
}


@@ 382,159 382,161 @@ cpmparam(ulong olda, int nb)
 *	May 1998
 */

/*S00600004844521B*/
static	ulong	ubase1 = 0x2000;

static	ulong	ucode1[] = {
 /* #02202000 */ 0x7FFFEFD9,
 /* #02202004 */ 0x3FFD0000,
 /* #02202008 */ 0x7FFB49F7,
 /* #0220200C */ 0x7FF90000,
 /* #02202010 */ 0x5FEFADF7,
 /* #02202014 */ 0x5F89ADF7,
 /* #02202018 */ 0x5FEFAFF7,
 /* #0220201C */ 0x5F89AFF7,
 /* #02202020 */ 0x3A9CFBC8,
 /* #02202024 */ 0xE7C0EDF0,
 /* #02202028 */ 0x77C1E1BB,
 /* #0220202C */ 0xF4DC7F1D,
 /* #02202030 */ 0xABAD932F,
 /* #02202034 */ 0x4E08FDCF,
 /* #02202038 */ 0x6E0FAFF8,
 /* #0220203C */ 0x7CCF76CF,
 /* #02202040 */ 0xFD1FF9CF,
 /* #02202044 */ 0xABF88DC6,
 /* #02202048 */ 0xAB5679F7,
 /* #0220204C */ 0xB0937383,
 /* #02202050 */ 0xDFCE79F7,
 /* #02202054 */ 0xB091E6BB,
 /* #02202058 */ 0xE5BBE74F,
 /* #0220205C */ 0xB3FA6F0F,
 /* #02202060 */ 0x6FFB76CE,
 /* #02202064 */ 0xEE0DF9CF,
 /* #02202068 */ 0x2BFBEFEF,
 /* #0220206C */ 0xCFEEF9CF,
 /* #02202070 */ 0x76CEAD24,
 /* #02202074 */ 0x90B2DF9A,
 /* #02202078 */ 0x7FDDD0BF,
 /* #0220207C */ 0x4BF847FD,
 /* #02202080 */ 0x7CCF76CE,
 /* #02202084 */ 0xCFEF7E1F,
 /* #02202088 */ 0x7F1D7DFD,
 /* #0220208C */ 0xF0B6EF71,
 /* #02202090 */ 0x7FC177C1,
 /* #02202094 */ 0xFBC86079,
 /* #02202098 */ 0xE722FBC8,
 /* #0220209C */ 0x5FFFDFFF,
 /* #022020A0 */ 0x5FB2FFFB,
 /* #022020A4 */ 0xFBC8F3C8,
 /* #022020A8 */ 0x94A67F01,
 /* #022020AC */ 0x7F1D5F39,
 /* #022020B0 */ 0xAFE85F5E,
 /* #022020B4 */ 0xFFDFDF96,
 /* #022020B8 */ 0xCB9FAF7D,
 /* #022020BC */ 0x5FC1AFED,
 /* #022020C0 */ 0x8C1C5FC1,
 /* #022020C4 */ 0xAFDD5FC3,
 /* #022020C8 */ 0xDF9A7EFD,
 /* #022020CC */ 0xB0B25FB2,
 /* #022020D0 */ 0xFFFEABAD,
 /* #022020D4 */ 0x5FB2FFFE,
 /* #022020D8 */ 0x5FCE600B,
 /* #022020DC */ 0xE6BB600B,
 /* #022020E0 */ 0x5FCEDFC6,
 /* #022020E4 */ 0x27FBEFDF,
 /* #022020E8 */ 0x5FC8CFDE,
 /* #022020EC */ 0x3A9CE7C0,
 /* #022020F0 */ 0xEDF0F3C8,
 /* #022020F4 */ 0x7F0154CD,
 /* #022020F8 */ 0x7F1D2D3D,
 /* #022020FC */ 0x363A7570,
 /* #02202100 */ 0x7E0AF1CE,
 /* #02202104 */ 0x37EF2E68,
 /* #02202108 */ 0x7FEE10EC,
 /* #0220210C */ 0xADF8EFDE,
 /* #02202110 */ 0xCFEAE52F,
 /* #02202114 */ 0x7D0FE12B,
 /* #02202118 */ 0xF1CE5F65,
 /* #0220211C */ 0x7E0A4DF8,
 /* #02202120 */ 0xCFEA5F72,
 /* #02202124 */ 0x7D0BEFEE,
 /* #02202128 */ 0xCFEA5F74,
 /* #0220212C */ 0xE522EFDE,
 /* #02202130 */ 0x5F74CFDA,
 /* #02202134 */ 0x0B627385,
 /* #02202138 */ 0xDF627E0A,
 /* #0220213C */ 0x30D8145B,
 /* #02202140 */ 0xBFFFF3C8,
 /* #02202144 */ 0x5FFFDFFF,
 /* #02202148 */ 0xA7F85F5E,
 /* #0220214C */ 0xBFFE7F7D,
 /* #02202150 */ 0x10D31450,
 /* #02202154 */ 0x5F36BFFF,
 /* #02202158 */ 0xAF785F5E,
 /* #0220215C */ 0xBFFDA7F8,
 /* #02202160 */ 0x5F36BFFE,
 /* #02202164 */ 0x77FD30C0,
 /* #02202168 */ 0x4E08FDCF,
 /* #0220216C */ 0xE5FF6E0F,
 /* #02202170 */ 0xAFF87E1F,
 /* #02202174 */ 0x7E0FFD1F,
 /* #02202178 */ 0xF1CF5F1B,
 /* #0220217C */ 0xABF80D5E,
 /* #02202180 */ 0x5F5EFFEF,
 /* #02202184 */ 0x79F730A2,
 /* #02202188 */ 0xAFDD5F34,
 /* #0220218C */ 0x47F85F34,
 /* #02202190 */ 0xAFED7FDD,
 /* #02202194 */ 0x50B24978,
 /* #02202198 */ 0x47FD7F1D,
 /* #0220219C */ 0x7DFD70AD,
 /* #022021A0 */ 0xEF717EC1,
 /* #022021A4 */ 0x6BA47F01,
 /* #022021A8 */ 0x2D267EFD,
 /* #022021AC */ 0x30DE5F5E,
 /* #022021B0 */ 0xFFFD5F5E,
 /* #022021B4 */ 0xFFEF5F5E,
 /* #022021B8 */ 0xFFDF0CA0,
 /* #022021BC */ 0xAFED0A9E,
 /* #022021C0 */ 0xAFDD0C3A,
 /* #022021C4 */ 0x5F3AAFBD,
 /* #022021C8 */ 0x7FBDB082,
 /* #022021CC */ 0x5F8247F8,
/*S30902202000*/ 0x7FFFEFD9,
/*S30902202004*/ 0x3FFD0000,
/*S30902202008*/ 0x7FFB49F7,
/*S3090220200C*/ 0x7FF90000,
/*S30902202010*/ 0x5FEFADF7,
/*S30902202014*/ 0x5F88ADF7,
/*S30902202018*/ 0x5FEFAFF7,
/*S3090220201C*/ 0x5F88AFF7,
/*S30902202020*/ 0x3A9CFBC8,
/*S30902202024*/ 0x77CAE1BB,
/*S30902202028*/ 0xF4DE7FAD,
/*S3090220202C*/ 0xABAE9330,
/*S30902202030*/ 0x4E08FDCF,
/*S30902202034*/ 0x6E0FAFF8,
/*S30902202038*/ 0x7CCF76CF,
/*S3090220203C*/ 0xFDAFF9CF,
/*S30902202040*/ 0xABF88DC8,
/*S30902202044*/ 0xAB5879F7,
/*S30902202048*/ 0xB0926A27,
/*S3090220204C*/ 0xDFD079F7,
/*S30902202050*/ 0xB090E6BB,
/*S30902202054*/ 0xE5BBE74F,
/*S30902202058*/ 0xAA616F0F,
/*S3090220205C*/ 0x6FFB76CE,
/*S30902202060*/ 0xEE0CF9CF,
/*S30902202064*/ 0x2BFBEFEF,
/*S30902202068*/ 0xCFEEF9CF,
/*S3090220206C*/ 0x76CEAD23,
/*S30902202070*/ 0x90B3DF99,
/*S30902202074*/ 0x7FDDD0C1,
/*S30902202078*/ 0x4BF847FD,
/*S3090220207C*/ 0x7CCF76CE,
/*S30902202080*/ 0xCFEF77CA,
/*S30902202084*/ 0x7EAF7FAD,
/*S30902202088*/ 0x7DFDF0B7,
/*S3090220208C*/ 0xEF7A7FCA,
/*S30902202090*/ 0x77CAFBC8,
/*S30902202094*/ 0x6079E722,
/*S30902202098*/ 0xFBC85FFF,
/*S3090220209C*/ 0xDFFF5FB3,
/*S309022020A0*/ 0xFFFBFBC8,
/*S309022020A4*/ 0xF3C894A5,
/*S309022020A8*/ 0xE7C9EDF9,
/*S309022020AC*/ 0x7F9A7FAD,
/*S309022020B0*/ 0x5F36AFE8,
/*S309022020B4*/ 0x5F5BFFDF,
/*S309022020B8*/ 0xDF95CB9E,
/*S309022020BC*/ 0xAF7D5FC3,
/*S309022020C0*/ 0xAFED8C1B,
/*S309022020C4*/ 0x5FC3AFDD,
/*S309022020C8*/ 0x5FC5DF99,
/*S309022020CC*/ 0x7EFDB0B3,
/*S309022020D0*/ 0x5FB3FFFE,
/*S309022020D4*/ 0xABAE5FB3,
/*S309022020D8*/ 0xFFFE5FD0,
/*S309022020DC*/ 0x600BE6BB,
/*S309022020E0*/ 0x600B5FD0,
/*S309022020E4*/ 0xDFC827FB,
/*S309022020E8*/ 0xEFDF5FCA,
/*S309022020EC*/ 0xCFDE3A9C,
/*S309022020F0*/ 0xE7C9EDF9,
/*S309022020F4*/ 0xF3C87F9E,
/*S309022020F8*/ 0x54CA7FED,
/*S309022020FC*/ 0x2D3A3637,
/*S30902202100*/ 0x756F7E9A,
/*S30902202104*/ 0xF1CE37EF,
/*S30902202108*/ 0x2E677FEE,
/*S3090220210C*/ 0x10EBADF8,
/*S30902202110*/ 0xEFDECFEA,
/*S30902202114*/ 0xE52F7D9F,
/*S30902202118*/ 0xE12BF1CE,
/*S3090220211C*/ 0x5F647E9A,
/*S30902202120*/ 0x4DF8CFEA,
/*S30902202124*/ 0x5F717D9B,
/*S30902202128*/ 0xEFEECFEA,
/*S3090220212C*/ 0x5F73E522,
/*S30902202130*/ 0xEFDE5F73,
/*S30902202134*/ 0xCFDA0B61,
/*S30902202138*/ 0x6A29DF61,
/*S3090220213C*/ 0xE7C9EDF9,
/*S30902202140*/ 0x7E9A30D5,
/*S30902202144*/ 0x1458BFFF,
/*S30902202148*/ 0xF3C85FFF,
/*S3090220214C*/ 0xDFFFA7F8,
/*S30902202150*/ 0x5F5BBFFE,
/*S30902202154*/ 0x7F7D10D0,
/*S30902202158*/ 0x144D5F33,
/*S3090220215C*/ 0xBFFFAF78,
/*S30902202160*/ 0x5F5BBFFD,
/*S30902202164*/ 0xA7F85F33,
/*S30902202168*/ 0xBFFE77FD,
/*S3090220216C*/ 0x30BD4E08,
/*S30902202170*/ 0xFDCFE5FF,
/*S30902202174*/ 0x6E0FAFF8,
/*S30902202178*/ 0x7EEF7E9F,
/*S3090220217C*/ 0xFDEFF1CF,
/*S30902202180*/ 0x5F17ABF8,
/*S30902202184*/ 0x0D5B5F5B,
/*S30902202188*/ 0xFFEF79F7,
/*S3090220218C*/ 0x309EAFDD,
/*S30902202190*/ 0x5F3147F8,
/*S30902202194*/ 0x5F31AFED,
/*S30902202198*/ 0x7FDD50AF,
/*S3090220219C*/ 0x497847FD,
/*S309022021A0*/ 0x7F9E7FED,
/*S309022021A4*/ 0x7DFD70A9,
/*S309022021A8*/ 0xEF7E7ECE,
/*S309022021AC*/ 0x6BA07F9E,
/*S309022021B0*/ 0x2D227EFD,
/*S309022021B4*/ 0x30DB5F5B,
/*S309022021B8*/ 0xFFFD5F5B,
/*S309022021BC*/ 0xFFEF5F5B,
/*S309022021C0*/ 0xFFDF0C9C,
/*S309022021C4*/ 0xAFED0A9A,
/*S309022021C8*/ 0xAFDD0C37,
/*S309022021CC*/ 0x5F37AFBD,
/*S309022021D0*/ 0x7FBDB081,
/*S309022021D4*/ 0x5F8147F8,
};

/*S00600004844521B*/
static	ulong	ubase2 = 0x2F00;
static	ulong	ucode2[] = {
 /* #02202F00 */ 0x3E303430,
 /* #02202F04 */ 0x34343737,
 /* #02202F08 */ 0xABF7BF9B,
 /* #02202F0C */ 0x994B4FBD,
 /* #02202F10 */ 0xBD599493,
 /* #02202F14 */ 0x349FFF37,
 /* #02202F18 */ 0xFB9B177D,
 /* #02202F1C */ 0xD9936956,
 /* #02202F20 */ 0xBBFDD697,
 /* #02202F24 */ 0xBDD2FD11,
 /* #02202F28 */ 0x31DB9BB3,
 /* #02202F2C */ 0x63139637,
 /* #02202F30 */ 0x93733693,
 /* #02202F34 */ 0x193137F7,
 /* #02202F38 */ 0x331737AF,
 /* #02202F3C */ 0x7BB9B999,
 /* #02202F40 */ 0xBB197957,
 /* #02202F44 */ 0x7FDFD3D5,
 /* #02202F48 */ 0x73B773F7,
 /* #02202F4C */ 0x37933B99,
 /* #02202F50 */ 0x1D115316,
 /* #02202F54 */ 0x99315315,
 /* #02202F58 */ 0x31694BF4,
 /* #02202F5C */ 0xFBDBD359,
 /* #02202F60 */ 0x31497353,
 /* #02202F64 */ 0x76956D69,
 /* #02202F68 */ 0x7B9D9693,
 /* #02202F6C */ 0x13131979,
 /* #02202F70 */ 0x79376935,
/*S30902202F00*/ 0x3E303430,
/*S30902202F04*/ 0x34343737,
/*S30902202F08*/ 0xABBF9B99,
/*S30902202F0C*/ 0x4B4FBDBD,
/*S30902202F10*/ 0x59949334,
/*S30902202F14*/ 0x9FFF37FB,
/*S30902202F18*/ 0x9B177DD9,
/*S30902202F1C*/ 0x936956BB,
/*S30902202F20*/ 0xFBDD697B,
/*S30902202F24*/ 0xDD2FD113,
/*S30902202F28*/ 0x1DB9F7BB,
/*S30902202F2C*/ 0x36313963,
/*S30902202F30*/ 0x79373369,
/*S30902202F34*/ 0x3193137F,
/*S30902202F38*/ 0x7331737A,
/*S30902202F3C*/ 0xF7BB9B99,
/*S30902202F40*/ 0x9BB19795,
/*S30902202F44*/ 0x77FDFD3D,
/*S30902202F48*/ 0x573B773F,
/*S30902202F4C*/ 0x737933F7,
/*S30902202F50*/ 0xB991D115,
/*S30902202F54*/ 0x31699315,
/*S30902202F58*/ 0x31531694,
/*S30902202F5C*/ 0xBF4FBDBD,
/*S30902202F60*/ 0x35931497,
/*S30902202F64*/ 0x35376956,
/*S30902202F68*/ 0xBD697B9D,
/*S30902202F6C*/ 0x96931313,
/*S30902202F70*/ 0x19797937,
/*S30902202F74*/ 0x69350000,
};

/*


@@ 554,6 556,7 @@ i2cspireloc(void)
	io->rccr &= ~3;
	memmove((uchar*)m->iomem+ubase1, ucode1, sizeof(ucode1));
	memmove((uchar*)m->iomem+ubase2, ucode2, sizeof(ucode2));

	io->rctr1 = 0x802a;	/* relocate SPI */
	io->rctr2 = 0x8028;	/* relocate SPI */
	io->rctr3 = 0x802e;	/* relocate I2C */

A mpc/cpm2.c => mpc/cpm2.c +819 -0
@@ 0,0 1,819 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

enum {
	BDSIZE=	1024,	/* IO memory reserved for buffer descriptors */
	CPMSIZE=	1024,	/* IO memory reserved for other uses */
};

static	Map	bdmapv[BDSIZE/sizeof(BD)];
static	RMap	bdmap = {"buffer descriptors"};

static	Map	cpmmapv[CPMSIZE/sizeof(ulong)];
static	RMap	cpmmap = {"CPM memory"};

static	Lock	cpmlock;

static struct {
	Lock;
	ulong	avail;
} brgens;

static struct {
	Lock;
	ulong	clash;	/* disable bits for mutually-exclusive options */
	ulong	active;	/* disable bit for current owner, or 0 */
	void	(*stop)(void*);
	void*	arg;
} scc2owner;

static	void	i2cspireloc(void);

/*
 * initialise the communications processor module
 * and associated device registers
 */
void
cpminit(void)
{
	IMM *io;

	io = m->iomem;
	io->rccr = 0;
	io->rmds = 0;
//	io->lccr &= ~1;	/* disable LCD */
	io->sdcr = 1;
	io->pcint = 0;	/* disable all port C interrupts */
	io->pcso = 0;
	io->pcdir =0;
	io->pcpar = 0;
	io->papar = 0;
	io->padir = 0;
	io->pbpar = 0;
	io->pbdir = 0;
	io->tgcr = 0x2222;	/* reset timers, low-power stop */
	eieio();

	for(io->cpcr = 0x8001; io->cpcr & 1;)	/* reset all CPM channels */
		eieio();

	mapinit(&bdmap, bdmapv, sizeof(bdmapv));
	mapfree(&bdmap, DPBASE, BDSIZE);
	mapinit(&cpmmap, cpmmapv, sizeof(cpmmapv));
	mapfree(&cpmmap, DPBASE+BDSIZE, CPMSIZE);

	if(m->cputype == 0x50 && (getimmr() & 0xFFFF) <= 0x2001)
		brgens.avail = 0x3;
	else
		brgens.avail = 0xF;

	scc2owner.clash = DisableEther|DisableIR|DisableRS232b;

	i2cspireloc();
}

/*
 * issue a request to a CPM device
 */
void
cpmop(int op, int cno, int param)
{
	IMM *io;

	ilock(&cpmlock);
	io = m->iomem;
	while(io->cpcr & 1)
		eieio();
	io->cpcr = (op<<8)|(cno<<4)|(param<<1)|1;
	eieio();
	while(io->cpcr & 1)
		eieio();
	iunlock(&cpmlock);
}

/*
 * lock the shared IO memory and return a reference to it
 */
IMM*
ioplock(void)
{
	ilock(&cpmlock);
	return m->iomem;
}

/*
 * release the lock on the shared IO memory
 */
void
iopunlock(void)
{
	eieio();
	iunlock(&cpmlock);
}

/*
 * connect SCCx clocks in NSMI mode (x=1 for USB)
 */
void
sccnmsi(int x, int rcs, int tcs)
{
	IMM *io;
	ulong v;
	int sh;

	sh = (x-1)*8;	/* each SCCx field in sicr is 8 bits */
	v = (((rcs&7)<<3) | (tcs&7)) << sh;
	io = ioplock();
	io->sicr = (io->sicr & ~(0xFF<<sh)) | v;
	iopunlock();
}

/*
 * request or grab (if force!=0) the use of SCC2
 * for the mode (uart, ether, etc) defined by the enable bits.
 * the `stop' function is invoked with the given argument
 * when the device is lost to another driver.
 */
int
scc2claim(int force, ulong enable, void (*stop)(void*), void *arg)
{
	ulong clash;

	clash = scc2owner.clash & ~enable;
	ilock(&scc2owner);
	if(/* ~m->bcsr[1] & clash */ 0){
		if(!force){
			iunlock(&scc2owner);
			return 0;
		}
		/* notify current owner */
		if(scc2owner.stop)
			scc2owner.stop(scc2owner.arg);
//		m->bcsr[1] |= clash;
	}
	scc2owner.stop = stop;
	scc2owner.arg = arg;
	scc2owner.active = enable;
//	m->bcsr[1] &= ~enable;	/* the bits are active low */
	iunlock(&scc2owner);
	/* beware: someone else can claim it during the `successful' return */
	return 1;
}

/*
 * if SCC2 is currently enabled, shut it down
 */
void
scc2stop(void *a)
{
	SCC *scc;

	scc = a;
	if(scc->gsmrl & (3<<4)){
		cpmop(GracefulStopTx, SCC2ID, 0);
		cpmop(CloseRxBD, SCC2ID, 0);
		delay(1);
		scc->gsmrl &= ~(3<<4);	/* disable current use */
//		m->bcsr[1] |= scc2owner.clash;
	}
}

/*
 * yield up control of SCC2
 */
void
scc2free(void)
{
	ilock(&scc2owner);
//	m->bcsr[1] |= scc2owner.active;
	scc2owner.active = 0;
	iunlock(&scc2owner);
}

/*
 * allocate a buffer descriptor
 */
BD *
bdalloc(int n)
{
	ulong a;

	a = rmapalloc(&bdmap, 0, n*sizeof(BD), sizeof(BD));
	if(a == 0)
		panic("bdalloc");
	return KADDR(a);
}

/*
 * free a buffer descriptor
 */
void
bdfree(BD *b, int n)
{
	if(b){
		eieio();
		mapfree(&bdmap, PADDR(b), n*sizeof(BD));
	}
}

/*
 * allocate memory from the shared IO memory space
 */
void *
cpmalloc(int n, int align)
{
	ulong a;

	a = rmapalloc(&cpmmap, 0, n, align);
	if(a == 0)
		panic("cpmalloc");
	return KADDR(a);
}

/*
 * free previously allocated shared memory
 */
void
cpmfree(void *p, int n)
{
	if(p != nil && n > 0){
		eieio();
		mapfree(&cpmmap, PADDR(p), n);
	}
}

/*
 * allocate a baud rate generator, returning its index
 * (or -1 if none is available)
 */
int
brgalloc(void)
{
	int n;

	lock(&brgens);
	for(n=0; brgens.avail!=0; n++)
		if(brgens.avail & (1<<n)){
			brgens.avail &= ~(1<<n);
			unlock(&brgens);
			return n;
		}
	unlock(&brgens);
	return -1;
}

/*
 * free a previously allocated baud rate generator
 */
void
brgfree(int n)
{
	if(n >= 0){
		if(n > 3 || brgens.avail & (1<<n))
			panic("brgfree");
		lock(&brgens);
		brgens.avail |= 1 << n;
		unlock(&brgens);
	}
}

/*
 * return a value suitable for loading into a baud rate
 * generator to produce the given rate if the generator
 * is prescaled by the given amount (typically 16).
 * the value must be or'd with BaudEnable to start the generator.
 */
ulong
baudgen(int rate, int scale)
{
	int d;

	rate *= scale;
	d = (2*m->cpuhz+rate)/(2*rate) - 1;
	if(d < 0)
		d = 0;
	if(d >= (1<<12))
		return ((d+15)>>(4-1))|1;	/* divider too big: enable prescale by 16 */
	return d<<1;
}

/*
 * initialise receive and transmit buffer rings.
 */
int
ioringinit(Ring* r, int nrdre, int ntdre, int bufsize)
{
	int i, x;

	/* the ring entries must be aligned on sizeof(BD) boundaries */
	r->nrdre = nrdre;
	if(r->rdr == nil)
		r->rdr = bdalloc(nrdre);
	if(r->rrb == nil)
		r->rrb = malloc(nrdre*bufsize);
	dcflush(r->rrb, nrdre*bufsize);
	if(r->rdr == nil || r->rrb == nil)
		return -1;
	x = PADDR(r->rrb);
	for(i = 0; i < nrdre; i++){
		r->rdr[i].length = 0;
		r->rdr[i].addr = x;
		r->rdr[i].status = BDEmpty|BDInt;
		x += bufsize;
	}
	r->rdr[i-1].status |= BDWrap;
	r->rdrx = 0;

	r->ntdre = ntdre;
	if(r->tdr == nil)
		r->tdr = bdalloc(ntdre);
	if(r->txb == nil)
		r->txb = malloc(ntdre*sizeof(Block*));
	if(r->tdr == nil || r->txb == nil)
		return -1;
	for(i = 0; i < ntdre; i++){
		r->txb[i] = nil;
		r->tdr[i].addr = 0;
		r->tdr[i].length = 0;
		r->tdr[i].status = 0;
	}
	r->tdr[i-1].status |= BDWrap;
	r->tdrh = 0;
	r->tdri = 0;
	r->ntq = 0;
	return 0;
}

/*
 * Allocate a new parameter block for I2C or SPI,
 * and plant a pointer to it for the microcode,
 * returning the kernel address.
 * See motorola errata and microcode package:
 * the design botch is that the parameters for the SCC2 ethernet overlap the
 * SPI/I2C parameter space; this compensates by relocating the latter.
 * This routine may be used iff i2cspireloc is used (and it is, above).
 */
void*
cpmparam(ulong olda, int nb)
{
	void *p;

	if(olda < INTMEM)
		olda += INTMEM;
	if(olda != SPIP && olda != I2CP)
		return (void*)(olda);
	p = cpmalloc(nb, 32);	/* ``RPBASE must be multiple of 32'' */
	if(p == nil)
		return p;
	*(ushort*)(olda+0x2C) = PADDR(p);	/* set RPBASE */
	eieio();
	return p;
}

/*
 * I2C/SPI microcode package from Motorola
 * (to relocate I2C/SPI parameters), which was distributed
 * on their web site in S-record format.
 *
 *	May 1998
 */

static	ulong	ubase1 = 0x2000;

/*S00600004844521B*/
static	ulong	ucode1[] = {
/*S30902202000*/ 0x3FFF0000,
/*S30902202004*/ 0x3FFD0000,
/*S30902202008*/ 0x3FFB0000,
/*S3090220200C*/ 0x3FF90000,
/*S30902202010*/ 0x5F13EFF8,
/*S30902202014*/ 0x5EB5EFF8,
/*S30902202018*/ 0x5F88ADF7,
/*S3090220201C*/ 0x5FEFADF7,
/*S30902202020*/ 0x3A9CFBC8,
/*S30902202024*/ 0x77CAE1BB,
/*S30902202028*/ 0xF4DE7FAD,
/*S3090220202C*/ 0xABAE9330,
/*S30902202030*/ 0x4E08FDCF,
/*S30902202034*/ 0x6E0FAFF8,
/*S30902202038*/ 0x7CCF76CF,
/*S3090220203C*/ 0xFDAFF9CF,
/*S30902202040*/ 0xABF88DC8,
/*S30902202044*/ 0xAB5879F7,
/*S30902202048*/ 0xB0925D8D,
/*S3090220204C*/ 0xDFD079F7,
/*S30902202050*/ 0xB090E6BB,
/*S30902202054*/ 0xE5BBE74F,
/*S30902202058*/ 0x9E046F0F,
/*S3090220205C*/ 0x6FFB76CE,
/*S30902202060*/ 0xEE0CF9CF,
/*S30902202064*/ 0x2BFBEFEF,
/*S30902202068*/ 0xCFEEF9CF,
/*S3090220206C*/ 0x76CEAD23,
/*S30902202070*/ 0x90B3DF99,
/*S30902202074*/ 0x7FDDD0C1,
/*S30902202078*/ 0x4BF847FD,
/*S3090220207C*/ 0x7CCF76CE,
/*S30902202080*/ 0xCFEF77CA,
/*S30902202084*/ 0x7EAF7FAD,
/*S30902202088*/ 0x7DFDF0B7,
/*S3090220208C*/ 0xEF7A7FCA,
/*S30902202090*/ 0x77CAFBC8,
/*S30902202094*/ 0x6079E722,
/*S30902202098*/ 0xFBC85FFF,
/*S3090220209C*/ 0xDFFF5FB3,
/*S309022020A0*/ 0xFFFBFBC8,
/*S309022020A4*/ 0xF3C894A5,
/*S309022020A8*/ 0xE7C9EDF9,
/*S309022020AC*/ 0x7F9A7FAD,
/*S309022020B0*/ 0x5F36AFE8,
/*S309022020B4*/ 0x5F5BFFDF,
/*S309022020B8*/ 0xDF95CB9E,
/*S309022020BC*/ 0xAF7D5FC3,
/*S309022020C0*/ 0xAFED8C1B,
/*S309022020C4*/ 0x5FC3AFDD,
/*S309022020C8*/ 0x5FC5DF99,
/*S309022020CC*/ 0x7EFDB0B3,
/*S309022020D0*/ 0x5FB3FFFE,
/*S309022020D4*/ 0xABAE5FB3,
/*S309022020D8*/ 0xFFFE5FD0,
/*S309022020DC*/ 0x600BE6BB,
/*S309022020E0*/ 0x600B5FD0,
/*S309022020E4*/ 0xDFC827FB,
/*S309022020E8*/ 0xEFDF5FCA,
/*S309022020EC*/ 0xCFDE3A9C,
/*S309022020F0*/ 0xE7C9EDF9,
/*S309022020F4*/ 0xF3C87F9E,
/*S309022020F8*/ 0x54CA7FED,
/*S309022020FC*/ 0x2D3A3637,
/*S30902202100*/ 0x756F7E9A,
/*S30902202104*/ 0xF1CE37EF,
/*S30902202108*/ 0x2E677FEE,
/*S3090220210C*/ 0x10EBADF8,
/*S30902202110*/ 0xEFDECFEA,
/*S30902202114*/ 0xE52F7D9F,
/*S30902202118*/ 0xE12BF1CE,
/*S3090220211C*/ 0x5F647E9A,
/*S30902202120*/ 0x4DF8CFEA,
/*S30902202124*/ 0x5F717D9B,
/*S30902202128*/ 0xEFEECFEA,
/*S3090220212C*/ 0x5F73E522,
/*S30902202130*/ 0xEFDE5F73,
/*S30902202134*/ 0xCFDA0B61,
/*S30902202138*/ 0x5D8FDF61,
/*S3090220213C*/ 0xE7C9EDF9,
/*S30902202140*/ 0x7E9A30D5,
/*S30902202144*/ 0x1458BFFF,
/*S30902202148*/ 0xF3C85FFF,
/*S3090220214C*/ 0xDFFFA7F8,
/*S30902202150*/ 0x5F5BBFFE,
/*S30902202154*/ 0x7F7D10D0,
/*S30902202158*/ 0x144D5F33,
/*S3090220215C*/ 0xBFFFAF78,
/*S30902202160*/ 0x5F5BBFFD,
/*S30902202164*/ 0xA7F85F33,
/*S30902202168*/ 0xBFFE77FD,
/*S3090220216C*/ 0x30BD4E08,
/*S30902202170*/ 0xFDCFE5FF,
/*S30902202174*/ 0x6E0FAFF8,
/*S30902202178*/ 0x7EEF7E9F,
/*S3090220217C*/ 0xFDEFF1CF,
/*S30902202180*/ 0x5F17ABF8,
/*S30902202184*/ 0x0D5B5F5B,
/*S30902202188*/ 0xFFEF79F7,
/*S3090220218C*/ 0x309EAFDD,
/*S30902202190*/ 0x5F3147F8,
/*S30902202194*/ 0x5F31AFED,
/*S30902202198*/ 0x7FDD50AF,
/*S3090220219C*/ 0x497847FD,
/*S309022021A0*/ 0x7F9E7FED,
/*S309022021A4*/ 0x7DFD70A9,
/*S309022021A8*/ 0xEF7E7ECE,
/*S309022021AC*/ 0x6BA07F9E,
/*S309022021B0*/ 0x2D227EFD,
/*S309022021B4*/ 0x30DB5F5B,
/*S309022021B8*/ 0xFFFD5F5B,
/*S309022021BC*/ 0xFFEF5F5B,
/*S309022021C0*/ 0xFFDF0C9C,
/*S309022021C4*/ 0xAFED0A9A,
/*S309022021C8*/ 0xAFDD0C37,
/*S309022021CC*/ 0x5F37AFBD,
/*S309022021D0*/ 0x7FBDB081,
/*S309022021D4*/ 0x5F8147F8,
/*S309022021D8*/ 0x3A11E710,
/*S309022021DC*/ 0xEDF0CCDD,
/*S309022021E0*/ 0xF3186D0A,
/*S309022021E4*/ 0x7F0E5F06,
/*S309022021E8*/ 0x7FEDBB38,
/*S309022021EC*/ 0x3AFE7468,
/*S309022021F0*/ 0x7FEDF4FC,
/*S309022021F4*/ 0x8FFBB951,
/*S309022021F8*/ 0xB85F77FD,
/*S309022021FC*/ 0xB0DF5DDD,
/*S30902202200*/ 0xDEFE7FED,
/*S30902202204*/ 0x90E1E74D,
/*S30902202208*/ 0x6F0DCBF7,
/*S3090220220C*/ 0xE7DECFED,
/*S30902202210*/ 0xCB74CFED,
/*S30902202214*/ 0xCFEDDF6D,
/*S30902202218*/ 0x91714F74,
/*S3090220221C*/ 0x5DD2DEEF,
/*S30902202220*/ 0x9E04E7DF,
/*S30902202224*/ 0xEFBB6FFB,
/*S30902202228*/ 0xE7EF7F0E,
/*S3090220222C*/ 0x9E097FED,
/*S30902202230*/ 0xEBDBEFFA,
/*S30902202234*/ 0xEB54AFFB,
/*S30902202238*/ 0x7FEA90D7,
/*S3090220223C*/ 0x7E0CF0C3,
/*S30902202240*/ 0xBFFFF318,
/*S30902202244*/ 0x5FFFDFFF,
/*S30902202248*/ 0xAC59EFEA,
/*S3090220224C*/ 0x7FCE1EE5,
/*S30902202250*/ 0xE2FF5EE1,
/*S30902202254*/ 0xAFFBE2FF,
/*S30902202258*/ 0x5EE3AFFB,
/*S3090220225C*/ 0xF9CC7D0F,
/*S30902202260*/ 0xAEF8770F,
/*S30902202264*/ 0x7D0FB0C6,
/*S30902202268*/ 0xEFFBBFFF,
/*S3090220226C*/ 0xCFEF5EDE,
/*S30902202270*/ 0x7D0FBFFF,
/*S30902202274*/ 0x5EDE4CF8,
/*S30902202278*/ 0x7FDDD0BF,
/*S3090220227C*/ 0x49F847FD,
/*S30902202280*/ 0x7EFDF0BB,
/*S30902202284*/ 0x7FEDFFFD,
/*S30902202288*/ 0x7DFDF0B7,
/*S3090220228C*/ 0xEF7E7E1E,
/*S30902202290*/ 0x5EDE7F0E,
/*S30902202294*/ 0x3A11E710,
/*S30902202298*/ 0xEDF0CCAB,
/*S3090220229C*/ 0xFB18AD2E,
/*S309022022A0*/ 0x1EA9BBB8,
/*S309022022A4*/ 0x74283B7E,
/*S309022022A8*/ 0x73C2E4BB,
/*S309022022AC*/ 0x2ADA4FB8,
/*S309022022B0*/ 0xDC21E4BB,
/*S309022022B4*/ 0xB2A1FFBF,
/*S309022022B8*/ 0x5E2C43F8,
/*S309022022BC*/ 0xFC87E1BB,
/*S309022022C0*/ 0xE74FFD91,
/*S309022022C4*/ 0x6F0F4FE8,
/*S309022022C8*/ 0xC7BA32E2,
/*S309022022CC*/ 0xF396EFEB,
/*S309022022D0*/ 0x600B4F78,
/*S309022022D4*/ 0xE5BB760B,
/*S309022022D8*/ 0x53ACAEF8,
/*S309022022DC*/ 0x4EF88B0E,
/*S309022022E0*/ 0xCFEF9E09,
/*S309022022E4*/ 0xABF8751F,
/*S309022022E8*/ 0xEFEF5BAC,
/*S309022022EC*/ 0x741F4FE8,
/*S309022022F0*/ 0x751E760D,
/*S309022022F4*/ 0x7FDBF081,
/*S309022022F8*/ 0x741CAFCE,
/*S309022022FC*/ 0xEFCC7FCE,
/*S30902202300*/ 0x751E70AC,
/*S30902202304*/ 0x741CE7BB,
/*S30902202308*/ 0x3372CFED,
/*S3090220230C*/ 0xAFDBEFEB,
/*S30902202310*/ 0xE5BB760B,
/*S30902202314*/ 0x53F2AEF8,
/*S30902202318*/ 0xAFE8E7EB,
/*S3090220231C*/ 0x4BF8771E,
/*S30902202320*/ 0x7E247FED,
/*S30902202324*/ 0x4FCBE2CC,
/*S30902202328*/ 0x7FBC30A9,
/*S3090220232C*/ 0x7B0F7A0F,
/*S30902202330*/ 0x34D577FD,
/*S30902202334*/ 0x308B5DB7,
/*S30902202338*/ 0xDE553E5F,
/*S3090220233C*/ 0xAF78741F,
/*S30902202340*/ 0x741F30F0,
/*S30902202344*/ 0xCFEF5E2C,
/*S30902202348*/ 0x741F3EAC,
/*S3090220234C*/ 0xAFB8771E,
/*S30902202350*/ 0x5E677FED,
/*S30902202354*/ 0x0BD3E2CC,
/*S30902202358*/ 0x741CCFEC,
/*S3090220235C*/ 0xE5CA53CD,
/*S30902202360*/ 0x6FCB4F74,
/*S30902202364*/ 0x5DADDE4B,
/*S30902202368*/ 0x2AB63D38,
/*S3090220236C*/ 0x4BB3DE30,
/*S30902202370*/ 0x751F741C,
/*S30902202374*/ 0x6C42EFFA,
/*S30902202378*/ 0xEFEA7FCE,
/*S3090220237C*/ 0x6FFC30BE,
/*S30902202380*/ 0xEFEC3FCA,
/*S30902202384*/ 0x30B3DE2E,
/*S30902202388*/ 0xADF85D9E,
/*S3090220238C*/ 0xAF7DAEFD,
/*S30902202390*/ 0x5D9EDE2E,
/*S30902202394*/ 0x5D9EAFDD,
/*S30902202398*/ 0x761F10AC,
/*S3090220239C*/ 0x1DA07EFD,
/*S309022023A0*/ 0x30ADFFFE,
/*S309022023A4*/ 0x4908FB18,
/*S309022023A8*/ 0x5FFFDFFF,
/*S309022023AC*/ 0xAFBB709B,
/*S309022023B0*/ 0x4EF85E67,
/*S309022023B4*/ 0xADF814AD,
/*S309022023B8*/ 0x7A0F70AD,
/*S309022023BC*/ 0xCFEF50AD,
/*S309022023C0*/ 0x7A0FDE30,
/*S309022023C4*/ 0x5DA0AFED,
/*S309022023C8*/ 0x3C12780F,
/*S309022023CC*/ 0xEFEF780F,
/*S309022023D0*/ 0xEFEF790F,
/*S309022023D4*/ 0xA7F85E0F,
/*S309022023D8*/ 0xFFEF790F,
/*S309022023DC*/ 0xEFEF790F,
/*S309022023E0*/ 0x14ADDE2E,
/*S309022023E4*/ 0x5D9EADFD,
/*S309022023E8*/ 0x5E2DFFFB,
/*S309022023EC*/ 0xE79ADDFD,
/*S309022023F0*/ 0xEFF96079,
/*S309022023F4*/ 0x607AE79A,
/*S309022023F8*/ 0xDDFCEFF9,
/*S309022023FC*/ 0x60795DFF,
/*S30902202400*/ 0x607ACFEF,
/*S30902202404*/ 0xEFEFEFDF,
/*S30902202408*/ 0xEFBFEF7F,
/*S3090220240C*/ 0xEEFFEDFF,
/*S30902202410*/ 0xEBFFE7FF,
/*S30902202414*/ 0xAFEFAFDF,
/*S30902202418*/ 0xAFBFAF7F,
/*S3090220241C*/ 0xAEFFADFF,
/*S30902202420*/ 0xABFFA7FF,
/*S30902202424*/ 0x6FEF6FDF,
/*S30902202428*/ 0x6FBF6F7F,
/*S3090220242C*/ 0x6EFF6DFF,
/*S30902202430*/ 0x6BFF67FF,
/*S30902202434*/ 0x2FEF2FDF,
/*S30902202438*/ 0x2FBF2F7F,
/*S3090220243C*/ 0x2EFF2DFF,
/*S30902202440*/ 0x2BFF27FF,
/*S30902202444*/ 0x4E08FD1F,
/*S30902202448*/ 0xE5FF6E0F,
/*S3090220244C*/ 0xAFF87EEF,
/*S30902202450*/ 0x7E0FFDEF,
/*S30902202454*/ 0xF11F6079,
/*S30902202458*/ 0xABF8F542,
/*S3090220245C*/ 0x7E0AF11C,
/*S30902202460*/ 0x37CFAE3A,
/*S30902202464*/ 0x7FEC90BE,
/*S30902202468*/ 0xADF8EFDC,
/*S3090220246C*/ 0xCFEAE52F,
/*S30902202470*/ 0x7D0FE12B,
/*S30902202474*/ 0xF11C6079,
/*S30902202478*/ 0x7E0A4DF8,
/*S3090220247C*/ 0xCFEA5DC4,
/*S30902202480*/ 0x7D0BEFEC,
/*S30902202484*/ 0xCFEA5DC6,
/*S30902202488*/ 0xE522EFDC,
/*S3090220248C*/ 0x5DC6CFDA,
/*S30902202490*/ 0x4E08FD1F,
/*S30902202494*/ 0x6E0FAFF8,
/*S30902202498*/ 0x7C1F761F,
/*S3090220249C*/ 0xFDEFF91F,
/*S309022024A0*/ 0x6079ABF8,
/*S309022024A4*/ 0x761CEE24,
/*S309022024A8*/ 0xF91F2BFB,
/*S309022024AC*/ 0xEFEFCFEC,
/*S309022024B0*/ 0xF91F6079,
/*S309022024B4*/ 0x761C27FB,
/*S309022024B8*/ 0xEFDF5DA7,
/*S309022024BC*/ 0xCFDC7FDD,
/*S309022024C0*/ 0xD09C4BF8,
/*S309022024C4*/ 0x47FD7C1F,
/*S309022024C8*/ 0x761CCFCF,
/*S309022024CC*/ 0x7EEF7FED,
/*S309022024D0*/ 0x7DFDF093,
/*S309022024D4*/ 0xEF7E7F1E,
/*S309022024D8*/ 0x771EFB18,
/*S309022024DC*/ 0x6079E722,
/*S309022024E0*/ 0xE6BBE5BB,
/*S309022024E4*/ 0xAE0AE5BB,
/*S309022024E8*/ 0x600BAE85,
/*S309022024EC*/ 0xE2BBE2BB,
/*S309022024F0*/ 0xE2BBE2BB,
/*S309022024F4*/ 0xAF02E2BB,
/*S309022024F8*/ 0xE2BB2FF9,
/*S309022024FC*/ 0x6079E2BB,
};

static	ulong	ubase2 = 0x2F00;
static	ulong	ucode2[] = {
/*S30902202F00*/ 0x30303030,
/*S30902202F04*/ 0x3E3E3434,
/*S30902202F08*/ 0xABBF9B99,
/*S30902202F0C*/ 0x4B4FBDBD,
/*S30902202F10*/ 0x59949334,
/*S30902202F14*/ 0x9FFF37FB,
/*S30902202F18*/ 0x9B177DD9,
/*S30902202F1C*/ 0x936956BB,
/*S30902202F20*/ 0xFBDD697B,
/*S30902202F24*/ 0xDD2FD113,
/*S30902202F28*/ 0x1DB9F7BB,
/*S30902202F2C*/ 0x36313963,
/*S30902202F30*/ 0x79373369,
/*S30902202F34*/ 0x3193137F,
/*S30902202F38*/ 0x7331737A,
/*S30902202F3C*/ 0xF7BB9B99,
/*S30902202F40*/ 0x9BB19795,
/*S30902202F44*/ 0x77FDFD3D,
/*S30902202F48*/ 0x573B773F,
/*S30902202F4C*/ 0x737933F7,
/*S30902202F50*/ 0xB991D115,
/*S30902202F54*/ 0x31699315,
/*S30902202F58*/ 0x31531694,
/*S30902202F5C*/ 0xBF4FBDBD,
/*S30902202F60*/ 0x35931497,
/*S30902202F64*/ 0x35376956,
/*S30902202F68*/ 0xBD697B9D,
/*S30902202F6C*/ 0x96931313,
/*S30902202F70*/ 0x19797937,
/*S30902202F74*/ 0x6935AF78,
/*S30902202F78*/ 0xB9B3BAA3,
/*S30902202F7C*/ 0xB8788683,
/*S30902202F80*/ 0x368F78F7,
/*S30902202F84*/ 0x87778733,
/*S30902202F88*/ 0x3FFFFB3B,
/*S30902202F8C*/ 0x8E8F78B8,
/*S30902202F90*/ 0x1D118E13,
/*S30902202F94*/ 0xF3FF3F8B,
/*S30902202F98*/ 0x6BD8E173,
/*S30902202F9C*/ 0xD1366856,
/*S30902202FA0*/ 0x68D1687B,
/*S30902202FA4*/ 0x3DAF78B8,
/*S30902202FA8*/ 0x3A3A3F87,
/*S30902202FAC*/ 0x8F81378F,
/*S30902202FB0*/ 0xF876F887,
/*S30902202FB4*/ 0x77FD8778,
/*S30902202FB8*/ 0x737DE8D6,
/*S30902202FBC*/ 0xBBF8BFFF,
/*S30902202FC0*/ 0xD8DF87F7,
/*S30902202FC4*/ 0xFD876F7B,
/*S30902202FC8*/ 0x8BFFF8BD,
/*S30902202FCC*/ 0x8683387D,
/*S30902202FD0*/ 0xB873D87B,
/*S30902202FD4*/ 0x3B8FD7F8,
/*S30902202FD8*/ 0xF7338883,
/*S30902202FDC*/ 0xBB8EE1F8,
/*S30902202FE0*/ 0xEF837377,
/*S30902202FE4*/ 0x3337B836,
/*S30902202FE8*/ 0x817D11F8,
/*S30902202FEC*/ 0x7378B878,
/*S30902202FF0*/ 0xD3368B7D,
/*S30902202FF4*/ 0xED731B7D,
/*S30902202FF8*/ 0x833731F3,
/*S30902202FFC*/ 0xF22F3F23,
/*S30902202E00*/ 0x27EEEEEE,
/*S30902202E04*/ 0xEEEEEEEE,
/*S30902202E08*/ 0xEEEEEEEE,
/*S30902202E0C*/ 0xEEEEEEEE,
/*S30902202E10*/ 0xEE4BF4FB,
/*S30902202E14*/ 0xDBD259BB,
/*S30902202E18*/ 0x1979577F,
/*S30902202E1C*/ 0xDFD2D573,
/*S30902202E20*/ 0xB773F737,
/*S30902202E24*/ 0x4B4FBDBD,
/*S30902202E28*/ 0x25B9B177,
/*S30902202E2C*/ 0xD2D17376,
/*S30902202E30*/ 0x956BBFDD,
/*S30902202E34*/ 0x697BDD2F,
/*S30902202E38*/ 0xFF9F79FF,
/*S30902202E3C*/ 0xFF9FF22F,
};

/*
 * compensate for chip design botch by installing
 * microcode to relocate I2C and SPI parameters away
 * from the ethernet parameters
 */
static void
i2cspireloc(void)
{
	IMM *io;
	static int done;

	if(done)
		return;
	io = m->iomem;
	io->rccr &= ~3;
	memmove((uchar*)m->iomem+ubase1, ucode1, sizeof(ucode1));
	memmove((uchar*)m->iomem+ubase2, ucode2, sizeof(ucode2));

	io->rctr1 = 0x8080;	/* relocate SPI */
	io->rctr2 = 0x808a;	/* relocate SPI */
	io->rctr3 = 0x8028;	/* relocate I2C */
	io->rctr4 = 0x802a;	/* relocate I2C */
	io->rccr |= 3;
	done = 1;
}

M mpc/dat.h => mpc/dat.h +21 -8
@@ 13,10 13,9 @@ typedef struct Map	Map;
typedef struct PCArch	PCArch;
typedef struct Proc	Proc;
typedef struct RMap RMap;
typedef struct Softtlb	Softtlb;
typedef struct Ureg	Ureg;

#define	MACHP(n)	(n==0? &mach0 : *(Mach**)0)

/*
 *  parameters for sysproc.c
 */


@@ 52,7 51,7 @@ struct Notsave
#define NCOLOR 1
struct PMMU
{
	ulong	UNUSED;
	int	pidonmach[MAXMACH];
};

/*


@@ 111,13 110,23 @@ struct Mach
{
	/* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
	int	machno;			/* physical id of processor (unused) */
	ulong	splpc;			/* pc of last caller to splhi */
	ulong	splpc;		/* pc of last caller to splhi */
	int	mmask;			/* 1<<m->machno (unused) */
	Proc	*proc;			/* current process on this processor */
	Proc	*proc;		/* current process on this processor */
	Softtlb	*stb;		/* software tlb cache */
	ulong tlbfault;		/* # of tlb faults */
	ulong dar;		/* # of tlb faults */
	ulong dsisr;		/* # of tlb faults */
	ulong epn;
	ulong cmp1;

	/* ordering from here on irrelevant */
	ulong	ticks;			/* of the clock since boot time */
	Label	sched;			/* scheduler wakeup */
	QLock	stlblk;		/* lock for allocating stlb entries on this mach */
	int	lastpid;		/* last pid allocated on this machine */
	int	purgepid;		/* last pid purged on this machine */
	Proc*	pidproc[NTLBPID];	/* proc that owns tlbpid on this mach */
	Lock	alarmlock;		/* access to alarm list */
	void	*alarm;			/* alarms bound to this clock */
	int	nrdy;


@@ 132,7 141,6 @@ struct Mach

	ulong	fairness;		/* for runproc */

	int	tlbfault;
	int	tlbpurge;
	int	pfault;
	int	cs;


@@ 146,14 154,19 @@ struct Mach
	/* MUST BE LAST */
	int	stack[1];
};
extern	Mach	mach0;

struct Softtlb
{
	ulong	virt;
	ulong	phys;
};

/*
 * Fake kmap
 */
typedef void		KMap;
#define	VA(k)		((ulong)(k))
#define	kmap(p)		(KMap*)((p)->pa)
#define	kmap(p)		(KMap*)(((p)->pa)|KZERO)
#define	kunmap(k)

/*

M mpc/devether.c => mpc/devether.c +1 -0
@@ 349,6 349,7 @@ etherreset(void)
		ether->mbps = 10;
		if(isaconfig("ether", ctlrno, ether) == 0)
			continue;
print("etherreset ether%d\n", ctlrno);
		for(n = 0; cards[n].type; n++){
			if(cistrcmp(cards[n].type, ether->type))
				continue;

M mpc/devrtc.c => mpc/devrtc.c +17 -1
@@ 11,6 11,7 @@ enum{
	Qrtc = 1,
	Qnvram,
	Qnvram2,
	Qled,

	/* sccr */
	RTDIV=	1<<24,


@@ 29,11 30,11 @@ enum{
static	QLock	rtclock;		/* mutex on clock operations */
static Lock nvrtlock;


static Dirtab rtcdir[]={
	"rtc",		{Qrtc, 0},	12,	0666,
	"nvram",	{Qnvram, 0},	Nvsize,	0664,
	"nvram2",	{Qnvram2, 0},	Nvsize,	0664,
	"led",	{Qled, 0},	0,	0664,
};
#define	NRTC	(sizeof(rtcdir)/sizeof(rtcdir[0]))



@@ 77,6 78,7 @@ rtcopen(Chan *c, int omode)
	omode = openmode(omode);
	switch(c->qid.path){
	case Qrtc:
	case Qled:
		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
			error(Eperm);
		break;


@@ 108,6 110,7 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
		n = readnum(offset, buf, n, t, 12);
		return n;
	case Qnvram:
		return 0;
		if(offset >= Nvsize)
			return 0;
		t = offset;


@@ 118,6 121,7 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
		iunlock(&nvrtlock);
		return n;
	case Qnvram2:
		return 0;
		if(offset >= Nvsize2)
			return 0;
		t = offset;


@@ 127,6 131,8 @@ rtcread(Chan *c, void *buf, long n, vlong offset)
		memmove(buf, (uchar*)(NVRAMMEM + Nvoff2 + t), n);
		iunlock(&nvrtlock);
		return n;
	case Qled:
		return 0;
	}
	error(Egreg);
	return 0;		/* not reached */


@@ 165,6 171,7 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
		iopunlock();
		return n;
	case Qnvram:
		return 0;
		if(offset >= Nvsize)
			return 0;
		t = offset;


@@ 175,6 182,7 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
		iunlock(&nvrtlock);
		return n;
	case Qnvram2:
		return 0;
		if(offset >= Nvsize2)
			return 0;
		t = offset;


@@ 184,6 192,14 @@ rtcwrite(Chan *c, void *buf, long n, vlong offset)
		memmove((uchar*)(NVRAMMEM + Nvoff2 + offset), buf, n);
		iunlock(&nvrtlock);
		return n;
	case Qled:
		if(strncmp(buf, "on", 2) == 0)
			powerupled();
		else if(strncmp(buf, "off", 3) == 0)
			powerdownled();
		else
			error("unknown command");
		return n;
	}
	error(Egreg);
	return 0;		/* not reached */

M mpc/devsac.c => mpc/devsac.c +19 -8
@@ 6,13 6,6 @@
#include "io.h"
#include "../port/error.h"

/*
 * Rather than reading /adm/users, which is a lot of work for
 * a toy program, we assume all groups have the form
 *	NNN:user:user:
 * meaning that each user is the leader of his own group.
 */

enum
{
	OPERM	= 0x3,		/* mask of all permission types in open mode */


@@ 85,7 78,8 @@ enum
	Powner =	64,
};

static uchar *data = SACMEM;
static char *sacfs = "fs.sac";
static uchar *data;
static int blocksize;
static Sac root;
static Cache cache[CacheSize];


@@ 104,9 98,26 @@ sacinit(void)
{
	SacHeader *hdr;
	uchar *p;
	char *s;
	int i;

print("sacinit\n");
	s = getconf("flash");
	if(s == nil) {
		print("devsac: no flash file system\n");
		return;
	}

	p = (uchar*)strtoul(s, 0, 0);
	if(p == 0) {
		print("devsac: bad address for flash file system\n");
		return;
	}
	data = tarlookup(p, sacfs, &i);
	if(data == 0) {
		print("devsac: could not find file: %s\n", sacfs);
		return;
	}
	hdr = (SacHeader*)data;
	if(getl(hdr->magic) != Magic) {
print("devsac: bad magic\n");

M mpc/devuart.c => mpc/devuart.c +13 -8
@@ 279,19 279,24 @@ smcsetup(Uart *up)
	up->brgc = brgalloc();
	if(up->brgc < 0)
		error(Eio);
//	m->bcsr[1] &= ~DisableRS232a;	/* enable rs232-1 */

	io = ioplock();
	io->pbpar |= IBIT(23)|IBIT(24)|IBIT(25);	/* enable SMC1 TX/RX/SYN */
	io->pbdir &= ~(IBIT(23)|IBIT(24)|IBIT(25));
	/* step 1 */
	io->papar |= SIBIT(8)|SIBIT(9);
	io->padir &= ~(SIBIT(8)|SIBIT(9));
	io->paodr &= ~(SIBIT(8)|SIBIT(9));

	io->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
	io->simode = (io->simode & ~0xF000) | (up->brgc<<12);	/* SMC1 to NMSI mode, set Tx/Rx clock */

	/* step 3: route clock to SMC2 */
	io->simode = (io->simode & ~0xF0000000) | (up->brgc<<28);

	iopunlock();

	up->param = KADDR(SMC1P);
	up->param = KADDR(SMC2P);
	uartsetbuf(up);

	cpmop(InitRxTx, SMC1ID, 0);
	cpmop(InitRxTx, SMC2ID, 0);

	/* SMC protocol parameters */
	p = (Uartsmc*)up->param;


@@ 300,12 305,12 @@ smcsetup(Uart *up)
	p->brkln = 0;
	p->brkec = 0;
	p->brkcr = 1;
	smc = IOREGS(0xA80, SMC);
	smc = IOREGS(0xA90, SMC);
	smc->smce = 0xff;	/* clear events */
	smc->smcm = BSY|RXB|TXB;	/* enable all possible interrupts */
	up->smc = smc;
	smc->smcmr = ((1+8+1-1)<<11)|(2<<4);	/* 8-bit, 1 stop, no parity; UART mode */
	intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN);
	intrenable(VectorCPIC+3, smcuintr, up, BUSUNKNOWN);
	smc->smcmr |= 3;	/* enable rx/tx */
}


A mpc/devusb.c => mpc/devusb.c +628 -0
@@ 0,0 1,628 @@
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

typedef struct USBparam USBparam;
struct USBparam {
	ushort	epptr[4];	/**/
	ulong	rstate;
	ulong	rptr;
	ushort	frame_n;	/**/
	ushort	rbcnt;
	ulong	rtemp;
};

typedef struct EPparam EPparam;
struct EPparam {
	ushort	rbase;
	ushort	tbase;
	uchar	rfcr;
	uchar	tfcr;
	ushort	mrblr;
	ushort	rbptr;
	ushort	tbptr;

	ulong	tstate;
	ulong	tptr;
	ushort	tcrc;
	ushort	tbcnt;
	ulong	res[2];
};

enum {
	Nrdre		= 8,	/* receive descriptor ring entries */
	Ntdre		= 8,	/* transmit descriptor ring entries */

	Rbsize		= 8+3,		/* ring buffer size (+3 for PID+CRC16) */
	Bufsize		= (Rbsize+7)&~7,	/* aligned */

	Nendpt		= 4,
};

#define	MkPID(x) (((~x&0xF)<<4)|(x&0xF))
enum {
	TokIN = MkPID(9),
	TokOUT = MkPID(1),
	TokSOF = MkPID(5),
	TokSETUP = MkPID(0xD),
	TokDATA0 = MkPID(3),
	TokDATA1 = MkPID(0xB),
	TokACK = MkPID(2),
	TokNAK = MkPID(0xA),
	TokPRE = MkPID(0xC),
};

enum {
	BDData0=		1<<7,
	BDData1=		1<<6,	/* DATA1 if set, DATA0 otherwise */
	BDrxerr=		0x3F,	/* various error flags */

	BDtxcrc=		1<<10,
	BDcnf=		1<<9,	/* transmit confirmation */
	/* BDData0, BDData1 */
	BDNak=		1<<4,	/* nak received */
	BDStall=		1<<3,	/* stall received */
	BDTmo=		1<<2,	/* timeout */
	BDUrun=		1<<1,	/* underrun */

	/* usmod */
	EN=		1<<0,	/* enable USB */
	HOST=	1<<1,	/* host mode */
	TEST=	1<<2,	/* test mode */
	RESUME=	1<<6,	/* generate resume condition */
	LSS=		1<<7,	/* low-speed signalling */

	/* usber */
	Freset=	1<<9,
	Fidle=	1<<8,
	Ftxe3=	1<<7,
	Ftxe2=	1<<6,
	Ftxe1=	1<<5,
	Ftxe0=	1<<4,
	Ftxe=	Ftxe0|Ftxe1|Ftxe2|Ftxe3,
	Fsof=	1<<3,
	Fbsy=	1<<2,
	Ftxb=	1<<1,
	Frxb=	1<<0,

	/* uscom */
	FifoFill=		1<<7,
	FifoFlush=	1<<6,

	/* USB commands (or'd with USBCmd) */
	StopTxEndPt	= 1<<4,
	RestartTxEndPt	= 2<<4,

	SOFmask=	(1<<11)-1,
};

#define	USBABITS	(SIBIT(14)|SIBIT(15))
#define	USBRXCBIT	(SIBIT(10)|SIBIT(11))
#define	USBTXCBIT	(SIBIT(6)|SIBIT(7))

/*
 * software structures
 */
typedef struct Ctlr Ctlr;
typedef struct Endpt Endpt;

struct Endpt {
	int	x;	/* index in Ctlr.pts */
	int	dev;	/* remote device (host endpt only) */
	int	endpt;	/* remote endpt (host endpt only) */
	uchar	addr[2];	/* crc5<<11 | endpt<<7 | dev */
	int	rtog;		/* DATA0 or DATA1 */
	int	xtog;	/* DATA0 or DATA1 */
	int	rxintr;
	Rendez	ir;
	EPparam*	ep;
	Ring;

	Queue*	oq;
	Queue*	iq;
	Ctlr*	ctlr;
};

struct Ctlr {
	Lock;
	int	init;
	USB*	usb;
	USBparam *usbp;
	Endpt	pts[4];
};

static	Ctlr	usbctlr[1];

static	void	dumpusb(Block*, char*);
static	void	interrupt(Ureg*, void*);
static	void	setupep(int, EPparam*);
static	void	usbtest(void);

/*
 * test driver for USB, host mode
 */
void
usbreset(void)
{
	IMM *io;
	USB *usb;
	USBparam *usbp;
	EPparam *ep;
	int brg, i;

	brg = brgalloc();
	if(brg < 0){
		print("usb: no baud rate generator is free\n");
		return;
	}

	io = m->iomem;
	usb = (USB*)((ulong)m->iomem+0xA00);
	usbp = (USBparam*)KADDR(SCC1P);

	/* select port pins */
	io->padir &= ~USBABITS;
	io->papar |= USBABITS;
	io->pcpar = (io->pcpar & ~USBRXCBIT) | USBTXCBIT;
	io->pcdir = (io->pcdir & ~USBRXCBIT) | USBTXCBIT;
	io->pcso |= USBRXCBIT;
	eieio();

	ep = cpmalloc(Nendpt*sizeof(*ep), 32);
	if(ep == nil){
		print("can't allocate USB\n");
		return;
	}
print("ep=#%.8ux\n", PADDR(ep));

	usbp->frame_n = 0;
	usbp->rstate = 0;
	for(i=0; i<Nendpt; i++){
		usb->uscom = FifoFlush|i;
		usb->usep[i] = 0;
		usbp->epptr[i] = PADDR(ep+i) & 0xffff;
		ep[i].rbase = 0;
		ep[i].tbase = 0;
		ep[i].rfcr = 0x10;
		ep[i].tfcr = 0x10;
		ep[i].mrblr = Bufsize;
		ep[i].rbptr = 0;
		ep[i].tbptr = 0;
		ep[i].tstate = 0;
		ep[i].tptr = 0;
	}

	usbctlr->usb = usb;
	usbctlr->usbp = usbp;

	usb->usmod = 0;
	if(1)
		usb->usmod = HOST;
	if(0)
		usb->usmod |= LSS;
	if(1)
		usb->usmod |= TEST|HOST;

	/* set up baud rate generator for appropriate speed */
	if(usb->usmod & LSS){
		print("USB: low speed\n");
		io->brgc[brg] = baudgen(1000000, 1) | BaudEnable;
	}else
		io->brgc[brg] = BaudEnable;
	eieio();
	io->sicr = (io->sicr & ~(7<<3)) | (brg<<3);	/* set R1CS */
	eieio();

	usb->usep[0] = (0<<12) | (2<<8) | (1<<5);	/* EPN=0, TM=bulk, multi frame */
	setupep(0, ep);
	if(usb->usmod & TEST){
		print("USB: loop back mode\n");
		usb->usep[1] = (1<<12) | (0<<8);	/* EPN=1, TM=control*/
		setupep(1, ep+1);
	}

	m->bcsr[4] &= ~(DisableUSB|DisableUSBVcc);
	if(usb->usmod & LSS)
		m->bcsr[4] &= ~USBFullSpeed;
	else
		m->bcsr[4] |= USBFullSpeed;
	if(usb->usmod & HOST && !(usb->usmod & TEST))
		usb->usadr = 0x7f;	/* unused in host mode, but just in case */
	else
		usb->usadr = 0;
	usb->usber = ~0;	/* clear events */
	intrenable(CPICvec+0x1E, interrupt, usbctlr, BUSUNKNOWN);
	usb->usbmr = ~0 & ~Fidle;	/* enable all events except idle */
	eieio();
	delay(12);
	usb->usmod |= EN;
}

static void
setupep(int n, EPparam *ep)
{
	Endpt *e;

	e = &usbctlr->pts[n];
	e->x = n;
	e->ctlr = usbctlr;
	e->xtog = TokDATA0;
	if(e->oq == nil)
		e->oq = qopen(8*1024, 1, 0, 0);
	if(e->iq == nil)
		e->iq = qopen(8*1024, 1, 0, 0);
	e->ep = ep;
	if(ioringinit(e, Nrdre, Ntdre, Bufsize) < 0)
		panic("usbreset");
	ep->rbase = PADDR(e->rdr);
	ep->rbptr = ep->rbase;
	ep->tbase = PADDR(e->tdr);
	ep->tbptr = ep->tbase;
	eieio();
}

static void
epprod(Ctlr *ctlr, int epn)
{
	ctlr->usb->uscom = FifoFill | (epn&3);
	eieio();
}

static void
txstart(Endpt *r)
{
	int len, flags;
	Block *b;
	BD *dre, *rdy;

	if(r->ctlr->init)
		return;
	rdy = nil;
	while(r->ntq < Ntdre-1){
		b = qget(r->oq);
		if(b == 0)
			break;

		dre = &r->tdr[r->tdrh];
		if(dre->status & BDReady)
			panic("txstart");
print("Tx%d: ", r->x); dumpusb(b, "TX");
	
		/*
		 * Give ownership of the descriptor to the chip, increment the
		 * software ring descriptor pointer and tell the chip to poll.
		 */
		flags = 0;
		switch(b->rp[0]){
		case TokDATA1:
			flags = BDData1|BDData0;
		case TokDATA0:
			flags |= BDtxcrc|BDcnf|BDReady;
			flags |= BDData0;
			/*b->rp++;	/* skip DATAn */
		}
		len = BLEN(b);
		dcflush(b->rp, len);
		if(r->txb[r->tdrh] != nil)
			panic("usb: txstart");
		r->txb[r->tdrh] = b;
		dre->addr = PADDR(b->rp);
		dre->length = len;
		eieio();
		dre->status = (dre->status & BDWrap) | BDInt|BDLast | flags;
		if(rdy){
			rdy->status |= BDReady;
			rdy = nil;
		}
		if((flags & BDReady) == 0)
			rdy = dre;
		eieio();
		r->ntq++;
		r->tdrh = NEXT(r->tdrh, Ntdre);
	}
	if(rdy)
		rdy->status |= BDReady;
	eieio();
}

static void
transmit(Endpt *r)
{
	ilock(r->ctlr);
	txstart(r);
	iunlock(r->ctlr);
}

static void
endptintr(Endpt *r, int events)
{
	int len, status;
	BD *dre;
	Block *b;

	if(events & Frxb || 1){
		dre = &r->rdr[r->rdrx];
		while(((status = dre->status) & BDEmpty) == 0){
			if(status & BDrxerr || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
				print("usb rx%d: %4.4ux %d ", r->x, status, dre->length);
				{uchar *p;int i; p=KADDR(dre->addr); for(i=0;i<14&&i<dre->length; i++)print(" %.2ux", p[i]);print("\n");}
			}
			else{
				/*
				 * We have a packet. Read it into the next
				 * free ring buffer, if any.
				 */
				len = dre->length-2;	/* discard CRC */
				if(len >= 0 && (b = iallocb(len)) != 0){
					memmove(b->wp, KADDR(dre->addr), len);
					dcflush(KADDR(dre->addr), len);
					b->wp += len;
					// usbiq(ctlr, b);
					print("rx%d: ", r->x); dumpusb(b, "RX");
					freeb(b);
				}
			}

			/*
			 * Finished with this descriptor, reinitialise it,
			 * give it back to the chip, then on to the next...
			 */
			dre->length = 0;
			dre->status = (dre->status & BDWrap) | BDEmpty | BDInt;
			eieio();

			r->rdrx = NEXT(r->rdrx, Nrdre);
			dre = &r->rdr[r->rdrx];
			r->rxintr = 1;
			wakeup(&r->ir);
		}
	}

	/*
	 * Transmitter interrupt: handle anything queued for a free descriptor.
	 */
	if(events & (Ftxb|Ftxe0|Ftxe1)){
		lock(r->ctlr);
		while(r->ntq){
			dre = &r->tdr[r->tdri];
			if(dre->status & BDReady)
				break;
			print("usbtx%d=#%.4x %8.8lux\n", r->x, dre->status, dre->addr);
			/* TO DO: error counting */
			b = r->txb[r->tdri];
			if(b == nil)
				panic("usb/interrupt: bufp");
			r->txb[r->tdri] = nil;
			freeb(b);
			r->ntq--;
			r->tdri = NEXT(r->tdri, Ntdre);
		}
		txstart(r);
		unlock(r->ctlr);
		if(r->ntq)
			epprod(r->ctlr, r->x);
	}
}

static void
interrupt(Ureg*, void *arg)
{
	int events;
	Ctlr *ctlr;
	USB *usb;

	ctlr = arg;
	usb = ctlr->usb;
	events = usb->usber;
	eieio();
	usb->usber = events;
	print("USB#%x\n", events);

	if(events & Fsof)
		print("SOF #%ux\n", ctlr->usbp->frame_n&SOFmask);
	endptintr(&ctlr->pts[0], events);
	if(usb->usmod & TEST)
		endptintr(&ctlr->pts[1], events);
	if(events & Ftxe0)
		cpmop(USBCmd|RestartTxEndPt, USBID, 0<<1);
	if(events & Ftxe1)
		cpmop(USBCmd|RestartTxEndPt, USBID, 1<<1);
}

void
usbinit(void)
{
	usbreset();
usbtest();
}

static void
dumpusb(Block *b, char *msg)
{
	int i;

	print("%s: %8.8lux [%d]: ", msg, (ulong)b->rp, BLEN(b));
	for(i=0; i<BLEN(b) && i < 16; i++)
		print(" %.2x", b->rp[i]);
	print("\n");
}

/*
 * could generate a table, but since the result can be precomputed
 * per connection, it doesn't seem worthwhile.
 */
static ulong
crc5(ushort v)
{
	int i;
	ulong x, poly;

	x = 0x1F;
	poly = 0x14;
	for(i=0; i<11; i++, v>>= 1){
		if((x^v) & 1)
			x = ((x>>1)&0x0F)^poly;
		else
			x = ((x>>1)&0x0F);
	}
	return ~x&0x1F;
}

static void
setaddr(Endpt *e, int dev, int endpt)
{
	ushort v;

	e->dev = dev;
	e->endpt = endpt;
	v = (e->endpt<<7) | e->dev;
	v |= crc5(v) << 11;
	e->addr[0] = v;
	e->addr[1] = v>>8;
}

/*
 * Token packets (watch bit/byte order; it's LSB on the wire):
 *
 * 4 bit PID, 4 bit check
 *	TokIN, etc.
 * 7 bit device, 4 bit end point
 * 5 bit CRC5
 */
static void
sendtoken(Endpt *e, int pid)
{
	Block *b;

	b = allocb(3);
	b->wp[0] = pid;
	b->wp[1] = e->addr[0];
	b->wp[2] = e->addr[1];
	b->wp += 3;
	if(pid == TokDATA0 || pid == TokDATA1)
		e->xtog ^= TokDATA1^TokDATA0;
	else
		e->xtog = TokDATA0;
	qbwrite(e->oq, b);
	/* wait for reply? */
//	transmit(e);
}

static void
sendSOF(Endpt *e, int frame)
{
	Block *b;

	b = allocb(3);
	b->wp[0] = TokSOF;
	frame &= SOFmask;
	frame |= crc5(frame) << 11;
	b->wp[1] = frame;
	b->wp[2] = frame>>8;
	b->wp += 3;
	qbwrite(e->oq, b);
	transmit(e);
}

static void
sendack(Endpt *e, int pid)
{
	Block *b;

	b = allocb(1);
	b->wp[0] = pid;
	b->wp += 1;
	qbwrite(e->oq, b);
	/* wait for reply? */
	transmit(e);
}

static void
senddata(Endpt *e, void *buf, long n)
{
	Block *b;

	b = allocb(n+4);
	b->wp += 3;	/* skip 3 bytes for word alignment of data */
	b->rp = b->wp;
	b->wp[0] = e->xtog;
	memmove(b->wp+1, buf, n);
	b->wp += n+1;
	e->xtog ^= TokDATA1^TokDATA0;
	qbwrite(e->oq, b);
	/* wait for reply? */
	transmit(e);
	epprod(e->ctlr, e->x);
}

static int
usbinput(void *a)
{
	return ((Endpt*)a)->rxintr;
}

static void
usbtest(void)
{
	Ctlr *ctlr;
	Endpt *e, *e1;
	uchar msg[8];
	int epn, testing, i;

	ctlr = usbctlr;
	epn = 0;
	testing = ctlr->usb->usmod & TEST;
	if(testing)
		epn = 1;
	e = &ctlr->pts[0];
	e1 = &ctlr->pts[1];
	if((ctlr->usb->usmod & LSS) == 0)
		sendSOF(e, 0);
	memset(msg, 0, 8);
	msg[0] = 0;
	msg[1] = 8;	/* set configuration */
	msg[2] = 1;
	setaddr(e, 0, epn);
	sendtoken(e, TokSETUP);
	senddata(e, msg, 8);
	if(testing){
		for(i=0; i<8; i++)
			msg[i] = 0x40+i;
		senddata(e1, msg, 8);
		tsleep(&up->sleep, return0, 0, 3);
	}
	if(1){
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, usbinput, e, 1000);
		if(!usbinput(e))
			print("RX: none\n");
	}
	sendtoken(e, TokSETUP);
	msg[0] = 0x23;
	msg[1] = 3;	/* set feature */
	msg[2] = 8;	/* port power */
	msg[3] = 0;
	msg[4] = 1;	/* port 1 */
	senddata(e, msg, 8);
	if(testing){
		for(i=0; i<8; i++)
			msg[i] = 0x60+i;
		senddata(e1, msg, 8);
		tsleep(&up->sleep, return0, 0, 3);
	}
	if(1){
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, usbinput, e, 1000);
		if(!usbinput(e))
			print("RX: none\n");
	}
}

M mpc/ether589.c => mpc/ether589.c +18 -46
@@ 111,11 111,8 @@ configASIC(Ether* ether, int port, int xcvr)
static int
reset(Ether* ether)
{
	int i, slot;
	int slot;
	int port;
	enum { WantAny, Want10BT, Want10B2 };
	int want;
	char *p;

	if(ether->irq == 0)
		ether->irq = 10;


@@ 123,56 120,31 @@ reset(Ether* ether)
		ether->port = 0x240;
	port = ether->port;

	if(ioalloc(port, 0x10, 0, "3C589") < 0)
	if((slot = pcmspecial(ether->type, ether)) < 0)
		return -1;

	if((slot = pcmspecial(ether->type, ether)) < 0){
		iofree(port);
	/* try configuring as a 10BaseT */
	if(configASIC(ether, port, xcvr10BaseT) < 0){
		pcmspecialclose(slot);
		return -1;
	}

	/*
	 * Allow user to specify desired media in plan9.ini
	 */
	want = WantAny;
	for(i = 0; i < ether->nopt; i++){
		if(cistrncmp(ether->opt[i], "media=", 6) != 0)
			continue;
		p = ether->opt[i]+6;
		if(cistrcmp(p, "10base2") == 0)
			want = Want10B2;
		else if(cistrcmp(p, "10baseT") == 0)
			want = Want10BT;
	}
	
	/* try configuring as a 10BaseT */
	if(want==WantAny || want==Want10BT){
		if(configASIC(ether, port, xcvr10BaseT) < 0){
			pcmspecialclose(slot);
			iofree(port);
			return -1;
		}
		delay(100);
		COMMAND(port, SelectRegisterWindow, Wdiagnostic);
		if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
			COMMAND(port, SelectRegisterWindow, Wop);
			print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, ether->type);
			return 0;
		}
	delay(100);
	COMMAND(port, SelectRegisterWindow, Wdiagnostic);
	if(ins(port+MediaStatus) & linkBeatDetect){
		COMMAND(port, SelectRegisterWindow, Wop);
		print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, ether->type);
		return 0;
	}

	/* try configuring as a 10base2 */
	if(want==WantAny || want==Want10B2){
		COMMAND(port, GlobalReset, 0);
		if(configASIC(ether, port, xcvr10Base2) < 0){
			pcmspecialclose(slot);
			iofree(port);
			return -1;
		}
		print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, ether->type);
		return 0;
	COMMAND(port, GlobalReset, 0);
	if(configASIC(ether, port, xcvr10Base2) < 0){
		pcmspecialclose(slot);
		return -1;
	}
	return -1;		/* not reached */
	print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, ether->type);

	return 0;
}

void

M mpc/etherif.h => mpc/etherif.h +1 -1
@@ 1,5 1,5 @@
enum {
	MaxEther	= 24,
	MaxEther	= 4,
	Ntypes		= 8,
};


M mpc/etherscc.c => mpc/etherscc.c +88 -45
@@ 137,10 137,10 @@ attach(Ether *ether)
static void
closed(Ether *ether)
{
	Ctlr *ctlr;

	ctlr = ether->ctlr;
	if(0){
		Ctlr *ctlr;

		ctlr = ether->ctlr;
		if(ether->port == 2)
			scc2stop(ctlr->scc);
		ilock(ctlr);


@@ 268,15 268,14 @@ interrupt(Ureg*, void *arg)
			ctlr->overrun++;
		if(events & TXE)
			ether->oerrs++;
		if(0 || events & TXE)
			print("ETHER.SCC#%d: scce = 0x%uX\n", ether->ctlrno, events);
	}

	/*
	 * Receiver interrupt: run round the descriptor ring logging
	 * errors and passing valid receive data up to the higher levels
	 * until we encounter a descriptor still owned by the chip.
	 */
	if(events & (RXF|RXB) || 1){
	if(events & (RXF|RXB)){
		dre = &ctlr->rdr[ctlr->rdrx];
		while(((status = dre->status) & BDEmpty) == 0){
			if(status & RxError || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){


@@ 288,7 287,7 @@ interrupt(Ureg*, void *arg)
					ether->crcs++;
				if(status & RxeOV)
					ether->overflows++;
				//print("eth rx: %ux\n", status);
				print("eth rx: %ux\n", status);
			}
			else{
				/*


@@ 320,7 319,7 @@ interrupt(Ureg*, void *arg)
	/*
	 * Transmitter interrupt: handle anything queued for a free descriptor.
	 */
	if(events & TXB){
	if(events & (TXB|TXE)){
		lock(ctlr);
		while(ctlr->ntq){
			dre = &ctlr->tdr[ctlr->tdri];


@@ 348,11 347,13 @@ interrupt(Ureg*, void *arg)
			ctlr->ntq--;
			ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
		}

		if(events & TXE)
			cpmop(RestartTx, ctlr->sccid, 0);

		txstart(ether);
		unlock(ctlr);
	}
	if(events & TXE)
		cpmop(RestartTx, ctlr->sccid, 0);
}

static long


@@ 391,52 392,84 @@ ifstat(Ether* ether, void* a, long n, ulong offset)
static void
sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
{
	int i, rcs, tcs;
	int i;
	Etherparam *p;
	IMM *io;

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

	// setp 3
	io->pcpar &= ~SIBIT(15);		/* disble TENA pin */

	// step 4: enable clocks
	io->papar |= SIBIT(6)|SIBIT(4);	/* enable CLK2 and CLK4 */
	io->padir &= ~(SIBIT(6)|SIBIT(4));
	eieio();

	// step 5/6: route clocks
	io->sicr = (7<<3) | (5);
	eieio();
	switch(ctlr->port) {
	default:
		iopunlock();
		return;
	case 2:
		p = (Etherparam*)(SCC2P);

		// step 1: enable TXD RXD ports
		io->papar |= SIBIT(12)|SIBIT(13);
		io->padir &= ~(SIBIT(12)|SIBIT(13));
		io->paodr &= ~(SIBIT(12)|SIBIT(13));

		// step 2: enable CLSN and RENA ports
		io->pcpar &= ~(SIBIT(8)|SIBIT(9));
		io->pcdir &= ~(SIBIT(8)|SIBIT(9));
		io->pcso |= SIBIT(8)|SIBIT(9);

		// setp 3: disble TENA pin */
		io->pcpar &= ~SIBIT(14);
		io->pcdir &= ~SIBIT(14);
	
		// step 4: enable clocks CLK3 and CLK4
		io->papar |= SIBIT(6)|SIBIT(7);
		io->padir &= ~(SIBIT(6)|SIBIT(7));

		// step 5/6: route clocks
		iopunlock();
		sccnmsi(2, CLK1, CLK2);	/* connect the clocks */
		io = ioplock();
		break;

	case 3:
		p = (Etherparam*)KADDR(SCC3P);

		// step 1: enable TXD RXD ports
		io->pbpar |= IBIT(24)|IBIT(25);
		io->pbdir |= IBIT(24)|IBIT(25);
		io->pbodr &= ~(IBIT(24)|IBIT(25));
			
		// step 2: enable CLSN and RENA ports
		io->pcpar &= ~(SIBIT(4)|SIBIT(5));
		io->pcdir &= ~(SIBIT(4)|SIBIT(5));
		io->pcso |= SIBIT(4)|SIBIT(5);
		eieio();
	
		// setp 3
		io->pcpar &= ~SIBIT(13);
		io->pcdir &= ~SIBIT(13);
	
		// step 4: enable clocks
		io->papar |= SIBIT(4)|SIBIT(5);
		io->padir &= ~(SIBIT(4)|SIBIT(5));
		eieio();
	
		// step 5/6: route clocks
		iopunlock();
		sccnmsi(3, CLK3, CLK4);
		io = ioplock();
		break;
	}

	// step 7: set dma priority
	io->sdcr = 1;

	
	iopunlock();

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

	// step 8:
	p->rbase = PADDR(ctlr->rdr);
	p->tbase = PADDR(ctlr->tdr);

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

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


@@ 514,9 547,17 @@ sccsetup(Ctlr *ctlr, SCC *scc, uchar *ea)
	// step 33:
	scc->psmr = 0x080A;	/* 32-bit CRC, non-promiscuous */

	// step 34
	io->pcpar |= SIBIT(15);	/* enable TENA pin (RTS2) */
	io->pcdir &= ~SIBIT(15);
	// step 34: enable TENA 
	switch(ctlr->port) {
	case 2:
		io->pcpar |= SIBIT(14);
		io->pcdir &= ~SIBIT(14);
		break;
	case 3:
		io->pcpar |= SIBIT(13);
		io->pcdir &= ~SIBIT(13);
		break;
	}

	// step 35: done at attach time
}


@@ 528,6 569,8 @@ reset(Ether* ether)
	Ctlr *ctlr;
	SCC *scc;

print("etherscc: reset\n");

	if(m->speed < 24){
		print("%s ether: system speed must be >= 24MHz for ether use\n", ether->type);
		return -1;


@@ 583,5 626,5 @@ void
etherscclink(void)
{
	addethercard("SCC", reset);
//	addethercard("SCC2", reset);
//	addethercard("SCC3", reset);
}

M mpc/fns.h => mpc/fns.h +7 -8
@@ 18,6 18,7 @@ void	dcflush(void*, ulong);
void	delay(int);
ulong	draminit(ulong*);
void	dtlbmiss(void);
void	dtlberror(void);
void	dumpregs(Ureg*);
void	delayloopinit(void);
void	eieio(void);


@@ 43,10 44,6 @@ void	gotopc(ulong);
void	icflush(void*, ulong);
void	idle(void);
#define	idlehands()			/* nothing to do in the runproc */
void	iofree(int);
void	ioinit(void);
int	iounused(int, int);
int	ioalloc(int, int, int, char*);
int	inb(int);
void	insb(int, void*, int);
ushort	ins(int);


@@ 84,6 81,7 @@ void	procsave(Proc*);
void	procsetup(Proc*);
void	putdec(ulong);
void	putmsr(ulong);
void	putcasid(ulong);
ulong	rmapalloc(RMap*, ulong, int, int);
void	screeninit(void);
void	setpanic(void);


@@ 94,19 92,20 @@ int	segflush(void*, ulong);
void	spireset(void);
long	spioutin(void*, long, void*);
int	tas(void*);
uchar*	tarlookup(uchar *addr, char *file, int *dlen);
void	touser(void*);
void	trapinit(void);
void	trapvec(void);
void	tlbflush(ulong);
void	tlbflushall(void);
void	uartinstall(void);
void	uartwait(void);	/* debugging */
int unsac(uchar *dst, uchar *src, int n, int nsrc);
void	wbflush(void);

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))

// identity map between kernel physical and virtual addresses
#define KADDR(a)	((void*)(a))
#define PADDR(a)	((ulong)(a))
#define KADDR(a)	((void*)((ulong)(a)|KZERO))
#define PADDR(a)	((ulong)(a)&~KZERO)

/* IBM bit field order */
#define	IBIT(b)		((ulong)1<<(31-(b)))

M mpc/l.s => mpc/l.s +471 -216
@@ 4,8 4,8 @@
 * common ppc special purpose registers
 */
#define DSISR	18
#define DAR	19	/* Data Address Register */
#define DEC	22	/* Decrementer */
#define DAR		19	/* Data Address Register */
#define DEC		22	/* Decrementer */
#define SRR0	26	/* Saved Registers (exception) */
#define SRR1	27
#define SPRG0	272	/* Supervisor Private Registers */


@@ 51,6 51,27 @@
#define	MD_DBRAM0	825
#define	MD_DBRAM1	826

/*
 * mpc8xx specific debug-level SPRs
 */ 
#define CMPA		144
#define CMPB		145
#define CMPC		146
#define CMPD		147
#define ICR			148
#define DER			149
#define COUNTA		150
#define COUNTB		151
#define CMPE		152
#define CMPF		153
#define CMPG		154
#define CMPH		155
#define LCTRL1		156
#define LCTRL2		157
#define ICTRL		158
#define BAR			159
#define DPDR		630

/* use of SPRG registers in save/restore */
#define	SAVER0	SPRG0
#define	SAVER1	SPRG1


@@ 66,21 87,46 @@
/* on some models mtmsr doesn't synchronise enough (eg, 603e) */
#define	MSRSYNC	SYNC; ISYNC

/*
 * The following code assume that the MPC8xx processor has been
 * configured to a certain extent.  In particular, we assume the following
 * following registers have been set up.
 *
 * SIU
 *		SIUMCR
 *		SYPCR
 *
 */

#define	UREGSPACE	(UREGSIZE+8)

	TEXT start(SB), $-4

	/* turn off interrupts but enable traps */
	/*
	 * setup MSR
	 * turn off interrupts
	 * use 0x000 as exception prefix
	 * enable machine check
	 */
	MOVW	MSR, R3
	MOVW	$~(MSR_EE|MSR_FP), R4
	AND	R4, R3
	OR	$(MSR_IP|MSR_ME), R3
	MOVW	$(MSR_EE|MSR_IP), R4
	ANDN	R4, R3
	OR		$(MSR_ME), R3
	ISYNC
	MOVW	R3, MSR
	MSRSYNC

	MOVW	$0, R0	/* except during trap handling, R0 is zero from now on */
	/* set internal memory base */
	MOVW	$INTMEM, R4
	MOVW	R4, SPR(IMMR)

	/* except during trap handling, R0 is zero from now on */
	MOVW	$0, R0

	/* setup SB for pre mmu */
	MOVW	$setSB(SB), R2
	MOVW	$KZERO, R3
	ANDN	R3, R2

/*
 * reset the caches and disable them for now


@@ 112,113 158,130 @@
	ISYNC

	MOVW	$7, R4
	MOVW	R4, SPR(158)	/* cancel `show cycle' for normal instruction execution */
	MOVW	R4, SPR(ICTRL)		/* cancel `show cycle' for normal instruction execution */
	ISYNC
	MOVW	R4, SPR(DER)
	ISYNC
	BL	mmuinit0(SB)

	/* running with MMU on!! */

	/* set R2 to it correct value */
	MOVW	$setSB(SB), R2

	/* enable i-cache */
	MOVW	$(1<<25), R4
	MOVW	R4, SPR(IC_CST)
	ISYNC

 	/* enable d-cache 	*/
	MOVW	$(2<<24), R4
	MOVW	R4, SPR(DC_CST)
	ISYNC


/*
 * set other system configuration values
 */
	MOVW	$INTMEM, R4
	MOVW	R4, SPR(IMMR)		/* set internal memory base */

	MOVW	$mach0(SB), R(MACH)

/*
 * setup mach
 */
	MOVW	$MACHADDR, R(MACH)
	ADD	$(MACHSIZE-8), R(MACH), R1	/* set stack */
	SUB	$4, R(MACH), R3
	ADD	$4, R1, R4

clrmach:
	MOVWU	R0, 4(R3)
	CMP	R3, R4
	BNE	clrmach

	MOVW	R0, R(USER)
	MOVW	R0, 0(R(MACH))

	/* zero bss */
	MOVW	$edata(SB), R3
	MOVW	$end(SB), R4
	ADD	$4, R4
	SUBCC	R3, R4
	BLE	skipz
	SRAW	$2, R4
	MOVW	R4, CTR
	SUB	$4, R3
clrbss:
zero:
	MOVWU	R0, 4(R3)
	CMP	R3, R4
	BNE	clrbss
	BDNZ	zero
skipz:

	/* off to main */
	BL	main(SB)
	BR	0(PC)


TEXT	kernelmmu(SB), $0
/*
 * on return from this function we will be running in virtual mode.
 * We setup two TLB entries:
 * 1) map the first 8Mb of RAM to KZERO
 * 2) map the region that contains the IMMR
 */
TEXT	mmuinit0(SB), $0
	/* reset all the tlbs */
	TLBIA

	/* dont use CASID yet - set to zero for now */
	MOVW	$0, R4
	MOVW	R4, SPR(M_CASID)
	
	/* set Ks = 0 Kp = 1 for all acess groups */
	/* set Ks = 0 Kp = 1 for all access groups */
	MOVW	$0x55555555, R4
	MOVW	R4, SPR(MI_AP)
	MOVW	R4, SPR(MD_AP)

	/*
	 * set:
	 *  PowerPC mode
	 *  Page protection mode - no 1K pages
	 *  ~CI when MMU is disbaled
	 *  WT when DMMU is disbaled - this will change
	 *  disable protected TLB for the momment
	 *  ignore user/supervisor state when looking for TLB
	 *  set first tlb entry to 28 - first lockable entry
	 *  GPM = 0: PowerPC mode
	 *  PPM = 0: Page protection mode - no 1K pages
	 *  CIDEF = 0: cache enable when MMU disabled
	 *  WTDEF = 0: write back when MMU is disbaled
	 *  RSV2 = 0: no reserved entries
	 *	TWAM = 0: don't use table walk assit
	 *  PPCS = 0: not used in PowerPC mode
	 *	INDX = 0: start at first entry
	 */
	MOVW	$((31<<8)), R4
	MOVW	R4, SPR(MI_CTR)	/* i-mmu control */
	ISYNC
	MOVW	$((31<<8)), R4
	MOVW	R4, SPR(MD_CTR)	/* d-mmu control */
	ISYNC

	/* map various things 1:1 */
	MOVW	$tlbtab(SB), R4
	MOVW	$tlbtabe(SB), R5
	SUB	R4, R5
	MOVW	$(3*4), R6
	DIVW	R6, R5
	SUB	$4, R4
	MOVW	R5, CTR
ltlb:
	MOVWU	4(R4), R5
	MOVW	R5, SPR(MD_EPN)
	MOVW	R5, SPR(MI_EPN)
	MOVWU	4(R4), R5
	MOVW	R5, SPR(MI_TWC)
	MOVW	R5, SPR(MD_TWC)
	MOVWU	4(R4), R5
	MOVW	R5, SPR(MD_RPN)
	MOVW	R5, SPR(MI_RPN)
	BDNZ	ltlb

	/* lock kernel entries in tlb - also reset tlb index*/
	MOVW	$(MMURSV4), R4
	MOVW	$0, R4
	MOVW	R4, SPR(MI_CTR)	/* i-mmu control */
	ISYNC
	MOVW	$(MMURSV4), R4
	MOVW	$0, R4
	MOVW	R4, SPR(MD_CTR)	/* d-mmu control */
	ISYNC

	/* enable i-cache */
	MOVW	$(1<<25), R4
	MOVW	R4, SPR(IC_CST)
	ISYNC

 	/* enable d-cache 	*/
	MOVW	$(1<<25), R4
	MOVW	R4, SPR(DC_CST)
	ISYNC
	/*
	 * map 8Mb of ram at 0 -> KZERO, cached, writeback, shared
	 */
	MOVW	$(KZERO|MMUEV), R4
	MOVW	R4, SPR(MD_EPN)
	MOVW	R4, SPR(MI_EPN)
	MOVW	$(MMUPS8M|MMUV), R4		/* |MMUWT */
	MOVW	R4, SPR(MD_TWC)
	MOVW	R4, SPR(MI_TWC)
	MOVW	$(0|MMUPP|MMUSPS|MMUSH|MMUV), R4
	MOVW	R4, SPR(MD_RPN)
	MOVW	R4, SPR(MI_RPN)

 	/* enable MMU */
	/*
	 * map 8mb IO at INTMEM->INTMEM, cache inhibit, shared
	 */
	MOVW	$(INTMEM|MMUEV), R4
	MOVW	R4, SPR(MD_EPN)
	MOVW	$(MMUPS8M|MMUWT|MMUV), R4
	MOVW	R4, SPR(MD_TWC)
	MOVW	$(INTMEM|MMUPP|MMUSPS|MMUSH|MMUCI|MMUV), R4
	MOVW	R4, SPR(MD_RPN)

	/* enable MMU */
	MOVW	LR, R3
	OR	$KZERO, R3
	MOVW	R3, SPR(SRR0)
	MOVW	MSR, R4
	OR	$(MSR_IR|MSR_DR), R4
	MOVW	R4, MSR
	ISYNC
	MOVW	R4, SPR(SRR1)
	RFI	/* resume in kernel mode in caller */

	RETURN



@@ 282,57 345,12 @@ TEXT	gotolabel(SB), $-4

TEXT	touser(SB), $-4
	MOVW	$(UTZERO+32), R5	/* header appears in text */
	MOVW	$(MSR_EE|MSR_PR|MSR_ME|MSR_IP|MSR_IR|MSR_DR|MSR_RI), R4
	MOVW	$(MSR_EE|MSR_PR|MSR_ME|MSR_IR|MSR_DR|MSR_RI), R4
	MOVW	R4, SPR(SRR1)
	MOVW	R3, R1
	MOVW	R5, SPR(SRR0)
	RFI

/*
 * enter with stack set and mapped.
 * on return, SB (R2) has been set, and R3 has the Ureg*,
 * the MMU has been re-enabled, kernel text and PC are in KSEG,
 * R(MACH) has been set, and R0 contains 0.
 *
 * this can be simplified in the Inferno regime
 */
TEXT	saveureg(SB), $-4
/*
 * save state
 */
	MOVMW	R2, 48(R1)	/* r2:r31 */
	MOVW	$setSB(SB), R2
	MOVW	$mach0(SB), R(MACH)
	MOVW	12(R(MACH)), R(USER)
	MOVW	SPR(SAVER1), R4
	MOVW	R4, 44(R1)
	MOVW	SPR(SAVER0), R5
	MOVW	R5, 40(R1)
	MOVW	CTR, R6
	MOVW	R6, 36(R1)
	MOVW	XER, R4
	MOVW	R4, 32(R1)
	MOVW	CR, R5
	MOVW	R5, 28(R1)
	MOVW	SPR(SAVELR), R6	/* LR */
	MOVW	R6, 24(R1)
	/* pad at 20(R1) */
	/* old PC(16) and status(12) saved earlier */
	MOVW	SPR(SAVEXX), R0
	MOVW	R0, 8(R1)	/* cause/vector */
	ADD	$8, R1, R3	/* Ureg* */
	STWCCC	R3, (R1)	/* break any pending reservations */
	MOVW	$0, R0	/* compiler/linker expect R0 to be zero */

	MOVW	MSR, R5
/*	OR	$(MSR_IR|MSR_DR), R5	/* enable MMU */
	MOVW	R5, SPR(SRR1)
	MOVW	LR, R31
/*	OR	$KZERO, R31	/* return PC in KSEG0 */
	MOVW	R31, SPR(SRR0)
	SYNC
	ISYNC
	RFI	/* returns to trap handler */

TEXT	icflush(SB), $-4	/* icflush(virtaddr, count) */
	MOVW	n+4(FP), R4


@@ 349,7 367,6 @@ icf0:	ICBI	(R5)
	RETURN

TEXT	dcflush(SB), $-4	/* dcflush(virtaddr, count) */
	SYNC
	MOVW	n+4(FP), R4
	RLWNM	$0, R3, $~(CACHELINESZ-1), R5
	CMP	R4, $0


@@ 362,15 379,13 @@ TEXT	dcflush(SB), $-4	/* dcflush(virtaddr, count) */
dcf0:	DCBF	(R5)
	ADD	$CACHELINESZ, R5
	BDNZ	dcf0
	SYNC
	ISYNC
dcf1:
	RETURN

TEXT	tas(SB), $0
	SYNC
	MOVW	R3, R4
	MOVW	$0xdeaddead,R5
	MOVW	$0xdead,R5
tas1:
	DCBF	(R4)	/* fix for 603x bug */
	LWAR	(R4), R3


@@ 423,6 438,14 @@ TEXT	getmsr(SB), $0
	MOVW	MSR, R3
	RETURN

TEXT	putder(SB), $0
	MOVW	R3, SPR(DER)
	RETURN

TEXT	getder(SB), $0
	MOVW	SPR(DER), R3
	RETURN

TEXT	putmsr(SB), $0
	SYNC
	MOVW	R3, MSR


@@ 433,55 456,38 @@ TEXT	eieio(SB), $0
	EIEIO
	RETURN

TEXT	_flushmmu(SB), $0
TEXT	tlbflushall(SB), $0
	TLBIA
	RETURN

TEXT	_putmmu(SB), $0
	MOVW	MSR, R7
	MOVW	$~(MSR_DR|MSR_IR), R8
	AND	R7, R8
	MOVW	R8, MSR
	OR	$MMUEV, R3
	MOVW	R3, SPR(MD_EPN)
	MOVW	R3, SPR(MI_EPN)
	MOVW	$(MMUWT|MMUV), R5
	MOVW	R5, SPR(MI_TWC)
	MOVW	R5, SPR(MD_TWC)
	MOVW	4(FP), R6
	MOVW	R6, SPR(MD_RPN)
	MOVW	R6, SPR(MI_RPN)
	MOVW	SPR(MD_CTR), R3
	MOVW	R7, MSR
TEXT	tlbflush(SB), $0
	TLBIE	R3
	RETURN

TEXT	putcasid(SB), $-4
	MOVW	LR, R4
	MOVW	MSR, R5
	BL	nommu(SB)
	MOVW	R3,	SPR(M_CASID)
	MOVW	R4, SPR(SRR0)
	MOVW	R5, SPR(SRR1)
	RFI

TEXT	nommu(SB), $-4
	MOVW	LR, R6
	RLWNM	$0, R6, $~KZERO, R6
	MOVW	$(MSR_DR|MSR_IR), R8
	MOVW	R5, R7
	ANDN	R8, R7
	MOVW	R6, SPR(SRR0)
	MOVW	R7, SPR(SRR1)
	RFI

TEXT	gotopc(SB), $0
	MOVW	R3, CTR
	MOVW	LR, R31	/* for trace back */
	BR	(CTR)

TEXT	firmware(SB), $0
	MOVW	MSR, R3
	MOVW	$(MSR_EE|MSR_ME), R4
	ANDN	R4, R3
	OR	$(MSR_IP), R3
	ISYNC
	MOVW	R3, MSR	/* turn off interrupts and machine checks */
	MSRSYNC
	MOVW	$(MSR_RI|MSR_IR|MSR_DR|MSR_ME), R4
	ANDN	R4, R3
	MOVW	R3, SPR(SRR1)
	MOVW	$(0xFF00<<16), R4
	MOVW	R4, SPR(IMMR)
	MOVW	$(0x0800<<16), R4
	MOVW	R4, SPR(SRR0)	/* force bad address */
	MOVW	R0, SPR(149)	/* ensure checkstop on machine check */
	MOVW	R0, R1
	MOVW	R0, R2
	EIEIO
	ISYNC
	RFI

/*
 * byte swapping of arrays of long and short;
 * could possibly be avoided with more changes to drivers


@@ 532,79 538,244 @@ TEXT	lesets(SB), $0
	MOVHBR	R4, (R3)
	RETURN

/*
 * ITLB miss
 *	avoid references that might need the right SB value;
 *	IR and DR are off.
 */

TEXT	itlbmiss(SB), $-4
	MOVW	R1, SPR(M_TW)
	MOVW	SPR(SRR0), R1	/* instruction miss address */
	MOVW	R1, SPR(MD_EPN)
	MOVW	SPR(M_TWB), R1	/* level one pointer */
	MOVW	(R1), R1
	MOVW	R1, SPR(MI_TWC)	/* save level one attributes */
	MOVW	R1, SPR(MD_TWC)	/* save base and attributes */
	MOVW	SPR(MD_TWC), R1	/* level two pointer */
	MOVW	(R1), R1	/* level two entry */
	MOVW	R1, SPR(MI_RPN)	/* write TLB */
	MOVW	SPR(M_TW), R1
	RFI
	MOVW	R1, SPR(SAVER1)
	MOVW	R2, SPR(M_TW)

/*
 * DTLB miss
 *	avoid references that might need the right SB value;
 *	IR and DR are off.
 */
	to enable hardware break points
	MOVW	MSR, R1
	OR		$(MSR_RI), R1
	MOVW	R1, MSR
	ISYNC	
*/

	/* m->tlbfault++ */
	MOVW	$(MACHADDR&~KZERO), R1		/* m-> */
	MOVW	20(R1), R2	
	ADD		$1, R2
	MOVW	R2, 20(R1)

	MOVW	CR, R2
	MOVW	SPR(MI_EPN), R1
	MOVW	R1, CR
	BC	4,0,itlblookup
	/*
	 * map ram
	 */
	MOVW	R2, CR
	MOVW	$(MMUPS8M|MMUV), R2
	MOVW	R2, SPR(MI_TWC)
	RLWNM	$0, R1, $0x7f800000, R1
	OR	$(MMUPP|MMUSPS|MMUSH|MMUV), R1
	MOVW	R1, SPR(MI_RPN)
	MOVW	SPR(M_TW), R2
	MOVW	SPR(SAVER1), R1
	RFI

itlblookup:
	MOVW	R0, SPR(SAVER0)
	MOVW	R3, SPR(SAVEXX)

	/*
	 * R1 = 20 bits of addr | 8 bits of junk | 4 bits of asid
	 * calulate ((x>>9)^(x>>21)^(x<<11)) & (0xfff<<3)
	 * note (x>>21)^(x<<11) = rotate left 11
	 */
	RLWNM	$(32-9), R1, $(0xfff<<3), R3
	RLWNM	$11, R1, $(0xfff<<3), R1
	XOR		R1, R3, R1
	MOVW	$(MACHADDR&~KZERO), R3	/* m-> */
	MOVW	16(R3), R3				/* m->stb */
	RLWNM	$0, R3, $~KZERO, R3		/* PADDR(m->stb) */
	ADD		R1, R3
	MOVW	4(R3), R0
	MOVW	0(R3), R3
	MOVW	SPR(MI_EPN), R1
	RLWNM	$20, R1, $0xffffff, R1
	RLWNM	$12, R1, $~0, R1
	CMP		R3, R1
	BNE		itlbtrap
	MOVW	R2, CR
	MOVW	$(MMUV), R1
	MOVW	R1, SPR(MI_TWC)
	MOVW	R0, SPR(MI_RPN)
	MOVW	SPR(SAVEXX), R3
	MOVW	SPR(M_TW), R2
	MOVW	SPR(SAVER1), R1
	MOVW	SPR(SAVER0), R0
	RFI
itlbtrap:
	MOVW	R2, CR

	MOVW	$(MACHADDR&~KZERO), R2	/* m-> */
	MOVW	R1, 32(R2)
	MOVW	R3, 36(R2)

	MOVW	SPR(SAVEXX), R3
	MOVW	SPR(M_TW), R2
	MOVW	LR, R0
	MOVW	R0, SPR(SAVELR)
	MOVW	$0x1100, R0
	BR	traps


TEXT	dtlbmiss(SB), $-4
	MOVW	R1, SPR(M_TW)
	MOVW	SPR(M_TWB), R1	/* level one pointer */
	MOVW	(R1), R1	/* level one entry */
	MOVW	R1, SPR(MD_TWC)	/* save base and attributes */
	MOVW	SPR(MD_TWC), R1	/* level two pointer */
	MOVW	(R1), R1	/* level two entry */
	MOVW	R1, SPR(MD_RPN)	/* write TLB */
	MOVW	SPR(M_TW), R1

	MOVW	R1, SPR(SAVER1)
	MOVW	R2, SPR(M_TW)
/*
	to enable hardware break points
	MOVW	MSR, R1
	OR		$(MSR_RI), R1
	MOVW	R1, MSR
	ISYNC
*/	

	/* m->tlbfault++ */
	MOVW	$(MACHADDR&~KZERO), R1		/* m-> */
	MOVW	20(R1), R2	
	ADD		$1, R2
	MOVW	R2, 20(R1)

	MOVW	CR, R2
	MOVW	SPR(MD_EPN), R1
	MOVW	R1, CR
	BC	4,0,dtlblookup
	BC	12,1,dtlbio
	/*
	 * map ram
	 */
	MOVW	R2, CR
	MOVW	$(MMUPS8M|MMUV), R2
	MOVW	R2, SPR(MD_TWC)
	RLWNM	$0, R1, $0x7f800000, R1
	OR	$(MMUPP|MMUSPS|MMUSH|MMUV), R1
	MOVW	R1, SPR(MD_RPN)
	MOVW	SPR(M_TW), R2
	MOVW	SPR(SAVER1), R1
	RFI
dtlbio:
	/*
	 * map io
	 */
	MOVW	R2, CR
	MOVW	$(MMUPS8M|MMUWT|MMUV), R2
	MOVW	R2, SPR(MD_TWC)
	RLWNM	$0, R1, $0xff800000, R1
	OR	$(MMUPP|MMUSPS|MMUSH|MMUCI|MMUV), R1
	MOVW	R1, SPR(MD_RPN)
	MOVW	SPR(M_TW), R2
	MOVW	SPR(SAVER1), R1
	RFI
dtlblookup:
	MOVW	R0, SPR(SAVER0)
	MOVW	R3, SPR(SAVEXX)

	/*
	 * R1 = 20 bits of addr | 8 bits of junk | 4 bits of asid
	 * calulate ((x>>9)^(x>>21)^(x<<11)) & (0xfff<<3)
	 * note (x>>21)^(x<<11) = rotate left 11
	 */
	RLWNM	$(32-9), R1, $(0xfff<<3), R3
	RLWNM	$11, R1, $(0xfff<<3), R1
	XOR		R1, R3, R1
	MOVW	$(MACHADDR&~KZERO), R3	/* m-> */
	MOVW	16(R3), R3				/* m->stb */
	RLWNM	$0, R3, $~KZERO, R3		/* PADDR(m->stb) */
	ADD	R1,R3,R3
	MOVW	4(R3), R0
	MOVW	0(R3), R3
	MOVW	SPR(MD_EPN), R1
	RLWNM	$20, R1, $0xffffff, R1
	RLWNM	$12, R1, $~0, R1
	CMP		R3, R1
	BNE		dtlbtrap
	MOVW	$(MMUV), R1
	MOVW	R1, SPR(MD_TWC)
	MOVW	R0, SPR(MD_RPN)
	MOVW	R2, CR
	MOVW	SPR(SAVEXX), R3
	MOVW	SPR(M_TW), R2
	MOVW	SPR(SAVER1), R1
	MOVW	SPR(SAVER0), R0
	RFI
dtlbtrap:
	MOVW	R2, CR

	MOVW	$(MACHADDR&~KZERO), R2	/* m-> */
	MOVW	R1, 32(R2)
	MOVW	R3, 36(R2)

	MOVW	SPR(MD_EPN), R1
	MOVW	$(MACHADDR&~KZERO), R3	/* m-> */
	MOVW	R1, 24(R3)				/* save dar */
	MOVW	SPR(SAVEXX), R3
	MOVW	SPR(M_TW), R2
	MOVW	LR, R0
	MOVW	R0, SPR(SAVELR)
	MOVW	$0x1200, R0
	BR	traps

TEXT	dtlberror(SB), $-4
	MOVW	R0, SPR(SAVER0)
	MOVW	R1, SPR(SAVER1)
	MOVW	LR, R0
	MOVW	R0, SPR(SAVELR)
	MOVW	$(MACHADDR&~KZERO), R1		/* m-> */
	MOVW	SPR(DAR), R0
	MOVW	R0, 24(R1)				/* save dar */
	MOVW	SPR(DSISR), R0
	MOVW	R0, 28(R1)				/* save dsisr */
	MOVW	$0x1400, R0
	BR	traps

/*
 * traps force memory mapping off.
 * the following code has been executed at the exception
 * vector location
 *	MOVW R0, SPR(SAVER0)
 *	MOVW LR, R0
 *	MOVW R0, SPR(SAVELR) 
 *	bl	trapvec(SB)
 */
TEXT	trapvec(SB), $-4
traps:
	MOVW	LR, R0

	MOVW	R0, SPR(SAVEXX)	/* vector */
	MOVW	R1, SPR(SAVER1)
	MOVW	CR, R1
	MOVW	MSR, R0
	OR	$(MSR_DR|MSR_IR), R0		/* make data space usable */
	MOVW	R0, MSR
	MOVW	SPR(SRR0), R0	/* save SRR0/SRR1 now, since DLTB might be missing stack page */
	MOVW	R0, LR
traps:
	MOVW	R0, SPR(SAVEXX)	/* vector */

/*
	to enable hardware break points
	MOVW	MSR, R1
	OR		$(MSR_RI), R1
	MOVW	R1, MSR
	ISYNC
*/	

	/* did we come from user space */
	MOVW	SPR(SRR1), R0
	ANDCC	$MSR_PR, R0
	BEQ	ktrap
	MOVW	CR, R1
	MOVW	R0, CR
	BC	4,17,ktrap
	
	/* switch to kernel stack */
	MOVW	R1, CR
	MOVW	R2, R0
	MOVW	$setSB(SB), R2
	MOVW	$mach0(SB), R1	/* m-> */
	MOVW	R0, R2
	MOVW	12(R1), R1	/* m->proc */
	MOVW	8(R1), R1	/* m->proc->kstack */
	MOVW	$(MACHADDR&~KZERO), R1	/* PADDR(m->) */
	MOVW	12(R1), R1				/* m->proc  */
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc) */
	MOVW	8(R1), R1				/* m->proc->kstack */
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc->kstack) */
	ADD	$(KSTACK-UREGSIZE), R1
	BR	trap1
	BL	saveureg(SB)
	BL	trap(SB)
	BR	restoreureg
ktrap:
	MOVW	R1, CR
	MOVW	SPR(SAVER1), R1
	RLWNM	$0, R1, $~KZERO, R1		/* PADDR(m->proc->kstack) */
	SUB	$UREGSPACE, R1
trap1:
	MOVW	SPR(SRR1), R0
	MOVW	R0, 12(R1)	/* save status: could take DLTB miss here */
	MOVW	LR, R0
	MOVW	R0, 16(R1)	/* old PC */
	BL	saveureg(SB)
	BL	trap(SB)
	BR	restoreureg


@@ 612,6 783,8 @@ trap1:
TEXT	intrvec(SB), $-4
	MOVW	LR, R0

	BR	0(PC)

/*
 * map data virtually and make space to save
 */


@@ 641,6 814,54 @@ TEXT	intrvec(SB), $-4
	MOVW	R5, isavetbl(SB)

	BL	intr(SB)
/*
 * enter with stack set and mapped.
 * on return, SB (R2) has been set, and R3 has the Ureg*,
 * the MMU has been re-enabled, kernel text and PC are in KSEG,
 * R(MACH) has been set, and R0 contains 0.
 *
 */
TEXT	saveureg(SB), $-4
/*
 * save state
 */
	MOVMW	R2, 48(R1)	/* r2:r31 */
	MOVW	$setSB(SB), R2
	MOVW	$(MACHADDR&~KZERO), R(MACH)
	MOVW	12(R(MACH)), R(USER)
	MOVW	$MACHADDR, R(MACH)
	MOVW	SPR(SAVER1), R4
	MOVW	R4, 44(R1)
	MOVW	SPR(SAVER0), R5
	MOVW	R5, 40(R1)
	MOVW	CTR, R6
	MOVW	R6, 36(R1)
	MOVW	XER, R4
	MOVW	R4, 32(R1)
	MOVW	CR, R5
	MOVW	R5, 28(R1)
	MOVW	SPR(SAVELR), R6	/* LR */
	MOVW	R6, 24(R1)
	/* pad at 20(R1) */
	MOVW	SPR(SRR0), R0
	MOVW	R0, 16(R1)				/* old PC */
	MOVW	SPR(SRR1), R0
	MOVW	R0, 12(R1)				/* old status */
	MOVW	SPR(SAVEXX), R0
	MOVW	R0, 8(R1)	/* cause/vector */
	ADD	$8, R1, R3	/* Ureg* */
	OR	$KZERO, R3	/* fix ureg */
	STWCCC	R3, (R1)	/* break any pending reservations */
	MOVW	$0, R0	/* compiler/linker expect R0 to be zero */

	MOVW	MSR, R5
	OR	$(MSR_IR|MSR_DR|MSR_RI), R5	/* enable MMU */
	MOVW	R5, SPR(SRR1)
	MOVW	LR, R31
	OR	$KZERO, R31	/* return PC in KSEG0 */
	MOVW	R31, SPR(SRR0)
	OR	$KZERO, R1	/* fix stack pointer */
	RFI	/* returns to trap handler */

/*
 * restore state from Ureg and return from trap/interrupt


@@ 660,7 881,7 @@ restoreureg:
	MOVW	28(R1), R0
	MOVW	R0, CR	/* CR */
	MOVW	24(R1), R0
	MOVW	R0, SPR(SAVELR)	/* LR */
	MOVW	R0, LR
	/* pad, skip */
	MOVW	16(R1), R0
	MOVW	R0, SPR(SRR0)	/* old PC */


@@ 668,13 889,47 @@ restoreureg:
	MOVW	R0, SPR(SRR1)	/* old MSR */
	/* cause, skip */
	MOVW	44(R1), R1	/* old SP */
	MOVW	SPR(SAVELR), R0
	MOVW	R0, LR
	MOVW	SPR(SAVER0), R0
	RFI

TEXT	flash(SB), $-4
flash0:
	BL	powerupled(SB);
	MOVW	$0x100000, R5
	MOVW	R5, CTR
delay0:
	BDNZ	delay0
	BL	powerdownled(SB);
	MOVW	$0x100000, R5
	MOVW	R5, CTR
delay1:
	BDNZ	delay1
	BR		flash0

TEXT	powerupled(SB), $0

	MOVW	$INTMEM,R11
	MOVH	0x970(R11), R7
	MOVW	$0x100,R8
	OR	R8,R7
	MOVH	R7,0x970(R11)
	MOVH	0x976(R11), R7
	ANDN	R8,R7
	MOVH	R7,0x976(R11)
	RETURN

TEXT	powerdownled(SB), $0

	MOVW	$INTMEM,R11
	MOVH	0x970(R11), R7
	MOVW	$0x100,R8
	OR	R8,R7
	MOVH	R7,0x970(R11)
	MOVH	0x976(R11), R7
	OR	R8,R7
	MOVH	R7,0x976(R11)
	RETURN
	
GLOBL	mach0+0(SB), $MACHSIZE
GLOBL	spltbl+0(SB), $4
GLOBL	intrtbl+0(SB), $4
GLOBL	isavetbl+0(SB), $4

M mpc/main.c => mpc/main.c +97 -173
@@ 7,11 7,7 @@
#include	"init.h"
#include	"pool.h"

#define MAXCONF 32

char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;
static char **confenv = (char**)(CONFPARSED);

int	predawn = 1;



@@ 23,13 19,17 @@ struct Bootargs
	uchar	chksum;
};

Conf	conf;
/*
 * software tlb simulation
 */
Softtlb stlb[MAXMACH][STLBSIZE];

static void options(void);
Conf	conf;

void
main(void)
{
	powerdownled();
	machinit();
	clockinit();
	confinit();


@@ 38,19 38,11 @@ main(void)
	printinit();
	cpminit();
	uartinstall();
print("hello world from kernel %ux %ux %ux\n", m->iomem->pddat, m->iomem->pddir, m->iomem->pdpar);
	mmuinit();

// turn on pcmcia
*(uchar*)(NVRAMMEM+0x100001) |= 0x60;

print("m->delayloop = %ld\n", m->delayloop);
	delayloopinit();
print("m->delayloop = %ld\n", m->delayloop);

	pageinit();
	procinit0();
	initseg();
	options();
	links();
	chandevreset();
	swapinit();


@@ 69,6 61,7 @@ machinit(void)
	m->delayloop = 20000;
	m->cputype = getpvr()>>16;
	m->iomem = KADDR(INTMEM);
	m->stb = &stlb[0][0];

	io = m->iomem;
	osc = 50;


@@ 78,24 71,39 @@ machinit(void)
	m->cpuhz = m->speed*MHz;	/* general system clock (cycles) */
	m->clockgen = osc*MHz;		/* clock generator frequency (cycles) */

	*(ushort*)&(io->memc[4].base) = 0x8060;
//	*(ushort*)&(io->memc[7].option) = 0xffe0;
	*(ushort*)&(io->memc[7].base) = 0xff00;
	active.machs = 1;
	active.exiting = 0;

	/* enable check stop reset */
	io->plprcrk = KEEP_ALIVE_KEY;	// unlock
	io->plprcr |= IBIT(24);		// enable checkstop reset
	putmsr(getmsr() | MSR_RI | MSR_ME);
//	putmsr(getmsr() & ~MSR_ME);
}


void
bootargs(ulong base)
char*
getconf(char *name)
{
print("bootargs = %ulx\n", base);
	USED(base);
	char **p, *q;
	int n;

	n = strlen(name);

	for(p = confenv; *p; p++) {
		q = *p;
		if(strncmp(q, name, n) == 0 && q[n] == '=')
			return q+n+1;
	}
	return 0;
}

void
init0(void)
{
	int i;
	char **p, *q, name[NAMELEN];
	int n;

print("init0\n");

	up->nerrlab = 0;



@@ 116,9 124,18 @@ init0(void)
			ksetenv("service", "cpu");
		else
			ksetenv("service", "terminal");
		for(i = 0; i < nconf; i++)
			if(confname[i] && confname[i][0] != '*')
				ksetenv(confname[i], confval[i]);
		
		for(p = confenv; *p; p++) {
			q = strchr(p[0], '=');
			if(q == 0)
				continue;
			n = q-p[0];
			if(n >= NAMELEN)
				n = NAMELEN-1;
			memmove(name, p[0], n);
			name[n] = 0;
			ksetenv(name, q+1);
		}
		poperror();
	}
	kproc("alarm", alarmkproc, 0);


@@ 162,9 179,6 @@ userinit(void)
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);
	k = kmap(pg);
	bootargs(VA(k));
	kunmap(k);

	/*
	 * Text


@@ 256,21 270,23 @@ confinit(void)
{
	int nbytes;
	ulong pa;
	char **p;

	/* fix up confenv */
	for(p = confenv; *p; p++)
		*p = KADDR(*p);

	conf.nmach = 1;		/* processors */
	conf.nproc = 60;	/* processes */

	// hard wire for now
	pa = 0xffd00000;		// leave 1 Meg for kernel
	nbytes = 2*1024*1024;	// leave room at the top as well
	pa = 0x200000;		// leave 2 Meg for kernel
	nbytes = 8*1024*1024;	// leave room at the top as well
	
	conf.npage0 = nbytes/BY2PG;
	conf.base0 = pa;
	
	pa = 0xfff04000;
	nbytes = 1024*1024 - 0x4000;

	conf.npage1 = nbytes/BY2PG;
	conf.npage1 = 0;
	conf.base1 = pa;

	conf.npage = conf.npage0 + conf.npage1;


@@ 279,8 295,8 @@ confinit(void)
	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;

	/* set up other configuration parameters */
	conf.nswap = 0; // conf.npage*3;
	conf.nswppo = 0; // 4096;
	conf.nswap = 0;
	conf.nswppo = 0; 
	conf.nimage = 20;

	conf.copymode = 0;		/* copy on write */


@@ 307,112 323,58 @@ getcfields(char* lp, char** fields, int n, char* sep)
	return i;
}

static char BOOTARGS[] = 
		"ether0=type=SCC port=1 ea=000086353a6b\r\n"
		"ether1=type=589E port=0x300\r\n";

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

	/*
	 *  parse configuration args from dos file plan9.ini
	 */
	ba = (Bootargs*)(NVRAMMEM+ 4*1024);
	if(ba->chksum == nvcsum(ba->args, sizeof(ba->args))) {
		cp = smalloc(strlen(ba->args)+1);
		memmove(cp, ba->args, strlen(ba->args)+1);
	} else
		cp = BOOTARGS;
print("bootargs = %s\n", cp);

	/*
	 * 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)
{
	char cc[NAMELEN], *p, *q, *r;
	int n;

	sprint(cc, "%s%d", class, ctlrno);
	for(n = 0; n < nconf; n++){
		if(strncmp(confname[n], cc, NAMELEN))
			continue;
		isa->nopt = 0;
		p = confval[n];
		while(*p){
			while(*p == ' ' || *p == '\t')
				p++;
			if(*p == '\0')
				break;
			if(strncmp(p, "type=", 5) == 0){
				p += 5;
				for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
					if(*p == '\0' || *p == ' ' || *p == '\t')
						break;
					*q = *p++;
				}
				*q = '\0';

	p = getconf(cc);
	if(p == 0)
		return 0;
print("%s=%s\n", cc, p);	
	isa->nopt = 0;
	while(*p){
		while(*p == ' ' || *p == '\t')
			p++;
		if(*p == '\0')
			break;
		if(strncmp(p, "type=", 5) == 0){
			p += 5;
			for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
				if(*p == '\0' || *p == ' ' || *p == '\t')
					break;
				*q = *p++;
			}
			else if(strncmp(p, "port=", 5) == 0)
				isa->port = strtoul(p+5, &p, 0);
			else if(strncmp(p, "irq=", 4) == 0)
				isa->irq = strtoul(p+4, &p, 0);
			else if(strncmp(p, "mem=", 4) == 0)
				isa->mem = strtoul(p+4, &p, 0);
			else if(strncmp(p, "size=", 5) == 0)
				isa->size = strtoul(p+5, &p, 0);
			else if(strncmp(p, "freq=", 5) == 0)
				isa->freq = strtoul(p+5, &p, 0);
			else if(strncmp(p, "dma=", 4) == 0)
				isa->dma = strtoul(p+4, &p, 0);
			else if(isa->nopt < NISAOPT){
				r = isa->opt[isa->nopt];
				while(*p && *p != ' ' && *p != '\t'){
					*r++ = *p++;
					if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
						break;
				}
				*r = '\0';
				isa->nopt++;
			*q = '\0';
		}
		else if(strncmp(p, "port=", 5) == 0)
			isa->port = strtoul(p+5, &p, 0);
		else if(strncmp(p, "irq=", 4) == 0)
			isa->irq = strtoul(p+4, &p, 0);
		else if(strncmp(p, "mem=", 4) == 0)
			isa->mem = strtoul(p+4, &p, 0);
		else if(strncmp(p, "size=", 5) == 0)
			isa->size = strtoul(p+5, &p, 0);
		else if(strncmp(p, "freq=", 5) == 0)
			isa->freq = strtoul(p+5, &p, 0);
		else if(strncmp(p, "dma=", 4) == 0)
			isa->dma = strtoul(p+4, &p, 0);
		else if(isa->nopt < NISAOPT){
			r = isa->opt[isa->nopt];
			while(*p && *p != ' ' && *p != '\t'){
				*r++ = *p++;
				if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1)
					break;
			}
			while(*p && *p != ' ' && *p != '\t')
				p++;
			*r = '\0';
			isa->nopt++;
		}
		return 1;
		while(*p && *p != ' ' && *p != '\t')
			p++;
	}
	return 0;
	return 1;
}

int


@@ 437,41 399,3 @@ cistrcmp(char *a, char *b)
	return 0;
}

int
cistrncmp(char *a, char *b, int n)
{
	unsigned ac, bc;

	while(n > 0){
		ac = *a++;
		bc = *b++;
		n--;

		if(ac >= 'A' && ac <= 'Z')
			ac = 'a' + (ac - 'A');
		if(bc >= 'A' && bc <= 'Z')
			bc = 'a' + (bc - 'A');

		ac -= bc;
		if(ac)
			return ac;
		if(bc == 0)
			break;
	}

	return 0;
}

/* dummy - not used */

void
iofree(int)
{
}

int
ioalloc(int, int, int, char*)
{
	return 1;
}


M mpc/mem.h => mpc/mem.h +25 -17
@@ 83,12 83,6 @@
#define	MACH		30		/* R30 is m-> */
#define	USER		29		/* R29 is up-> */

/*
 * Fundamental addresses
 */
#define	MACHADDR	((long)&mach0)

#define	UREGSIZE	((8+32)*4)

/*
 *  virtual MMU


@@ 100,10 94,17 @@
#define PPN(x)		((x)&~(BY2PG-1))

/*
 * Fundamental addresses
 */
#define	MACHADDR	(KTZERO-MAXMACH*MACHSIZE)
#define	MACHP(n)	((Mach *)(MACHADDR+(n)*MACHSIZE))

#define	UREGSIZE	((8+32)*4)

/*
 * MMU
 */

#ifdef notdef
/* L1 table entry and Mx_TWC flags */
#define PTEWT		(1<<1)	/* write through */
#define PTE4K		(0<<2)


@@ 119,11 120,18 @@
#define	PTEKERNEL	(0<<2)
#define	PTEUSER		(1<<2)
#define PTESIZE		(1<<7)
#endif

#define	NTLBPID		16
#define	TLBPID(n)	((n)&(NTLBPID-1))

/* soft tlb */
#define	STLBLOG		12
#define	STLBSIZE	(1<<STLBLOG)

/*
 *  portable MMU bits for fault.c - though still machine specific
 */
#define PTEVALID	(MMUPP|MMUSH|MMUV)
#define PTEVALID	(MMUPP|MMUV)
#define PTEWRITE	(2<<10)
#define	PTERONLY	(3<<10)
#define	PTEUNCACHED	(1<<4)


@@ 167,26 175,26 @@
#define	UZERO		0			/* base of user address space */
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	KZERO		0x80000000		/* base of kernel address space */
#define	KTZERO		0xffc00000		/* first address in kernel text */
#define	KTZERO		0x80010000		/* first address in kernel text */
#define	USTKTOP		(KZERO-BY2PG)		/* byte just beyond user stack */
#define	USTKSIZE	(16*1024*1024)		/* size of user stack */
#define	TSTKTOP		(USTKTOP-USTKSIZE)	/* end of new stack in sysexec */
#define TSTKSIZ 	100
#define	CONFPARSED	(KZERO+0x2000)

#define	INTMEM		0x80000000
#define	ISAMEM		0x80100000
#define	FLASHMEM	0xff000000
#define	INTMEM		0xff000000
#define	ISAMEM		0xfe000000
#define	FLASHMEM	0xff200000
#define	SACMEM		FLASHMEM + 0x80000
#define	NVRAMMEM	0x80600000
#define DRAMMEM		0xff800000		/* to 0xffffffff: 8 Meg */
#define	NVRAMMEM	0xfc000000
#define DRAMMEM		0x80000000

#define	SIRAM	(INTMEM+0xC00)
#define	LCDCOLR	(INTMEM+0xE00)
#define	DPRAM	(INTMEM+0x2000)
#define	DPLEN1	0x200
#define	DPLEN2	0x400
#define	DPLEN3	0x800
#define	DPBASE	(DPRAM+DPLEN1)
#define	DPBASE	(DPRAM+DPLEN3)

#define	SCC1P	(INTMEM+0x3C00)
#define	I2CP	(INTMEM+0x3C80)

A mpc/memspeed.c => mpc/memspeed.c +53 -0
@@ 0,0 1,53 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

char	d0[1000008], d1[1000008];

static void	test(int size, int align);


void
memspeed()
{
	int j;

	spllo();

	memmove(d0, d1, sizeof(d0));
	
	for(j = 0; j<8; j++)
		test(12, j);
	for(j = 0; j<8; j++)
		test(100, j);
	for(j = 0; j<8; j++)
		test(400, j);
	for(j = 0; j<8; j++)
		test(1000, j);
	for(j = 0; j<8; j++)
		test(10000, j);
	for(j = 0; j<8; j++)
		test(100000, j);
	for(j = 0; j<8; j++)
		test(1000000, j);
}

static void
test(int size, int align)
{
	int n;
	int t;

	t = -TK2MS(m->ticks);
	n = 10000000/size;
	while(n) {
		memmove(d0+align, d1, size);
		n--;
	}
	t += TK2MS(m->ticks);
	print("size = %d align = %d KB/s %d %d\n", size, align, 10000000/t, t);
}


M mpc/mmu.c => mpc/mmu.c +122 -15
@@ 5,46 5,154 @@
#include	"fns.h"
#include	"io.h"

#define TLBINVLAID	KZERO

void
mmuinit(void)
{
	int i;

	print("mmuinit\n");
	kernelmmu();
	for(i=0; i<STLBSIZE; i++)
		m->stb[i].virt = TLBINVLAID;
}

void
flushmmu(void)
{
//	print("flushmmu()\n");
	_flushmmu();
	int x;

if(0)print("flushmmu(%d)\n", up->pid);
	x = splhi();
	up->newtlb = 1;
	mmuswitch(up);
	splx(x);
}

/*
 * called with splhi
 */
void
mmuswitch(Proc *p)
{
	int tp;

if(0)print("mmuswitch()\n");
	if(p->newtlb) {
		memset(p->pidonmach, 0, sizeof p->pidonmach);
		p->newtlb = 0;
	}
	tp = p->pidonmach[m->machno];
	putcasid(tp);
}

void
mmuswitch(Proc*)
mmurelease(Proc* p)
{
	flushmmu();
if(0)print("mmurelease(%d)\n", p->pid);
	memset(p->pidonmach, 0, sizeof p->pidonmach);
}

void
mmurelease(Proc* proc)
purgetlb(int pid)
{
	USED(proc);
	int i, mno;
	Proc *sp, **pidproc;
	Softtlb *entry, *etab;

if(0)print("purgetlb: pid = %d\n", pid);
	m->tlbpurge++;
	/*
	 * find all pid entries that are no longer used by processes
	 */
	mno = m->machno;
	pidproc = m->pidproc;
	for(i=1; i<NTLBPID; i++) {
		sp = pidproc[i];
		if(sp && sp->pidonmach[mno] != i)
			pidproc[i] = 0;
	}

	/*
	 * shoot down the one we want
	 */
	sp = pidproc[pid];
	if(sp != 0)
		sp->pidonmach[mno] = 0;
	pidproc[pid] = 0;

	/*
	 * clean out all dead pids from the stlb;
	 */
	entry = m->stb;
	for(etab = &entry[STLBSIZE]; entry < etab; entry++)
		if(pidproc[TLBPID(entry->virt)] == 0)
			entry->virt = TLBINVLAID;

	/*
	 * clean up the hardware
	 */
	tlbflushall();
}

int
newtlbpid(Proc *p)
{
	int i, s;
	Proc **h;

	i = m->lastpid;
	h = m->pidproc;
	for(s = 0; s < NTLBPID; s++) {
		i++;
		if(i >= NTLBPID)
			i = 1;
		if(h[i] == 0)
			break;
	}

	if(h[i]) {
		i = m->purgepid+1;
		if(i >= NTLBPID)
			i = 1;
		 m->purgepid = i;
		purgetlb(i);
	}

	if(h[i] != 0)
		panic("newtlb");

	m->pidproc[i] = p;
	p->pidonmach[m->machno] = i;
	m->lastpid = i;
if(0)print("newtlbpid: pid=%d = tlbpid = %d\n", p->pid, i);
	return i;
}

void
putmmu(ulong va, ulong pa, Page *pg)
{
	int x, r;
	char *ctl;
	int tp;
	ulong h;

//if((va&0x8000000) == 0)
//print("putmmu va=%ux pa=%ux\n", va, pa);
	x = splhi();
	r = _putmmu(va, pa);
	qlock(&m->stlblk);

	tp = up->pidonmach[m->machno];
	if(tp == 0) {
		tp = newtlbpid(up);
		putcasid(tp);
	}

	h = ((va>>12)^(va>>24)^(tp<<8)) & 0xfff;
	m->stb[h].virt = va|tp;
	m->stb[h].phys = pa;
	tlbflush(va);

	qunlock(&m->stlblk);

	ctl = &pg->cachectl[m->machno];
if(0)print("putmmu tp=%d h=%d va=%ux pa=%ux ctl=%x\n", tp, h,va, pa, *ctl);
	switch(*ctl) {
	default:
		panic("putmmu: %d\n", *ctl);


@@ 52,14 160,13 @@ putmmu(ulong va, ulong pa, Page *pg)
	case PG_NOFLUSH:
		break;
	case PG_TXTFLUSH:
		dcflush((void*)pg->va, BY2PG);
		icflush((void*)pg->va, BY2PG);
		*ctl = PG_NOFLUSH;
		break;
	case PG_NEWCOL:
		dcflush((void*)pg->va, BY2PG);
print("PG_NEWCOL!!\n");
		*ctl = PG_NOFLUSH;
		break;
	}

	splx(x);
}

A mpc/ms.c => mpc/ms.c +82 -0
@@ 0,0 1,82 @@
#include <u.h>
#include <libc.h>

char	d0[1000008], d1[1000008];

void	test(int size, int align);

memtest(char *pp, int n)
{
	static int seed = 0;
	ulong *p, *ep;
	ulong x;

if(seed % 100 == 0)
print("memtest seed = %d\n", seed);

	p = (ulong*)pp;
	ep = (ulong*)(pp+n);

	x = seed;
	while(p < ep) {
		*p++ = x;
		x *= 1103515245;
	}

	x = seed;
	p = (ulong*)pp;
	ep = (ulong*)(pp+n);
	while(p < ep) {
		if(*p++ != x) {
			print("error %ux!!\n", ((char*)p) - pp);
			return;
		}
		x *= 1103515245;
	}
	seed++;
}

void
main()
{
	int j;

	memmove(d0, d1, sizeof(d0));
	
	for(j=0; j<10; j++) {
		memtest(d0, sizeof(d0));
	}

	for(j = 0; j<8; j++)
		test(12, j);
	for(j = 0; j<8; j++)
		test(100, j);
	for(j = 0; j<8; j++)
		test(400, j);
	for(j = 0; j<8; j++)
		test(1000, j);
	for(j = 0; j<8; j++)
		test(10000, j);
	for(j = 0; j<8; j++)
		test(100000, j);
	for(j = 0; j<8; j++)
		test(1000000, j);

	exits(0);
}

void
test(int size, int align)
{
	int n;
	int t;

	t = -times(0);
	n = 10000000/size;
	while(n) {
		memmove(d0+align, d1, size);
		n--;
	}
	t += times(0);
	print("size = %d align = %d KB/s %d %d\n", size, align, 10000000/t, t);
}

M mpc/nocache.c => mpc/nocache.c +0 -1
@@ 15,7 15,6 @@ cinit(void)
void
copen(Chan *c)
{
print("copen called!\n");
	USED(c);
}


M mpc/sh.c => mpc/sh.c +1 -1
@@ 57,7 57,7 @@ main(int argc, char *argv[])
	open("#c/cons", OWRITE);
	open("#c/cons", OWRITE);
	
	print("hello world\n");
	print("hello world from sh\n");

	if(argc>1 && strcmp(argv[1], "-t")==0)
		tflag++;

A mpc/spi.c => mpc/spi.c +521 -0
@@ 0,0 1,521 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

typedef struct SPIparam SPIparam;
struct SPIparam {
	ushort	rbase;
	ushort	tbase;
	uchar	rfcr;
	uchar	tfcr;
	ushort	mrblr;
	ulong	rstate;
	ulong	rptr;
	ushort	rbptr;
	ushort	rcnt;
	ulong	rtmp;
	ulong	tstate;
	ulong	tptr;
	ushort	tbptr;
	ushort	tcnt;
	ulong	ttmp;
};

enum {
	Nrdre		= 2,	/* receive descriptor ring entries */
	Ntdre		= 2,	/* transmit descriptor ring entries */

	Rbsize		= 8,		/* ring buffer size (+3 for PID+CRC16) */
	Bufsize		= (Rbsize+7)&~7,	/* aligned */
};

enum {
	/* spi-specific BD flags */
	BDContin=	1<<9,	/* continuous mode */
	BDrxov=		1<<1,	/* overrun */
	BDtxun=		1<<1,	/* underflow */
	BDme=		1<<0,	/* multimaster error */
	BDrxerr=		BDrxov|BDme,
	BDtxerr=		BDtxun|BDme,

	/* spmod */
	MLoop=	1<<14,	/* loopback mode */
	MClockInv= 1<<13,	/* inactive state of SPICLK is high */
	MClockPhs= 1<<12,	/* SPCLK starts toggling at beginning of transfer */
	MDiv16=	1<<11,	/* use BRGCLK/16 as input to SPI baud rate */
	MRev=	1<<10,	/* normal operation */
	MMaster=	1<<9,
	MSlave=	0<<9,
	MEnable=	1<<8,
	/* LEN, PS fields */

	/* spie */
	MME =	1<<5,
	TXE =	1<<4,
	RES =	1<<3,
	BSY =	1<<2,
	TXB =	1<<1,
	RXB =	1<<0,
};

/*
 * software structures
 */
typedef struct Ctlr Ctlr;

struct Ctlr {
	QLock;
	int	init;
	SPI*	spi;
	SPIparam*	sp;

	int	rxintr;
	Rendez	ir;
	Ring;
};

static	Ctlr	spictlr[1];

static	void	interrupt(Ureg*, void*);

/*
 * test driver for SPI, host mode
 */
void
spireset(void)
{
	IMM *io;
	SPI *spi;
	SPIparam *sp;
	Ctlr *ctlr;

	io = m->iomem;
	sp = (SPIparam*)cpmparam(SPIP, sizeof(*sp));
	memset(sp, 0, sizeof(*sp));
	if(sp == nil){
		print("SPI: can't allocate new parameter memory\n");
		return;
	}

	spi = (SPI*)((ulong)m->iomem+0xAA0);
	ctlr = spictlr;

	/* step 1: select port pins */
	io->pbdir |= IBIT(30)|IBIT(29)|IBIT(28);
	io->pbpar |= IBIT(30)|IBIT(29)|IBIT(28);	/* SPICLK, SPIMOSI, SPIMISO */

	/* step 2: set CS pin - also disables SPISEL */
	io->pbpar &= ~(IBIT(31));
	io->pbdir |= IBIT(31);
	io->pbodr &= ~(IBIT(31));
	io->pbdat &= ~(IBIT(31));

	ctlr->spi = spi;
	ctlr->sp = sp;

	if(ioringinit(ctlr, Nrdre, Ntdre, Bufsize)<0)
		panic("spireset: ioringinit");

	/* step 3: configure rbase and tbase */
	sp->rbase = PADDR(ctlr->rdr);
	sp->tbase = PADDR(ctlr->tdr);

	/* step 4: do not issue InitRxTx command - due to microcode bug */

	/* step 5: */
	io->sdcr = 1;

	/* step 6: */
	sp->rfcr = 0x10;
	sp->tfcr = 0x10;

	/* step 7: */
	sp->mrblr = Bufsize;

	/* step 7.5: init other params because of bug in microcode */
	sp->rstate = 0;
	sp->rbptr = sp->rbase;
	sp->rcnt = 0;
	sp->tstate = 0;
	sp->tbptr = sp->tbase;
	sp->tcnt = 0;

	/* step 8-9: done by ioringinit */

	/* step 10: clear events */
	spi->spie = ~0;	

	/* step 11-12: enable interrupts  */
	intrenable(VectorCPIC+0x05, interrupt, spictlr, BUSUNKNOWN);
	spi->spim = ~0;

	/* step 13: enable in master mode, 8 bit chacters, slow clock */
	spi->spmode = MMaster|MRev|MDiv16|MEnable|(0x7<<4)|0xf;
print("spi->spmode = %ux\n", spi->spmode);
}

static void
interrupt(Ureg*, void *arg)
{
	int events;
	Ctlr *ctlr;
	SPI *spi;

	ctlr = arg;
	spi = ctlr->spi;
	events = spi->spie;
	spi->spie = events;
	print("SPI#%x\n", events);
}

void
spdump(SPIparam *sp)
{
	print("rbase = %ux\n", sp->rbase);
	print("tbase = %ux\n", sp->tbase);
	print("rfcr = %ux\n", sp->rfcr);
	print("tfcr = %ux\n", sp->tfcr);
	print("mrblr = %ux\n", sp->mrblr);
	print("rstate = %lux\n", sp->rstate);
	print("rptr = %lux\n", sp->rptr);
	print("rbptr = %ux\n", sp->rbptr);
	print("rcnt = %ux\n", sp->rcnt);
	print("rtmp = %ux\n", sp->rtmp);
	print("tstate = %lux\n", sp->tstate);
	print("tptr = %lux\n", sp->tptr);
	print("tbptr = %ux\n", sp->tbptr);
	print("tcnt = %ux\n", sp->tcnt);
	print("ttmp = %ux\n", sp->ttmp);
}

void
spitest(void)
{
	BD *dre;
	Block *b;
	int len;
	Ctlr *ctlr;
	ulong status;

	ctlr = spictlr;

	dre = &ctlr->tdr[ctlr->tdrh];
	if(dre->status & BDReady)
		panic("spitest: txstart");

print("dre->status %ux %ux\n", dre[0].status, dre[1].status);	
	b = allocb(4);
	b->wp[0] = 0xc0;
	b->wp[1] = 0x00;
	b->wp[2] = 0x00;
	b->wp[3] = 0x00;
	b->wp += 4;
	len = BLEN(b);
print("len = %d\n", len);
	dcflush(b->rp, len);
	if(ctlr->txb[ctlr->tdrh] != nil)
		panic("scc/ether: txstart");
	ctlr->txb[ctlr->tdrh] = b;
	dre->addr = PADDR(b->rp);
print("addr = %lux\n", PADDR(b->rp));
	dre->length = len;
	dre->status = (dre->status & BDWrap) | BDReady|BDInt|BDLast;
	eieio();
spdump(ctlr->sp);
m->iomem->pbdat |= IBIT(31);
microdelay(1);
	ctlr->spi->spcom = 1<<7;	/* transmit now */
print("cpcom = %ux\n", &ctlr->spi->spcom);
spdump(ctlr->sp);
	eieio();
	ctlr->ntq++;
	ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
print("going into loop %ux %ux\n", dre->status, ctlr->spi->spcom);
	while(dre->status&BDReady) {
print("ctrl->spi->spim = %ux %ux\n", ctlr->spi->spie, dre->status);
spdump(ctlr->sp);
		delay(10000);
	}
delay(100);
	dre = &ctlr->rdr[ctlr->rdrx];
	status = dre->status;
	len = dre->length;
print("%d status = %ux len=%d\n", ctlr->rdrx, status, len);
	b = iallocb(len);
	memmove(b->wp, KADDR(dre->addr), len);
	b->wp += len;
print("%ux %ux %ux %ux\n", b->rp[0], b->rp[1], b->rp[2], b->rp[3]);
	dcflush(KADDR(dre->addr), len);
	dre->status = (status & BDWrap) | BDEmpty | BDInt;
	ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
m->iomem->pbdat &= ~(IBIT(31));
microdelay(1);
}


void
spiinit(void)
{
	spireset();
	spitest();
}

#ifdef XXX

static void
epprod(Ctlr *ctlr, int epn)
{
	ctlr->spi->uscom = FifoFill | (epn&3);
	eieio();
}

static void
txstart(Endpt *r)
{
	int len, flags;
	Block *b;
	BD *dre, *rdy;

	if(r->ctlr->init)
		return;
	rdy = nil;
	while(r->ntq < Ntdre-1){
		b = qget(r->oq);
		if(b == 0)
			break;

		dre = &r->tdr[r->tdrh];
		if(dre->status & BDReady)
			panic("txstart");
dumpspi(b, "TX");
	
		/*
		 * Give ownership of the descriptor to the chip, increment the
		 * software ring descriptor pointer and tell the chip to poll.
		 */
		flags = 0;
		switch(b->rp[0]){
		case TokDATA1:
			flags = BDData1|BDData0;
		case TokDATA0:
			flags |= BDtxcrc|BDcnf|BDReady;
			flags |= BDData0;
			b->rp++;	/* skip DATAn */
		}
		len = BLEN(b);
		dcflush(b->rp, len);
		if(r->txb[r->tdrh] != nil)
			panic("spi: txstart");
		r->txb[r->tdrh] = b;
		dre->addr = PADDR(b->rp);
		dre->length = len;
		eieio();
		dre->status = (dre->status & BDWrap) | BDInt|BDLast | flags;
		if(rdy){
			rdy->status |= BDReady;
			rdy = nil;
		}
		if((flags & BDReady) == 0)
			rdy = dre;
		eieio();
		r->ntq++;
		r->tdrh = NEXT(r->tdrh, Ntdre);
	}
	if(rdy)
		rdy->status |= BDReady;
	eieio();
}

static void
transmit(Endpt *r)
{
	ilock(r->ctlr);
	txstart(r);
	iunlock(r->ctlr);
}

static void
endptintr(Endpt *r, int events)
{
	int len, status;
	BD *dre;
	Block *b;

	if(events & Frxb || 1){
		dre = &r->rdr[r->rdrx];
		while(((status = dre->status) & BDEmpty) == 0){
			if(status & BDrxerr || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
				print("spi rx: %4.4ux %d ", status, dre->length);
				{uchar *p;int i; p=KADDR(dre->addr); for(i=0;i<14&&i<dre->length; i++)print(" %.2ux", p[i]);print("\n");}
			}
			else{
				/*
				 * We have a packet. Read it into the next
				 * free ring buffer, if any.
				 */
				len = dre->length-2;	/* discard CRC */
				if(len >= 0 && (b = iallocb(len)) != 0){
					memmove(b->wp, KADDR(dre->addr), len);
					dcflush(KADDR(dre->addr), len);
					b->wp += len;
					// spiiq(ctlr, b);
					dumpspi(b, "RX");
					freeb(b);
				}
			}

			/*
			 * Finished with this descriptor, reinitialise it,
			 * give it back to the chip, then on to the next...
			 */
			dre->length = 0;
			dre->status = (dre->status & BDWrap) | BDEmpty | BDInt;
			eieio();

			r->rdrx = NEXT(r->rdrx, Nrdre);
			dre = &r->rdr[r->rdrx];
			r->rxintr = 1;
			wakeup(&r->ir);
		}
	}

	/*
	 * Transmitter interrupt: handle anything queued for a free descriptor.
	 */
	if(events & (Ftxb|Ftxe0|Ftxe1)){
		lock(r->ctlr);
		while(r->ntq){
			dre = &r->tdr[r->tdri];
			if(dre->status & BDReady)
				break;
			print("spitx=#%.4x %8.8lux\n", dre->status, dre->addr);
			/* TO DO: error counting */
			b = r->txb[r->tdri];
			if(b == nil)
				panic("spi/interrupt: bufp");
			r->txb[r->tdri] = nil;
			freeb(b);
			r->ntq--;
			r->tdri = NEXT(r->tdri, Ntdre);
		}
		txstart(r);
		unlock(r->ctlr);
		if(r->ntq)
			epprod(r->ctlr, r->x);
	}
}


static void
dumpspi(Block *b, char *msg)
{
	int i;

	print("%s: %8.8lux [%d]: ", msg, (ulong)b->rp, BLEN(b));
	for(i=0; i<BLEN(b) && i < 16; i++)
		print(" %.2x", b->rp[i]);
	print("\n");
}

static void
setaddr(Endpt *e, int dev, int endpt)
{
	ushort v;

	e->dev = dev;
	e->endpt = endpt;
	v = (e->endpt<<7) | e->dev;
	v |= crc5(v) << 11;
	e->addr[0] = v;
	e->addr[1] = v>>8;
}

static int
spiinput(void *a)
{
	return ((Ctlr*)a)->rxintr;
}

static void
spitest(void)
{
	Ctlr *ctlr;
	Endpt *e, *e1;
	uchar msg[8];
	int epn, testing, i;

	ctlr = spictlr;
	epn = 0;
	testing = ctlr->spi->usmod & TEST;
	if(testing)
		epn = 1;
	e = &ctlr->pts[0];
	e1 = &ctlr->pts[1];
	memset(msg, 0, 8);
	msg[0] = 0;
	msg[1] = 8;	/* set configuration */
	msg[2] = 1;
	setaddr(e, 0, epn);
	sendtoken(e, TokSETUP);
	senddata(e, msg, 8);
	if(!testing){
		for(i=0; i<8; i++)
			msg[i] = 0x40+i;
		senddata(e1, msg, 8);
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, spiinput, e, 1000);
		if(!spiinput(e))
			print("RX: none\n");
	}
	sendtoken(e, TokSETUP);
	msg[0] = 0x23;
	msg[1] = 3;	/* set feature */
	msg[2] = 8;	/* port power */
	msg[3] = 0;
	msg[4] = 1;	/* port 1 */
	senddata(e, msg, 8);
	if(!testing){
		for(i=0; i<8; i++)
			msg[i] = 0x60+i;
		senddata(e1, msg, 8);
		e->rxintr = 0;
		sendtoken(e, TokIN);
		transmit(e);
		epprod(ctlr, 0);
		tsleep(&e->ir, spiinput, e, 1000);
		if(!spiinput(e))
			print("RX: none\n");
	}
}

static void
setupep(int n, EPparam *ep)
{
	Endpt *e;

	e = &usbctlr->pts[n];
	e->x = n;
	e->ctlr = usbctlr;
	e->xtog = TokDATA0;
	if(e->oq == nil)
		e->oq = qopen(8*1024, 1, 0, 0);
	if(e->iq == nil)
		e->iq = qopen(8*1024, 1, 0, 0);
	e->ep = ep;
	if(ioringinit(e, Nrdre, Ntdre, Bufsize) < 0)
		panic("usbreset");
	ep->rbase = PADDR(e->rdr);
	ep->rbptr = ep->rbase;
	ep->tbase = PADDR(e->tdr);
	ep->tbptr = ep->tbase;
	eieio();
}


#endif

A mpc/tar.c => mpc/tar.c +86 -0
@@ 0,0 1,86 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

typedef union Hblock Hblock;

#define TBLOCK	512
#define NAMSIZ	100
union	Hblock
{
	char	dummy[TBLOCK];
	struct	header
	{
		char	name[NAMSIZ];
		char	mode[8];
		char	uid[8];
		char	gid[8];
		char	size[12];
		char	mtime[12];
		char	chksum[8];
		char	linkflag;
		char	linkname[NAMSIZ];
	} dbuf;
};

static int getdir(Hblock *hb, Dir *sp);
static int checksum(Hblock *hb);

uchar*
tarlookup(uchar *addr, char *file, int *dlen)
{
	Hblock *hp;
	Dir dir;

print("tarlookup: %x\n", addr);
	hp = (Hblock*)addr;
	while(getdir(hp, &dir) != 0) {
print("name = %s\n", hp->dbuf.name);
		if(strcmp(file, hp->dbuf.name) == 0) {
			*dlen = dir.length;
			return (uchar*)(hp+1);
		}
		hp += (dir.length+TBLOCK-1)/TBLOCK + 1;
	}
	return 0;
}

static int
getdir(Hblock *hp, Dir *sp)
{
	int chksum;

	if (hp->dbuf.name[0] == '\0')
		return 0;
	sp->mode = strtol(hp->dbuf.mode, 0, 8);
	strncpy(sp->uid, "adm", sizeof(sp->uid));
	strncpy(sp->gid, "adm", sizeof(sp->gid));
	sp->length = strtol(hp->dbuf.size, 0, 8);
	sp->mtime = strtol(hp->dbuf.mtime, 0, 8);
	chksum = strtol(hp->dbuf.chksum, 0, 8);
	if (chksum != checksum(hp)) {
		print("directory checksum error\n");
		return 0;
	}	
	return 1;
}

static int
checksum(Hblock *hp)
{
	int i;
	char *cp;

	i = 0;
	for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++) {
		if(cp < hp->dbuf.chksum || cp >= &hp->dbuf.chksum[sizeof(hp->dbuf.chksum)])
			i += *cp & 0xff;
		else
			i += ' ' & 0xff;
	}
	return(i);
}

M mpc/trap.c => mpc/trap.c +36 -24
@@ 35,6 35,7 @@ void	faultpower(Ureg *ur, ulong addr, int read);
void	kernfault(Ureg*, int);
void	syscall(Ureg* ureg);
void	noted(Ureg*, ulong);
void	reset(void);

char *excname[] =
{


@@ 119,7 120,7 @@ sethvec(int v, void (*r)(void))
{
	ulong *vp, pa, o;

	vp = (ulong*)(0xfff00000+v);
	vp = KADDR(v);
	vp[0] = 0x7c1043a6;	/* MOVW R0, SPR(SPRG0) */
	vp[1] = 0x7c0802a6;	/* MOVW LR, R0 */
	vp[2] = 0x7c1243a6;	/* MOVW R0, SPR(SPRG2) */


@@ 151,11 152,14 @@ trap(Ureg *ur)
{
	int ecode;
	static struct {int callsched;} c = {1};
	int user = (ur->srr1 & MSR_PR) != 0;
	char buf[ERRLEN];

	m->intrts = fastticks(nil);
	ecode = (ur->cause >> 8) & 0xff;
	if(ecode < 0 || ecode >= 0x1F)
		ecode = 0x1F;

if(ur->status & MSR_RI == 0)
print("double fault?: ecode = %d\n", ecode);
	switch(ecode){
	case CEI:
		intr(ur);


@@ 164,21 168,24 @@ trap(Ureg *ur)
	case CDEC:
		clockintr(ur);
		break;

	case CIMISS:
		faultpower(ur, ur->pc, 1);
		break;
	case CITLBE:
		faultpower(ur, ur->pc, 1);
		break;
	case CDMISS:
		faultpower(ur, getdepn(), 1);
if(0) print("CDMISS: %lux %lux\n", m->epn, m->cmp1);
		faultpower(ur, m->dar, 1);
		break;
	case CDTLBE:
		faultpower(ur, getdar(), !(getdsisr() & (1<<25)));
		faultpower(ur, m->dar, !(m->dsisr & (1<<25)));
		break;

	case CEMU:
		print("pc=#%lux op=#%8.8lux\n", ur->pc, *(ulong*)ur->pc);
		goto Default;
		print("CEMU: pc=#%lux op=#%8.8lux\n", ur->pc, *(ulong*)ur->pc);
		sprint(buf, "sys: trap: illegal op addr=0x%lux", ur->pc);
		postnote(up, 1, buf, NDebug);
		break;

	case CSYSCALL:


@@ 196,14 203,20 @@ trap(Ureg *ur)

	Default:
	default:
		spllo();
		print("ecode = %d\n", ecode);
		if(ecode < 0 || ecode >= 0x1F)
			ecode = 0x1F;
		print("kernel %s pc=0x%lux\n", excname[ecode], ur->pc);
		dumpregs(ur);
		dumpstack();
		spllo();
		exit(1);
		delay(100);
		reset();
	}

	splhi();
	if(user)
		notify(ur);
}

void


@@ 211,9 224,8 @@ faultpower(Ureg *ureg, ulong addr, int read)
{
	int user, insyscall, n;
	char buf[ERRLEN];

	user = (ureg->srr1 & MSR_PR) != 0;
//print("fault: pid=%d pc = %ux, addr = %ux read = %d user = %d stack=%ux\n", up->pid, ureg->pc, addr, read, user, &ureg);
if(0)print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg);
	insyscall = up->insyscall;
	up->insyscall = 1;
	spllo();


@@ 223,7 235,8 @@ faultpower(Ureg *ureg, ulong addr, int read)
			dumpregs(ureg);
			panic("fault: 0x%lux\n", addr);
		}
print("sys: trap: fault %s addr=0x%lux\n", read? "read" : "write", addr);
print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg);
dumpregs(ureg);
		sprint(buf, "sys: trap: fault %s addr=0x%lux",
			read? "read" : "write", addr);
		postnote(up, 1, buf, NDebug);


@@ 269,12 282,13 @@ trapinit(void)
	/*
	 * set all exceptions to trap
	 */
	for(i = 0x0; i < 0x3000; i += 0x100)
	for(i = 0x0; i < 0x2000; i += 0x100)
		sethvec(i, trapvec);

	//sethvec(CEI<<8, intrvec);
	//sethvec2(CIMISS<<8, itlbmiss);
	//sethvec2(CDMISS<<8, dtlbmiss);
	sethvec2(CIMISS<<8, itlbmiss);
	sethvec2(CDMISS<<8, dtlbmiss);
	sethvec2(CDTLBE<<8, dtlberror);
}

void


@@ 315,9 329,6 @@ intrenable(int v, void (*r)(Ureg*, void*), void *arg, int)
	iunlock(&veclock);
}

/*
 * called directly by l.s:/intrvec
 */
void
intr(Ureg *ur)
{


@@ 497,8 508,12 @@ reset(void)
	io = m->iomem;
	io->plprcrk = KEEP_ALIVE_KEY;	// unlock
	io->plprcr |= IBIT(24);		// enable checkstop reset
	putmsr(getmsr() & ~MSR_ME);
	putmsr(getmsr() & ~(MSR_ME|MSR_RI));
predawn = 1;
print("reset = %ulx\n", getmsr());
	delay(1000);
	// cause checkstop -> causes reset
	*(uchar*)(0xdeadbeef) = 0;
	*(ulong*)(0) = 0;
}



@@ 616,7 631,7 @@ syscall(Ureg* ureg)
	up->dbgreg = ureg;

	scallnr = ureg->r3;
//print("scall %s\n", sysctab[scallnr]);
//print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
	up->scallnr = scallnr;
	spllo();



@@ 676,8 691,6 @@ notify(Ureg* ur)
	ulong s, sp;
	Note *n;

//print("***notify %ld\n", up->pid);

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


@@ 753,7 766,6 @@ noted(Ureg* ureg, ulong arg0)
	Ureg *nureg;
	ulong oureg, sp;

//print("***noted\n");
	qlock(&up->debug);
	if(arg0!=NRSTR && !up->notified) {
		qunlock(&up->debug);

M port/devdraw.c => port/devdraw.c +4 -4
@@ 360,7 360,7 @@ addflush(Rectangle r)
	/*
	 * absorb if:
	 *	total area is small
	 *	waste is less than ½ total area
	 *	waste is less than half total area
	 * 	rectangles touch
	 */
	if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){


@@ 981,7 981,7 @@ drawclose(Chan *c)
		/* all screens are freed, so now we can free images */
		dp = cl->dimage;
		for(i=0; i<NHASH; i++){
			while(d = *dp){	/* assign = */
			while((d = *dp) != nil){
				*dp = d->next;
				drawfreedimage(d);
			}


@@ 1288,7 1288,7 @@ drawmesg(Client *client, void *av, int n)
	fmt = nil;
	if(waserror()){
		if(fmt) printmesg(fmt, a, 1);
	//	iprint("error: %s\n", up->error);
	/*	iprint("error: %s\n", up->error);	*/
		nexterror();
	}
	while((n-=m) > 0){


@@ 1297,7 1297,7 @@ drawmesg(Client *client, void *av, int n)
		switch(*a){
		default:
			error("bad draw command");
		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbαα[4] */
		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
		case 'b':
			printmesg(fmt="LLbLbRRL", a, 0);
			m = 1+4+4+1+4+1+4*4+4*4+4;

M port/devmouse.c => port/devmouse.c +1 -0
@@ 142,6 142,7 @@ mouseopen(Chan *c, int omode)
		unlock(&mouse);
		break;
	case Qmousein:
		error("disabled");
		lock(&mouse);
		if(mouse.inopen){
			unlock(&mouse);

M port/devpipe.c => port/devpipe.c +15 -1
@@ 113,6 113,8 @@ static int
pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	int id;
	int len;
	Pipe *p;

	if(i == DEVDOTDOT){
		devdir(c, c->qid, "#|", 0, eve, CHDIR|0555, dp);


@@ 125,7 127,19 @@ pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
	if(tab==0 || i>=ntab)
		return -1;
	tab += i;
	devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, tab->length, eve, tab->perm, dp);
	p = c->aux;
	switch(tab->qid.path){
	case Qdata0:
		len = qlen(p->q[0]);
		break;
	case Qdata1:
		len = qlen(p->q[1]);
		break;
	default:
		len = tab->length;
		break;
	}
	devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, len, eve, tab->perm, dp);
	return 1;
}