Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/dist/9legacy/applied/jtagfs.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


--- /sys/lib/acid/jtag	Sun Apr  7 17:18:58 2013
+++ /sys/lib/acid/jtag	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,245 @@
+include("/sys/lib/acid/arm");
+
+// feroceon memory definitions
+TmrWDenable=1<<4;
+PHYSIO=0xf1000000;
+TIMERREG=0xf1020300;
+PsrMsvc=0x00000013;
+timerctl=0;
+KZERO=0x60000000;
+
+ureg = 0;
+complex Ureg ureg;
+uregtypeaddr=60;	//kludge
+
+//generated from 8c -a
+sizeofMMURegs = 32;
+aggr MMURegs
+{
+	'U' 0 cpid;
+	'U' 4 control;
+	'U' 8 ttb;
+	'U' 12 dac;
+	'U' 16 fsr;
+	'U' 20 far;
+	'U' 24 ct;
+	'U' 28 pid;
+};
+
+defn
+remapdata()
+{
+	mps = map();
+	
+	while mps do {
+		m = head mps;
+		name = head m;
+		if name == "*data" then {
+			dend = head tail tail m;
+			map({"*data", KZERO, dend, KZERO});
+		}
+		mps = tail mps;
+	}
+}
+//I want to be able to access MACH and other stuff
+remapdata();
+memmap=map();
+//TO DO is there any arm with fpregs?
+map({"regs", 0, sizeofUreg+sizeofMMURegs, 0});
+
+defn
+MMURegs(addr) {
+	complex MMURegs addr;
+	print("	cpid	", addr.cpid\X, "\n");
+	print("	control	", addr.control\X, "\n");
+	print("	ttb	", addr.ttb\X, "\n");
+	print("	dac	", addr.dac\X, "\n");
+	print("	fsr	", addr.fsr\X, "\n");
+	print("	far	", addr.far\X, "\n");
+	print("	ct	", addr.ct\X, "\n");
+	print("	pid	", addr.pid\X, "\n");
+};
+
+complex MMURegs mmuregs;
+mmuregs=sizeofUreg; // plus size of floating point registers
+
+defn
+mmuregs()
+{
+	MMURegs(mmuregs);
+}
+
+defn
+stopwdog()
+{
+	// change to svc mode to be able to access the address
+	stype = ureg.type;
+	*uregtypeaddr=PsrMsvc;
+	timerctl=*TIMERREG;
+	*TIMERREG = ~TmrWDenable&*TIMERREG;
+	*uregtypeaddr=stype;
+}
+
+defn
+startwdog()
+{
+	stype = ureg.type;
+	*uregtypeaddr=PsrMsvc;
+	*TIMERREG = TmrWDenable|timerctl;
+	*uregtypeaddr=stype;
+}
+
+defn
+hwbpset(addr, mask)
+{
+	printto("/proc/"+itoa(pid)+"/ctl", "breakpoint ", itoa(addr), " ", itoa(mask));
+}
+
+defn
+veccatch(vecstr)
+{
+	printto("/proc/"+itoa(pid)+"/ctl", "veccatch ", vecstr);
+}
+
+defn
+reset()
+{
+	printto("/proc/"+itoa(pid)+"/ctl", "reset ");
+}
+
+defn
+debug(dbstr)
+{
+	printto("/proc/"+itoa(pid)+"/ctl", "debug ", dbstr);
+}
+
+defn
+cpuid()
+{
+	printto("/proc/"+itoa(pid)+"/ctl", "cpuid");
+}
+
+defn
+jtaginfo()
+{
+	rc("cat /proc/"+itoa(pid)+"/ctl");
+}
+
+defn
+sheevastop()
+{
+	stop(pid);
+	stopwdog();
+}
+
+defn
+sheevastart()
+{
+	startwdog();
+	start(pid);
+}
+
+defn
+sheevawaitstop()
+{
+	waitstop(pid);
+	stopwdog();
+}
+
+// FROM here down on, UNTRIED BUG BUG BUG!!!!!
+
+//CpCONTROL, h2acid
+CpCmmu = 0x00000001;
+CpCalign = 0x00000002;
+CpCdcache = 0x00000004;
+CpCwb = 0x00000008;
+CpCi32 = 0x00000010;
+CpCd32 = 0x00000020;
+CpCbe = 0x00000080;
+CpCsystem = 0x00000100;
+CpCrom = 0x00000200;
+CpCicache = 0x00001000;
+CpChv = 0x00002000;
+
+//MMU definitions, h2acid
+KB=1024;
+MB=1024*1024;
+Mbo = 0x10;
+Coarse = (Mbo|1);
+Section = (Mbo|2);
+Fine = (Mbo|3);
+
+defn
+ismmuon()
+{
+	mmu = mmuregs;
+	complex MMURegs mmu;
+	return mmu.control&CpCmmu;
+}
+
+defn
+l1x(vaddr)
+{
+	return ((vaddr>>20) & 0x0fff)<<2;
+}
+
+defn
+l2x(vaddr)
+{
+	return ((vaddr>>12) & 0xff)<<2;
+}
+
+defn
+pgsz(type)
+{
+	if type == Fine then {
+		return KB;
+	} else if type == Section then {
+		return MB;
+	} else if type == Coarse then {
+		return 4*KB;
+	}
+	return 4*KB;
+}
+
+defn
+kaddr(vaddr)
+{
+	return KZERO|vaddr;	//very non portable
+}
+
+defn
+ttbpaddr(ttb, vaddr)
+{
+	if ! ismmuon() then {
+		print("paddr: mmu is off\n");
+		return 0;
+	}
+	l1idx = l1x(vaddr);
+	l2idx = l2x(vaddr);
+	pte1 = *((kaddr(ttb)&~0x1fff) + l1idx);
+	if pte1 == 0 then {
+		return 0;
+	}
+	type = pte1 & (Fine|Section|Coarse);
+	sz = pgsz(type);
+	if type == Section then {
+		return (pte1 & ~(sz - 1)) + (vaddr & (sz - 1));
+	}
+
+	l2addr = pte1 & ~(sz - 1);
+	if l2addr == 0 then {
+		return 0;
+	}
+	pte2 = *(kaddr(l2addr) + l2idx);
+	return  (pte2 & ~(sz - 1)) + (vaddr & (sz - 1));
+}
+
+defn
+paddr(vaddr)
+{
+	mmu = mmuregs;
+	complex MMURegs mmu;
+	return ttbpaddr(mmu.ttb, vaddr);
+}
+
--- /sys/man/4/jtagfs	Sun Apr  7 17:19:00 2013
+++ /sys/man/4/jtagfs	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,202 @@
+.TH JTAGFS 4
+.SH NAME
+jtagfs \- jtag kernel debugging file system
+.SH SYNOPSIS
+.B jtagfs
+[
+.B -d
+.I debugstr
+]
+[
+.B -b
+.I motherbname
+]
+[
+.B -t
+.I text
+]
+[
+.B -m
+.I mountpoint
+]
+[
+.B -s
+.I srvfile
+]
+.I jtagfile
+.SH DESCRIPTION
+.I Jjagfs
+presents in 
+.BI /n/jtagfs/ctl
+a set of process files for debugging
+a kernel running on an arm over a jtag
+.I device
+in a manner similarly to
+.IR rdbfs (4)
+but without any need for the kernel collaborating.
+In debug mode an arm stops and isolates itself from the
+surroundings and can be probed and instructions injected
+at will.
+There are a number of options:
+.TP
+.B  -d
+Can be used to set the debug string, see below.
+.TP
+.B  -m
+and
+.B -s
+Set the mount point and srv name respectively. By default
+the mount point is
+.BI /n/jtagfs/ctl .
+.TP
+.B  -b
+Motherboard kind jtagfs is going to be run against. Valid parameters
+are
+.B sheeva,
+which stands for the Feroceon Guruplug and the sheevaplug and is the default and
+.B gurudisp
+which stands for the Armada Guru Display.
+.TP
+.B  -t
+The 
+.B text
+file presented is just a copy of
+.I text
+(default
+.BR /arm/s9plug ).
+It can usually be ignored, since
+the debuggers open kernel
+files directly rather than
+using
+.BI /proc/ n /text\fR.
+.PP
+Kernels can be remotely debugged  only when they are
+stopped and put in debug mode. This can be done
+through instruction breakpoints, vector catching (on entry
+to interrupts) or on demand using
+.B stop().
+.PP
+An acid library to use with the most common operations
+called jtag is provided to make most common operations
+simpler. In particular
+.B start(),
+.B stop()
+and
+.B waitstop()
+have jtag specific variants
+(for example
+.B sheevastart()
+)
+which disable and reenable the watchdog.
+Other than this functions and the symbol translations, this
+program can be used to debug kernels from other operating systems.
+.PP
+The function
+.B veccatch(str)
+can be used to set a vectorcatch, which stops the processor right after
+an interrupt. The string describes which interrupts to cacth.
+Each caracter represents a type of interrupt:
+.sp
+.EX
+.ta 4n +6n 
+ 'R'	Reset
+ 'S'	SWI
+ 'P'	PAbort
+ 'D'	DAbort
+ 'I'	Irq
+ 'F'	Fiq
+.fi
+.EE
+.PP
+The function
+.B debug(str)
+can be used to set different levels of debug. Each character on
+the string represent a different software layer:
+.PP
+.EX
+.ta 6n +2n +4n +4n +4n +4n +4n
+.sp
+DFile	  	= 'f',		/* Reads, writes, flushes*/
+DPath  	= 'p',		/* path for state transitions for tap debugging */
+DState  	= 's',		/* state calculation and changes on tap interface */
+Dinst  	= 'i',		/* mpsse instruction assembling debug */
+Dassln  	= 'a',		/* print instructions before assembling */
+Dmach  	= 'm',		/* print mpsse machine code and op results */
+Djtag  	= 'j',		/* print jtag level operations */
+Dice	  	= 'e',		/* print icert level operations */
+Dchain  	= 'h',		/* print icert chains */
+Dmmu  	= 'u',		/* print MMU ops */
+Dctxt  	= 'c',		/* dump context in and out */
+Darm  	= 'w',		/* standard insts and so */
+Dmem  	= 'y',		/* memory ops */
+Dfs	  	= 'k',		/* filesystem ops */
+DAll	  	= 'A'
+.fi
+.EE
+.SH EXAMPLES
+.EX
+jtagfs /dev/eiaU*/jtag
+bind /n/jtagfs /proc/1
+term% acid -l jtag -k 1 /arm/s9plug
+/arm/s9plug:ARM plan 9 boot image
+/sys/lib/acid/port
+/sys/lib/acid/arm
+acid: reset()
+acid: sheevastop()
+ID: 0x20a023d3
+Must be 1: 1
+Manufacturer id: 0x1e9
+Part no: 0xa02
+Version: 0x2
+1: SVC/SWI Exception	0xc02e1094	no instruction
+acid: dump(0xc02e1094, 4, "Xi")
+0xc02e1094: 0x1204e0ff CMP.S	$#0x100,R0 
+0xc02e109c: 0xe0266003 B.NE	etext+0x5fa536bc 
+0xc02e10a4: 0xe20c2040 AND	$#0x8,R12,R0 
+0xc02e10ac: 0xe20e1080 AND	$#0x1,R14,R3 
+0xc02e10b4: 0xe1811002 ORR	(R0<<4),R3,R3 
+acid: regs()
+R0	0x5e20a2dc R1	0xf5518723 R2	0x001d1d00
+R3	0x369244e0 R4	0x2b9244fd R5	0xbbc54739
+R6	0x5e20a2dc R7	0x00000eb0 R8	0xdfd7ceb0
+R9	0x00000006 R10	0xc08c1f20 R11	0xc08c1f04
+R12	0x1d00001d R13	0xc08c1ea0 R14	0x00000000
+R15	0xc031fa8c
+acid: sheevastart()
+.EE
+.SH SOURCE
+.B /sys/src/cmd/jtag
+.br
+.B /sys/lib/acid/jtag
+.SH "SEE ALSO"
+.IR acid (1),
+.IR db (1).
+.br
+``ARM9E-S Technical Reference Manual''.
+.br
+``ARM7TDMI-S Core Technical Reference Manual".
+.br
+``Application note 205 "Writing JTAG Sequences for Arm 9 Processors".
+.br
+``Design and Implementation of an On-Chip Debug for Embedded Target Systems",
+Dominic Rath.
+.br
+``IEEE Standard 1149-1-2001 Test Access Port and Boundary Scan Architecture",
+JTag IEEE standard.
+.br
+``AN2232C-01 Command Processor for MPSSE and MCU Host Bus Emulation Modes",
+Future Technology Devices International Ltd.
+.SH BUGS
+After a while of the machine being on, the jtag will stop
+working; maybe an autentication register needs to be set.
+If this is the case
+.B cpuid()
+will return error.
+Reset always works.
+Reading and writing from memory is slow.
+The filesystems needs a lot of cleaning.
+Only the feroceon cpu and sheeva/guruplug boards are
+supported, though more can be added.
+Error report is sparse.
+Jtagfs should be rewritten using the 9p library and it would shrink
+to half.
diff -Nru /sys/src/cmd/jtagfs/README /sys/src/cmd/jtagfs/README
--- /sys/src/cmd/jtagfs/README	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/README	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,33 @@
+To install
+
+cp acidjtag /sys/lib/acid/jtag
+cp acidarm /sys/lib/acid/arm
+cp jtagfs.man /sys/man/4/jtagfs
+mkdir /sys/src/cmd/jtagfs
+cp * /sys/src/cmd/jtagfs
+cd /sys/src/cmd/jtagfs
+mk install
+
+change attachproc in libmach so that we can modify the kernel
+registers.
+
+/sys/src/libmach/map.c:94
+< 		mode = ORDWR;
+---
+> 		mode = OREAD;
+recompile libmach and acid
+It could also be done through acid using map(), but in this case
+it is better this way.
+
+The armada implementation has never been run even once.
+
+
+Byte endianness. As it is now, it depends on endianness of ARM being the
+same as 386. Specifically, the /proc served is in the machine where it runs
+order (i.e. in a little endian machine it would not work). This should be
+changed on jtagfs, just before serving them.
+
+MMU state is served after the Uregs (there is no floating point, if not, it would
+be after the floating point too). A map has been added to map it in read only.
+h2acid for constants and macros
+
diff -Nru /sys/src/cmd/jtagfs/TODO /sys/src/cmd/jtagfs/TODO
--- /sys/src/cmd/jtagfs/TODO	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/TODO	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,36 @@
+
+Use openocd on a fake GURU to see reset
+Unknown
+
+Fix start
+
+Fix the sheeva nsrst must be asserted while stopping/cpuiding
+but this is just for the feroceon, an extra reset state before
+cpuid/request. The order is strictly this:
+
+- UNTESTED
+reset 0 1
+cpuid
+set DBGRQ
+reset 0 0
+wait halt
+
+It may work to break it into:
+reset 0 1
+cpuid
+reset 0 0
+
+and
+
+reset 0 1
+set DBGRQ
+reset 0 0
+
+
+Put currentch inside the tap description in an Armtap state.
+
+Add a ctl to identify the motherboard, not sure how to call initmpsse...
+break it in two pieces maybe.
+Identify which part is board dependant.
+
+Get more info about the GURU display.
diff -Nru /sys/src/cmd/jtagfs/bebo.c /sys/src/cmd/jtagfs/bebo.c
--- /sys/src/cmd/jtagfs/bebo.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/bebo.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,76 @@
+#include <u.h>
+#include <libc.h>
+
+void
+hbeputv(void *p, uvlong v)
+{
+	uchar *a;
+
+	a = p;
+	a[0] = v>>56;
+	a[1] = v>>48;
+	a[2] = v>>40;
+	a[3] = v>>32;
+	a[4] = v>>24;
+	a[5] = v>>16;
+	a[6] = v>>8;
+	a[7] = v;
+}
+
+void
+hbeputl(void *p, uint v)
+{
+	uchar *a;
+
+	a = p;
+	a[0] = v>>24;
+	a[1] = v>>16;
+	a[2] = v>>8;
+	a[3] = v;
+}
+
+void
+hbeputs(void *p, ushort v)
+{
+	uchar *a;
+
+	a = p;
+	a[0] = v>>8;
+	a[1] = v;
+}
+
+uvlong
+behgetv(void *p)
+{
+	uchar *a;
+	uvlong v;
+
+	a = p;
+	v = (uvlong)a[0]<<56;
+	v |= (uvlong)a[1]<<48;
+	v |= (uvlong)a[2]<<40;
+	v |= (uvlong)a[3]<<32;
+	v |= a[4]<<24;
+	v |= a[5]<<16;
+	v |= a[6]<<8;
+	v |= a[7]<<0;
+	return v;
+}
+
+uint
+behgetl(void *p)
+{
+	uchar *a;
+
+	a = p;
+	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
+}
+
+ushort
+behgets(void *p)
+{
+	uchar *a;
+
+	a = p;
+	return (a[0]<<8)|(a[1]<<0);
+}
diff -Nru /sys/src/cmd/jtagfs/bebo.h /sys/src/cmd/jtagfs/bebo.h
--- /sys/src/cmd/jtagfs/bebo.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/bebo.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,6 @@
+extern uint	behgetl(void *p);
+extern ushort	behgets(void *p);
+extern uvlong	behgetv(void *p);
+extern void	hbeputl(void *p, uint v);
+extern void	hbeputs(void *p, ushort v);
+extern void	hbeputv(void *p, uvlong v);
diff -Nru /sys/src/cmd/jtagfs/chain.c /sys/src/cmd/jtagfs/chain.c
--- /sys/src/cmd/jtagfs/chain.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/chain.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,219 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "lebo.h"
+#include "bebo.h"
+#include "debug.h"
+#include "chain.h"
+
+/* functions to deal with bit chains, weird bit orderings an such */
+
+#define Upper(byte, nbits)	((byte)>>(nbits))
+#define Lower(byte, nbits)	((bytes)&MSK(nbits))
+#define IsCut(bbits, ebits)		(((ebits)/8 - (bbits)/8) > 0)
+
+/* 8: H L | 8: Next */
+/* Put at most 8 bits*/
+static void
+put8bits(Chain *ch, void *p, int nbits)
+{
+	int e, nbye, nbie, nle;
+	uchar low, high, byte;
+
+	byte = *(uchar *)p;
+	e = ch->e+nbits-1;	/* offset of last bit to put in */
+	nbie = ch->e%8;
+	nbye = ch->e/8;
+	nle = 8 - nbie;
+
+
+	if(IsCut(ch->e, e))
+		ch->buf[nbye + 1] = byte >> nle;
+
+	high = (byte & MSK(nle)) << nbie;
+	low = ch->buf[nbye]&MSK(nbie);
+
+
+	ch->buf[nbye] = low|high;
+	ch->e += nbits;
+}
+
+/* Get at most 8 bits*/
+static uchar
+get8bits(Chain *ch, int nbits)
+{
+	int b, nbyb, nbib, nlb;
+	uchar low, high, res;
+
+	b = ch->b+nbits-1;
+	nbib = ch->b % 8;
+	nbyb = ch->b / 8;
+	nlb = 8 - nbib;
+	if(nlb > nbits)
+		nlb = nbits;
+
+	low = MSK(nlb) & (ch->buf[nbyb] >> nbib);
+	if(IsCut(ch->b, b))
+		high = (ch->buf[nbyb + 1] & MSK(nbib)) << nlb;
+	else
+		high = 0;
+	res = MSK(nbits)&(high | low);
+	ch->b += nbits;
+	return res;
+}
+
+/*
+ * Putbits and getbits could be made more efficient
+ * simply by using memmove in the special case where
+ * a bunch of bytes is aligned, but I don't care.
+ * Packing in words would also help the so inclined.
+ */
+void
+putbits(Chain *ch, void *p, int nbits)
+{
+	int nby, nbi, i;
+	uchar *vp;
+
+	vp = p;
+	nby = nbits / 8;
+	nbi = nbits % 8;
+
+	for(i = 0; i < nby; i++)
+		put8bits(ch, vp++, 8);
+	
+	if(nbi != 0)
+		put8bits(ch, vp, nbi);
+}
+
+void
+getbits(void *p, Chain *ch, int nbits)
+{
+	int nby, nbi, i;
+	uchar *vp;
+
+	assert(ch->e >= ch->b);
+	nby = nbits / 8;
+	nbi = nbits % 8;
+
+	vp = p;
+	for(i = 0; i < nby; i++)
+		*vp++ = get8bits(ch, 8);
+	
+	if(nbi != 0)
+		*vp = get8bits(ch, nbi);
+}
+
+static void
+revbych(Chain *ch)
+{
+	int i, nb;
+
+	nb = (ch->e-ch->b+7)/8;
+
+	for(i = 0; i < nb; i++)
+		ch->buf[i] = rtab[ch->buf[i]];
+}
+
+void
+printchain(Chain *ch)
+{
+	int i, ng, nb;
+	uchar msk, c;
+	Chain *ch2;
+
+	fprint(2, "chain buf:%#p b:%d e:%d\n", ch->buf, ch->b, ch->e);
+	ch2 = malloc(sizeof(Chain));
+	if(ch2 == nil)
+		sysfatal("no memory");
+	memmove(ch2, ch, sizeof(Chain));
+
+
+	ng = 8;
+	nb = (ch2->e-ch2->b+7)/8;
+
+	for(i = 0; i < nb; i++){
+		if(ch2->e - ch2->b < ng)
+			ng = ch2->e - ch2->b;
+		getbits(&c, ch2, ng);
+		if(i != 0 && i%15 == 0)	
+			fprint(2, "\n");
+		if(ng < 8){
+			msk = MSK(ng);
+			fprint(2, "%#2.2x ", c&msk);
+		}
+		else
+			fprint(2, "%#2.2x ", c);
+		
+	}
+	if(i%16 != 0)
+		fprint(2, "\n");
+
+	free(ch2);
+}
+
+/* Good for debugging */
+static void
+printchslice(Chain *ch, int b, int e)
+{
+	Chain *ch2;
+
+	fprint(2, "Slice [%d, %d], b:%d e:%d\n", b, e, ch->b, ch->e);
+	ch2 = malloc(sizeof(Chain));
+	if(ch2 == nil)
+		sysfatal("memory");
+	memmove(ch2, ch, sizeof(Chain));
+	if(b > e){
+		fprint(2, "bad args in region\n");
+		return;
+	}
+	if(b < ch2->b || b > ch2->e || e > ch2-> e || e < ch2->b){
+		fprint(2, "bad region\n");
+		return;
+	}
+	ch2->b = b;
+	ch2->e = e;
+
+	fprint(2, "Slice - ");
+	printchain(ch2);
+	free(ch2);
+}
+
+
+static u32int
+revbytes(u32int *v)
+{
+	u32int rv;
+	uchar *a, *b;
+
+	a = (uchar *)v;
+	b = (uchar *)&rv;
+
+	b[3] = rtab[a[3]];
+	b[2] = rtab[a[2]];
+	b[1] = rtab[a[1]];
+	b[0] = rtab[a[0]];
+
+	return rv;
+}
+
+u32int
+hmsbputl(u32int *v)
+{
+	u32int rv, bev;
+
+	hbeputl(&bev, *v);
+	rv = revbytes(&bev);
+
+	return rv;
+}
+
+u32int
+msbhgetl(u32int *v)
+{
+	u32int rv, rev;
+
+	rev = revbytes(v);
+	rv = lehgetl(&rev);
+	return rv;
+}
+
diff -Nru /sys/src/cmd/jtagfs/chain.h /sys/src/cmd/jtagfs/chain.h
--- /sys/src/cmd/jtagfs/chain.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/chain.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,23 @@
+typedef struct Chain Chain;
+
+extern uchar rtab[]; 		/* generated by genrtab.c */
+
+#define MSK(nbits)		((1UL<<(nbits))-1)
+
+enum{
+	MaxChLen	= 128,	/* bytes */
+};
+
+
+/* bit chain, can put at the beginning, get at the end */
+struct Chain {
+	int	b;			/* offset start in bits, (first full) */
+	int	e;			/* offset end in bits (first empty) */
+	uchar buf[MaxChLen];
+};
+
+extern void	getbits(void *p, Chain *ch, int nbits);
+extern u32int	hmsbputl(u32int *v);
+extern u32int	msbhgetl(u32int *v);
+extern void	printchain(Chain *ch);
+extern void	putbits(Chain *ch, void *p, int nbits);
diff -Nru /sys/src/cmd/jtagfs/debug.c /sys/src/cmd/jtagfs/debug.c
--- /sys/src/cmd/jtagfs/debug.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/debug.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+
+uchar debug[255];
+
+int
+dprint(char d, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	if(!debug['A'] && !debug[d])
+		return -1;
+	va_start(args, fmt);
+	n = vfprint(2, fmt, args);
+	va_end(args);
+	return n;
+}
+
+
+void
+dumpbuf(char d, uchar *buf, int bufsz)
+{
+	int i;
+
+	if(d != 0 && !debug[d])
+		return;
+	for(i = 0; i < bufsz; i++){
+		fprint(2, "%#2.2x ", buf[i]);
+		if(i != 0 && (i + 1) % 8 == 0)	
+			fprint(2, "\n");
+	}
+	if(i %16 != 0)
+		fprint(2, "\n");
+}
diff -Nru /sys/src/cmd/jtagfs/debug.h /sys/src/cmd/jtagfs/debug.h
--- /sys/src/cmd/jtagfs/debug.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/debug.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,24 @@
+extern uchar debug[];
+
+enum {
+	DXFlush	= 'x',		/* special markers for debugging on the commands, disrupts behaviour*/
+
+	DFile		= 'f',		/* Reads, writes, flushes*/
+	DPath	= 'p',		/* path for state transitions for tap debugging */
+	DState	= 's',		/* state calculation and changes on tap interface */
+	Dinst	= 'i',		/* mpsse instruction assembling debug */
+	Dassln	= 'a',		/* print instructions before assembling */
+	Dmach	= 'm',	/* print mpsse machine code and op results */
+	Djtag	= 'j',		/* print jtag level operations */
+	Dice		= 'e',		/* print icert level operations */
+	Dchain	= 'h',		/* print icert chains */
+	Dmmu	= 'u',		/* print MMU ops */
+	Dctxt	= 'c',		/* dump context in and out */
+	Darm	= 'w',		/* arm insts and so */
+	Dmem	= 'y',		/* memory ops */
+	Dfs		= 'k',		/* filesystem ops */
+	DAll		= 'A'
+};
+
+extern int	dprint(char d, char *fmt, ...);
+extern void	dumpbuf(char d, uchar *buf, int bufsz);
diff -Nru /sys/src/cmd/jtagfs/genrtab.c /sys/src/cmd/jtagfs/genrtab.c
--- /sys/src/cmd/jtagfs/genrtab.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/genrtab.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,45 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "debug.h"
+
+static uchar
+reverse(uchar c)
+{
+	uchar rc;
+	int i, j, ns;
+
+	rc = 0;
+	for(i = 0, j = 1; i < 8; i++, j <<= 1){
+		ns = (7 - 2*i);
+		if( ns < 0){
+			ns = -ns;
+			rc |= (c&j) >> ns;
+		}
+		else
+			rc |= (c&j) << ns;
+	}
+	return rc;
+}
+
+
+void
+main(int , char *[])
+{
+	int i;
+
+	print("/* Generated automatically, *DO NOT EDIT* */\n\n");
+	print("#include <u.h>\n");
+	print("#include <libc.h>\n\n");
+	print("uchar rtab[256]=\n");
+	print("{\n\t");
+	for(i = 0; i < 256; i++){
+		print("%#2.2ux, ", reverse(i));
+		if(i != 0 && (i + 1) % 8 == 0)
+			print("\n\t");
+	}
+	print("\n};");
+	exits(nil);
+}
+
diff -Nru /sys/src/cmd/jtagfs/guide /sys/src/cmd/jtagfs/guide
--- /sys/src/cmd/jtagfs/guide	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/guide	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,85 @@
+hwbpset(0x60800c28, 0x3ff)
+hwbpset(_vpabt, 0x0)
+hwbpset(_vsvc, 0x0)
+hwbpset(_vdabt, 0x0)
+hwbpset(_vund, 0x0)
+hwbpset(_virq, 0x0)
+veccatch("SPDIF")
+
+dump(_vrst, 30, "Xi")
+
+usb/serial
+
+echo b115200 s15 l8 pn > /dev/eiaU3.1/eiaUctl
+window -m
+window -m
+con /dev/eiaU3.1/eiaU
+
+echo debug . > /n/jtagfs/ctl
+
+window -scroll -r 0 5 700 369 plug
+
+
+kill 8.tagfs|rc
+/usr/paurea/src/jtag/8.jtagfs /dev/jtag*/jtag
+echo reset > /n/jtagfs/ctl
+
+#start the jtag
+echo cpuid > /n/jtagfs/ctl
+echo breakpoint 0xc02dc244 0x0 > /n/jtagfs/ctl
+
+echo breakpoint 0x0062822c 0x00000000 > /n/jtagfs/ctl
+ echo breakpoint 0xc0208124 0xffff0000  > /n/jtagfs/ctl
+
+#see debug.h for the string
+echo debugstr kc> /n/jtagfs/ctl
+
+BR 9 , pcadjust -5 works well
+BR 6, 2 works well
+
+cat /n/jtagfs/ctl
+echo stop > /n/jtagfs/ctl
+echo start > /n/jtagfs/ctl
+
+ echo debustr ew > /n/jtagfs/ctl
+#/n/jtagfs/mem can be used to read raw memory at an arbitrary offset
+
+
+#	set entry on exceptions
+#	changed so that turn it is turn on in debug state
+#	
+
+#wait for entry in debug state (with timeout)
+
+
+echo veccatch D > /n/jtagfs/ctl
+
+echo waitstop > /n/jtagfs/ctl
+echo start > /n/jtagfs/ctl
+
+
+window -scroll -r 0 5 700 369 plug
+
+bind /n/jtagfs /proc/1
+echo stop > /n/jtagfs/ctl
+echo debug ky > /proc/1/ctl
+acid -l /usr/paurea/src/jtag/acidjtag -k 1 /arm/s9plug
+
+_tiki:
+	//B	_tiki
+dump(*R15, 4, "X")
+dump(*R15, 4, "Xi")
+dump(0xc03207fc, 4, "X")
+mem(0x00621120, "X")
+regs()
+troff -man jtagfs.man|page -w
+
+bootcmd=bootp ; bootp; tftp 0x1000 /srv/tftp/plugini ; bootp ; tftp 0x800000 /srv/tftp/9plug ; go 0x800000
+
+
+
+boot linux:
+
+setenv bootargs $(bootargs) $(mtdpartitions) $(bootargs_root);
+nand read.e 0x00800000 0x00100000 0x00400000;
+bootm 0x00800000;
diff -Nru /sys/src/cmd/jtagfs/h2acid /sys/src/cmd/jtagfs/h2acid
--- /sys/src/cmd/jtagfs/h2acid	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/h2acid	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,30 @@
+#!/bin/awk -f
+
+#	cat /sys/src/9/kw/mem.h /sys/src/9/kw/arm.h|h2acid|grep -v define
+
+BEGIN{
+	isparen=0
+}
+
+
+/#define ?[^ 	\(]+\(/{
+	isparen=1
+	fullname=$0
+	sub(/\/\*.*\*\//, "", fullname)
+	sub(/\/\/.*/, "", fullname)
+	sub(/[ 	]+$/, "", fullname);
+	name=$2
+	sub(/\(.*/, "", name);
+	params=fullname
+	sub(/[^\(]+\(/, "", params)
+	sub(/\).*/, "", params);
+	val=fullname
+	sub(/[^\)]+\)/, "", val);
+	print("\ndefn", name"("params")", " {\n\t"name "res = " val ";\n}\n")
+}
+
+/#define.*/ && !isparen{
+	print($2 " = " $3 ";");
+}
+
+/.*/{ isparen = 0}
diff -Nru /sys/src/cmd/jtagfs/icert.c /sys/src/cmd/jtagfs/icert.c
--- /sys/src/cmd/jtagfs/icert.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/icert.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,970 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "chain.h"
+#include "debug.h"
+#include "tap.h"
+#include "lebo.h"
+#include "bebo.h"
+#include "jtag.h"
+#include "icert.h"
+#include "mpsse.h"
+#include "/sys/src/9/kw/arm.h"
+#include "mmu.h"
+
+/* 
+ *	Read, paying special atention to anything called 
+ *	embedded-ice/debug of the arm core, normally
+ *	there is a chapter called Debug or Debugging and some
+ *	details sprinkled around.
+ *	- ARM9E-S "Technical Reference Manual"
+ *	- ARM7TDMI-S "Core Technical Reference Manual"
+ *	- Open On-Chip Debugger thesis
+ *	"Design and Implementation of an On-Chip Debug for Embedded
+ *	Target Systems"
+ *	- Application note 205 "Writing JTAG Sequences for Arm 9 Processors"
+ *	The bit ordering on the last one is confusing/wrong, but the
+ *	procedures for doing things clarify a lot.
+ */
+
+
+/*
+ *	BUG: print pack and unpack could be generated automatically 
+ *	except for the wild endianness of the instr. Minilanguage?
+ */
+
+static char *
+printech1(EiceChain1 *ec1, char *s, int ssz)
+{
+	char *e, *te;
+
+	te = s + ssz -1;
+	
+	e = seprint(s, te, "rwdata: %#8.8ux\n", ec1->rwdata);
+	e = seprint(e, te, "wptandbkpt: %1.1d\n", ec1->wptandbkpt);
+	e = seprint(e, te, "sysspeed: %1.1d\n", ec1->sysspeed);
+	e = seprint(e, te, "instr: %#8.8ux\n", ec1->instr);
+	return e;
+}
+
+static int
+packech1(Chain *ch, EiceChain1 *ec1)
+{
+	EiceChain1	lec;
+	uchar unused;
+
+	unused = 0;
+
+	lec.instr = hmsbputl(&ec1->instr);
+	hbeputl(&lec.rwdata, ec1->rwdata);
+
+	putbits(ch, &lec.rwdata, RWDataSz);
+	putbits(ch, &unused, 1);
+	putbits(ch, &lec.wptandbkpt, WpTanDBKptSz);
+	
+	putbits(ch, &ec1->sysspeed, SysSpeedSz);
+	putbits(ch, &lec.instr, InstrSz);
+
+	return 0;
+}
+
+static int
+unpackech1(EiceChain1 *ec1, Chain *ch)
+{
+	uchar unused;
+
+	unused = 0;
+
+
+	getbits(&ec1->rwdata, ch, RWDataSz);
+	getbits(&unused, ch, 1);
+	getbits(&ec1->wptandbkpt, ch, WpTanDBKptSz);
+	getbits(&ec1->sysspeed, ch, SysSpeedSz);
+	getbits(&ec1->instr, ch, InstrSz);
+
+	ec1->instr = msbhgetl(&ec1->instr);
+	ec1->rwdata = lehgetl(&ec1->rwdata);
+
+	return 0;
+}
+
+
+static char *
+printech2(EiceChain2 *ec2, char *s, int ssz)
+{
+	char *e, *te;
+
+	te = s + ssz -1;
+	
+	e = seprint(s, te, "data: %#8.8ux\n", ec2->data);
+	e = seprint(e, te, "addr: %#2.2ux\n", ec2->addr);
+	e = seprint(e, te, "rw: %1.1d\n", ec2->rw);
+	return e;
+}
+
+static int
+valregaddr(uchar addr)
+{
+	if(addr <= CtlMskReg)
+		return 1;
+	if( (addr&Wp0)  <= CtlMskReg ||  (addr&Wp1)  <= CtlMskReg)
+		return 1;
+	return 0;
+}
+
+static int
+packech2(Chain *ch, EiceChain2 *ec2)
+{
+	EiceChain2	lec;
+
+	if(!valregaddr(ec2->addr))
+		return -1;
+
+	hleputl(&lec.data, ec2->data);
+	
+	putbits(ch, &lec.data, DataSz);
+	putbits(ch, &ec2->addr, AddrSz);
+	putbits(ch, &ec2->rw, RWSz);
+	return 0;
+}
+
+static int
+unpackech2(EiceChain2 *ec2, Chain *ch)
+{
+
+	getbits(&ec2->data, ch, DataSz);
+	getbits(&ec2->addr, ch, AddrSz);
+	getbits(&ec2->rw, ch, RWSz);
+
+	if(!valregaddr(ec2->addr))
+		return -1;
+
+	ec2->data = lehgetl(&ec2->data);
+
+	return 0;
+}
+
+
+static char *
+printwp(EiceWp *wp, char *s, int ssz)
+{
+	char *e, *te;
+
+	te = s + ssz -1;
+	
+	e = seprint(s, te, "addrval: %#8.8ux\n", wp->addrval);
+	e = seprint(e, te, "addmsk: %#8.8ux\n", wp->addrmsk);
+	e = seprint(e, te, "dataval: %#8.8ux\n", wp->dataval);
+	e = seprint(e, te, "datamsk: %#8.8ux\n", wp->datamsk);
+
+	e = seprint(e, te, "ctlval: %#4.4ux\n", wp->ctlval);
+	e = seprint(e, te, "ctlmsk: %#2.2ux\n", wp->ctlmsk);
+	return e;
+}
+
+static char *
+printregs(EiceRegs *regs, char *s, int ssz)
+{
+	char *e, *te, i;
+
+	te = s + ssz -1;
+	
+	e = seprint(s, te, "debug: %#2.2ux\n", regs->debug);
+	e = seprint(e, te, "debsts: %#2.2ux\n", regs->debsts);
+	e = seprint(e, te, "veccat: %#2.2ux\n", regs->veccat);
+	e = seprint(e, te, "debcomctl: %#2.2ux\n", regs->debcomctl);
+	e = seprint(e, te, "debcomdata: %#8.8ux\n", regs->debcomdata);
+
+	for(i = 0; i<nelem(regs->wp); i++)
+		e = printwp(regs->wp + i, e, ssz+(s-e));
+	return e;
+}
+
+static u32int
+unpackcpuid(uchar *v)
+{
+	u32int id;
+
+	id = lehgetl(v);
+	return id;
+}
+
+static void
+prcpuid(u32int id)
+{
+
+	fprint(2, "ID: %#8.8ux\n", id);
+	fprint(2, "Must be 1: %d\n", id&1);
+	fprint(2, "Manufacturer id: %#lux\n", MANID(id));
+	fprint(2, "Part no: %#lux\n", PARTNO(id));
+	fprint(2, "Version: %#lux\n", VERS(id));
+	return;
+}
+
+
+
+int
+setinst(JMedium *jmed, uchar inst, int nocommit)
+{
+	int res, com;
+	ShiftTDesc req;
+	uchar buf[1+ShiftMarg];
+
+	memset(buf, 0, 5);
+	buf[0] = inst;
+	com = 0;
+
+	dprint(Djtag, "Setting jtag instr: %#2.2ux, commit: %d\n",
+			inst, !nocommit);
+	if(nocommit)
+		com = ShiftNoCommit;
+	req.reg = TapIR;
+	req.buf = buf;
+	req.nbits = InLen;
+	req.op = ShiftOut|com;
+
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0){
+		werrstr("setinst: shifting instruction %#2.2ux for jtag", inst);
+		return -1;
+	}
+	return res;
+}
+
+int
+icesetreg(JMedium *jmed, int regaddr, u32int val)
+{
+	Chain ch;
+	ShiftTDesc req;
+	EiceChain2 ec2;
+	char debugstr[128];
+	int res;
+
+	dprint(Dice, "Set eice 2 reg[%#2.2ux] to %#8.8ux\n", regaddr, val);
+	ec2.data = val;
+	ec2.addr = regaddr;
+	ec2.rw = 1;
+	memset(&ch, 0, sizeof ch);
+
+
+	res = packech2(&ch, &ec2);
+	if(res < 0)
+		return -1;
+	if(debug[Dchain] || debug[DAll]){
+		printech2(&ec2, debugstr, sizeof debugstr);
+		fprint(2, "%s", debugstr);
+		printchain(&ch);
+	}
+	req.reg = TapDR;
+	req.buf = ch.buf;
+	req.nbits = EiceCh2Len;
+	req.op = ShiftOut;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		return -1;
+
+	return 0;
+}
+
+
+u32int
+icegetreg(JMedium *jmed, int regaddr)
+{
+	Chain ch;
+	ShiftTDesc req;
+	int res;
+	EiceChain2 ec2;
+	char debugstr[128];
+
+	ec2.data = 0;
+	ec2.addr = regaddr;
+	ec2.rw = 0;
+	memset(&ch, 0, sizeof ch);
+
+	res = packech2(&ch, &ec2);
+	if(res < 0)
+		return -1;
+	if(debug[Dchain] || debug[DAll]){
+		printech2(&ec2, debugstr, sizeof debugstr);
+		fprint(2, "%s", debugstr);
+		printchain(&ch);
+	}
+	req.reg = TapDR;
+	req.buf = ch.buf;
+	req.nbits = EiceCh2Len;
+	req.op = ShiftOut;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		return -1;
+	req.reg = TapDR;
+	req.buf = ch.buf;
+	req.nbits = EiceCh2Len;
+	req.op = ShiftOut|ShiftIn;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		return -1;
+	ch.b = 0;
+	ch.e = EiceCh2Len;
+	res = unpackech2(&ec2, &ch);
+	if(res < 0)
+		return -1;
+	if(debug[Dice] || debug[DAll]){
+		printchain(&ch);
+		printech2(&ec2, debugstr, sizeof debugstr);
+		fprint(2, "Get eice 2 reg[%#2.2ux] to %#8.8ux\n", regaddr, ec2.data);
+	}
+	return ec2.data;
+}
+
+int
+setchain(JMedium *jmed, int commit, uchar chain)
+{
+	ShiftTDesc req;
+	uchar data[1+ShiftMarg];
+	int res, com;
+
+	dprint(Dice, "Set chain %d, chain before %d\n", chain, jmed->currentch);
+	if(jmed->currentch == chain)
+		return 0;
+	res = setinst(jmed, InScanN, 1);
+	if(res < 0)
+		return -1;
+	data[0] = chain;
+	com = 0;
+	if(!commit)
+		com = ShiftNoCommit;
+	req.reg = TapDR;
+	req.buf = data;
+	req.nbits = 5;
+	req.op = ShiftPauseIn|ShiftOut|com;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		return -1;
+	res = setinst(jmed, InTest, 1);
+	if(res < 0)
+		return -1;
+	jmed->currentch = chain;
+	return 0;
+}
+
+
+int
+armgofetch(JMedium *jmed, u32int instr, int sysspeed)
+{
+	char debugstr[128];
+	ShiftTDesc req;
+	EiceChain1 ec1;
+	Chain ch;
+	int res;
+
+	ec1.instr = instr;
+	ec1.sysspeed = sysspeed;
+	ec1.wptandbkpt = 0;
+	ec1.rwdata = 0;
+	memset(&ch, 0, sizeof (Chain));
+	res = packech1(&ch, &ec1);
+	if(res < 0)
+		return -1;
+	if(debug[Dchain] || debug[DAll]){
+		printech1(&ec1, debugstr, sizeof debugstr);
+		fprint(2, "%s", debugstr);
+		printchain(&ch);
+	}
+	req.reg = TapDR;
+	req.buf = ch.buf;
+	req.nbits = ch.e-ch.b;
+	req.op = ShiftOut|ShiftPauseOut|ShiftPauseIn;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		return -1;
+	return 0;
+
+}
+
+int
+armgetexec(JMedium *jmed, int nregs, u32int *regs, u32int inst)
+{
+	ShiftTDesc req;
+	int i, res, flags;
+	uchar *buf;
+	ShiftRDesc *replies;
+
+	dprint(Darm, "Exec: %#8.8ux\n", inst);
+	replies = mallocz(nregs*sizeof(ShiftRDesc), 1);
+	if(replies == nil)
+		sysfatal("read, no mem %r");
+	buf = mallocz(EiceCh1Len+ShiftMarg, 1);	
+	if(buf == nil)
+		sysfatal("read, no mem %r");
+	armgofetch(jmed, inst, 0);
+	/* INST in decode stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* INST in execute stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* INST in access stage */
+	flags = ShiftAsync|ShiftIn|ShiftPauseIn|ShiftPauseOut;
+	for(i = 0; i < nregs; i++){
+		req.reg = TapDR;
+		req.buf = buf;
+		req.nbits = EiceCh1Len;
+		req.op = flags;
+		res = tapshift(jmed, &req,  &replies[i], jmed->tapcpu);
+		if(res < 0)
+			return -1;
+	}
+	for(i = 0; i < nregs; i++){
+		res = jmed->rdshiftrep(jmed, buf, &replies[i]);
+		if(res < 0)
+			return -1;
+		regs[i] = *(u32int *)buf;
+		dprint(Darm, "Read [%d]: %#8.8ux\n", i, regs[i]);
+	}	
+	armgofetch(jmed, ARMNOP, 0);
+	/* INST in writeback stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* INST end, pipeline full of NOPs */
+
+	free(buf);
+	free(replies);
+	return 0;
+}
+
+int
+armsetexec(JMedium *jmed, int nregs, u32int *regs, u32int inst)
+{
+	ShiftTDesc req;
+	int i, res, flags;
+	uchar *buf;
+
+	ShiftRDesc *replies;
+
+	dprint(Darm, "Exec: %#8.8ux\n", inst);
+	replies = mallocz(nregs*sizeof(ShiftRDesc), 1);
+	if(replies == nil)
+		sysfatal("read, no mem %r");
+	buf = mallocz(EiceCh1Len+ShiftMarg, 1);
+	if(buf == nil)
+		sysfatal("readregs, no mem %r");
+	armgofetch(jmed, inst, 0);
+	/* STMIA in decode stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* STMIA in execute stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* STMIA in memory acess stage */
+	flags = ShiftOut|ShiftPauseIn|ShiftPauseOut;
+	for(i = 0; i < nregs; i++){
+		*(u32int *)buf = regs[i];
+		dprint(Darm, "Set [%d]: %#8.8ux\n", i, regs[i]);
+		req.reg = TapDR;
+		req.buf = buf;
+		req.nbits = EiceCh1Len;
+		req.op = flags;
+		res = tapshift(jmed, &req,  nil, jmed->tapcpu);
+		if(res < 0)
+			return -1;
+	}
+	armgofetch(jmed, ARMNOP, 0);
+	/* STMIA in writeback stage */
+	armgofetch(jmed, ARMNOP, 0);
+	/* STMIA end, pipeline full of NOPs */
+
+	free(buf);
+	free(replies);
+	return 0;
+}
+
+/* reads r0-r15 to regs if bits of mask are 1 */
+static int
+armgetregs(JMedium *jmed, u32int mask, u32int *regs)
+{
+	int ireps, nregs, r, i;
+	u32int *regrd;
+
+	nregs = 0;
+	ireps = 0;
+	for(i = 0; i < 16; i++){
+		if( (1 << i) & mask)
+			nregs++;
+	}
+	regrd = mallocz(nregs*sizeof(u32int), 1);
+	if(regrd == nil)
+		sysfatal("read, no mem %r");
+
+	r = armgetexec(jmed, nregs, regrd, ARMSTMIA|mask);
+	if(r < 0)
+		return -1;
+
+	for(i = 0; i < 16; i++){
+		if( (1 << i) & mask){
+			regs[i] = regrd[ireps++];
+			dprint(Darm, "rd register r%d: %#8.8ux\n", i, regs[i]);
+		}
+	}
+	free(regrd);
+	return 0;
+}
+/* sets r0-r15 to regs if bits of mask are 1 */
+int
+armsetregs(JMedium *jmed, int mask, u32int *regs)
+{
+	int ireps, nregs, r, i;
+	u32int *regrw;
+
+	nregs = 0;
+	ireps = 0;
+	for(i = 0; i < 16; i++){
+		if( (1 << i) & mask)
+			nregs++;
+	}
+	regrw = mallocz(nregs*sizeof(u32int), 1);
+	if(regrw == nil)
+		sysfatal("read, no mem %r");
+	for(i = 0; i < 16; i++){
+		if( (1 << i) & mask){
+			regrw[ireps++] = regs[i];
+			dprint(Darm, "wr register r%d: %#8.8ux\n", i, regs[i]);
+		}
+	}
+	r = armsetexec(jmed, nregs, regrw, ARMLDMIA|mask);
+	if(r < 0)
+		return -1;
+
+	free(regrw);
+	return 0;
+}
+
+static void
+armprctxt(ArmCtxt *ctxt)
+{
+	int i;
+
+	fprint(2, "Arm is in debug: %d\nregs\n", ctxt->debug);
+	for(i = 0; i < 16; i++)
+		fprint(2, "r%d: %#8.8ux\n", i, ctxt->r[i]);
+	fprint(2, "cpsr: %#8.8ux\n", ctxt->cpsr);
+	fprint(2, "spsr: %#8.8ux\n", ctxt->spsr);
+}
+
+char *
+armsprctxt(ArmCtxt *ctxt, char *s, int ssz)
+{
+	char *e, *te;
+	int i;
+
+	te = s + ssz -1;
+
+	e = seprint(s, te, "Arm is in debug: %d\nregs\n", ctxt->debug);
+	for(i = 0; i < 16; i++)
+		e = seprint(e, te, "r%d: %#8.8ux\n", i, ctxt->r[i]);
+	e = seprint(e, te, "cpsr: %#8.8ux\n", ctxt->cpsr);
+	e = seprint(e, te, "spsr: %#8.8ux\n", ctxt->spsr);
+	return e;
+}
+
+static char dbgstr[4*1024];
+
+int
+armsavectxt(JMedium *jmed, ArmCtxt *ctxt)
+{
+	int res;
+
+	res = setchain(jmed, 0, 1);
+	if(res < 0)
+		goto Error;
+	
+	res = armgetregs(jmed, 0xffff, ctxt->r);
+	if(res < 0)
+		goto Error;
+	res = armgofetch(jmed, ARMMRSr0CPSR, 0);
+	if(res < 0)
+		goto Error;
+	res = armgetexec(jmed, 1, &ctxt->cpsr, ARMSTMIA|0x0001);
+	if(res < 0)
+		goto Error;
+	res = armgofetch(jmed, ARMMRSr0SPSR, 0);
+	if(res < 0)
+		goto Error;
+	res = armgetexec(jmed, 1, &ctxt->spsr, ARMSTMIA|0x0001);
+	if(res < 0)
+		goto Error;
+	res = mmurdregs(jmed, ctxt);
+	if(res < 0){
+		werrstr("mmurdregs %r");
+		return -1;
+	}
+	if(debug[Dmmu] || debug[DAll]){
+		printmmuregs(ctxt, dbgstr, sizeof dbgstr);
+		dprint(Dfs, "MMU state:\n%s\n", dbgstr);
+	}
+	if(debug[Dctxt] || debug[DAll]){
+		fprint(2, "Arm save ctxt\n");
+		armprctxt(ctxt);
+	}
+	return 0;
+Error:
+	return -1;
+}
+
+static int
+armjmpctxt(JMedium *jmed, ArmCtxt *ctxt)
+{
+	int res;
+
+	if(debug[Dctxt] || debug[DAll]){
+		fprint(2, "Arm jmp ctxt\n");
+		armprctxt(ctxt);
+	}
+	res = armsetexec(jmed, 1, &ctxt->cpsr, ARMLDMIA|0x0001);
+	if(res < 0)
+		return -1;
+	res = armgofetch(jmed, ARMMSRr0CPSR, 0);
+	if(res < 0)
+		return -1;
+	 /*	it is quite important this is the last instr for PC calculations */
+	ctxt->r[15] += ctxt->pcadjust;
+	res = armsetregs(jmed, 0xffff, ctxt->r);
+	if(res < 0)
+		return -1;
+
+	return 0;
+}
+
+
+int
+armfastexec(JMedium *jmed, u32int inst)
+{
+	int res;
+
+	dprint(Darm, "Exec: %#8.8ux\n", inst);
+	res = armgofetch(jmed, ARMNOP, 0);
+	if(res < 0)
+		return -1;
+
+	res = armgofetch(jmed, ARMNOP, 0);
+	if(res < 0)
+		return -1;
+	res = armgofetch(jmed, ARMNOP, 0);
+	if(res < 0)
+		return -1;
+	res = armgofetch(jmed, inst, 0);
+	if(res < 0)
+		return -1;
+	res = armgofetch(jmed, ARMNOP, 1);
+	if(res < 0)
+		return -1;
+	return 0;
+}
+
+int
+icedebugstate(JMedium *jmed)
+{
+	int res;
+
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return 0;
+	return icegetreg(jmed, DebStsReg) & DBGACK;
+}
+
+int
+icewaitdebug(JMedium *jmed)
+{
+	int i, res;
+
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+
+	for(i = 0; i < 20; i ++){
+		if(icedebugstate(jmed))
+			break;
+		sleep(100);
+	}
+	if( i == 20)
+		return -1;
+
+	icesetreg(jmed, DebugCtlReg, INTDIS|DBGACK); /* clear RQ */
+	return 0;
+}
+
+int
+armrdmemwd(JMedium *jmed, u32int addr, u32int *data, int sz)
+{
+	int res;
+	u32int d, byte;
+
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		sysfatal("setchain %r");
+	byte = 0;
+	if(sz == 1)
+		byte = BYTEWDTH;
+	/* load address in r0 */
+	res = armsetexec(jmed, 1, &addr, ARMLDMIA|0x0001);
+	if(res < 0)
+		return -1;
+
+	/* LDR r1, [r0] place data in r1 */
+	res = armfastexec(jmed, byte|ARMLDRindr1xr0);
+	if(res < 0)
+		return -1;
+
+	setinst(jmed, InRestart, 0);
+	res = icewaitdebug(jmed);
+	if(res < 0)
+		return -1;
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		sysfatal("setchain %r");
+	armgetexec(jmed, 1, &d, byte|ARMSTMIA|0x0002);
+
+	*data = d;
+	dprint(Dmem, "Read data %#8.8ux addr %#8.8ux \n",
+				d, addr);
+	return sz;
+}
+
+int
+armwrmemwd(JMedium *jmed, u32int addr, u32int data, int sz)
+{
+	int res;
+	u32int byte;
+
+	dprint(Dmem, "Write data %#8.8ux addr %#8.8ux \n",
+				data, addr);
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		sysfatal("setchain %r");
+	byte = 0;
+	if(sz == 1)
+		byte = BYTEWDTH;
+	/* load address in r0 */
+	res = armsetexec(jmed, 1, &addr, ARMLDMIA|0x0001);
+	if(res < 0)
+		return -1;
+	/* load data in r1 */
+	res = armsetexec(jmed, 1, &data, byte|ARMLDMIA|0x0002);
+	if(res < 0)
+		return -1;
+
+	/* STR [r0], r1 place data in [r0] */
+	res = armfastexec(jmed, ARMSTRindxr0r1);
+	if(res < 0)
+		return -1;
+
+	setinst(jmed, InRestart, 0);
+	res = icewaitdebug(jmed);
+	if(res < 0)
+		return -1;
+	return sz;
+}
+
+
+u32int
+armidentify(JMedium *jmed)
+{
+	uchar *buf;
+	ShiftTDesc req;
+	u32int cpuid;
+	int res, i;
+
+	//if(jmed->motherb == Sheeva)
+	//	jmed->resets(jmed->mdata, 0, 1);
+	buf = malloc(sizeof(u32int)*0x100+	ShiftMarg);
+	if(buf == nil)
+		sysfatal("memory");
+
+	for(i = 0; i < sizeof(u32int)*0x100; i++)
+		buf[i] = i;	/* just a pattern to see in debugging */
+
+	req.reg = TapDR;
+	req.buf = buf;
+	req.nbits = sizeof(u32int)*0x100;	/* Bug by 8? */
+	req.op = ShiftOut|ShiftIn;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0){
+		free(buf);
+		return ~0;
+	}
+	//if(jmed->motherb == Sheeva)
+	//	jmed->resets(jmed->mdata, 0, 0);
+	cpuid = unpackcpuid(buf);
+	if(cpuid != jmed->taps[jmed->tapcpu].hwid){
+		fprint(2, "cpuid: %#8.8ux != %#8.8ux\n", cpuid, jmed->taps[jmed->tapcpu].hwid);
+		free(buf);
+		return ~0;
+	}
+	prcpuid(cpuid);
+	free(buf);
+	return cpuid;
+}
+
+/* see if the fixed bypass value is ok */
+int
+armbpasstest(JMedium *jmed)
+{
+	ShiftTDesc req;
+	uchar buf[2+ShiftMarg];
+	int res;
+
+	memset(buf, 0xff, sizeof(buf));
+	req.reg = TapIR;
+	req.buf = buf;
+	req.nbits = 2+InLen;
+	req.op = ShiftOut|ShiftIn;
+	res = tapshift(jmed, &req, nil, jmed->tapcpu);
+	if(res < 0)
+		sysfatal("jmed->regshift %r");
+	if((buf[0] & 0xf) !=  0x1){
+		fprint(2, "bad bypass: %#2.2ux\n", buf[0]);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* BUG: werrstr in the inner functions to indicate error, warnings... */
+
+
+int
+icewaitentry(JMedium *jmed, ArmCtxt *ctxt)
+{
+	int res;
+
+	if(ctxt->debugreas == NoReas){
+		werrstr("No debug activated");
+		return -1;
+	}
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+	res = icewaitdebug(jmed);
+	if(res < 0)
+		return -1;
+	
+	res = setchain(jmed, ChNoCommit, 1);
+	if(res < 0)
+		return -1;
+	
+	/*	BUG: should change to Arm from Thumb or Jazelle, adjust, keep PC.
+	 *	If I ever come down to doing this, Remember to repeat Thumb inst
+	 *	to be endian independant...
+	  */
+	res = armsavectxt(jmed, ctxt);
+	if(res < 0)
+		return -1;
+	ctxt->debug = 1;
+
+	ctxt->pcadjust = 0;	/* BUG: Thumb not impl */
+	ctxt->r[15] -= 6*ArmInstSz;
+	switch(ctxt->debugreas){
+		case BreakReas:
+		case VeccatReas:
+			ctxt->pcadjust = -2*ArmInstSz;
+		break;
+		case DebugReas:
+		break;
+	}
+	return 0;
+}
+
+int
+iceenterdebug(JMedium *jmed, ArmCtxt *ctxt)
+{
+	int res;
+
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+
+	//if(jmed->motherb == Sheeva)
+	//	jmed->resets(jmed->mdata, 0, 1);
+	if(!(icegetreg(jmed, DebStsReg) & DBGACK)){
+			icesetreg(jmed, DebugCtlReg, DBGRQ);	/* freeze */
+	}
+
+	//if(jmed->motherb == Sheeva)
+	//	jmed->resets(jmed->mdata, 0, 0);
+	ctxt->debugreas = DebugReas;
+	res = icewaitentry(jmed, ctxt);
+	if(res < 0)
+		return -1;
+	ctxt->exitreas = NoReas;
+	return 0;
+}
+
+
+/*
+ *	The branch is the way to exit debug permanently
+ * 	no branch and you fall back to debug
+ *	The context needs to be restored (some register needs
+ *	to be written), don't know why
+ *	but you will fall back to debug if not, no matter what doc says.
+ *	The bypass is not mentioned to be necessary anywhere, but
+ *	the feroceon will not restart without it.
+ */
+
+int
+iceexitdebug(JMedium *jmed, ArmCtxt *ctxt)
+{
+	int res, i;
+	uchar wctl;
+	u32int sts;
+
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		return -1;
+
+	res = armjmpctxt(jmed, ctxt);
+	if(res < 0)
+		return -1;
+
+	/* 4 entry to debug,  Store(does not count)  3 NOPS, Branch = -8 */
+	res = armfastexec(jmed, ARMBRIMM|0xfffffb);
+	if(res < 0)
+		return -1;
+
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+
+	wctl = icegetreg(jmed, Wp0|CtlValReg);
+	if(ctxt->exitreas != BreakReqReas)
+		icesetreg(jmed, Wp0|CtlValReg, wctl&~EnableWPCtl);
+
+	if(ctxt->exitreas != VeccatReqReas)
+		icesetreg(jmed, VecCatReg, 0);
+	icesetreg(jmed, DebugCtlReg, 0); /* clear all,*/
+	setinst(jmed, InBypass, 0);
+	setinst(jmed, InRestart, 0);
+	sleep(100);
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+
+	for(i = 0; i < 10; i ++){
+		sts = icegetreg(jmed, DebStsReg);
+		if((sts&DBGACK) == 0)
+			break;
+		sleep(100);
+	}
+	if( i == 10)
+		return -1;
+
+	switch(ctxt->exitreas){
+		case NoReas:
+			ctxt->debugreas = NoReas;
+		break;
+		case VeccatReqReas:
+			ctxt->debugreas = VeccatReas;
+		break;
+		case BreakReqReas:
+			ctxt->debugreas = BreakReas;
+		break;
+		default:
+			ctxt->debugreas = NoReas;
+		break;
+	}
+	ctxt->debug = 0;
+	return 0;
+}
diff -Nru /sys/src/cmd/jtagfs/icert.h /sys/src/cmd/jtagfs/icert.h
--- /sys/src/cmd/jtagfs/icert.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/icert.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,273 @@
+typedef struct ArmCtxt ArmCtxt;
+typedef struct EiceChain1 EiceChain1;
+typedef struct EiceChain2 EiceChain2;
+typedef struct EiceRegs EiceRegs;
+typedef struct EiceWp EiceWp;
+typedef struct MMURegs MMURegs;
+typedef struct PackedSz PackedSz;
+
+enum{
+	/*
+	  *	This is an arm 926, except no MOE, only 1 Wpoint
+	  *	I think this means "mcr access"
+	  * 	for the MMU. It would be good knowing for real
+	  *	what the good doc for it is or if it is just
+	  *	random mix and match!!.
+	  */
+	FeroceonId	= 0x20a023d3,
+	
+	/* Looks like a pxa/feroceon frankenstein */
+	ArmadaId	= 0x304113d3,
+
+	ArmInstSz = 4,
+	ThumbInstSz = 2,
+};
+
+
+/* instructions for the IR, 4 bits */
+enum {
+	InExtest	= 0x0,
+	InScanN	= 0x2,		/* shift the scan chain id, 5 bits */
+	InSampPre	= 0x3,
+	InRestart	= 0x4,
+	InHighZ	= 0x7,
+	InClampZ	= 0x9,
+	InTest		= 0xc,
+	InIdCode	= 0xe,
+	InBypass	= 0xf,
+
+	InGuruTapctl = 0x98,
+	InGuruLen = 9,
+	DrGuruTapctl = 0x00a,
+	DrGuruLen = 16,
+
+	InLen		= 4,		/* bits */
+	EiceCh1Len	= 67,		/* bits */
+	EiceCh2Len	= 38,		/* bits */
+};
+
+/* sizes are in bits */
+#define WpN(nreg, field) ((nreg<<(nreg))|(field))
+
+enum {
+
+	/* chain 1 */
+	InstrSz			= 32,
+	SysSpeedSz		= 1,
+	WpTanDBKptSz		= 1,
+	Ch1ResvdSz,
+	RWDataSz			= 32,
+	
+
+	/* chain 2, here registers are directed through addr */
+	DataSz			= 32,
+	AddrSz			= 5,
+	RWSz			= 1,
+
+	DebugCtlReg		= 0x00,
+	DebStsReg		= 0x01,
+	VecCatReg		= 0x02,
+	DebComCtlReg		= 0x04,
+	DebComDataReg	= 0x05,
+
+	Wp0				= 1<<4,	/* Wp0|AddrValReg and so on */
+	Wp1				= 1<<5,	/* Wp1|AddrValReg and so on */
+
+	AddrValReg		= 0x00,
+	AddrMskReg		= 0x01,
+	DataValReg		= 0x02,
+	DataMskReg		= 0x03,
+	CtlValReg			= 0x04,
+	CtlMskReg		= 0x05,
+	
+	/* sizes in bits */
+	DebugCtlRegSz		= 6,
+	DebStsRegSz		= 10,		/* in feroceon 5, no Moe */
+	VecCatRegSz		= 8,
+	DebComCtlRegSz	= 6,
+	DebComDataRegSz	= 32,
+
+	AddrValRegSz		= 32,
+	AddrMskRegSz		= 32,
+	DataValRegSz		= 32,
+	DataMskRegSz		= 32,
+	CtlValRegSz		= 9,
+	CtlMskRegSz		= 8,
+	
+	/*	DebugCtlReg (write) */
+	DBGACK			= 1,		/* I am dealing with debug mode */
+	DBGRQ			= 1<<1,	/* Enter debug mode */
+	INTDIS			= 1<<2,	/* Disable interrupts */
+	SBZ0				= 1<<3,	/* Should be Zero */
+	MONENAB		= 1<<4,	/* Monitor mode/halt mode */
+	EICEDISAB		= 1<<5,	/* Power down */
+
+	/*	DebugSTSReg (read)
+	 * 	two first bits same as ctl
+	 */
+	IFEN			= 1<<2,		/* Are interrupts enabled */
+	SYSCOMP		= 1<<3,		/* Memory access complete */
+	ITBIT		= 1<<4,		/* Thumb/Arm mode */
+	SBZ1			= 1<<5,
+	MOEMSK		= 0xf<<6,		/* Method of entry */
+
+	/*	VecCatReg (write), one bit per exception to catch */
+	ResetCat		= 1,
+	UndefCat		= 1<<1,
+	SWICat		= 1<<2,
+	PAbortCat		= 1<<3,
+	DAbortCat	= 1<<4,
+	RsvdCat		= 1<<5,
+	IrqCat		= 1<<6,
+	FiqCat		= 1<<7,
+
+	/*
+	 *	Watchpoint control registers:
+	 *	CtlValReg CtlMskReg
+	 *	Bit 1 in Msk makes condition ignored.
+	 */
+	
+	/* Data version of CtlValReg bits 6, 7, 8 are shared */
+	DnRWWPCtl		= 1,		/*  0 access is read 1 write */
+	DmasWPCtlMsk	= 3<<1,	/*  this two bits represent size of access */
+	DataWPCtl		= 1<<3,	/* compare against data/0 is inst */
+	DnTransWPCtl		= 1<<4,	/* 0 user 1 privileged */
+	DbgExtWPCtl		= 1<<5,	/* External condition for watchpoint */
+	ChainWPCtl		= 1<<6,	/* Chain together watchpoints */
+	RangeWPCtl		= 1<<7,	/* Range connecting watchpoints together */
+	EnableWPCtl		= 1<<8,	/* Cannot be masked */
+	/* Inst version of CtlValReg */
+	IgnWPCtl			= 1,	/*  ignored */
+	ITbitWPCtlMsk		= 3<<1,	/*  1 Thumb  */
+	IJbitWPCtl			= 1<<2,	/*  1 Jazelle  */
+	InTransWPCtl		= 1<<4,	/* 0 user 1 privileged */
+
+
+	/*	Id code */
+	ManIdSz		= 11,
+	PartNoSz		= 16,
+	VerSz		= 4,
+
+};
+
+enum{
+	ChNoCommit	= 0,
+	ChCommit	= 1,
+};
+
+struct PackedSz {
+	uchar unpkSz;
+	uchar pkSz;
+};
+
+/*
+ * The bit ordering on this one is peculiar, see packech1()
+ * in particular the instruction is upside down,
+ */
+
+struct EiceChain1 {
+	u32int	instr;			/* 32 bits */
+	uchar	sysspeed;		/* 1 bit */
+	uchar	wptandbkpt;	/* 1 bit */
+	/* 1 bit rsvd */
+	u32int	rwdata;		/* 32 bits */
+};
+
+struct EiceChain2 {
+	u32int data;		/* 32 bits */
+	uchar addr;		/* 5 bits */
+	uchar	rw;		/* 1 bit */
+};
+
+struct EiceWp {
+	u32int	addrval;	/* 32 bits */
+	u32int	addrmsk;	/* 32 bits */
+	u32int	dataval;	/* 32 bits */
+	u32int	datamsk;	/* 32 bits */
+	u16int	ctlval;	/* 9 bits */
+	uchar	ctlmsk;	/* 8 bits */
+};
+
+struct EiceRegs {
+	uchar	debug;		/* 4 bits */
+	uchar	debsts;		/* 5 bits */
+	uchar	veccat;		/* 8 bits */
+	uchar	debcomctl;	/* 6 bits */
+	u32int	debcomdata;	/* 32 bits */
+	EiceWp wp[2];
+};
+
+enum{
+	ARMSTMIA = 0xe8800000,
+	ARMLDMIA = 0xe8900000,
+	BYTEWDTH = 0x00400000,
+	ARMLDRindr1xr0 = 0xe5901000,	/* LDR r1, [r0]	|| [r0]->r1*/
+	ARMSTRindxr0r1 = 0xe5801000,	/* STR [r0], r1 || r1->[r0] */
+	ARMNOP = 0xe1a08008,
+	ARMMRSr0CPSR = 0xE10F0000,
+	ARMMSRr0CPSR = 0xE12FF000,
+	SPSR = 1<<22,
+	ARMMRSr0SPSR = ARMMRSr0CPSR|SPSR,
+	ARMMSRr0SPSR = ARMMSRr0CPSR|SPSR,
+	ARMBRIMM = 0xea000000,
+};
+
+
+#define MOE(dbgreg)	(((dbgreg)&MOEMSK)>>6);
+
+#define MANID(id)	(((id)>>1)&MSK(ManIdSz))
+#define PARTNO(id)	(((id)>>ManIdSz+1)&MSK(PartNoSz))
+#define VERS(id)	(((id)>>ManIdSz+1+PartNoSz)&MSK(VerSz))
+
+struct MMURegs {
+	u32int	cpid;		/* main ID */
+	u32int	control;	/* control */
+	u32int	ttb;		/* translation table base */
+	u32int	dac;		/* domain access control */
+	u32int	fsr;		/* fault status */
+	u32int	far;		/* fault address */
+	u32int	ct;		/* cache type */
+	u32int	pid;		/* address translation pid */
+};
+
+enum{
+	NoReas,
+	BreakReqReas,
+	BreakReas,
+	VeccatReqReas,
+	VeccatReas,
+	DebugReas,
+};
+
+struct ArmCtxt {
+	int pcadjust;
+	int debug;
+	int debugreas;
+	int exitreas;
+	int cpuid;
+	u32int r[16];
+	u32int cpsr;
+	u32int spsr;
+	MMURegs;
+};
+
+extern int	armbpasstest(JMedium *jmed);
+extern int	armfastexec(JMedium *jmed, u32int inst);
+extern int	armgetexec(JMedium *jmed, int nregs, u32int *regs, u32int inst);
+extern int	armgofetch(JMedium *jmed, u32int instr, int sysspeed);
+extern u32int	armidentify(JMedium *jmed);
+extern int	armrdmemwd(JMedium *jmed, u32int addr, u32int *data, int sz);
+extern int	armsavectxt(JMedium *jmed, ArmCtxt *ctxt);
+extern int	armsetexec(JMedium *jmed, int nregs, u32int *regs, u32int inst);
+extern int	armsetregs(JMedium *jmed, int mask, u32int *regs);
+extern int	armwrmemwd(JMedium *jmed, u32int addr, u32int data, int sz);
+extern int	icedebugstate(JMedium *jmed);
+extern int	iceenterdebug(JMedium *jmed, ArmCtxt *ctxt);
+extern int	iceexitdebug(JMedium *jmed, ArmCtxt *ctxt);
+extern u32int	icegetreg(JMedium *jmed, int regaddr);
+extern int	icesetreg(JMedium *jmed, int regaddr, u32int val);
+extern int	icewaitdebug(JMedium *jmed);
+extern int	icewaitentry(JMedium *jmed, ArmCtxt *ctxt);
+extern int	setchain(JMedium *jmed, int commit, uchar chain);
+extern int	setinst(JMedium *jmed, uchar inst, int nocommit);
+extern char *	armsprctxt(ArmCtxt *ctxt, char *s, int ssz);
diff -Nru /sys/src/cmd/jtagfs/jtag.c /sys/src/cmd/jtagfs/jtag.c
--- /sys/src/cmd/jtagfs/jtag.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/jtag.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "debug.h"
+#include "tap.h"
+#include "chain.h"
+#include "jtag.h"
+
+/*
+	We will only have one active tap at a time.
+	For now we will suppose they are concatenated.
+	IR will be 1s for the rest of the bits (Bypass the rest)
+	DR will be 1 bit per ignored Tap
+*/
+
+static uchar  bufch[4*1024];
+int
+tapshift(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep, int tapidx)
+{
+	int i;
+	u32int ones;
+	ShiftTDesc lreq;
+	Chain *ch;
+
+	lreq = *req;
+	ones = ~0;
+	memset(bufch, 0, sizeof bufch);
+	ch = (Chain *)bufch;
+
+	for(i = 0; i < jmed->ntaps; i++){
+		if(req->reg == TapDR){
+			if(i == tapidx){
+				dprint(DState, "tap %d, DR\n", tapidx);
+				putbits(ch, req->buf, req->nbits);
+			}
+			else {
+				dprint(DState, "tap %d, ignoring DR\n", i);
+				putbits(ch, &ones, 1);
+			}
+		}
+		else if(req->reg == TapIR){
+			if(i == tapidx){
+				dprint(DState, "tap %d, IR\n", tapidx);
+				putbits(ch, req->buf, req->nbits);
+			}
+			else {
+				dprint(DState, "tap %d, IR\n", tapidx);
+				putbits(ch, &ones, jmed->taps[tapidx].irlen);
+			}
+		}
+	}
+
+	lreq.buf = ch->buf;
+	lreq.nbits = ch->e - ch->b;
+	jmed->TapSm = jmed->taps[tapidx].TapSm;
+	if(jmed->regshift(jmed, &lreq, rep) < 0)
+		return -1;
+	jmed->taps[tapidx].TapSm = jmed->TapSm;
+
+	if(req->op & ShiftIn)
+		for(i = 0; i < jmed->ntaps; i++){
+			if(req->reg == TapDR){
+				if(i == tapidx)
+					getbits(req->buf, ch, ch->e - ch->b);
+				else
+					getbits(&ones, ch, 1);
+			}
+			else if(req->reg == TapIR){
+				if(i == tapidx)
+					getbits(req->buf, ch, ch->e - ch->b);
+				else 
+					getbits(&ones, ch, jmed->taps[tapidx].irlen);
+			}
+		}
+	
+	return 0;
+}
diff -Nru /sys/src/cmd/jtagfs/jtag.h /sys/src/cmd/jtagfs/jtag.h
--- /sys/src/cmd/jtagfs/jtag.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/jtag.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,47 @@
+typedef struct JMedium JMedium;
+typedef struct ShiftTDesc ShiftTDesc;
+typedef struct ShiftRDesc ShiftRDesc;
+
+
+/* descriptor for a shift if not there are too many parameters */
+struct ShiftTDesc {
+	int		reg;
+	uchar	*buf;
+	int		nbits;
+	int		op;
+};
+
+/* descriptor for a reply to do async replies, timing agh... */
+struct ShiftRDesc{
+	int	nbyread;	/* total bytes */
+	int	nbiprelast;	/* bits of next to last */
+	int	nbilast;	/* bits of last */
+};
+
+/* this is the interface for the medium */
+struct JMedium {
+	TapSm;				/* of the tap I am currently addressing */
+	int		motherb;
+	int		tapcpu;
+	Tap		taps[16];
+	int		ntaps;
+	uchar	currentch;	/* BUG: in tap[tapcpu]->private */
+	void		*mdata;
+	int		(*regshift)(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep);
+	int		(*flush)(void *mdata);
+	int		(*term)(void *mdata);
+	int		(*resets)(void *mdata, int trst, int srst);
+	int		(*rdshiftrep)(JMedium *jmed, uchar *buf, ShiftRDesc *rep);
+};
+
+enum{
+	ShiftMarg		= 4,		/* Max number of extra bytes in response */
+
+	ShiftIn		= 1,
+	ShiftOut		= 2,
+	ShiftNoCommit	= 4,		/* Normally you want to commit... */
+	ShiftPauseOut	= 8,		/* go through pause on the way out */
+	ShiftPauseIn	= 16,		/* go through pause on the way in */
+	ShiftAsync	= 32,		/* do not read reply synch */
+};
+extern int	tapshift(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep, int tapidx);
diff -Nru /sys/src/cmd/jtagfs/jtagfs.c /sys/src/cmd/jtagfs/jtagfs.c
--- /sys/src/cmd/jtagfs/jtagfs.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/jtagfs.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,1590 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include <regexp.h>
+#include <bio.h>
+#include "debug.h"
+#include "tap.h"
+#include "chain.h"
+#include "jtag.h"
+#include "icert.h"
+#include "mmu.h"
+#include "mpsse.h"
+#include "/sys/src/9/kw/arm.h"
+#include "/arm/include/ureg.h"
+#include "lebo.h"
+
+/*
+ * Like rdbfs + jtag icert control for arm cores.
+ * Memory just goes through in arm order, registers get translated
+ * to host order and back after.
+ */
+
+typedef struct Fid Fid;
+typedef struct Fs Fs;
+enum
+{
+	OPERM	= 0x3,		/* mask of all permission types in open mode */
+	Nfidhash	= 32,
+
+	/*
+	 * qids
+	 */
+	Qroot	= 1,
+	Qctl,
+	Qnote,
+	Qmem,
+			/* copied from rdbfs */
+	Qkregs,
+	Qfpregs,
+	Qproc,
+	Qregs,
+	Qtext,
+	Qstatus,
+};
+
+static int		textfd;
+static char*	textfile = "/arm/s9plug";
+
+
+struct Fid
+{
+	Lock;
+	Fid	*next;
+	Fid	**last;
+	uint	fid;
+	int	ref;			/* number of fcalls using the fid */
+	int	attached;		/* fid has beed attached or cloned and not clunked */
+
+	int	open;
+	Qid	qid;
+};
+
+static int			dostat(int, uchar*, int);
+static void*		emalloc(uint);
+static void			fatal(char*, ...);
+static void			usage(void);
+
+struct Fs
+{
+	Lock;				/* for fids */
+
+	Fid		*hash[Nfidhash];
+	uchar	statbuf[1024];	/* plenty big enough */
+	JMedium *jmed;
+};
+
+static	void		fsrun(Fs*, int);
+static	Fid*		getfid(Fs*, uint);
+static	Fid*		mkfid(Fs*, uint);
+static	void		putfid(Fs*, Fid*);
+static	char*	fsversion(Fs*, Fcall*);
+static	char*	fsauth(Fs*, Fcall*);
+static	char*	fsattach(Fs*, Fcall*);
+static	char*	fswalk(Fs*, Fcall*);
+static	char*	fsopen(Fs*, Fcall*);
+static	char*	fscreate(Fs*, Fcall*);
+static	char*	fsread(Fs*, Fcall*);
+static	char*	fswrite(Fs*, Fcall*);
+static	char*	fsclunk(Fs*, Fcall*);
+static	char*	fsremove(Fs*, Fcall*);
+static	char*	fsstat(Fs*, Fcall*);
+static	char*	fswstat(Fs*, Fcall*);
+
+static char	*(*fcalls[])(Fs*, Fcall*) =
+{
+	[Tversion]		fsversion,
+	[Tattach]		fsattach,
+	[Tauth]		fsauth,
+	[Twalk]		fswalk,
+	[Topen]		fsopen,
+	[Tcreate]		fscreate,
+	[Tread]		fsread,
+	[Twrite]		fswrite,
+	[Tclunk]		fsclunk,
+	[Tremove]	fsremove,
+	[Tstat]		fsstat,
+	[Twstat]		fswstat
+};
+
+static char	Eperm[]		=	"permission denied";
+static char	Enotdir[]		=	"not a directory";
+static char	Enotexist[]	=	"file does not exist";
+static char	Eisopen[]		= 	"file already open for I/O";
+static char	Einuse[]		=	"fid is already in use";
+static char	Enofid[]		= 	"no such fid";
+static char	Enotopen[]	=	"file is not open";
+static char	Ebadcmd[]	=	"error in jtag operation";
+
+static ArmCtxt ctxt;
+static Fs		fs;
+static int		messagesize = 8192+IOHDRSZ;
+
+static int
+cmdsetdebug(uchar *deb)
+{
+	int i;
+
+	memset(debug, 0, 255);
+	for(i = 0; i < strlen((char *)deb); i++){
+		debug[deb[i]]++;
+	}
+	return 0;
+}
+
+
+
+void
+main(int argc, char **argv)
+{
+	char buf[12], *mnt, *srv, *mbname;
+	int fd, p[2], mb;
+	uchar *deb;
+	
+	deb = nil;
+	mb = Sheeva;
+	mbname = nil;
+	mnt = "/n/jtagfs";
+	srv = nil;
+	ARGBEGIN{
+		case 'b':
+			mbname = EARGF(usage());
+			break;
+		case 's':
+			srv = ARGF();
+			mnt = nil;
+			break;
+		case 'm':
+			mnt = ARGF();
+			break;
+		case 'd':
+			deb = (uchar *)EARGF(usage());
+			break;
+		case 't':
+			textfile = EARGF(usage());
+			break;
+	}ARGEND
+
+	fmtinstall('F', fcallfmt);
+	if(deb  != nil)
+		cmdsetdebug(deb);
+	if(argc != 1)
+		usage();
+	print("jtagfs: %s\n", argv[0]);
+	fd = open(argv[0], ORDWR);
+	if(fd < 0)
+		fatal("can't open jtag file %s: %r", argv[0]);
+
+	if(mbname == nil)
+		mb = Sheeva;
+	else if(strncmp(mbname, "sheeva", 6) == 0)
+		mb = Sheeva;
+	else if(strncmp(mbname, "gurudisp", 6) == 0)
+		mb = GuruDisp;
+	fs.jmed = initmpsse(fd, mb);
+	if(fs.jmed == nil)
+		fatal("jtag initialization %r");
+	
+	if(pipe(p) < 0)
+		fatal("pipe failed");
+
+	switch(rfork(RFPROC|RFMEM|RFNOTEG|RFNAMEG)){
+	case 0:
+		fsrun(&fs, p[0]);
+		exits(nil);
+	case -1:	
+		fatal("fork failed");
+	}
+
+	if(mnt == nil){
+		if(srv == nil)
+			usage();
+		fd = create(srv, OWRITE, 0666);
+		if(fd < 0){
+			remove(srv);
+			fd = create(srv, OWRITE, 0666);
+			if(fd < 0){
+				close(p[1]);
+				fatal("create of %s failed", srv);
+			}
+		}
+		sprint(buf, "%d", p[1]);
+		if(write(fd, buf, strlen(buf)) < 0){
+			close(p[1]);
+			fatal("writing %s", srv);
+		}
+		close(p[1]);
+		exits(nil);
+	}
+
+	if(mount(p[1], -1, mnt, MREPL, "") < 0){
+		close(p[1]);
+		fatal("mount failed");
+	}
+	close(p[1]);
+	exits(nil);
+}
+
+static void
+fsrun(Fs *fs, int fd)
+{
+	Fcall rpc;
+	char *err;
+	uchar *buf;
+	int n;
+
+	buf = emalloc(messagesize);
+	for(;;){
+		/*
+		 * reading from a pipe or a network device
+		 * will give an error after a few eof reads
+		 * however, we cannot tell the difference
+		 * between a zero-length read and an interrupt
+		 * on the processes writing to us,
+		 * so we wait for the error
+		 */
+		n = read9pmsg(fd, buf, messagesize);
+		if(n == 0)
+			continue;
+		if(n < 0)
+			fatal("mount read");
+
+		rpc.data = (char*)buf + IOHDRSZ;
+		if(convM2S(buf, n, &rpc) == 0)
+			continue;
+		// fprint(2, "recv: %F\n", &rpc);
+
+
+		/*
+		 * TODO: flushes are broken
+		 */
+		if(rpc.type == Tflush)
+			continue;
+		else if(rpc.type >= Tmax || !fcalls[rpc.type])
+			err = "bad fcall type";
+		else
+			err = (*fcalls[rpc.type])(fs, &rpc);
+		if(err){
+			rpc.type = Rerror;
+			rpc.ename = err;
+		}
+		else
+			rpc.type++;
+		n = convS2M(&rpc, buf, messagesize);
+		// fprint(2, "send: %F\n", &rpc);
+		if(write(fd, buf, n) != n)
+			fatal("mount write");
+	}
+}
+
+static Fid*
+mkfid(Fs *fs, uint fid)
+{
+	Fid *f;
+	int h;
+
+	h = fid % Nfidhash;
+	for(f = fs->hash[h]; f; f = f->next){
+		if(f->fid == fid)
+			return nil;
+	}
+
+	f = emalloc(sizeof *f);
+	f->next = fs->hash[h];
+	if(f->next != nil)
+		f->next->last = &f->next;
+	f->last = &fs->hash[h];
+	fs->hash[h] = f;
+
+	f->fid = fid;
+	f->ref = 1;
+	f->attached = 1;
+	f->open = 0;
+	return f;
+}
+
+static Fid*
+getfid(Fs *fs, uint fid)
+{
+	Fid *f;
+	int h;
+
+	h = fid % Nfidhash;
+	for(f = fs->hash[h]; f; f = f->next){
+		if(f->fid == fid){
+			if(f->attached == 0)
+				break;
+			f->ref++;
+			return f;
+		}
+	}
+	return nil;
+}
+
+static void
+putfid(Fs *, Fid *f)
+{
+	f->ref--;
+	if(f->ref == 0 && f->attached == 0){
+		*f->last = f->next;
+		if(f->next != nil)
+			f->next->last = f->last;
+		free(f);
+	}
+}
+
+static char*
+fsversion(Fs *, Fcall *rpc)
+{
+	if(rpc->msize < 256)
+		return "version: message size too small";
+	if(rpc->msize > messagesize)
+		rpc->msize = messagesize;
+	messagesize = rpc->msize;
+	if(strncmp(rpc->version, "9P2000", 6) != 0)
+		return "unrecognized 9P version";
+	rpc->version = "9P2000";
+	return nil;
+}
+
+static char*
+fsauth(Fs *, Fcall *)
+{
+	return "searchfs: authentication not required";
+}
+
+static char*
+fsattach(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+
+	f = mkfid(fs, rpc->fid);
+	if(f == nil)
+		return Einuse;
+	f->open = 0;
+	f->qid.type = QTDIR;
+	f->qid.path = Qroot;
+	f->qid.vers = 0;
+	rpc->qid = f->qid;
+	putfid(fs, f);
+	return nil;
+}
+
+typedef struct DEntry DEntry;
+struct DEntry {
+	uvlong path;
+	char *name;
+};
+
+DEntry entries[] = {
+	{Qctl,	"ctl"},
+	{Qmem,	"mem"},
+	{Qkregs,	"kregs"},
+	{Qfpregs,	"fpregs"},
+	{Qproc,	"proc"},
+	{Qregs,	"regs"},
+	{Qtext,	"text"},
+	{Qstatus,	"status"},
+	{Qnote,	"note"},
+	{~0,	nil},
+};
+
+static uvlong
+nm2qpath(char *name)
+{
+	int i;
+	
+	for(i = 0; entries[i].name != nil; i++)
+		if(strcmp(name, entries[i].name) == 0)
+			return entries[i].path;
+
+	return ~0;
+}
+
+static char*
+fswalk(Fs *fs, Fcall *rpc)
+{
+	Fid *f, *nf;
+	int nqid, nwname, type;
+	char *err, *name;
+	ulong path, fpath;
+
+	f = getfid(fs, rpc->fid);
+	if(f == nil)
+		return Enofid;
+	nf = nil;
+	if(rpc->fid != rpc->newfid){
+		nf = mkfid(fs, rpc->newfid);
+		if(nf == nil){
+			putfid(fs, f);
+			return Einuse;
+		}
+		nf->qid = f->qid;
+		putfid(fs, f);
+		f = nf;	/* walk f */
+	}
+
+	err = nil;
+	path = f->qid.path;
+	nwname = rpc->nwname;
+	for(nqid=0; nqid<nwname; nqid++){
+		if(path != Qroot){
+			err = Enotdir;
+			break;
+		}
+		name = rpc->wname[nqid];
+		/* BUG this is a kludge, rewrite */
+		fpath = nm2qpath(name);
+		if(fpath != ~0){
+			type = QTFILE;
+			path = fpath;
+		}
+		else	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+			type = QTDIR;
+		else {
+			err = Enotexist;
+			break;
+		}
+
+		rpc->wqid[nqid] = (Qid){path, 0, type};
+	}
+
+	if(nwname > 0){
+		if(nf != nil && nqid < nwname)
+			nf->attached = 0;
+		if(nqid == nwname)
+			f->qid = rpc->wqid[nqid-1];
+	}
+
+	putfid(fs, f);
+	rpc->nwqid = nqid;
+	f->open = 0;
+	return err;
+}
+
+static char *
+fsopen(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+	int mode;
+	char buf[512];
+
+	f = getfid(fs, rpc->fid);
+	if(f == nil)
+		return Enofid;
+	if(f->open){
+		putfid(fs, f);
+		return Eisopen;
+	}
+	mode = rpc->mode & OPERM;
+	if(mode == OEXEC
+	|| f->qid.path == Qroot && (mode == OWRITE || mode == ORDWR)){
+		putfid(fs, f);
+		return Eperm;
+	}
+	if(f->qid.path == Qtext){
+		close(textfd);
+		textfd = open(textfile, OREAD);
+		if(textfd < 0) {
+			snprint(buf, sizeof buf, "text: %r");
+			putfid(fs, f);
+			return "opening text file";
+		}
+	}
+	f->open = 1;
+	rpc->qid = f->qid;
+	rpc->iounit = messagesize-IOHDRSZ;
+	putfid(fs, f);
+	return nil;
+}
+
+static char *
+fscreate(Fs *, Fcall *)
+{
+	return Eperm;
+}
+
+static int
+readbuf(Fcall *rpc, void *s, long n)
+{
+	int count;
+	count = rpc->count;
+	if(rpc->offset >= n){
+		count = 0;
+	}
+	if(rpc->offset+count > n)
+		count = n - rpc->offset;
+	memmove(rpc->data, (char*)s+rpc->offset, count);
+	rpc->count = count;
+	return count;
+}
+
+enum{
+	Maxctl = 4*1024,
+};
+
+static char ctlread[Maxctl];
+
+static int
+readctl(Fs *fs, Fcall *rpc)
+{
+	char *e;
+	int ssz;
+
+	ssz = Maxctl;
+	ctxt.debug = icedebugstate(fs->jmed);
+
+	if(ctxt.debug == 0){
+		e = seprint(ctlread, ctlread+Maxctl, "Arm is in debug: %d", ctxt.debug);
+		ssz = readbuf(rpc, ctlread, e - ctlread);
+		return ssz;
+	}
+	e = armsprctxt(&ctxt, ctlread, ssz);
+	if(e >= ctlread + Maxctl)
+		return e - ctlread;
+	ssz = Maxctl - (ctlread - e);
+	e = printmmuregs(&ctxt, e, ssz);
+
+	ssz = readbuf(rpc, ctlread, e - ctlread);
+	return ssz;
+
+}
+
+static int
+readbytes(JMedium *jmed, u32int startaddr, u32int nbytes, u32int dataoff, Fcall *rpc)
+{
+	u32int i, data;
+	int nb, res;
+
+	nb = 0;
+	for(i = startaddr; i < startaddr+nbytes; i++){
+		res = armrdmemwd(jmed, i, &data, 1);
+		if(res < 0){
+			fprint(2, "Error reading [%#8.8ux]\n",
+				i);
+			werrstr("read error");
+			return -1;
+			break;
+		}
+		nb += res;
+		rpc->data[dataoff] = (char)data;
+		dprint(Dfs, "[B%#8.8ux] = %#2.2ux \n",
+				i, data);
+	}
+	return nb;
+
+}
+
+/* 
+ *	BUG: This is horrifyingly slow, could be made much (10x)
+ *	faster using load multiple/store multiple
+ * 	both on memory and while reading back the registers.
+ *	but it doesn't matter for acid (normally it reads words
+ *	or byte long chunks). There may also be another way
+ *	where you can inject instructions without waiting for
+ *	debug mode on the way back. I haven't been able to
+ *	make it work.
+ */
+static int
+readmem(Fs *fs, Fcall *rpc)
+{
+	u32int count, i, data, addr, prenb, nb, postnb, st;
+	int res;
+
+	count = (u32int)rpc->count;
+	
+	addr = (u32int)rpc->offset;
+	dprint(Dfs, "[%#8.8ux, %ud] =?\n", 
+				addr, count);
+
+	prenb = 0;
+	nb = 0;
+	/* The start is not aligned */
+	if(addr & 0x3U){
+		prenb = sizeof(u32int) - (addr & 0x3U);
+		res = readbytes(fs->jmed, addr, prenb, 0, rpc);
+		if(res < 0){
+			werrstr("read error");
+			return -1;
+		}
+		nb += res;
+		dprint(Dfs, "readmem: aligned now\n");
+	}
+	for(i = prenb; i/4 < (count-prenb)/sizeof(u32int); i += sizeof(u32int)){
+		res = armrdmemwd(fs->jmed, addr+i, &data, 4);
+		if(res < 0){
+			fprint(2, "Error reading %#8.8ux [%#8.8ux]\n",
+				addr+i, i);
+			werrstr("read error");
+			return -1;
+			break;
+		}
+		nb += res;
+
+		*(u32int *)(rpc->data+i) = data;
+		dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
+				i, addr+i, data);
+	}
+	
+	dprint(Dfs, "readmem: end of aligned\n");
+	/* The end is not aligned */
+	if((count-prenb) & 0x3U){
+		postnb = (count-prenb)%sizeof(u32int);
+		st = addr + 1 + ((count-prenb)& 0x3U);
+		res = readbytes(fs->jmed, st, postnb, nb, rpc);
+		if(res < 0){
+			werrstr("read error");
+			return -1;
+		}
+		nb += res;
+		dprint(Dfs, "readmem: end of non aligned\n");
+	}
+	return nb;
+}
+
+static int
+writebytes(JMedium *jmed, u32int startaddr, u32int nbytes, u32int dataoff, Fcall *rpc)
+{
+	u32int i, data;
+	int nb, res;
+
+	nb = 0;
+	for(i = startaddr; i < startaddr+nbytes; i++){
+		data = (char)rpc->data[dataoff];
+		res = armwrmemwd(jmed, i, data, 1);
+		if(res < 0){
+			fprint(2, "Error writing [%#8.8ux]\n",
+				i);
+			werrstr("read error");
+			return -1;
+			break;
+		}
+		nb += res;
+		dprint(Dfs, "[B%#8.8ux] = %#2.2ux \n",
+				i, data);
+	}
+	return nb;
+
+}
+
+static int
+writemem(Fs *fs, Fcall *rpc)
+{
+	u32int count, i, addr, *p, prenb, nb, postnb, st;
+	int res;
+
+	count = rpc->count;
+	addr = rpc->offset;
+	
+	prenb = 0;
+	nb = 0;
+	/* not aligned offset */
+	if(addr & 0x3U){
+		prenb = sizeof(u32int) - (addr & 0x3U);
+		res = writebytes(fs->jmed, addr, prenb, 0, rpc);
+		if(res < 0){
+			werrstr("write error");
+			return -1;
+		}
+		nb += res;
+		dprint(Dfs, "writemem: aligned now\n");
+	}
+	for(i = prenb; i/4 < (count-prenb)/sizeof(u32int); i += sizeof(u32int)){
+		p = (u32int *)(rpc->data + i);
+		dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
+				i, addr+i, *p);
+		res = armwrmemwd(fs->jmed, addr + i, *p, 4);
+		if(res < 0){
+			fprint(2, "Error writing %#8.8ux [%#8.8ux]\n",
+				addr+i, i);
+			werrstr("write error");
+			return -1;
+			break;
+		}
+		nb += res;
+	}
+	dprint(Dfs, "writemem: end of aligned\n");
+	/* not aligned end */
+	if((count-prenb)  & 0x3U){
+		postnb = (count-prenb)%sizeof(u32int);
+		st = addr + 1 + ((count-prenb)& 0x3U);
+		res = writebytes(fs->jmed, st, postnb, nb, rpc);
+		if(res < 0){
+			werrstr("write error");
+			return -1;
+		}
+		nb += res;
+		dprint(Dfs, "writemem: end of non aligned\n");
+	}
+	return nb;
+}
+
+/* host to Arm (le) */
+static void
+setkernur(Ureg *kur, ArmCtxt *context)
+{
+	int i;
+	u32int *p;
+
+	kur->type = context->cpsr&PsrMask;
+	hleputl(&kur->type, kur->type);
+
+	kur->psr = context->spsr;
+	hleputl(&kur->psr, kur->psr);
+
+	p = (u32int *)kur;
+	for(i = 0; i < 14; i++)
+		hleputl(p + i, context->r[i]);
+	kur->pc = context->r[15];
+	hleputl(&kur->pc, kur->pc);
+}
+
+typedef struct Regs Regs;
+struct Regs {
+	Ureg kur;
+	MMURegs mmust;
+};
+
+static Regs procregs;	/* kludge: just for reading */
+
+/* host to Arm (le) */
+static void
+setmmust(MMURegs *mmust, ArmCtxt *context)
+{
+	int i;
+	u32int *o, *d;
+	d = (u32int *)mmust;
+	o = (u32int *) &context->MMURegs;
+	for(i = 0; i < sizeof(MMURegs)/sizeof(u32int); i++)
+		hleputl(d + i, o[i]);
+}
+
+static char*
+fsread(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+	int off, count, len, i;
+	uchar *rptr;
+	char buf[512];
+
+	f = getfid(fs, rpc->fid);
+	if(f == nil)
+		return Enofid;
+	if(!f->open){
+		putfid(fs, f);
+		return Enotopen;
+	}
+	count = rpc->count;
+	off = rpc->offset;
+	if(f->qid.path == Qroot){
+		if(off > 0)
+			rpc->count = 0;
+		else {
+			rpc->count = 0;
+			for(i = 0; entries[i].name != nil; i++)
+				rpc->count += dostat(entries[i].path,
+					rpc->count+(uchar*)rpc->data, count-rpc->count);
+		}
+		
+		putfid(fs, f);
+		if(off == 0 && rpc->count <= BIT16SZ)
+			return "directory read count too small";
+		return nil;
+	}
+	len = 0;
+	if(f->qid.path == Qctl){
+		dprint(Dfs, "ctlread\n");
+		len = readctl(fs, rpc);
+		dprint(Dfs, "ctlread read %d %s\n", len, ctlread);
+		if(len < 0){
+			putfid(fs, f);
+			return "ctl read";
+		}
+	}
+	else if(f->qid.path == Qmem){
+		dprint(Dfs, "readmem\n");
+		len = readmem(fs, rpc);
+		dprint(Dfs, "readmem read %d %s\n", len, ctlread);
+		if(len < 0){
+			putfid(fs, f);
+			return "readmem read";
+		}
+	}
+	else if(f->qid.path == Qkregs){
+		dprint(Dfs, "kregs read n %d off %d\n", rpc->count, rpc->offset);
+		memset(&procregs, 0, sizeof(Regs));
+		setkernur(&procregs.kur, &ctxt);
+		setmmust(&procregs.mmust, &ctxt);
+		rptr = (uchar*)&procregs;
+		len = readbuf(rpc, rptr, sizeof(Regs));
+	}
+	else if(f->qid.path == Qtext){
+		dprint(Dfs, "text\n");
+		len = pread(textfd, rpc->data, rpc->count, rpc->offset);
+		if(len < 0) {
+			rerrstr(buf, sizeof buf);
+			fprint(2, "error reading text: %r");
+			putfid(fs, f);
+			return "text read";
+		}
+	}
+	else if(f->qid.path == Qstatus){
+		dprint(Dfs, "status\n");
+		len = snprint(buf, sizeof buf, "%-28s%-28s%-28s", "remote", "system", "New");
+		for(i = 0; i < 9; i++)
+			len += snprint(buf + len, sizeof buf - len, "%-12d", 0);
+		len = readbuf(rpc, buf, len);
+
+	}
+	putfid(fs, f);
+	rpc->count = len;
+	return nil;
+}
+
+typedef struct Cmdbuf Cmdbuf;
+typedef struct Cmdtab Cmdtab;
+struct Cmdbuf
+{
+	char	*buf;
+	char	**f;
+	int	nf;
+};
+
+struct Cmdtab
+{
+	int	index;	/* used by client to switch on result */
+	char	*cmd;	/* command name */
+	int	narg;	/* expected #args; 0 ==> variadic */
+};
+/*
+ * Generous estimate of number of fields, including terminal nil pointer
+ */
+static int
+ncmdfield(char *p, int n)
+{
+	int white, nwhite;
+	char *ep;
+	int nf;
+
+	if(p == nil)
+		return 1;
+
+	nf = 0;
+	ep = p+n;
+	white = 1;	/* first text will start field */
+	while(p < ep){
+		nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0);	/* UTF is irrelevant */
+		if(white && !nwhite)						/* beginning of field */
+			nf++;
+		white = nwhite;
+	}
+	return nf+1;								/* +1 for nil */
+}
+
+/*
+ *  parse a command written to a device
+ */
+static Cmdbuf*
+parsecmd(char *p, int n)
+{
+	Cmdbuf *cb;
+	int nf;
+	char *sp;
+
+	nf = ncmdfield(p, n);
+
+	/* allocate Cmdbuf plus string pointers plus copy of string including \0 */
+	sp = malloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
+	if(sp == nil)
+		sysfatal("memory");
+	cb = (Cmdbuf*)sp;
+	cb->f = (char**)(&cb[1]);
+	cb->buf = (char*)(&cb->f[nf]);
+
+	memmove(cb->buf, p, n);
+
+	/* dump new line and null terminate */
+	if(n > 0 && cb->buf[n-1] == '\n')
+		n--;
+	cb->buf[n] = '\0';
+
+	cb->nf = tokenize(cb->buf, cb->f, nf-1);
+	cb->f[cb->nf] = nil;
+
+	return cb;
+}
+
+/*
+ * Look up entry in table
+ */
+
+static Cmdtab*
+lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
+{
+	int i;
+	Cmdtab *ct;
+
+	if(cb->nf == 0){
+		werrstr("empty control message");
+		return nil;
+	}
+
+	for(ct = ctab, i=0; i<nctab; i++, ct++){
+		if(strcmp(ct->cmd, "*") !=0)	/* wildcard always matches */
+		if(strcmp(ct->cmd, cb->f[0]) != 0)
+			continue;
+		if(ct->narg != 0 && ct->narg != cb->nf){
+			werrstr("bad # args to command");
+			return nil;
+		}
+		return ct;
+	}
+
+	werrstr("unknown control message");
+	return nil;
+}
+
+enum {
+	CMcpuid,
+	CMdebug,
+	CMreset,
+	CMstop,
+	CMstartstop,
+	CMwaitstop,
+	CMstart,
+	CMdump,
+	CMveccatch,
+	CMbreakpoint,
+};
+
+static Cmdtab ctab[] = {
+	CMdebug,	"debug",	2,
+	CMreset,	"reset",	1,
+	CMcpuid,	"cpuid",	1,
+	CMstop,	"stop",	1,
+	CMstart,	"start",	1,
+	CMdump,	"dump",	3,
+	CMveccatch,	"veccatch",	2,
+	CMwaitstop,	"waitstop",	1,
+	CMstartstop,	"startstop",	1,
+	CMbreakpoint,	"breakpoint",	0,	/* 2 or 3 args, optional mask */
+};
+
+static int
+cmdcpuid(JMedium *jmed)
+{
+	u32int cpuid;
+
+	cpuid = armidentify(jmed);
+	dprint(Dfs, "---- Cpuid --- %8.8ux\n", cpuid);
+	if(cpuid == ~0){
+		werrstr("not feroceon or nstrs bug...");
+		return -1;
+	}
+
+	dprint(Dfs, "---- Bypass probe --- \n");
+	if(armbpasstest(jmed) < 0){
+		fprint(2, "error in bypass\n");
+		werrstr("bypass test");
+		return -1;
+	}
+	ctxt.cpuid = cpuid;
+	return 0;
+}
+
+static int
+checkcpuid(JMedium *jmed)
+{
+	if(ctxt.cpuid != 0)
+		return 0;
+
+	return cmdcpuid(jmed);
+}
+
+
+typedef struct VecMode VecMode;
+struct VecMode{
+	char c;
+	u32int mode;
+};
+
+static VecMode vmode[] = {
+	{'R',	ResetCat},
+	{'S',	SWICat},
+	{'P',	PAbortCat},
+	{'D',	DAbortCat},
+	{'I',	IrqCat},
+	{'F',	FiqCat},
+};
+
+static u32int
+vecval(char *conds)
+{
+	int i, j;
+	u32int vcregval;
+
+	vcregval = 0;
+	for(i = 0; i < strlen(conds); i++){
+		for(j = 0; j < nelem(vmode); j++){
+			if(vmode[j].c == conds[i])
+				vcregval |= vmode[j].mode;
+		}
+	}
+	
+	return vcregval;
+}
+/* if running, stop, set catch, start, else, set catch, not start*/
+static int
+cmdveccatch(JMedium *jmed, char *conds)
+{
+	u32int vcregval;
+	int res, wasdebug;
+
+	wasdebug = ctxt.debug;
+	if(!wasdebug){
+		res = iceenterdebug(jmed, &ctxt);
+		if(res< 0){
+			werrstr("entering debug to set veccat");
+			return -1;
+		}
+	}
+
+	vcregval = vecval(conds);
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+	fprint(Dice, "veccatch: %#8.8ux\n", vcregval);
+	res = icesetreg(jmed, VecCatReg, vcregval);
+	if(res < 0)
+		return -1;
+
+	ctxt.exitreas = VeccatReqReas;
+	if(!wasdebug){
+		res = iceexitdebug(jmed, &ctxt);
+		if(res < 0){
+			werrstr("exiting debug to set veccat");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* if running, stop, set breakpoint, start, else, set breakpoint, not start*/
+static int
+cmdbreakpoint(JMedium *jmed, u32int addr, u32int mask)
+{
+	int res, wasdebug;
+
+	wasdebug = ctxt.debug;
+	if(!wasdebug){	
+		if(ctxt.debugreas != BreakReas && ctxt.debugreas != NoReas){
+			werrstr("already waiting debug");
+			return -1;
+		}
+		res = iceenterdebug(jmed, &ctxt);
+		if(res< 0){
+			werrstr("entering debug to set breakpoint");
+			return -1;
+		}
+	}
+
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		return -1;
+	res = icesetreg(jmed, Wp0|AddrValReg, addr);
+	if(res < 0)
+		return -1;
+
+	res = icesetreg(jmed, Wp0|AddrMskReg, mask);
+	if(res < 0)
+		return -1;
+
+	res = icesetreg(jmed, Wp0|DataMskReg, 0xffffffff);
+	if(res < 0)
+		return -1;
+
+	res = icesetreg(jmed, Wp0|CtlMskReg, 0xff&~DataWPCtl);
+	if(res < 0)
+		return -1;
+	res = icesetreg(jmed, Wp0|CtlValReg, EnableWPCtl);
+	if(res < 0)
+		return -1;
+	fprint(Dice, "breakpoint: addr %#8.8ux msk %#8.8ux \n", addr, mask);
+
+	ctxt.exitreas = BreakReqReas;
+	if(!wasdebug){
+		res = iceexitdebug(jmed, &ctxt);
+		if(res < 0){
+			werrstr("exiting debug to set breakpoint");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static char dbgstr[4*1024];
+
+static int
+cmdstop(JMedium *jmed)
+{
+	int res;
+
+	res = iceenterdebug(jmed, &ctxt);
+	if(res < 0){
+		return -1;
+	}
+
+	ctxt.debug = icedebugstate(fs.jmed);
+	return 0;
+}
+
+static int
+cmdwaitstop(JMedium *jmed)
+{
+	int res;
+
+	res = icewaitentry(jmed, &ctxt);
+	if(res < 0){
+		werrstr("timeout waiting for entry to debug state");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+cmdstart(JMedium *jmed)
+{
+	int res;
+	res = iceexitdebug(jmed, &ctxt);
+	if(res < 0){
+		werrstr("could not exit debug");
+		return -1;
+	}
+	ctxt.debug = icedebugstate(fs.jmed);
+	return 0;
+}
+
+static int
+cmddump(JMedium *jmed, u32int start, u32int end)
+{
+	int res, i;
+	u32int data;
+	debug[Dctxt] = 1;
+
+
+	for(i = 0; i < end-start; i+=4){
+		res = armrdmemwd(jmed, start+i, &data, 4);
+		if(res < 0){
+			fprint(2, "Error reading %#8.8ux [%#8.8ux]\n", start+i, i);
+			werrstr("read error");
+			return -1;
+			break;
+		}
+		dprint(Dfs, "%d[%#8.8ux] = %#8.8ux \n",
+				i, start+i, data);
+	}
+	return 0;
+}
+
+static int
+cmdhwreset(Fs *fs)
+{
+	JMedium *jmed;
+
+	jmed = fs->jmed;
+	if(jmed->flush(jmed->mdata)){
+		werrstr("flush");
+		return -1;
+	}
+
+	fs->jmed = resetmpsse(fs->jmed);
+	if(fs->jmed == nil)
+		return -1;
+	ctxt.debug = 0;
+
+	jmed = fs->jmed;
+	/* BUG make this medium independant..., add a send 5 TMS to interface */
+	if(pushcmd(jmed->mdata, "TmsCsOut EdgeDown LSB B0x7 0x7f") < 0) {
+		werrstr("going to reset");
+		return -1;
+	}
+	if(jmed->flush(jmed->mdata)){
+		werrstr("flush");
+		return -1;
+	}
+	sleep(1000);
+	jmed->resets(jmed->mdata, 1, 0);
+	sleep(200);
+	jmed->resets(jmed->mdata, 1, 1);
+	sleep(200);
+	jmed->resets(jmed->mdata, 0, 1);
+	sleep(200);
+	jmed->resets(jmed->mdata, 0, 0);
+	sleep(200);
+	if(jmed->flush(jmed->mdata)){
+		werrstr("flush");
+		return -1;
+	}
+	memset(&ctxt, 0, sizeof(ArmCtxt));
+	return 0;
+}
+
+static int
+cmdstartstop(JMedium *jmed)
+{
+	if(cmdstart(jmed) < 0){
+		werrstr("starting");
+		return -1;
+	}
+	if(cmdstop(jmed) < 0){
+		werrstr("stopping");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int
+runcmd(Fs *fs, char *data, int count)
+{
+	Cmdtab *t;
+	Cmdbuf *cb;
+	int res;
+	u32int st, end, addr, msk;
+
+	cb = parsecmd(data, count);
+	if(cb->nf < 1){
+		werrstr("empty control message");
+		free(cb);
+		return -1;
+	}
+
+	t = lookupcmd(cb, ctab, nelem(ctab));
+	if(t == nil){
+		free(cb);
+		return -1;
+	}
+
+	if(t->index != CMreset && t->index != CMcpuid &&
+		t->index != CMdebug && 
+		checkcpuid(fs->jmed) < 0)
+		return -1;
+
+	switch(t->index){
+	case CMdebug:
+		res = cmdsetdebug((uchar *)cb->f[1]);
+		break;
+	case CMreset:
+		dprint(Dfs, "reset\n");
+		res = cmdhwreset(fs);
+		break;
+	case CMcpuid:
+		dprint(Dfs, "cpuid\n");
+		res = checkcpuid(fs->jmed);
+		break;
+	case CMstop:
+		dprint(Dfs, "stop\n");
+		res = cmdstop(fs->jmed);
+		break;
+	case CMwaitstop:
+		dprint(Dfs, "waitstop\n");
+		res = cmdwaitstop(fs->jmed);
+		break;
+	case CMstart:
+		dprint(Dfs, "start\n");
+		res = cmdstart(fs->jmed);
+		break;
+	case CMdump:
+		st = atol(cb->f[1]);
+		end = atol(cb->f[2]);
+		dprint(Dfs, "dump %#8.8ux %#8.8ux\n", st, end);
+		res = cmddump(fs->jmed, st, end);
+		break;
+	case CMveccatch:
+		dprint(Dfs, "veccatch %s\n", cb->f[1]);
+		res = cmdveccatch(fs->jmed, cb->f[1]);
+		break;
+	case CMbreakpoint:
+		addr = atol(cb->f[1]);
+		if(cb->nf > 0 && cb->nf == 3)
+			msk = atol(cb->f[2]);
+		else	if(cb->nf > 0 && cb->nf == 2)
+				msk = 0;
+		else {
+			res = -1;
+			goto Exit;
+		}
+	
+		dprint(Dfs, "breakpoint addr %#8.8ux mask %#8.8ux\n", addr, msk);
+		res = cmdbreakpoint(fs->jmed, addr, msk);
+		break;
+	default:
+		res = -1;
+	}
+Exit:
+	free(cb);
+	return res;
+}
+
+/* Arm (le) order to host */
+static void
+getkernur(ArmCtxt *ct, Ureg *kur)
+{
+	int i;
+
+	ct->cpsr = (ct->cpsr&~PsrMask) | kur->type;
+	ct->cpsr = lehgetl(&ct->cpsr);
+
+	ct->spsr = kur->psr;
+	ct->spsr = lehgetl(&ct->spsr);
+
+	memmove(ct->r, kur, 14*sizeof(u32int));
+	ct->r[15] = kur->pc;
+	for(i = 0; i < 15; i++)
+		ct->r[i] = lehgetl(ct->r + i);
+}
+
+static int
+setkregs(Fs *fs, Fcall *rpc)
+{
+	Ureg kur;
+	ArmCtxt lc;
+	u32int mask, *lp, *gp;
+	int res, nb, i;
+	char *p;
+	JMedium *jmed;
+
+	jmed = fs->jmed;
+
+	nb = 0;
+	lc = ctxt;
+	setkernur(&kur, &ctxt);
+	p = (char *)&kur;
+	if(rpc->count + rpc->offset > sizeof(Ureg))	/* cannot write mmuregs*/
+		return -1;
+	else
+		memmove(p + rpc->offset, rpc->data, rpc->count);
+
+	getkernur(&ctxt, &kur);
+
+	/* BUG? hmm, order matters here, if I get both I am not sure of what to do */
+	if(ctxt.cpsr != lc.cpsr){
+		res = armsetexec(jmed, 1, &ctxt.cpsr, ARMLDMIA|0x0001);
+		if(res < 0)
+			return -1;
+		res = armgofetch(jmed, ARMMSRr0CPSR, 0);
+		if(res < 0)
+			return -1;
+		nb += sizeof(u32int);
+	}
+		
+	if(ctxt.spsr != lc.spsr){
+		res = armsetexec(jmed, 1, &ctxt.spsr, ARMLDMIA|0x0001);
+		if(res < 0)
+			return -1;
+		res = armgofetch(jmed, ARMMSRr0SPSR, 0);
+		if(res < 0)
+			return -1;
+		nb += sizeof(u32int);
+	}
+		
+
+
+	/* last I update the registers */
+	lp = (u32int *)&lc;
+	gp = (u32int *)&ctxt;
+	mask = 0;
+	for(i = 0; i < 16; i++){
+		if(lp[i] != gp[i]){	/* see which ones changed */
+			mask |= (1 << i);
+			nb += sizeof(u32int);
+		}
+	}
+	mask |= 0x0001;	/* this one I contaminated myself */
+	res = armsetregs(jmed, mask, ctxt.r);
+	if(res < 0)
+		return -1;
+	return nb;
+}
+
+static char*
+fswrite(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+	int res, len;
+
+	f = getfid(fs, rpc->fid);
+	if(f == nil)
+		return Enofid;
+	if(!f->open){
+		putfid(fs, f);
+		return Enotopen;
+	}
+
+	if(f->qid.path == Qctl){
+		res = runcmd(fs, rpc->data, rpc->count);
+		if(res < 0){
+			fprint(2, "error %r\n");
+			putfid(fs, f);
+			return Ebadcmd;
+		}
+	}
+	else if(f->qid.path == Qmem){
+		len = writemem(fs, rpc);
+		if(len < 0){
+			putfid(fs, f);
+			return "reading memory";
+		}
+	}
+	else if(f->qid.path == Qkregs){
+		dprint(Dfs, "kregs write n %d off %d\n", rpc->count, rpc->offset);
+		len = setkregs(fs, rpc);
+		if(len < 0){
+			putfid(fs, f);
+			return "writing kregs";
+		}
+	}
+	else {
+		putfid(fs, f);
+		return Eperm;
+	}
+	putfid(fs, f);
+	return nil;
+}
+
+static char *
+fsclunk(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+
+	f = getfid(fs, rpc->fid);
+	if(f != nil){
+		f->attached = 0;
+		putfid(fs, f);
+	}
+	return nil;
+}
+
+static char *
+fsremove(Fs *, Fcall *)
+{
+	return Eperm;
+}
+
+static char *
+fsstat(Fs *fs, Fcall *rpc)
+{
+	Fid *f;
+
+	f = getfid(fs, rpc->fid);
+	if(f == nil)
+		return Enofid;
+	rpc->stat = fs->statbuf;
+	rpc->nstat = dostat(f->qid.path, rpc->stat, sizeof fs->statbuf);
+	putfid(fs, f);
+	if(rpc->nstat <= BIT16SZ)
+		return "stat count too small";
+	return nil;
+}
+
+static char *
+fswstat(Fs *, Fcall *)
+{
+	return Eperm;
+}
+
+static int
+dostat(int path, uchar *buf, int nbuf)
+{
+	Dir d;
+
+	switch(path){
+	case Qroot:
+		d.name = ".";
+		d.mode = DMDIR|0555;
+		d.qid.type = QTDIR;
+		break;
+	case Qctl:
+		d.name = "ctl";
+		d.mode = 0666;
+		d.qid.type = QTFILE;
+		break;
+	case Qmem:
+		d.name = "mem";
+		d.mode = 0666;
+		d.qid.type = QTFILE;
+		break;
+	case Qkregs:
+		d.name = "kregs";
+		d.mode = 0666;
+		d.qid.type = QTFILE;
+		break;
+	case Qfpregs:
+		d.name = "fpregs";
+		d.mode = 0666;
+		d.qid.type = QTFILE;
+		break;
+	case Qproc:
+		d.name = "proc";
+		d.mode = 0444;
+		d.qid.type = QTFILE;
+		break;
+	case Qregs:
+		d.name = "regs";
+		d.mode = 0666;
+		d.qid.type = QTFILE;
+		break;
+	case Qtext:
+		d.name = "text";
+		d.mode = 0444;
+		d.qid.type = QTFILE;
+		break;
+	case Qstatus:
+		d.name = "status";
+		d.mode = 0444;
+		d.qid.type = QTFILE;
+		break;
+	}
+	d.qid.path = path;
+	d.qid.vers = 0;
+	d.length = 0;
+	d.uid = d.gid = d.muid = "none";
+	d.atime = d.mtime = time(nil);
+	return convD2M(&d, buf, nbuf);
+}
+
+static void
+fatal(char *fmt, ...)
+{
+	va_list arg;
+	char buf[1024];
+
+	write(2, "jtagfs: ", 8);
+	va_start(arg, fmt);
+	vseprint(buf, buf+1024, fmt, arg);
+	va_end(arg);
+	write(2, buf, strlen(buf));
+	write(2, "\n", 1);
+	exits(fmt);
+}
+
+static void *
+emalloc(uint n)
+{
+	void *p;
+
+	p = malloc(n);
+	if(p == nil)
+		fatal("out of memory");
+	memset(p, 0, n);
+	return p;
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: jtagfs  [-t text] [-d debug] [-m mountpoint] [-s srvfile] jtag\n");
+	exits("usage");
+}
diff -Nru /sys/src/cmd/jtagfs/lebo.c /sys/src/cmd/jtagfs/lebo.c
--- /sys/src/cmd/jtagfs/lebo.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/lebo.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <lebo.h>
+
+void
+hleputv(void *p, uvlong v)
+{
+	uchar *a;
+
+	a = p;
+	a[7] = v>>56;
+	a[6] = v>>48;
+	a[5] = v>>40;
+	a[4] = v>>32;
+	a[3] = v>>24;
+	a[2] = v>>16;
+	a[1] = v>>8;
+	a[0] = v;
+}
+
+void
+hleputl(void *p, uint v)
+{
+	uchar *a;
+
+	a = p;
+	a[3] = v>>24;
+	a[2] = v>>16;
+	a[1] = v>>8;
+	a[0] = v;
+}
+
+void
+hleputs(void *p, ushort v)
+{
+	uchar *a;
+
+	a = p;
+	a[1] = v>>8;
+	a[0] = v;
+}
+
+uvlong
+lehgetv(void *p)
+{
+	uchar *a;
+	uvlong v;
+
+	a = p;
+	v = (uvlong)a[7]<<56;
+	v |= (uvlong)a[6]<<48;
+	v |= (uvlong)a[5]<<40;
+	v |= (uvlong)a[4]<<32;
+	v |= a[3]<<24;
+	v |= a[2]<<16;
+	v |= a[1]<<8;
+	v |= a[0]<<0;
+	return v;
+}
+
+uint
+lehgetl(void *p)
+{
+	uchar *a;
+
+	a = p;
+	return (a[3]<<24)|(a[2]<<16)|(a[1]<<8)|(a[0]<<0);
+}
+
+ushort
+lehgets(void *p)
+{
+	uchar *a;
+
+	a = p;
+	return (a[1]<<8)|(a[0]<<0);
+}
diff -Nru /sys/src/cmd/jtagfs/lebo.h /sys/src/cmd/jtagfs/lebo.h
--- /sys/src/cmd/jtagfs/lebo.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/lebo.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,6 @@
+uint		lehgetl(void *p);
+ushort		lehgets(void *p);
+uvlong		lehgetv(void *p);
+void		hleputl(void *p, uint v);
+void		hleputs(void *p, ushort v);
+void		hleputv(void *p, uvlong v);
diff -Nru /sys/src/cmd/jtagfs/ma.c /sys/src/cmd/jtagfs/ma.c
--- /sys/src/cmd/jtagfs/ma.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/ma.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,820 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h> /* BUG: yes I know... ascii*/
+#include <bio.h>
+#include "debug.h"
+#include "tap.h"
+#include "jtag.h"
+#include "icert.h"	/* BUG: separate medium and ice */
+#include "mpsse.h"
+
+/*
+ *	Mpsse assembler
+ *	Based on AN2232C-01 Command Processor for MPSSE and MCU Host Bus
+ *	and various magical commands from source code all around.
+ */
+
+
+enum{
+	/* MPSSE  */
+
+	/*
+	 *	This are used only to make opcodes
+	 *	for Clocking in/out data to TD0 to TDI
+	 */
+	OpModOut = 0x10,
+	OpTmsCs = 0x4a,			/* clock data to TmsCs */
+
+	/* Modifiers for both */
+	OpModShort = 0x02,		/* len only one byte */
+	OpModOutFalling = 0x01,
+	OpModInFalling = 0x04,
+	OpModLSB = 0x08,
+	OpModIn = 0x20,
+
+	OpModBitsH = 0x02,
+	OpModBitsIn = 0x01,
+	OpSetBits = 0x80,			/* value(?)/direction on pins*/
+
+	OpLoop = 0x84,			/* loop connect TDI/DO with TDO/DI */
+	OpBreakLoop = 0x85,		/* break loop */
+	OpTckSkDiv = 0x86,			/* valL valH,  ?? description of reset */
+
+	OpDiv5ClkEnab = 0x8b,
+	OpDiv5ClkDisab = 0x8a,
+	
+
+	/* MCU host emulation */
+	OpModLong = 0x01,			/* addrH addrL */
+
+	OpMCURd = 0x90,			/* addr */
+	OpMCUWr = 0x92,			/* addr Data */
+
+	OpBad = 0,				/* made this up */
+
+	/* Both modes */
+	OpSendImm = 0x87,		/* flush buffer back to PC  ??? */
+	OpWaitIOHigh = 0x88,		/* IO high, GPIOH in MPSSE, I/O1 on MCU */
+	OpWaitIOLow = 0x89,		/* IO low, GPIOH in MPSSE, I/O1 on MCU */
+
+	OpAdaptClkEnab = 0x96,
+	OpAdaptClkDisab = 0x97,
+	RBad = 0xFA,				/* followed by the bad command */
+
+	MaxDataSz = 0xffff+1,
+};
+
+typedef struct Inst Inst;
+struct Inst{
+	int hasresp;
+	int isshort;
+	int islsb;	/* bits come/go LSB */
+	int nedge;
+	uchar edge[2];
+	uchar opcode;
+	int lensz;
+	uchar len[2];
+	int immsz;
+	uchar imm[3];
+	int datasz;
+	uchar data[1];
+};
+
+enum{
+	DataIn,
+	DataOut,
+	DataOutIn,
+	TmsCsOut,
+	TmsCsOutIn,
+	SetBitsL,
+	SetBitsH,
+	TckSkDiv,
+	MCURd,	/* from this down, no param */
+	MCUWr,
+	SendImm,
+	WaitIOHigh,
+	WaitIOLow,
+	AdaptClkEnab,
+	AdaptClkDisab,
+	Div5ClkEnab,
+	Div5ClkDisab,
+	GetBitsL,
+	GetBitsH,
+	Loop,
+	BreakLoop,
+	ILast,
+};
+
+static char *inst[] = {
+	[DataIn]			"DataIn",
+	[DataOut]			"DataOut",
+	[DataOutIn]		"DataOutIn",
+	[TmsCsOut]		"TmsCsOut",
+	[TmsCsOutIn]		"TmsCsOutIn",
+	[SetBitsL]			"SetBitsL",
+	[SetBitsH]			"SetBitsH",
+	[TckSkDiv]		"TckSkDiv",
+	[MCURd]			"MCURd",
+	[MCUWr]			"MCUWr",
+	[SendImm]		"SendImm",
+	[WaitIOHigh]		"WaitIOHigh",
+	[WaitIOLow]		"WaitIOLow",
+	[AdaptClkEnab]		"AdaptClkEnab",
+	[AdaptClkDisab]	"AdaptClkDisab",
+	[Div5ClkEnab]		"Div5ClkEnab",
+	[Div5ClkDisab]		"Div5ClkDisab",
+	[GetBitsL]			"GetBitsL",
+	[GetBitsH]			"GetBitsH",
+	[Loop]			"Loop",
+	[BreakLoop]		"BreakLoop",
+	[ILast]			nil,
+	
+};
+
+
+enum{
+	EdgeNone,
+	EdgeUp,
+	EdgeDown,
+	EdgeBad,
+};
+
+static uchar
+dataopcode(Inst *inst, int instid, int issh, int islsb)
+{
+	uchar opcode = 0;
+
+	switch(instid){
+	case DataOutIn:
+		if(inst->edge[1] == EdgeDown)
+				opcode = OpModInFalling;
+		/* fall through */
+	case DataOut:
+		opcode |= OpModOut;
+		if (inst->edge[0] == EdgeDown)
+			opcode |= OpModOutFalling;
+		break;
+	case DataIn:
+		if (inst->edge[0] == EdgeDown)
+			opcode |= OpModInFalling;
+		break;
+	}
+	
+	opcode |= inst->hasresp? OpModIn : 0;
+	opcode |= issh? OpModShort : 0;
+	opcode |= islsb? OpModLSB : 0;
+
+	return opcode;
+}
+
+
+static uchar
+opcode(Inst *inst, int instid)
+{
+	int issh, islsb;
+	uchar opcode;
+
+	opcode = 0;
+	issh = inst->isshort;
+	islsb = inst->islsb;
+
+	if(instid != TmsCsOutIn && instid != TmsCsOut&& instid != DataOutIn)
+		if(inst->edge[1] != EdgeNone){
+			werrstr("should not have edge");
+			return OpBad;
+		}
+	
+	switch(instid){
+	case DataOutIn:
+	case DataOut:
+	case DataIn:
+		opcode = dataopcode(inst, instid, issh, islsb);
+		break;
+
+	case TmsCsOutIn:
+		opcode = OpModIn;
+		if (inst->edge[1] == EdgeDown)
+			opcode |= OpModInFalling;
+	/* fall through */
+	case TmsCsOut:
+		opcode |= OpTmsCs;
+		if(!issh || (inst->len[0] + 1) > 7){
+			werrstr("len too big: %d, issh:%d",
+				inst->len[0]+1, issh);
+			return OpBad;
+		}
+		if (inst->edge[0] == EdgeDown)
+			opcode |= OpModOutFalling;
+		opcode |= OpModShort;
+		opcode |= OpModLSB;
+		break;
+	case MCURd:
+		opcode = OpMCURd;
+		opcode |= !issh? OpModLong : 0;
+		break;
+	case MCUWr:
+		opcode = OpMCUWr;
+		opcode |= !issh? OpModLong : 0;
+		break;
+	case SendImm:
+		opcode = OpSendImm;
+		break;
+	case WaitIOHigh:
+		opcode = OpWaitIOHigh;
+		break;
+	case TckSkDiv:
+		opcode = OpTckSkDiv;
+		break;
+	case WaitIOLow:
+		opcode = OpWaitIOLow;
+		break;
+	case AdaptClkEnab:
+		opcode = OpAdaptClkEnab;
+		break;
+	case AdaptClkDisab:
+		opcode = OpAdaptClkDisab;
+		break;
+	case Div5ClkEnab:
+		opcode = OpDiv5ClkEnab;
+		break;
+	case Div5ClkDisab:
+		opcode = OpDiv5ClkDisab;
+		break;
+	case GetBitsH:
+	case SetBitsH:
+		opcode = OpModBitsH;
+	case GetBitsL:
+	/* fall through */
+		if(instid == GetBitsL || instid == GetBitsH)
+			opcode |= OpModBitsIn;
+	case SetBitsL:
+		opcode |= OpSetBits;
+		break;
+	case Loop:
+		opcode = OpLoop;
+		break;
+	case BreakLoop:
+		opcode = OpBreakLoop;
+		break;
+	default:
+		werrstr("unknown instruction");
+		return OpBad;
+	}
+	return opcode;
+}
+
+enum {
+	ParLen	=	'L',		/* Data len 2 bytes or 1 byte (bit len) */
+	ParShLen	=	'l', 		/* bit len Bnumber */
+	ParData	=	'D',		/* data or @ to place data later */
+	ParShData = 	'd',		/* short data, 1 byte at most */
+	ParImm 	=	'I',		/* immediate operator, 2/1 bytes */
+	ParLImm	=	'i',		/* immediate operator, 2 bytes */
+	ParShImm =	'c',		/* immediate operator, 1 byte */
+	ParEdge	=	'E',		/* EdgeUp or EdgeDown */
+	ParEndian	=	'N',		/* LSB or MSB */
+	ParLsb	=	'n',		/* LSB */
+};
+
+typedef struct InstDesc InstDesc;
+struct InstDesc
+{
+	char *name;
+	char *desc;
+	int hasresp;
+};
+
+static InstDesc idesc[] = {
+	[DataIn]			{"DataIn",	"ENL", 1},
+	[DataOut]			{"DataOut",	"ENLD", 0},
+	[DataOutIn]		{"DataOutIn",	"EENLD", 1},
+	[TmsCsOut]		{"TmsCsOut",	"ENld", 0},
+	[TmsCsOutIn]		{"TmsCsOutIn",	"EENld", 1},
+	[MCURd]			{"MCURd",	"I", 1},
+	[MCUWr]			{"MCUWr",	"Id", 0},
+	[SendImm]		{"SendImm",	"", 0},
+	[WaitIOHigh]		{"WaitIOHigh",	"", 0},
+	[WaitIOLow]		{"WaitIOLow",	"", 0},
+	[AdaptClkEnab]		{"AdaptClkEnab",	"", 0},
+	[AdaptClkDisab]	{"AdaptClkDisab",	"", 0},
+	[Div5ClkEnab]		{"Div5ClkEnab",	"", 0},
+	[Div5ClkDisab]		{"Div5ClkDisab",	"", 0},
+	[SetBitsL]			{"SetBitsL",	"cc", 0},
+	[GetBitsL]			{"GetBitsL",	"c", 0},
+	[SetBitsH]			{"SetBitsH",	"cc", 0},
+	[GetBitsH]			{"GetBitsH",	"c", 0},
+	[TckSkDiv]		{"TckSkDiv",	"i", 0},
+	[Loop]			{"Loop",	"", 0},
+	[BreakLoop]		{"BreakLoop",	"", 0},
+	[ILast]			{nil,		nil, 0},
+};
+
+
+static int
+nametoid(char *name)
+{
+	int i;
+	for (i = 0; i < ILast; i++){
+		if(strcmp(inst[i], name) == 0)
+			break;
+	}
+	if(i == ILast)
+		return -1;
+	return i;
+}
+
+static int
+edgetoid(char *edgename)
+{
+	if(strcmp(edgename, "EdgeUp") == 0)
+		return EdgeUp;
+	else if(strcmp(edgename, "EdgeDown") == 0)
+		return EdgeDown;
+
+	return EdgeBad;
+}
+
+static int
+isendian(char *endianname)
+{
+	if(strcmp(endianname, "LSB") == 0)
+		return 1;
+	else if(strcmp(endianname, "MSB") == 0)
+		return 1;
+
+	return 0;
+}
+
+
+static int
+datalen(Inst *inst, char *p)
+{
+	int len;
+	if(p[0] == 'B'){
+		inst->isshort++;
+		p++;
+	}
+	else
+		inst->isshort = 0;
+	len = atoi(p); //strtol and check
+	if(inst->isshort && len > 8)
+		return -1;
+	if(len > MaxDataSz)
+		return -1;
+	return len;
+}
+
+static void
+setlen(Inst *inst, int dlen)
+{
+	if(dlen != 0){
+		inst->lensz++;
+		inst->len[0] = (dlen - 1 ) & 0xff;
+		if(!inst->isshort){
+			inst->len[1] = 0xff & ((dlen - 1) >> 8);
+			inst->lensz++;
+		}
+	}
+}
+
+
+static int
+setdata(Inst *inst, char *nm, char *p, char *te, int bdlen)
+{
+	int i;
+	char *e;
+
+	if(p == nil){
+		werrstr("%s: should have data", nm);
+		return -1;
+	}
+	if(*p == '@'){
+		inst->datasz = bdlen;
+		return 0;
+	}
+	
+	if(te != p)
+		p[strlen(p)] = ' '; /* untokenize */
+
+	for (i = 0; i < bdlen; i++){
+		inst->data[i] = strtol(p, &e, 0);
+		if(!isspace(*e) && i != bdlen-1)
+			return -1;
+		p = e;
+	}
+	inst->datasz = i;
+	return 0;
+
+}
+
+static int
+hasresp(int instid)
+{
+	return idesc[instid].hasresp;
+}
+
+
+static int
+hasnoparam(int instid)
+{
+	return strlen(idesc[instid].desc) == 0;
+}
+
+static char *
+endfield(char *p)
+{
+	char *s;
+
+	s = p;
+	if(*p =='\0')
+		return nil;
+	while(*p != '\0'){
+		if(isspace(*p)){
+			if(s == p)
+				return nil;
+			return p;
+		}
+		p++;
+	}
+	return p;
+}
+
+enum{
+	LongSz,
+	ShortSz,
+	AnySz,
+};
+
+static int
+setimm(Inst *inst, int imm, int kindsz)
+{	
+	int isl, immh, imml;
+
+	isl = imm&~0xff;
+
+	if(isl && kindsz == ShortSz)
+		return -1;
+
+
+	if(isl || kindsz == LongSz){
+		immh = (imm >> 8)&0xff;
+		inst->imm[inst->immsz++] = immh; /* High, then low */
+	}
+	imml = imm&0xff;
+	inst->imm[inst->immsz++] = imml;
+	return 0;
+}
+
+static Inst*
+parseinst(int instid, char *pars, char *idname)
+{
+	char *tok[15], *err, *e;
+	char tf;
+	int i, ntok, tnf, dlen, bdlen, imm, ndata;
+	Inst *inst;
+	
+	tf = '\0';
+	dlen = bdlen = 0;
+	err = "";
+	inst = mallocz(sizeof(Inst) + 1, 1);
+	if(inst == nil)
+		return nil;
+	tnf = strlen(idesc[instid].desc);
+	e = pars + strlen(pars) + 1;
+	ntok = tokenize(pars, tok, tnf);
+	if(tnf != ntok){
+		werrstr("%s: bad nr param %d!=%d", idname, tnf, ntok);
+		return nil;
+	}
+	
+	for(i = 0; i < tnf; i++){
+		tf = idesc[instid].desc[i];
+		switch(tf){	
+		case ParLen:
+			dlen = datalen(inst, tok[i]);
+			if(dlen < 0){
+				err = "bad len";
+				goto Err;
+			}
+			if(inst->isshort)
+				bdlen = 1;
+			else {
+				bdlen = dlen;
+				inst = realloc(inst, sizeof(Inst) + bdlen);
+				if(inst == nil)
+					return nil;
+			}
+			break;
+		case ParShLen:
+			dlen = datalen(inst, tok[i]);
+			if(dlen < 0){
+				err = "bad len";
+				goto Err;
+			}
+			bdlen = 1;
+			if(!inst->isshort) {
+				err = "should be short";
+				goto Err;
+			}
+			break;
+		case ParData:
+			if(bdlen != 0){
+				ndata = setdata(inst, idname, tok[i], e, bdlen);
+				if(ndata < 0){
+					err = "short data";
+					goto Err;
+				}
+			}
+			else {
+				err = "no data";
+				goto Err;
+			}
+			break;
+		case ParShData:
+			if(bdlen != 0){
+				ndata = setdata(inst, idname, tok[i], e, bdlen);
+				if(ndata < 0){
+					err = "short data";
+					goto Err;
+				}
+			}
+			else {
+				err = "no data";
+				goto Err;
+			}
+			if(ndata > 1){
+				err = "more than 1 byte data";
+				goto Err;
+			}
+			break;
+		case ParImm:
+			imm = atoi(tok[i]);
+			if(setimm(inst, imm, AnySz) < 0)
+				goto Err;
+			break;
+		case ParLImm:
+			imm = atoi(tok[i]);
+			if(setimm(inst, imm, LongSz) < 0)
+				goto Err;
+			break;
+		case ParShImm:
+			imm = atoi(tok[i]);
+			if(setimm(inst, imm, ShortSz) < 0)
+				goto Err;
+			break;
+		case ParEdge:
+			inst->edge[inst->nedge] = edgetoid(tok[i]);
+			if(inst->edge[inst->nedge] == EdgeBad)
+				goto Err;
+			inst->nedge++;
+			break;
+		case ParEndian:
+			inst->islsb = strcmp(tok[i], "LSB") == 0;
+			if(!isendian(tok[i])){
+				err = "bad endianness";
+				goto Err;
+			}
+			break;
+		case ParLsb:
+			inst->islsb = strcmp(tok[i], "LSB") == 0;
+			if(inst->islsb){
+				err = "bad endianness: not LSB";
+				goto Err;
+			}
+			break;
+		default:
+			err = "bad param";
+			goto Err;
+		}
+		
+		if(bdlen > MaxDataSz || (inst->isshort && dlen > 8)){
+			err = "len too big";
+			goto Err;
+		}
+	}
+	
+	setlen(inst, dlen);
+	inst->hasresp = hasresp(instid);
+	inst->opcode = opcode(inst, instid);
+	if(inst->opcode == OpBad){
+		err = "bad opcode";
+		goto Err;
+	}
+	return inst;
+Err:
+	werrstr("inst:%s, nf:%d, ftype:%c, fval:%s:%s\n", idname, i, tf, tok[i], err);
+	free(inst);
+	return nil;	
+}
+
+static Inst *
+parseassln(char *assline)
+{
+	int instid, lnsz;
+	Inst *inst;
+	char *ef, inm[32];
+
+	dprint(Dassln, "%s\n", assline);
+
+	lnsz = strlen(assline);
+	if(lnsz == 0){
+	 	werrstr("%s: line does not match instruction", assline);
+		return nil;
+	}
+
+	ef = endfield(assline);
+	if(ef == nil){
+	 	werrstr("%s: empty inst", assline);
+		return nil;
+	}
+	strncpy(inm, assline, ef-assline);
+	inm[ef-assline] = '\0';
+	instid = nametoid(inm);
+	if(instid < 0){
+		werrstr("unrecognized instruction %s", inm);
+		return nil;
+	}
+	inst = parseinst(instid, ef, inm);
+	return inst;
+}
+
+static int
+unpacklen(Inst *inst)
+{
+	int len;
+
+	if (inst->lensz == 0)
+		return 0;
+	len =  ((inst->len[1]<<8) | inst->len[0]) + 1;
+
+	return len;
+}
+
+static int
+instpacksz(Inst *inst)
+{
+	return 1 + inst->immsz + inst->lensz + inst->datasz;
+}
+
+static void
+sdumpinst(char *s, int ssz, Inst *inst)
+{
+	int i;
+	char *e, *te;
+
+	e = s + ssz - 1;
+	te = e;
+
+	e = seprint(s, te, "op: %#2.2ux\n", inst->opcode);
+	if(e >= te)
+		return;
+	if(inst->hasresp){
+		e = seprint(e, te, "hasresp: %d\n", inst->hasresp);
+		if(e >= te)
+			return;
+	}
+	if(inst->isshort){
+		e = seprint(e, te, "isshort: %d\n", inst->isshort);
+		if(e >= te)
+			return;
+	}
+	e = seprint(e, te, "islsb: %d\n", inst->islsb);
+	if(e >= te)
+		return;
+
+	for(i = 0; i < inst->immsz; i++){
+		e = seprint(e, te, "imm%d: %#2.2ux\n", i, inst->imm[i]);
+		if(e >= te)
+			return;
+	}
+
+	if(inst->lensz != 0){	
+		e = seprint(e, te, "lensz: %d\n", inst->lensz);
+		if(e >= te)
+			return;
+		e = seprint(e, te, "len: %d\n", unpacklen(inst));
+		if(e >= te)
+			return;
+		e = seprint(e, te, "datasz: %d\n", inst->datasz);
+		if(e >= te)
+			return;
+		for(i = 0; i < inst->datasz; i++){
+			e = seprint(e, te, "%#2.2ux ", inst->data[i]);
+			if(e >= te)
+				return;
+		}
+	}
+}
+
+static void
+debpack(Inst *inst)
+{
+	int i;
+	if(!debug[Dmach] && !debug[DAll])
+		return;
+	fprint(2, "%#2.2ux ", inst->opcode);
+
+	for(i = 0; i <  inst->immsz; i++)
+		fprint(2, "%#2.2ux ", inst->imm[i]);
+	for(i = 0; i <  inst->lensz; i++)
+		fprint(2, "%#2.2ux ", inst->len[i]);
+	fprint(2, "\n");
+	dumpbuf(Dmach, inst->data, inst->datasz);
+	fprint(2, "\n");
+}
+
+
+static int
+instpack(Mpsse *mpsse, Inst *inst)
+{
+	int n;
+	int sz;
+	Biobufhdr *bp;
+
+	bp = &mpsse->bout;
+
+	sz = instpacksz(inst);
+	if(sz + Bbuffered(bp) > MpsseBufSz){
+		n = mpsseflush(mpsse);
+		if(n < 0)
+			return -1;
+	}
+	debpack(inst);
+	n = Bwrite(bp, &inst->opcode, 1);
+	if(n < 0)
+		return -1;
+	n = Bwrite(bp, inst->imm, inst->immsz);
+	if(n < 0)
+		return -1;
+	n = Bwrite(bp, inst->len, inst->lensz);
+	if(n < 0)
+		return -1;
+	n = Bwrite(bp, inst->data, inst->datasz);
+	if(n < 0)
+		return -1;
+	return 0;
+}
+
+int
+pushcmd(Mpsse *mpsse, char *ln)
+{
+	Inst *inst;
+	int res;
+	char *dmp, *lln;
+
+	res = 0;
+	lln = strdup(ln);
+	inst = parseassln(lln);
+	free(lln);
+
+	if(inst == nil)
+		return -1;
+	if(debug[Dinst]){
+		dmp = malloc(255);
+		if(dmp == nil)
+			return -1;
+		sdumpinst(dmp, 255, inst);
+		fprint(2, "%s\n", dmp);
+		free(dmp);
+	}
+
+	if(instpack(mpsse, inst) < 0)
+		res = -1;
+	free(inst);
+	return res;
+}
+
+int
+pushcmdwdata(Mpsse *mpsse, char *ln, uchar *buf, int buflen)
+{
+	Inst *inst;
+	int res;
+	char *dmp, *lln;
+
+	res = 0;
+	lln = strdup(ln);
+	inst = parseassln(lln);
+	free(lln);
+
+	if(inst == nil)
+		return -1;
+	if(inst->datasz != buflen){
+		werrstr("wrong data in cmd %d != %d", inst->datasz, buflen);
+		return -1;
+	}
+	memmove(inst->data, buf, inst->datasz);
+	if(debug[Dinst]){
+		dmp = malloc(255);
+		if(dmp == nil)
+			return -1;
+		sdumpinst(dmp, 255, inst);
+		fprint(2, "%s\n", dmp);
+		free(dmp);
+	}
+
+	if(instpack(mpsse, inst) < 0)
+		res = -1;
+	free(inst);
+	return res;
+}
+
diff -Nru /sys/src/cmd/jtagfs/maexamples /sys/src/cmd/jtagfs/maexamples
--- /sys/src/cmd/jtagfs/maexamples	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/maexamples	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,16 @@
+DataIn EdgeDown LSB 3
+DataIn EdgeDown LSB B3
+DataOutIn EdgeDown EdgeUp LSB 3 0x42 0x34 0x56
+DataOutIn EdgeDown EdgeDown LSB 3 @
+DataOutIn EdgeDown EdgeUp LSB B3 0x42
+DataOutIn EdgeDown EdgeDown LSB B3 @
+TmsCsOut EdgeDown MSB B0x7 0x7
+TmsCsOut EdgeDown LSB B7 0x7
+TmsCsOutIn EdgeDown EdgeUp LSB B0x7 0x7
+MCURd 0x34
+SendImm
+WaitIOHigh
+AdaptClkDisab
+Div5ClkEnab
+Loop
+SetBitsL 0x32 0x34
diff -Nru /sys/src/cmd/jtagfs/maexamplesbad /sys/src/cmd/jtagfs/maexamplesbad
--- /sys/src/cmd/jtagfs/maexamplesbad	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/maexamplesbad	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,11 @@
+DataOutIn EdgeDown LSB 3
+DataOutIn EdgeDown LSB 3 0x42 x34 0x56
+DataOutIn EdgeDown EdgeUp LSB 3 0x42 x34 0x56
+DataOutIn EdgeDown LSB B3 0x42 0x34 0x56
+TmsCsOut EdgeDown B0x7 0x7
+TmsCsOut EdgeDown B8 0x7
+TmsCsOut EdgeDown LSB 0x7 0x7
+TmsCsOutIn EdgeDown EdgeDown LSB 0x7 0x7
+TmsCsOutIn EdgeUp MSB 0x7 0x7
+TmsCsOutIn 0x2 0x7
+tiki
diff -Nru /sys/src/cmd/jtagfs/matest /sys/src/cmd/jtagfs/matest
--- /sys/src/cmd/jtagfs/matest	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/matest	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,10 @@
+#!/bin/rc
+
+./8.mpssetest -t <examples xdg >[2] errors
+xd -c -bx xdg
+
+#this should all error:
+./8.mpssetest -t < examplesbad  xdb >[2] errors
+cat errors
+xd -c -bx xdb
+
diff -Nru /sys/src/cmd/jtagfs/mkfile /sys/src/cmd/jtagfs/mkfile
--- /sys/src/cmd/jtagfs/mkfile	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mkfile	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,62 @@
+</$objtype/mkfile
+BIN=/$objtype/bin
+
+#bad bad...
+Oo=`{cat /$cputype/mkfile|grep '^O'|sed 's/.*=//g'}
+
+TARG=mpssetest\
+	jtagfs\
+
+CLEANFILES=*.genrtab\
+	errors\
+	rtab.c\
+	xdb\
+	xdg\
+
+OFILES=\
+	bebo.$O\
+	chain.$O\
+	debug.$O\
+	icert.$O\
+	jtag.$O\
+	lebo.$O\
+	ma.$O\
+	mmu.$O\
+	mpsse.$O\
+	rtab.$O\
+	tap.$O\
+
+HFILES=\
+	bebo.h\
+	debug.h\
+	icert.h\
+	lebo.h\
+	mmu.h\
+	mpsse.h\
+	tap.h\
+
+UPDATE=\
+	mkfile\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+
+</sys/src/cmd/mkmany
+
+$O.out:	/$objtype/lib/libregexp.a
+
+rtab.c: genrtab.c
+	$Oo^c -FVw genrtab.c && $Oo^l -o $Oo.genrtab genrtab.$Oo
+	./$Oo.genrtab > rtab.c
+
+rtest:V: all
+	./test
+
+pubfiles=`{ls}
+
+
+/usr/paurea/src/jtag/jtag.tgz: $pubfiles
+	cd /usr/paurea/src/jtag/ &&  tar cv jtag/^$pubfiles|gzip > jtag.tgz
+
+dist:V: /usr/paurea/src/jtag/jtag.tgz
+	mk all && mk clean && 9fs sources  && cp ../jtag.tgz /n/sources/contrib/paurea
+	
diff -Nru /sys/src/cmd/jtagfs/mmu.c /sys/src/cmd/jtagfs/mmu.c
--- /sys/src/cmd/jtagfs/mmu.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mmu.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,125 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "chain.h"
+#include "debug.h"
+#include "tap.h"
+#include "lebo.h"
+#include "bebo.h"
+#include "jtag.h"
+#include "icert.h"
+#include "mmu.h"
+#include "mpsse.h"
+#include "/sys/src/9/kw/arm.h"
+
+/* 
+ *	Feroceon's scan chain 15 does not work, I suspect it has the multi-ice
+ *	40 bits limit (even if it is only one core). Just pushing MCR/MRC and
+ *	reading back seems to be more portable
+ *	The only bad thing is that using chain 15 one can
+ *	change things secondary effects (I cannot think of any, but there may be)
+ */
+
+char *
+printmmuregs(MMURegs *mmuregs, char *s, int ssz)
+{
+	char *e, *te;
+
+	te = s + ssz - 1;
+	
+	e = seprint(s, te, "cpid: %#8.8ux\n", mmuregs->cpid);
+	e = seprint(e, te, "ct: %#8.8ux\n", mmuregs->ct);
+	e = seprint(e, te, "control: %#8.8ux\n", mmuregs->control);
+	e = seprint(e, te, "ttb: %#8.8ux\n", mmuregs->ttb);
+	e = seprint(e, te, "dac: %#8.8ux\n", mmuregs->dac);
+	e = seprint(e, te, "fsr: %#8.8ux\n", mmuregs->fsr);
+	e = seprint(e, te, "far: %#8.8ux\n", mmuregs->far);
+	e = seprint(e, te, "pid: %#8.8ux\n", mmuregs->pid);
+	return e;
+}
+
+/* Chain 15 does not work properly and is not portable, use MCR/MRC */
+
+static int
+jtagmrc(JMedium *jmed, u32int *data, uchar op1, uchar op2, uchar crn, uchar crm)
+{
+	int res;
+	u32int d;
+
+	res = armfastexec(jmed, ARMMRC(CpSC, op1, 0, crn, crm, op2));
+	if(res < 0)
+		return -1;
+
+	setinst(jmed, InRestart, 0);
+	res = icewaitdebug(jmed);
+	if(res < 0)
+		return -1;
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		sysfatal("setchain %r");
+	armgetexec(jmed, 1, &d, ARMSTMIA|0x0001);
+
+	*data = d;
+	dprint(Dmmu, "MCR data %#8.8ux \n", d);
+	return 0;
+}
+
+static int
+jtagmcr(JMedium *jmed, u32int data, uchar op1, uchar op2, uchar crn, uchar crm)
+{
+	int res;
+	dprint(Dmem, "MCR data %#8.8ux\n",
+				data);
+	/* load data in r0 */
+	res = armsetexec(jmed, 1, &data, ARMLDMIA|0x0001);
+	if(res < 0)
+		return -1;
+
+	res = armfastexec(jmed, ARMMCR(CpSC, op1, 0, crn, crm, op2));
+	if(res < 0)
+		return -1;
+
+	setinst(jmed, InRestart, 0);
+	res = icewaitdebug(jmed);
+	if(res < 0)
+		return -1;
+	return 0;
+}
+
+
+int
+mmurdregs(JMedium *jmed, MMURegs *regs)
+{
+	int res;
+	res = setchain(jmed, ChCommit, 1);
+	if(res < 0)
+		sysfatal("setchain %r");
+	res = jtagmrc(jmed, &regs->cpid, 0, CpIDid, C(CpID), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->control, 0, 0,  C(CpCONTROL), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->ttb, 0, 0,  C(CpTTB), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->dac, 0, 0,  C(CpDAC), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->fsr, 0, 0,  C(CpFSR), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->far, 0, 0,  C(CpFAR), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->ct, 0, CpIDct, C(CpID), C(0));
+	if(res < 0)
+		return -1;
+	res = jtagmrc(jmed, &regs->pid, 0, 0,  C(CpPID), C(0));
+	if(res < 0)
+		return -1;
+
+	return 0;
+}
+
+
diff -Nru /sys/src/cmd/jtagfs/mmu.h /sys/src/cmd/jtagfs/mmu.h
--- /sys/src/cmd/jtagfs/mmu.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mmu.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,36 @@
+typedef struct MMUMcrChain15 MMUMcrChain15;
+
+/* Version of the 15 Chain for mcr access */
+struct MMUMcrChain15 {
+	uchar	rw;		/* 1bit */
+	uchar	op1;		/* 3 bits */
+	uchar	op2;		/* 3 bits */
+	uchar	crn;		/* 4 bits */
+	uchar	crm;		/* 4 bits */
+	uchar	access;	/* 1 bit */
+	u32int	data;		/* 32 bits */
+};
+
+enum {
+	/* other sizes taken from icert.h */
+	AccessSz		= 1,
+	OpSz		= 3,
+	CrxSz		= 4,
+};
+
+enum{
+	ARMMCROP		= 0xee000010,
+	ARMMRCLFLAG	= 0x00100000,
+};
+
+#define C(cr)	((cr)&0x7)
+#define ARMMCR(cp, op1, rd, crn, crm, op2) (ARMMCROP | \
+				crm | (op2 << 5) | (cp<<8) | \
+				(rd<<12) | (crn<<16) | (op1<<21))
+
+
+#define ARMMRC(cp, op1, rd, crn, crm, op2) (ARMMRCLFLAG | \
+				ARMMCR(cp, op1, rd, crn, crm, op2))
+
+extern int	mmurdregs(JMedium *jmed, MMURegs *regs);
+extern char *	printmmuregs(MMURegs *mmuregs, char *s, int ssz);
diff -Nru /sys/src/cmd/jtagfs/mpsse.c /sys/src/cmd/jtagfs/mpsse.c
--- /sys/src/cmd/jtagfs/mpsse.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mpsse.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,648 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "debug.h"
+#include "lebo.h"
+#include "tap.h"
+#include "chain.h"
+#include "jtag.h"
+#include "icert.h"
+#include "mpsse.h"
+
+/*
+	See schematics, openocd code.
+	Guessing for the GuruDisp...
+ */
+
+static uchar cablingH[][4] = {
+	[Sheeva]		{[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
+	[GuruDisp]	{[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
+};
+
+static uchar cablingL[][5] = {
+	[Sheeva]		{[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
+	[GuruDisp]	{[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
+};
+
+static uchar valcabling[][2] = {
+	[Sheeva]		{isPushPull, isOpenDrain},
+	[GuruDisp]	{isPushPull, isPushPull},
+};
+
+static u32int cpuids[] = {
+	[Sheeva]		FeroceonId,
+	[GuruDisp]	ArmadaId,
+};
+
+static uchar
+hinitvalH(int motherb, int trst, int srst)
+{
+	uchar hout;
+
+	hout = 0;
+
+	if(trst){
+		hout |= cablingH[motherb][TRSTnOE];
+		hout &= ~cablingH[motherb][TRST];
+	}
+	else{
+		hout &= ~cablingH[motherb][TRSTnOE];
+		hout |= cablingH[motherb][TRST];
+	}
+	if(srst){
+		hout &= ~cablingH[motherb][SRSTnOE];
+		hout |= cablingH[motherb][SRST];
+	}
+	else{
+		hout |= cablingH[motherb][SRSTnOE];
+		hout &= ~cablingH[motherb][SRST];
+	}
+
+	return hout;
+}
+
+static uchar
+hinitdirH(int motherb)
+{
+	USED(motherb);
+	//int i;
+	//uchar dir;
+	//dir = 0;
+	//for(i = 0; i < 4; i++)
+	//	dir |= cablingH[motherb][i];	/* BUG: TODO */
+	return 0xf;
+}
+
+int
+mpsseflush(void *mdata)
+{
+	int r, nb;
+	ushort s;
+	Mpsse *mpsse;
+
+	mpsse = mdata;
+	s = 0xbebe;
+
+	r = 0;
+
+	nb = Bbuffered(&mpsse->bout);
+	if(debug[DFile] || debug[DAll])
+		fprint(2, "Flush %d\n", nb);
+
+	if(debug[DXFlush])
+		Bwrite(&mpsse->bout, &s, sizeof s);
+	if(nb && Bflush(&mpsse->bout) == Beof)
+		r = -1;
+	
+	return r;
+}
+
+static int
+mpsseresets(void *mdata, int trst, int srst)
+{
+	char cmd[128];
+	uchar hout, hdir;
+	int motherb;
+	Mpsse *mpsse;
+
+	mpsse = mdata;
+	motherb = mpsse->motherb;
+
+	hdir = hinitdirH(motherb);
+	hout = hinitvalH(motherb, trst, srst);
+
+	snprint(cmd, sizeof(cmd), "SetBitsH %#2.2ux %#2.2ux", hout, hdir);
+	if(pushcmd(mpsse, cmd) < 0)
+		return -1;
+	if(mpsseflush(mpsse) < 0)
+		return -1;
+	return 0;
+}
+
+
+static int
+initpins(Mpsse *mpsse)
+{
+	char cmd[128];
+	uchar hout, hdir;
+	int motherb;
+	Biobufhdr *bout;
+
+	motherb = mpsse->motherb;
+	bout = &mpsse->bout;
+
+	/* value of this also depends on opendrain etc?, seems it does not */
+	hout = cablingL[motherb][TMS];
+	hdir =  cablingL[motherb][TCK]|cablingL[motherb][TDI];
+	hdir |= cablingL[motherb][TMS]|cablingL[motherb][nOE];
+	snprint(cmd, sizeof(cmd), "SetBitsL %#2.2ux %#2.2ux", hout, hdir);
+	if(pushcmd(mpsse, cmd) < 0){
+		Bterm(bout);
+		return -1;
+	}
+	if(mpsseflush(mpsse) < 0)
+		return -1;
+
+	/* is this Board dependant? */
+	if(mpsseresets(mpsse, 0, 0) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+mpsseterm(void *mdata)
+{
+	Mpsse *mpsse;
+	int r;
+	
+	mpsse = mdata;
+	r =  Bterm(&mpsse->bout);
+	free(mpsse);
+	
+	return r;
+}
+
+/* I always work with bits on the lsb side, nbits count the
+ * n less significant bits, no matter msb or lsb order
+ * I know that mpsse works with lsb on the lsb side and
+ * msb I am not sure how it is codified msb on lsb side would be
+ * 00001234, instead of lsb on msb side 12340000
+ * In any case I never use msb on the mpsse,
+ * just on the paths for convenience and they are lsb side
+ * like 000001234
+ * in other words, nbits always counts from lsb bit
+ */
+static ulong
+msb2lsb(ulong msbl, int nbits)
+{
+	int i;
+	ulong lsbl, bit;
+
+	lsbl = 0;
+	for(i = 0; i < nbits; i++){
+		bit = (msbl >> (nbits - i - 1))&1;
+		lsbl |= bit << i;
+	}
+	return lsbl;
+}
+
+/* how many clk bits takes to clock out a data bit */
+static int 
+tmsdata2clk(int nbits)
+{
+	return ((nbits + 6)/7) * 3;
+}
+
+#define takebits(byte, nbits, offset) (((byte) >> (offset)) & ((1U << (nbits))-1))
+
+static void
+dropbits(Mpsse *mpsse, int nbits)
+{
+	int nby, nbi;
+
+	nby = nbits / 8;
+	nbi = nbits % 8;
+
+	assert(mpsse->nbits >= nbits);
+	
+	mpsse->nbits -= 8*nby;
+	mpsse->rb += nby;
+
+	mpsse->rbits = (mpsse->rbits + nbi) %8;
+	
+	mpsse->nbits -= nbi;
+}
+
+static int
+runpath(JMedium *jmed, SmPath *pth, int isrd, int issend)
+{
+	SmPath pref;
+	uchar tmslsb, lastbit;
+	int nclkbits;
+	char cmd[128];
+	Mpsse *mpsse;
+	
+	mpsse = jmed->mdata;
+	lastbit = 0;
+	nclkbits = 0;
+	if(issend && mpsse->nbits != 0){
+		lastbit = mpsse->lastbit;
+		mpsse->nbits--;
+		nclkbits = 1;
+	}
+	
+	while(pth->ptmslen != 0){
+		pref = takepathpref(pth, MaxNbitsT);
+		tmslsb = msb2lsb(pref.ptms, pref.ptmslen);
+
+		if(issend && nclkbits--){
+			tmslsb |= lastbit<<7;
+		}
+		if(isrd)
+			snprint(cmd, sizeof(cmd), "TmsCsOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
+				(uchar)pref.ptmslen, tmslsb);
+		else
+			snprint(cmd, sizeof(cmd), "TmsCsOut EdgeDown LSB B%#2.2ux %#2.2ux",
+				(uchar)pref.ptmslen, tmslsb);
+		
+		if(pushcmd(mpsse, cmd) < 0)
+			return -1;
+	}
+
+	moveto(jmed, pth->st);
+	return 0;
+}
+
+static int
+sendbytes(Mpsse *mpsse, int nbytes, int op)
+{
+	char cmd[128];
+	int totbytes, nwbytes;
+	uchar *buf;
+
+	buf = mpsse->rb;
+	totbytes = mpsse->nbits/8;
+	nwbytes = nbytes;
+	if(totbytes < nbytes){
+		werrstr("sendbytes: not enough %d<%d", totbytes, nbytes);
+		return -1;
+	}
+	if( (op&ShiftIn ) && !(op&ShiftOut) ){
+		snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB %#2.2ux",
+				nbytes);
+		nwbytes = 0;
+	}
+	else if( !(op&ShiftIn) && (op&ShiftOut) )
+		snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB %#2.2ux @",
+				nbytes);
+	else if( (op&ShiftIn) && (op&ShiftOut) )
+		
+		snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB %#2.2ux @",
+				nbytes);
+	else
+		return -1;
+
+
+	if(pushcmdwdata(mpsse, cmd, buf, nwbytes) < 0)
+		return -1;
+
+	dropbits(mpsse, 8*nbytes);
+	return 0;
+}
+
+
+static int
+sendbits(Mpsse *mpsse, int nbits, int op)
+{
+	char cmd[128];
+	uchar lastbyte, obyte;
+
+	lastbyte = *mpsse->rb;
+	if(nbits > 8){
+		werrstr("too many bits %d>%d", nbits, MaxNbitsS);
+		return -1;
+	}
+
+
+	obyte = takebits(lastbyte, nbits, mpsse->rbits);
+
+	if( (op&ShiftIn ) && !(op&ShiftOut) )
+		snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB B%#2.2ux",
+				nbits);
+	else  if( !(op&ShiftIn) && (op&ShiftOut) )
+		snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB B%#2.2ux %#2.2ux",
+				nbits, obyte);
+	else if( (op&ShiftIn) && (op&ShiftOut) )
+		
+		snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
+				nbits, obyte);
+	else
+		return -1;
+
+
+	if(pushcmd(mpsse, cmd) < 0)
+		return -1;
+
+	dropbits(mpsse, nbits);
+	return 0;
+}
+
+static int
+movetost(JMedium *jmed, int dst, int isrd, int issend)
+{
+	SmPath pth;
+	int len;
+
+	pth = pathto(jmed, dst);
+	len = pth.ptmslen;
+	if(runpath(jmed, &pth, isrd, issend) < 0)
+		return -1;
+	return len;
+}
+
+static int
+stayinst(JMedium *jmed, int nclock)
+{
+	SmPath pth;
+
+	pth.ptms = 0;
+	pth.ptmslen = nclock;
+	if(runpath(jmed, &pth, 0, 0) < 0)
+		return -1;
+	return nclock;
+}
+
+static int
+mpsserdshiftrep(JMedium *jmed, uchar *buf, ShiftRDesc *rep)
+{
+	int nr, npartial, nby;
+	uchar msk;
+
+	Mpsse *mpsse;
+
+	mpsse = jmed->mdata;
+	dprint(DFile, "Reading %d\n", rep->nbyread);
+
+	nr = readn(mpsse->jtagfd, buf, rep->nbyread);
+
+	npartial = 0;
+
+	dprint(DFile, "Read %d\n", nr);
+	dumpbuf(DFile, buf, nr);
+	if(nr <= 0)
+		return -1;
+	if(rep->nbiprelast != 0){
+		npartial++;
+	}
+	if(rep->nbilast != 0){
+		npartial++;
+	}
+	nby = rep->nbyread - npartial;
+	if(rep->nbiprelast != 0){
+		buf[nby] = buf[nby] >> (8 - rep->nbiprelast);
+	}
+	if(rep->nbilast != 0){
+		msk = MSK(rep->nbilast);
+		buf[nby] |= (buf[nby+1] & msk) << (8 - rep->nbilast);
+	}
+	return (7 + nby + npartial) / 8;	/* readjust after compacting */
+}
+
+/*
+ * May need a couple of two or three bytes of margin for reading,
+ * do not call it with just enough bytes
+*/
+
+static int
+mpsseregshift(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep)
+{
+	int npsend, nr, nl, isrd, nback, nby, ntrail, reg, nbits, op;
+	ShiftRDesc rr;
+	uchar *buf;
+	Mpsse *mpsse;
+
+	reg = req->reg;
+	buf = req->buf;
+	nbits = req->nbits;
+	op = req->op;
+
+	mpsse = jmed->mdata;
+	if(rep == nil)
+		rep = &rr;
+
+	nr = 0;
+	nby = 0;
+	nback = 0;
+	npsend = 0;
+
+
+	if(reg != TapDR && reg != TapIR)
+		sysfatal("unknown register");
+
+	isrd = op&ShiftIn;
+
+	/* 	
+	 *	May need to go to Pause to cross capture before starting
+	 *	May still have a trailing bit from last shifting
+	 */
+
+	if(op&ShiftPauseIn){
+		nl = movetost(jmed, TapPauseDR+reg, 0, mpsse->nbits != 0);
+		if(nl < 0){
+			werrstr("regshift: going to pause in");
+			return -1;
+		}
+	}
+
+	if(movetost(jmed, TapShiftDR+reg, 0, mpsse->nbits != 0) < 0){
+		werrstr("regshift: going to shift");
+		return -1;
+	}
+
+	mpsse->nbits = nbits;
+	mpsse->rb = buf;
+	mpsse->rbits = 0;
+
+	if((mpsse->nbits / 8)  > 1){
+		nby = mpsse->nbits / 8;
+		if(mpsse->nbits % 8 == 0)
+			nby--;
+		if(sendbytes(mpsse, nby, op) < 0){
+			werrstr("regshift: shifting bytes");
+			return -1;
+		}
+		nback = nby;
+	}
+
+
+	if(mpsse->nbits > 1){
+		nback++;				/* each op gives a partial byte */
+		npsend = mpsse->nbits;
+		if(mpsse->nbits > 7)		/* apparently hw does not like 8 bytes */
+			npsend = MaxNbitsS;
+		npsend -= 1;	/* one is for the way */
+		if(sendbits(mpsse, npsend, op) < 0){
+			werrstr("regshift: shifting bits");
+			return -1;
+		}
+		mpsse->lastbit = takebits(*mpsse->rb, 1, mpsse->rbits);
+	}
+
+
+	/* 	I only go through pause if I need extra time to shift
+	 *	for example, I need a command to read or if I am told
+	*/
+
+	if(isrd || (op&ShiftPauseOut)){
+		nback++;
+		nl = movetost(jmed, TapPauseDR+reg, isrd, mpsse->nbits != 0);
+		if(nl < 0){
+			werrstr("regshift: going to pause out");
+			return -1;
+		}
+	}
+
+	if(! (op&ShiftNoCommit)){
+		nl = movetost(jmed, TapIdle, 0, mpsse->nbits != 0);
+		if(nl < 0){
+			werrstr("regshift: going to idle out");
+			return -1;
+		}
+	}
+	if(isrd){
+		if(mpsseflush(mpsse) < 0){
+			werrstr("regshift: flushing");
+			return -1;
+		}
+
+		ntrail = nbits - npsend - 8*nby;
+		rep->nbyread = nback;
+		rep->nbiprelast = npsend;
+		rep->nbilast = ntrail;
+		if( !(op&ShiftAsync) )
+			nr = mpsserdshiftrep(jmed, buf, rep);
+	}
+	return nr;
+}
+
+JMedium *
+newmpsse(int fd, int motherb)
+{
+	Mpsse *mpsse;
+	Biobufhdr *bout;
+	JMedium *jmed;
+	int i;
+
+	jmed = mallocz(sizeof(JMedium), 1);
+	if(jmed == nil)
+		return nil;
+
+	mpsse = malloc(sizeof(Mpsse));
+	if(mpsse == nil)
+		return nil;
+
+	jmed->motherb = motherb;
+	jmed->mdata = mpsse;
+	jmed->regshift = mpsseregshift;
+	jmed->rdshiftrep = mpsserdshiftrep;
+	jmed->flush = mpsseflush;
+	jmed->term = mpsseterm;
+	jmed->resets = mpsseresets;
+
+	/* BUG: configuration file? */
+	if(motherb == Sheeva){
+		jmed->ntaps = 1;
+		jmed->tapcpu = 0;
+		jmed->taps[0].hwid = FeroceonId;
+		jmed->taps[0].irlen = InLen;
+	}
+	else if(motherb == GuruDisp){
+		/* BUG: set concatenating mode */
+		jmed->ntaps = 3;
+		jmed->taps[0].hwid = 0;
+		jmed->taps[0].irlen = 1;
+		jmed->tapcpu = 1;
+		jmed->taps[1].hwid = ArmadaId;
+		jmed->taps[1].irlen = InLen;
+		jmed->taps[2].hwid = 0;
+		jmed->taps[2].irlen = 9;
+	}
+	else
+		sysfatal("Unkwown motherboard");
+
+	for(i = 0; i < jmed->ntaps; i++)
+		jmed->taps[i].state = TapUnknown;
+	jmed->state = TapUnknown;
+
+	mpsse->jtagfd = fd;
+	mpsse->motherb = motherb;
+	
+
+	bout = &mpsse->bout;
+
+	if(Binits(bout, fd, OWRITE, mpsse->bp, MpsseBufSz) == Beof){
+		free(mpsse);
+		return nil;
+	}
+	return jmed;
+}
+
+JMedium *
+initmpsse(int fd, int motherb)
+{
+	Mpsse *mpsse;
+	JMedium *jmed;
+	uchar buf[32];
+	ShiftTDesc req;
+
+
+	jmed = newmpsse(fd, motherb);
+	if(jmed == nil){
+		free(jmed);
+		return nil;
+	}
+	mpsse = jmed->mdata;
+
+	if(initpins(mpsse) < 0)
+		goto Err;
+
+	if(pushcmd(mpsse, "TckSkDiv 0x0200") < 0)
+		goto Err;
+	if(mpsseflush(mpsse) < 0)
+		goto Err;
+
+	if(pushcmd(mpsse, "BreakLoop") < 0)
+		goto Err;
+	if(mpsseflush(mpsse) < 0)
+		goto Err;
+
+	/* Board dependant ? */
+	if(mpsseresets(mpsse, 0, 0) < 0)
+		goto Err;
+
+	if(motherb == GuruDisp){	/* set concat mode */
+		req.reg = TapIR;
+		hleputs(buf, InGuruTapctl);
+		req.buf = buf;
+		req.nbits = InGuruLen;
+		req.op = ShiftOut;
+		
+		jmed->regshift(jmed, &req, nil);
+		req.reg = TapDR;
+		hleputs(buf, DrGuruTapctl);
+		req.buf = buf;
+		req.nbits = 16;
+		req.op = ShiftOut;
+		jmed->regshift(jmed, &req, nil);
+		jmed->taps[2].TapSm = jmed->TapSm;
+	}
+	return jmed;
+Err:
+	mpsseterm(mpsse);
+	free(jmed);
+	return nil;
+}
+
+static void
+termmpsse(JMedium *jmed)
+{
+	mpsseterm(jmed->mdata);
+	free(jmed);
+}
+
+
+JMedium *
+resetmpsse(JMedium *jmed)
+{
+	Mpsse mpsse;
+	JMedium *jmnew;
+
+	mpsse = *(Mpsse *)jmed->mdata;
+	mpsseflush((Mpsse *)jmed->mdata);
+	free(jmed->mdata);
+
+	jmnew = initmpsse(mpsse.jtagfd, mpsse.motherb);
+	return jmnew;
+}
+
diff -Nru /sys/src/cmd/jtagfs/mpsse.h /sys/src/cmd/jtagfs/mpsse.h
--- /sys/src/cmd/jtagfs/mpsse.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mpsse.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,59 @@
+typedef struct Mpsse Mpsse;
+
+enum {
+	KHz = 1000,
+	FtdiHSpeedClk = 30*KHz,		/* 2232H 4232H */
+	FtdiMaxClk = 60*KHz,		/* 2232C */
+	FtdiReqTck = -1,
+};
+
+enum{
+	isPushPull,
+	notPushPull,
+	isOpenDrain,
+	notOpenDrain,
+};
+
+enum{
+	MpsseBufSz	= 131072,	/* from openocd, noone knows why */
+	MaxNbitsT	= 7,			/* maximum bits per state transition */
+	MaxNbitsS	= 7,			/* maximum bits of data clocked */
+
+	nOE = 0,
+	TDI,
+	TDO,
+	TMS,
+	TCK,
+
+	TRSTnOE = 0,
+	TRST,
+	SRSTnOE,
+	SRST,
+
+	Sheeva = 0,
+	GuruDisp = 1,
+};
+
+
+struct Mpsse{
+	int nread;	/* bytes left to read */
+	int nbits;	/* length of bits left to process */
+	uchar *rb;	/* current point of buf processing */
+	int rbits;	/* offset in the last bit to process counting from LSB */
+	int lastbit;
+	int motherb;
+	int jtagfd;
+	Biobufhdr bout;
+	uchar bp[Bungetsize+MpsseBufSz];
+};
+
+int	mpsseflush(void *mdata);	/* internal, for ma.c */
+
+/* from ma.c */
+extern int	pushcmd(Mpsse *mpsse, char *ln);
+extern int	pushcmdwdata(Mpsse *mpsse, char *ln, uchar *buf, int buflen);
+
+/* from mpsse.c */
+extern JMedium *	initmpsse(int fd, int motherb);
+extern JMedium *	newmpsse(int fd, int motherb);
+extern JMedium *	resetmpsse(JMedium *jmed);
diff -Nru /sys/src/cmd/jtagfs/mpssetest.c /sys/src/cmd/jtagfs/mpssetest.c
--- /sys/src/cmd/jtagfs/mpssetest.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/mpssetest.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,193 @@
+#include <u.h>
+#include <libc.h>
+#include <regexp.h>
+#include <bio.h>
+#include "debug.h"
+#include "tap.h"
+#include "chain.h"
+#include "jtag.h"
+#include "icert.h"
+#include "mmu.h"
+#include "mpsse.h"
+
+static Biobuf bin;
+
+static void
+testsh(JMedium *jmed)
+{
+	char *ln;
+	while(ln = Brdstr(&bin, '\n', 1)){
+		if(ln == nil)
+			break;
+		fprint(2, "[%s]\n", ln);
+		if(strcmp(ln, "") == 0 || ln[0] == '#'){
+			free(ln);
+			continue;
+		}
+		if(pushcmd(jmed->mdata, ln) < 0)
+			fprint(2, "error: %r\n");
+		free(ln);
+	}
+}
+
+static void
+hwreset(JMedium *jmed)
+{
+	/* BUG make this medium independant... */
+	if(pushcmd(jmed->mdata, "TmsCsOut EdgeDown LSB B0x7 0x7f") < 0) 
+		sysfatal("resetting %r");
+	if(jmed->flush(jmed->mdata))
+		sysfatal("resetting %r");
+	sleep(1000);
+	jmed->resets(jmed->mdata, 1, 0);
+	sleep(200);
+	jmed->resets(jmed->mdata, 1, 1);
+	sleep(200);
+	jmed->resets(jmed->mdata, 0, 1);
+	sleep(200);
+	jmed->resets(jmed->mdata, 0, 0);
+	sleep(200);
+}
+
+static void
+usage(void)
+{
+	fprint(2, "Usage: %s [-t] [-r] [-d 'a'...] jtagfile\n", argv0);
+	exits("usage");
+}
+
+static Chain ch;
+static EiceChain1 ec1;
+static EiceChain2 ec2;
+static char dbgstr[256];
+
+static ArmCtxt ctxt;
+static u32int regs[16];
+
+static void
+testice(JMedium *jmed)
+{
+	int res, i;
+	u32int cpuid, data;
+	debug[Dctxt] = 1;
+
+	cpuid = armidentify(jmed);
+	fprint(2, "---- Cpuid --- %8.8ux\n", cpuid);
+	if(cpuid == ~0)
+		sysfatal("not feroceon or WFI bug...");
+
+	fprint(2, "---- Bypass probe --- \n");
+	if(armbpasstest(jmed) < 0)
+		sysfatal("bypass test");
+
+	fprint(2, "---- Check state --- \n");
+	res = setchain(jmed, ChCommit, 2);
+	if(res < 0)
+		sysfatal("setchain %r");
+
+	icegetreg(jmed, DebStsReg);
+
+	fprint(2, "---- Freeze  --- \n");
+	res = iceenterdebug(jmed, &ctxt);
+	if(res < 0)
+		sysfatal("could not enter debug");
+	fprint(2, "\n\n\tIn debug state for 1 sec\n\n");
+	sleep(1000);
+	fprint(2, "---- MMU test  --- \n");
+	res = mmurdregs(jmed, &ctxt);
+	if(res < 0)
+		sysfatal("mmurdregs %r");
+
+	printmmuregs(&ctxt, dbgstr, sizeof dbgstr);
+	fprint(2, "MMU state:\n%s\n", dbgstr);
+
+	fprint(2, "---- Read mem  --- \n");
+	for(i = 0; i < 10; i++){
+		res = armrdmemwd(jmed, ctxt.r[15]+4*i, &data, 4);
+		if(res < 0){
+			fprint(2, "Error reading %#8.8ux pc[%d]\n", ctxt.r[15]+4*i, i);
+			break;
+		}
+		fprint(2, "Read data %#8.8ux addr %#8.8ux pc[%d]\n",
+				data, ctxt.r[15]+4*i, i);
+	}
+	
+	fprint(2, "---- Write mem (dangerous test) --- \n");
+
+	if(0)
+		for(i = 0; i < 10; i++){
+			data = 0;
+			fprint(2, "Write data %#8.8ux addr %#8.8ux pc[%d]\n", data, ctxt.r[15]+4*i, i);
+			res = armwrmemwd(jmed, ctxt.r[15]+4*i, data, 4);
+			if(res < 0){
+				fprint(2, "Error reading %#8.8ux pc[%d]\n", ctxt.r[15]+4*i, i);
+				break;
+			}
+		}
+	
+	fprint(2, "---- Unfreeze  --- \n");
+	res = iceexitdebug(jmed, &ctxt);
+	if(res < 0)
+		sysfatal("could not exit debug");
+}
+
+
+void
+main(int argc, char *argv[])
+{
+	JMedium *jmed;
+	int tsh, rsh, i, jtagfd;
+	char *deb;
+	
+	deb = nil;
+	argv0 = "mpssetest";
+	tsh = rsh = 0;
+
+	ARGBEGIN{
+	case 't':
+		tsh = 1;
+		break;
+	case 'r':
+		rsh = 1;
+		break;
+	case 'd':
+		deb = EARGF(usage());
+		break;
+	default:
+		usage();
+	} ARGEND
+	
+	if(argc != 1)
+		usage();
+
+	jtagfd = open(argv[0], ORDWR);
+	if(jtagfd < 0)
+		sysfatal("cannot open jtag file"); 
+
+	if(deb  != nil)
+		for(i = 0; i < strlen(deb); i++)
+			debug[deb[i]]++;
+	Binit(&bin, 0, OREAD);
+
+	if(tsh){
+		 jmed = newmpsse(jtagfd, Sheeva);
+		if(jmed == nil)
+			sysfatal("newmpsse %r");
+		testsh(jmed);
+	}
+	else if(rsh){
+		jmed = initmpsse(jtagfd, Sheeva);
+		if(jmed == nil)
+			sysfatal("initialization %r");
+		hwreset(jmed);
+	}
+	else {
+		jmed = initmpsse(jtagfd, Sheeva);
+		if(jmed == nil)
+			sysfatal("initialization %r");
+	
+		testice(jmed);
+	}
+	Bterm(&bin);
+	jmed->term(jmed);
+}
diff -Nru /sys/src/cmd/jtagfs/tap.c /sys/src/cmd/jtagfs/tap.c
--- /sys/src/cmd/jtagfs/tap.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/tap.c	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,269 @@
+#include <u.h>
+#include <libc.h>
+#include "debug.h"
+#include "tap.h"
+
+
+static stdebug = 1;
+
+/*
+	!8c -FVw tap.c
+	!8l -o tap tap.8
+	!tap > /tmp/l 
+*/
+
+static char *stnames[] = {
+	[TapReset]		"TapReset",
+	[TapIdle]			"TapIdle",
+	[TapSelDR]		"TapSelDR",
+	[TapCaptureDR]	"TapCaptureDR" ,
+	[TapShiftDR]		"TapShiftDR",
+	[TapExit1DR]		"TapExit1DR",
+	[TapPauseDR]		"TapPauseDR",
+	[TapExit2DR]		"TapExit2DR",
+	[TapUpdateDR]		"TapUpdateDR",
+	[TapSelIR]			"TapSelIR",
+	[TapCaptureIR]		"TapCaptureIR",
+	[TapShiftIR]		"TapShiftIR",
+	[TapExit1IR]		"TapExit1IR",
+	[TapPauseIR]		"TapPauseIR",
+	[TapExit2IR]		"TapExit2IR",
+	[TapUpdateIR]		"TapUpdateIR",
+	[NStates]			"",
+	[TapUnknown]		"TapUnknown",
+};
+
+typedef struct TapState TapState;
+struct TapState {
+	int next[2];
+};
+
+
+static TapState sm[]	= {
+	[TapReset]		{TapIdle, TapReset},
+	[TapIdle]			{TapIdle, TapSelDR},
+	[TapSelDR]		{TapCaptureDR, TapSelIR},
+	[TapCaptureDR]	{TapShiftDR, TapExit1DR},
+	[TapShiftDR]		{TapShiftDR, TapExit1DR,},
+	[TapExit1DR]		{TapPauseDR, TapUpdateDR},
+	[TapPauseDR]		{TapPauseDR, TapExit2DR},
+	[TapExit2DR]		{TapShiftDR, TapUpdateDR},
+	[TapUpdateDR]		{TapIdle, TapSelDR},
+	[TapSelIR]			{TapCaptureIR, TapReset},
+	[TapCaptureIR]		{TapShiftIR, TapExit1IR},
+	[TapShiftIR]		{TapShiftIR, TapExit1IR},
+	[TapExit1IR]		{TapPauseIR, TapUpdateIR},
+	[TapPauseIR]		{TapPauseIR, TapExit2IR},
+	[TapExit2IR]		{TapShiftIR, TapUpdateIR},
+	[TapUpdateIR]		{TapIdle, TapSelDR},
+};
+
+static int state=TapReset;
+
+static int
+isvalidst(int state)
+{
+	if(state < 0 || state >= NStates && state != TapUnknown){
+		fprint(2, "invalid state: %d\n", state);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+tapsmmove(int state, int tms)
+{
+	assert(tms == 0 || tms == 1);
+
+	state = sm[state].next[tms];
+
+       return state;
+}
+
+/*
+ * To find the shortest path from here to a state
+ * go in parallel through all neighbour states till I find it
+ * with memoization of advancing passed states
+ * (Breadth First Search)
+ * (all paths weight the same, simple topology)
+ * could probably use this to generate a lookup table
+ * but all time is spent waiting for usb anyway
+ */
+
+static void
+movepath(SmPath *path, int tms, int newst)
+{
+	path->st = newst;
+	path->ptmslen++;
+	path->ptms <<= 1;
+	path->ptms |= tms;
+}
+
+
+static SmPath
+findpath(int origin, int dest)
+{
+	int np, memost, tms, nc, i, j, ip, st;
+	SmPath paths[NStates],  nextp, newp;
+
+	memset(paths, 0, sizeof(SmPath));
+	paths[0].st = origin;
+	np = 1;
+	memost = 0;
+	if(origin == dest)
+		return *paths;
+	
+	for(i = 0; i < NStates; i++){
+		for(j = 0; j < np; j++){
+			nc = 0;
+			nextp = paths[j];
+			for(tms = 0; tms < 2; tms++){
+				newp = nextp;
+				st = tapsmmove(newp.st, tms);
+				if((1 << st) & memost){
+					if(++nc == 2)		/*trapped state kill*/
+						paths[j] = paths[--np];
+					continue;
+				}
+				movepath(&newp, tms, st);
+				memost |= 1 << newp.st;
+
+				if(newp.st == dest)
+					return newp;
+				if(tms == 0)
+					ip = j;
+				else
+					ip = np++;
+				paths[ip] = newp;
+	
+			}
+		}
+	}
+	fprint(2, "should not come through here\n");
+	newp.st = -1;
+	return newp;
+}
+
+
+static void
+concatpath(SmPath *p1, SmPath *p2)
+{
+	ulong msk;
+	assert(p1->ptmslen < 8*sizeof(p1->ptms));
+		
+	msk = (1 << p2->ptmslen)-1;
+	p1->ptms = (p1->ptms << p2->ptmslen)|(p2->ptms & msk);
+	p1->ptmslen += p2->ptmslen;
+	p1->st = p2->st;
+}
+
+static void
+dumppath(SmPath *pth)
+{
+	uchar frstbit;
+	int i;
+
+	fprint(2, "\n(");
+	for(i = 0; i < pth->ptmslen; i++){
+		frstbit = (pth->ptms >> (pth->ptmslen-i-1))&1;
+		fprint(2, "tms[%d] = %ud ", i, frstbit);
+	}
+	fprint(2, ")\n");
+}
+
+SmPath
+pathto(TapSm *sm, int dest)
+{
+	SmPath pth1, pth2;
+
+	if(!isvalidst(sm->state) || !isvalidst(dest))
+		sysfatal("invalid state");
+	dprint(DState, "pathto: %s -> %s\n",
+		stnames[sm->state], stnames[dest]);
+	if(sm->state == TapUnknown){
+		pth1.ptmslen = 5;	/* resynch */
+		pth1.ptms = 0x1f;
+		pth2 = findpath(TapReset, dest);
+
+		concatpath(&pth1, &pth2);
+		if(debug[DPath])
+			dumppath(&pth1);
+		return pth1;
+	}
+	pth1 = findpath(sm->state, dest);
+	if(debug[DPath])
+		dumppath(&pth1);
+	return pth1;
+}
+
+void
+moveto(TapSm *sm, int dest)
+{
+	dprint(DState, "moveto: %s -> %s\n",
+		stnames[sm->state], stnames[dest]);
+	sm->state = dest;
+}
+
+static ulong
+pathpref(SmPath *pth, int nbits)
+{	
+	ulong msk;
+	assert(pth->ptmslen >= nbits);
+
+	msk = (1 << nbits)-1;
+	return msk & (pth->ptms >> (pth->ptmslen - nbits));
+}
+
+SmPath
+takepathpref(SmPath *pth, int nbits)
+{
+	SmPath pref;
+
+	pref.ptmslen = 0;
+	if(pth->ptmslen == 0)
+		return pref;
+	if(nbits > pth->ptmslen)
+		nbits = pth->ptmslen;
+	pref.ptmslen = nbits;
+	pref.ptms = pathpref(pth, nbits);
+	pth->ptmslen -= nbits;
+	return pref;
+}
+
+/*
+ * Testing
+
+void
+main(int, char *[])
+{
+	SmPath pth;
+	TapSm sm;
+	int orig, dest;
+
+	orig = TapReset;
+	dest = TapExit2DR;
+
+	print("origin %s dest %s\n", stnames[orig], stnames[dest]);
+	pth = findpath(orig, dest);
+	print("\n");
+	dumppath(&pth);
+	orig = TapShiftIR;
+	dest = TapExit2DR;
+
+	print("origin %s dest %s\n", stnames[orig], stnames[dest]);
+	pth = findpath(orig, dest);
+	print("\n");
+	dumppath(&pth);
+	orig = TapIdle;
+	dest = TapExit2IR;
+
+	print("origin %s dest %s\n", stnames[orig], stnames[dest]);
+	pth = findpath(orig, dest);
+	print("\n");
+	dumppath(&pth);
+	sm.state = TapUnknown;
+	pth = pathto(&sm, TapExit2DR);
+	dumppath(&pth);
+	
+}
+*/
diff -Nru /sys/src/cmd/jtagfs/tap.h /sys/src/cmd/jtagfs/tap.h
--- /sys/src/cmd/jtagfs/tap.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/jtagfs/tap.h	Sun Apr  7 00:00:00 2013
@@ -0,0 +1,53 @@
+typedef struct SmPath SmPath;
+typedef struct TapSm TapSm;
+typedef struct Tap Tap;
+
+enum{
+	TapReset,
+	TapIdle,
+	TapSelDR,
+	TapCaptureDR,
+	TapShiftDR,
+	TapExit1DR,
+	TapPauseDR,
+	TapExit2DR,
+	TapUpdateDR,
+	TapSelIR,
+	TapCaptureIR,
+	TapShiftIR,
+	TapExit1IR,
+	TapPauseIR,
+	TapExit2IR,
+	TapUpdateIR,
+	NStates,
+	TapUnknown,
+};
+
+
+enum {
+	TapDR,
+	TapIR = TapSelIR-TapSelDR,
+};
+
+struct TapSm{
+	int state;
+};
+
+struct SmPath{
+	ulong ptms;	/* msb order on the lsb side, see comment on msb2lsb */
+	ulong ptmslen;
+	int st;
+};
+
+struct Tap {
+	TapSm;
+	u32int hwid;
+	int irlen;
+	int drlen;
+	char name[32];
+	void *private;
+};
+
+extern void	moveto(TapSm *sm, int dest);
+extern SmPath	pathto(TapSm *sm, int dest);
+extern SmPath	takepathpref(SmPath *pth, int nbits);

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].