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