--- /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, ®s->cpid, 0, CpIDid, C(CpID), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->control, 0, 0, C(CpCONTROL), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->ttb, 0, 0, C(CpTTB), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->dac, 0, 0, C(CpDAC), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->fsr, 0, 0, C(CpFSR), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->far, 0, 0, C(CpFAR), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->ct, 0, CpIDct, C(CpID), C(0));
+ if(res < 0)
+ return -1;
+ res = jtagmrc(jmed, ®s->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);
|