usbmon

minimal linux usbmon commandline tool
git clone http://frotz.net/git/usbmon.git
Log | Files | Refs | README

dismpsse.c (10637B)


      1 // Copyright 2014 Brian Swetland <swetland@frotz.net>
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <ctype.h>
     19 
     20 typedef unsigned char u8;
     21 typedef unsigned short u16;
     22 typedef unsigned int u32;
     23 typedef unsigned long u64;
     24 
     25 #define TRACE_MPSSE	0
     26 #define TRACE_JTAG	0
     27 #define TRACE_DAP	0
     28 
     29 // ----- simulate arm dap -----
     30 
     31 void dap_abort(u64 v) {
     32 	u32 data = v;
     33 #if TRACE_DAP
     34 	printf("dpacc: wr %08x -> ABORT\n", data); // 36?
     35 #endif
     36 }
     37 
     38 u32 dap_apnum = 0;
     39 u32 dap_bank = 0;
     40 
     41 const char *dp_addr2name(unsigned addr) {
     42 	switch (addr) {
     43 	case 0x00: return "RESERVED";
     44 	case 0x04: return "CSW";
     45 	case 0x08: return "SELECT";
     46 	case 0x0C: return "RDBUFF";
     47 	default: return "XXX";
     48 	}
     49 }
     50 
     51 void dap_dpacc(u64 v) {
     52 	u32 data = v >> 3;
     53 	u32 cmd = v & 7;
     54 	u32 addr = (cmd & 6) << 1;
     55 
     56 #if TRACE_DAP
     57 	printf("dpacc: %s %08x -> DP  %02x %s\n",
     58 		(cmd & 1) ? "rd" : "wr", data, addr, dp_addr2name(addr));
     59 #endif
     60 	if ((cmd & 1) == 0) {
     61 		if (addr == 0x08) { // DPSEL
     62 			dap_apnum = data >> 24;
     63 			dap_bank = data & 0xF0;
     64 		}
     65 	}
     66 }
     67 
     68 const char *ap_addr2name(unsigned addr) {
     69 	switch (addr) {
     70 	case 0x00: return "CSW";
     71 	case 0x04: return "TAR";
     72 	case 0x0C: return "DRW";
     73 	case 0x10: return "BD0";
     74 	case 0x14: return "BD1";
     75 	case 0x18: return "BD2";
     76 	case 0x1C: return "BD3";
     77 	case 0xF4: return "CFG";
     78 	case 0xF8: return "BASE";
     79 	case 0xFC: return "IDR";
     80 	default: return "XXX";
     81 	}
     82 }
     83 
     84 struct {
     85 	u32 tar;
     86 	u32 csw;
     87 } AP[256];
     88 
     89 // not handled:
     90 // - auto-incr modes other than single
     91 // - transfer sizes other than 32
     92 
     93 void dap_apacc(u64 v) {
     94 	u32 data = v >> 3;
     95 	u32 cmd = v & 7;
     96 	u32 addr = dap_bank | ((cmd & 6) << 1);
     97 #if TRACE_DAP
     98 	printf("apacc: %s %08x -> AP%d %02x %s\n",
     99 		(cmd & 1) ? "rd" : "wr", data, dap_apnum, addr,
    100 		ap_addr2name(addr));
    101 #endif
    102 
    103 	if ((cmd & 1) == 0) {
    104 		switch (addr) {
    105 		case 0x00:
    106 			AP[dap_apnum].csw = data;
    107 			break;
    108 		case 0x04:
    109 			AP[dap_apnum].tar = data;
    110 			break;
    111 		case 0x0C:
    112 			printf("mem: wr%d %08x -> %08x\n",
    113 				dap_apnum, data, AP[dap_apnum].tar);
    114 			if ((AP[dap_apnum].csw & 0x30) == 0x10) {
    115 				AP[dap_apnum].tar += 4;
    116 			}
    117 			break;
    118 		case 0x10:
    119 		case 0x14:
    120 		case 0x18:
    121 		case 0x1C:
    122 			printf("mem: wr%d %08x -> %08x\n", dap_apnum, data,
    123 				(AP[dap_apnum].tar & 0xFFFFFFF0) | (addr & 0xF));
    124 			break;
    125 		} 
    126 	} else {
    127 		switch (addr) {
    128 		case 0x0C:
    129 			printf("mem: rd%d %08x\n",
    130 				dap_apnum, AP[dap_apnum].tar);
    131 			if ((AP[dap_apnum].csw & 0x30) == 0x10) {
    132 				AP[dap_apnum].tar += 4;
    133 			}
    134 			break;
    135 		case 0x10:
    136 		case 0x14:
    137 		case 0x18:
    138 		case 0x1C:
    139 			printf("mem: rd%d %08x\n", dap_apnum,
    140 				(AP[dap_apnum].tar & 0xFFFFFFF0) | (addr & 0xF));
    141 			break;
    142 		} 
    143 	}
    144 }
    145 
    146 
    147 // ----- simulate zynq jtag chain --------
    148 
    149 // TDI -> ARM(4) -> FPGA(6) -> TDO
    150 u32 ir_fpga = 0xffffffff;
    151 u32 ir_arm = 0xffffffff;
    152 
    153 void sim_ir(u64 data) {
    154 	ir_fpga = data & 0x3f;
    155 	ir_arm = (data >> 6) & 0xf;
    156 }
    157 
    158 void sim_dr(u64 data) {
    159 	// if fpga's not in bypass, no idea what we're doing
    160 	if (ir_fpga != 0x3f) return;
    161 	// discard the bit being fed into fpga's bypass register
    162 	data >>= 1;
    163 
    164 	switch (ir_arm) {
    165 	case 0x08: dap_abort(data); break;
    166 	case 0x0a: dap_dpacc(data); break;
    167 	case 0x0b: dap_apacc(data); break;
    168 	}
    169 }
    170 
    171 // ----- simulate jtag core -----
    172 
    173 #define JTAG_RESET      0
    174 #define JTAG_IDLE       1
    175 #define JTAG_DRSELECT   2
    176 #define JTAG_DRCAPTURE  3
    177 #define JTAG_DRSHIFT    4
    178 #define JTAG_DREXIT1    5
    179 #define JTAG_DRPAUSE    6
    180 #define JTAG_DREXIT2    7
    181 #define JTAG_DRUPDATE   8
    182 #define JTAG_IRSELECT   9
    183 #define JTAG_IRCAPTURE  10
    184 #define JTAG_IRSHIFT    11
    185 #define JTAG_IREXIT1    12
    186 #define JTAG_IRPAUSE    13
    187 #define JTAG_IREXIT2    14
    188 #define JTAG_IRUPDATE   15
    189 
    190 static const char *JSTATE[16] = {
    191         "RESET", "IDLE", "DRSELECT", "DRCAPTURE",
    192         "DRSHIFT", "DREXIT1", "DRPAUSE", "DREXIT2",
    193         "DRUPDATE", "IRSELECT", "IRCAPTURE", "IRSHIFT",
    194         "IREXIT1", "IRPAUSE", "IREXIT1", "IRUPDATE"
    195 };
    196 
    197 struct {
    198 	u8 next0;
    199 	u8 next1;
    200 } GRAPH[16] = {
    201 	[JTAG_RESET] = { JTAG_IDLE, JTAG_RESET },
    202 	[JTAG_IDLE] = { JTAG_IDLE, JTAG_DRSELECT },
    203 	[JTAG_DRSELECT] = { JTAG_DRCAPTURE, JTAG_IRSELECT },
    204 	[JTAG_DRCAPTURE] = { JTAG_DRSHIFT, JTAG_DREXIT1 },
    205 	[JTAG_DRSHIFT] = { JTAG_DRSHIFT, JTAG_DREXIT1 },
    206 	[JTAG_DREXIT1] = { JTAG_DRPAUSE, JTAG_DRUPDATE },
    207 	[JTAG_DRPAUSE] = { JTAG_DRPAUSE, JTAG_DREXIT2 },
    208 	[JTAG_DREXIT2] = { JTAG_DRSHIFT, JTAG_DRUPDATE },
    209 	[JTAG_DRUPDATE] = { JTAG_IDLE, JTAG_DRSELECT },
    210 	[JTAG_IRSELECT] = { JTAG_IRCAPTURE, JTAG_RESET },
    211 	[JTAG_IRCAPTURE] = { JTAG_IRSHIFT, JTAG_IREXIT1 },
    212 	[JTAG_IRSHIFT] = { JTAG_IRSHIFT, JTAG_IREXIT1 },
    213 	[JTAG_IREXIT1] = { JTAG_IRPAUSE, JTAG_IRUPDATE },
    214 	[JTAG_IRPAUSE] = { JTAG_IRPAUSE, JTAG_IREXIT2 },
    215 	[JTAG_IREXIT2] = { JTAG_IRSHIFT, JTAG_IRUPDATE },
    216 	[JTAG_IRUPDATE] = { JTAG_IDLE, JTAG_DRSELECT },
    217 };
    218 
    219 unsigned state = JTAG_RESET;
    220 unsigned shiftcount = 0;
    221 unsigned statecount = 1;
    222 u64 shiftdata = 0;
    223 
    224 void _sim_jtag(unsigned tdi, unsigned tms) {
    225 	u32 newstate = tms ? GRAPH[state].next1 : GRAPH[state].next0;
    226 	u32 n;
    227 
    228 #if TRACE_JTAG
    229 	if (newstate != state) {
    230 		if (statecount > 1) {
    231 			printf("jtag: %s x %d\n", JSTATE[state], statecount);
    232 		} else {
    233 			printf("jtag: %s\n", JSTATE[state]);
    234 		}
    235 		statecount = 1;
    236 	} else {
    237 		statecount++;
    238 	}
    239 #endif
    240 
    241 	switch (state) {
    242 #if 0
    243 	case JTAG_IDLE:
    244 		idlecount++;
    245 		if (newstate != JTAG_IDLE) {
    246 			printf("jtag: IDLE for %d TCKs\n", idlecount);
    247 			idlecount = 0;
    248 		}
    249 		break;
    250 #endif
    251 	case JTAG_DRSHIFT:
    252 	case JTAG_IRSHIFT:
    253 		if (shiftcount < 64) {
    254 			if (tdi) shiftdata |= (1ULL << shiftcount);
    255 #if 0
    256 		} else {
    257 			shiftdata >>= 1;
    258 			if (tdi) shiftdata |= 0x8000000000000000ULL;
    259 #endif
    260 		}
    261 		shiftcount++;
    262 		break;
    263 	case JTAG_DRCAPTURE:
    264 	case JTAG_IRCAPTURE:
    265 		shiftcount = 0;
    266 		shiftdata = 0;
    267 		break;
    268 	case JTAG_DRUPDATE:
    269 #if TRACE_JTAG
    270 		n = (shiftcount + 3) >> 2;
    271 		if (n > 16) n = 16;
    272 		printf("jtag: DR(%d) = %s%0*lx\n", shiftcount,
    273 			(shiftcount > 64) ? "..." : "", n, shiftdata);
    274 #endif
    275 		sim_dr(shiftdata);
    276 		break;
    277 	case JTAG_IRUPDATE:
    278 #if TRACE_JTAG
    279 		n = (shiftcount + 3) >> 2;
    280 		if (n > 16) n = 16;
    281 		printf("jtag: IR(%d) = %s%0*lx\n", shiftcount,
    282 			(shiftcount > 64) ? "..." : "", n, shiftdata);
    283 #endif
    284 		sim_ir(shiftdata);
    285 		break;
    286 	};
    287 	state = newstate;
    288 }
    289 
    290 u8 stream[1024*1024];
    291 unsigned scount = 0;
    292 unsigned last_tms;
    293 
    294 void sim_jtag(void) {
    295 	u8 *x = stream;
    296 	while (scount > 0) {
    297 		_sim_jtag(*x & 1, *x >> 1);
    298 		x++;
    299 		scount--;
    300 	}
    301 }
    302 
    303 void wr_jtag(unsigned tdi, unsigned tms) {
    304 	if (scount == sizeof(stream)) {
    305 		fprintf(stderr,"OVERFLOW\n");
    306 		exit(-1);
    307 	}
    308 	stream[scount++] = tdi | (tms << 1);
    309 	last_tms = tms;
    310 }
    311 
    312 void wr_tdi(unsigned count, unsigned bits) {
    313 	while (count > 0) {
    314 		wr_jtag(bits & 1, last_tms);
    315 		bits >>= 1;
    316 		count--;
    317 	}	
    318 }
    319 
    320 void wr_tms(unsigned count, unsigned bits, unsigned tdi) {
    321 	while (count > 0) {
    322 		wr_jtag(tdi, bits & 1);
    323 		bits >>= 1;
    324 		count--;
    325 	}
    326 }
    327 
    328 // ----- disassemble mpsse stream into tdi/tms jtag vectors -----
    329 
    330 #if TRACE_MPSSE
    331 #define dprintf(x...) printf(x)
    332 #else
    333 #define dprintf(x...) do {} while(0)
    334 #endif
    335 
    336 static void pbin(u32 val, u32 bits) {
    337 	u32 n;
    338 	for (n = 0; n < bits; n++) {
    339 		dprintf( "%c", (val & 1) ? '1' : '0');
    340 		val >>= 1;
    341 	}
    342 }
    343 
    344 // display mpsse command stream in a (sortof) human readable form
    345 static void dismpsse(u8 *data, u32 n) {
    346 	u32 x, i;
    347 	while (n > 0) {
    348 		dprintf("mpsse: %02x: ", data[0]);
    349 		switch(data[0]) {
    350 		case 0x6B: // tms rw
    351 		case 0x6F: // tms rw -veWr -veRd
    352 			dprintf( "x1 <- TDO, ");
    353 			// fall through
    354 		case 0x4B: // tms wo
    355 			dprintf( "TMS <- ");
    356 			pbin(data[2],data[1]+1);
    357 			dprintf( ", TDI <- ");
    358 			pbin((data[2] & 0x80) ? 0xFF : 0, data[1] + 1);
    359 			dprintf( "\n");
    360 			wr_tms(data[1] + 1, data[2], (data[2] & 0x80) ? 1 : 0);
    361 			data += 3;
    362 			n -= 3;
    363 			break;
    364 		case 0x2A: // ro bits
    365 			dprintf( "x%d <- TDO\n", data[1] + 1);
    366 			data += 2;
    367 			n -= 2;
    368 			break;
    369 		case 0x28: // ro bytes
    370 		case 0x2C: // ro bytes -veWr -veRd
    371 			x = ((data[2] << 8) | data[1]) + 1;
    372 			dprintf( "x%d <- TDO\n", (int) x * 8);
    373 			data += 3;
    374 			n -= 3;
    375 			break;
    376 		case 0x1B: // wo bits
    377 		case 0x3B: // rw bits
    378 		case 0x3F: // rw bits -veWR -veRD
    379 			dprintf( "TDI <- ");
    380 			pbin(data[2], data[1] + 1);
    381 			if (data[0] == 0x3B) {
    382 				dprintf( ", x%d <- TDO\n", data[1] + 1);
    383 			} else {
    384 				dprintf( "\n");
    385 			}
    386 			wr_tdi(data[1] + 1, data[2]);
    387 			data += 3;
    388 			n -= 3;
    389 			break;
    390 		case 0x19: // wo bytes
    391 		case 0x39: // rw bytes
    392 		case 0x3D: // rw bytes -veWR -veRD
    393 			x = ((data[2] << 8) | data[1]) + 1;
    394 			dprintf( "TDI <- ");
    395 			for (i = 0; i < x; i++) pbin(data[3+i], 8);
    396 			if (data[0] == 0x1B) {
    397 				dprintf( ", x%d <- TDO\n", (int) x);
    398 			} else {
    399 				dprintf("\n");
    400 			}
    401 			for (i = 0; i < x; i++) wr_tdi(8, data[3+i]);
    402 			data += (3 + x);
    403 			n -= (3 + x);
    404 			break;
    405 		case 0x87:
    406 			dprintf("FLUSH\n");
    407 			data += 1;
    408 			n -= 1;
    409 			break;
    410 		case 0xAA:
    411 		case 0xAB:
    412 			dprintf("BADCMD\n");
    413 			data += 1;
    414 			n -=1;
    415 			break;
    416 		case 0x80:
    417 		case 0x82:
    418 			dprintf("SET%s %02x %02x\n", (data[0] & 2) ? "HI" : "LO", data[1], data[2]);
    419 			data += 3;
    420 			n -= 3;
    421 			break;
    422 		case 0x81:
    423 		case 0x83:
    424 			dprintf("READ%s\n", (data[0] & 2) ? "HI" : "LO");
    425 			data += 1;
    426 			n -= 1;
    427 			break;
    428 		case 0x84:
    429 		case 0x85:
    430 			dprintf("LOOPBACK %s\n", (data[0] & 1) ? "OFF" : "ON");
    431 			data += 1;
    432 			n -= 1;
    433 			break;
    434 		case 0x86:
    435 			dprintf("CLOCKDIV %d\n", (data[1] | (data[2] << 8)));
    436 			data += 3;
    437 			n -= 3;
    438 			break;
    439 		case 0x8A:
    440 		case 0x8B:
    441 			dprintf("DIVBY5 %s\n", (data[0] & 1) ? "ENABLE" : "DISABLE");
    442 			data += 1;
    443 			n -= 1;
    444 			break;
    445 		default:
    446 			fprintf(stderr, "INVALID OPCODE %02x\n",data[0]);
    447 			n = 0;
    448 		}
    449 		sim_jtag();
    450 	}
    451 }
    452 
    453 u8 buffer[1024*1024];
    454 
    455 int main(int argc, char **argv) {
    456 	char hex[32];
    457 	int n, c, count;
    458 
    459 	n = 0;
    460 	count = 0;
    461 	for (;;) {
    462 		if ((c = getchar()) < 0) break;
    463 		if (isspace(c)) {
    464 			if (n != 2) {
    465 				printf("bad input\n");
    466 				return -1;
    467 			}
    468 			hex[n] = 0;
    469 			buffer[count++] = strtoul(hex, 0, 16);
    470 			n = 0;
    471 			continue;
    472 		}
    473 		if (n == 2) {
    474 			printf( "bad input\n");
    475 			return -1;
    476 		}
    477 		hex[n++] = c;
    478 	}
    479 	printf("count %d\n", count);
    480 	dismpsse(buffer, count);
    481 	printf("scount %d\n", scount);
    482 	sim_jtag();
    483 	return 0;
    484 	
    485 }
    486 
    487 // notes
    488 //
    489 // extract bulk out data from usbmon dump:
    490 // grep " Bo " LOG | grep -v OK | sed 's/.* Bo .... //'
    491