summaryrefslogtreecommitdiffstats
path: root/reverse-engineering
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2010-03-14 11:26:02 +0100
committerMichael Buesch <mb@bu3sch.de>2010-03-14 11:26:02 +0100
commit32a2164bd89a831f2ec1904f49f00c77c78212d1 (patch)
tree6ae2f9d78d6601f024a7ae530ac7060b8c7938e8 /reverse-engineering
parent714a997e10c4af9dcecf1100300a3a13ae764d36 (diff)
downloadtoprammer-32a2164bd89a831f2ec1904f49f00c77c78212d1.tar.xz
toprammer-32a2164bd89a831f2ec1904f49f00c77c78212d1.zip
Add a USB dump parser
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Diffstat (limited to 'reverse-engineering')
-rw-r--r--reverse-engineering/HWPROTOCOL12
-rwxr-xr-xreverse-engineering/dump-parser.py191
2 files changed, 201 insertions, 2 deletions
diff --git a/reverse-engineering/HWPROTOCOL b/reverse-engineering/HWPROTOCOL
index a7c47b7..69c162e 100644
--- a/reverse-engineering/HWPROTOCOL
+++ b/reverse-engineering/HWPROTOCOL
@@ -8,8 +8,6 @@ TOP2049 USB protocol (incomplete)
01 >= Read a byte from the FPGA into the status register.
-10xx >= Write a byte (xx) to the FPGA.
-
07 >= Read the status register.
The register is read by sending 07h via bulk out
and reading 64bytes via bulk in.
@@ -18,6 +16,10 @@ TOP2049 USB protocol (incomplete)
xx is the address (clocked via ALE).
yy is the data (clocked via WR).
+0Bxx >= Read a byte from the FPGA at address xx into the status register.
+
+0D >= Unknown
+
0E110000 >= Put the device ID string into the status register.
String length is 16 bytes.
@@ -52,4 +54,10 @@ TOP2049 USB protocol (incomplete)
0E220000... >= Program the FPGA. 60bytes of data is appended.
+10xx >= Write a byte (xx) to the FPGA.
+
+19 >= Unknown
+
+34 >= Unknown
+
1B >= Flush (and/or commit) command
diff --git a/reverse-engineering/dump-parser.py b/reverse-engineering/dump-parser.py
new file mode 100755
index 0000000..0484825
--- /dev/null
+++ b/reverse-engineering/dump-parser.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+"""
+# TOP2049 Open Source programming suite
+#
+# USB dump parser
+#
+# Copyright (c) 2010 Michael Buesch <mb@bu3sch.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+"""
+
+import sys
+import re
+
+packethdr_re = re.compile(r"Dev\s+([0-9a-fA-F]{4,4}):([0-9a-fA-F]{4,4})\s+EP([0-9a-fA-F]+)\s+(\w+)\s(\w+)\s+len=(\d+)")
+payload_re = re.compile(r"\[([0-9a-fA-F]+)\]:\s+([0-9a-fA-F\s]+)\s+.+")
+
+
+def generateHexdump(mem):
+ def toAscii(char):
+ if char >= 32 and char <= 126:
+ return chr(char)
+ return "."
+
+ ret = ""
+ ascii = ""
+ for i in range(0, len(mem)):
+ if i % 16 == 0 and i != 0:
+ ret += " " + ascii + "\n"
+ ascii = ""
+ if i % 16 == 0:
+ ret += "0x%04X: " % i
+ c = mem[i]
+ ret += "%02X" % c
+ if (i % 2 != 0):
+ ret += " "
+ ascii += toAscii(c)
+ ret += " " + ascii + "\n\n"
+ return ret
+
+def dumpMem(mem):
+ sys.stdout.write(generateHexdump(mem))
+
+def dumpInstr(instr, description):
+ for i in instr:
+ sys.stdout.write("%02X" % i)
+ sys.stdout.write(" " * (10 - len(instr)))
+ sys.stdout.write(": " + description)
+ sys.stdout.write("\n")
+
+def parseBulkIn(data):
+ if len(data) == 64:
+ print "Read status register"
+ dumpMem(data)
+
+def parseBulkOut(data):
+ i = 0
+ while i < len(data):
+ if data[i] == 0x00:
+ dumpInstr(data[i:i+1], "NOP")
+ elif data[i] == 0x01:
+ dumpInstr(data[i:i+1], "Read byte from FPGA")
+ elif data[i] == 0x07:
+ dumpInstr(data[i:i+1], "Read status register request")
+ elif data[i] == 0x0A:
+ dumpInstr(data[i:i+3], "Write 0x%02X to the FPGA at address 0x%02X" % (data[i+2], data[i+1]))
+ i += 2
+ elif data[i] == 0x0B:
+ dumpInstr(data[i:i+2], "Read data from FPGA at address 0x%02X" % (data[i+1]))
+ i += 1
+ elif data[i] == 0x0E and data[i+1] == 0x11:
+ dumpInstr(data[i:i+4], "Read device ID request")
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x12:
+ centivolts = data[i+2]
+ dumpInstr(data[i:i+4], "Set VPP to %.2f Volts" % (float(centivolts) / 10))
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x13:
+ centivolts = data[i+2]
+ dumpInstr(data[i:i+4], "Set VCCX to %.2f Volts" % (float(centivolts) / 10))
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x14:
+ dumpInstr(data[i:i+4], "Loading VPP layout %d" % data[i+1])
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x15:
+ dumpInstr(data[i:i+4], "Loading VCCX layout %d" % data[i+1])
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x16:
+ dumpInstr(data[i:i+4], "Loading GND layout %d" % data[i+1])
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x20:
+ dumpInstr(data[i:i+4], "Unknown 0x0E20%02X%02X" % (data[i+2], data[i+3]))
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x21:
+ dumpInstr(data[i:i+4], "Initiate FPGA programming")
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x22:
+ dumpInstr(data[i:i+4], "Upload FPGA configuration data")
+ i += 63
+ elif data[i] == 0x0E and data[i+1] == 0x25:
+ dumpInstr(data[i:i+4], "Unknown 0x0E25")
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x28:
+ dumpInstr(data[i:i+4], "Unknown 0x0E28")
+ i += 3
+ elif data[i] == 0x0E and data[i+1] == 0x1F:
+ dumpInstr(data[i:i+4], "Unknown 0x0E1F")
+ i += 3
+ elif data[i] == 0x0D:
+ dumpInstr(data[i:i+1], "Unknown 0x0D")
+ elif data[i] == 0x10:
+ dumpInstr(data[i:i+2], "Write 0x%02X to the FPGA" % data[i+1])
+ i += 1
+ elif data[i] == 0x19:
+ dumpInstr(data[i:i+1], "Unknown 0x19")
+ elif data[i] == 0x1B:
+ dumpInstr(data[i:i+1], "Flush request")
+ elif data[i] == 0x34:
+ dumpInstr(data[i:i+1], "Unknown 0x34")
+ else:
+ print "UNKNOWN INSTRUCTION 0x%02X. Aborting..." % data[i]
+ for j in range(i, len(data)):
+ sys.stdout.write("%02X " % data[j])
+ print ""
+ sys.exit(1)
+ i += 1
+
+def parseDumpFile(fd):
+ transtype = None
+ bulkData = []
+ for line in fd.readlines():
+ if transtype == "BULK":
+ # Bulk IN or OUT transfer
+ m = payload_re.match(line)
+ if m:
+ offset = int(m.group(1), 16)
+ dataString = m.group(2)
+
+ dataString = dataString.replace(" ", "").strip()
+ assert(len(dataString) % 2 == 0)
+ for i in range(0, len(dataString), 2):
+ byteStr = dataString[i:i+2]
+ bulkData.append(int(byteStr, 16))
+ else:
+ # Transfer done
+ assert(len(bulkData) == length)
+ if direction == "IN":
+ parseBulkIn(bulkData)
+ elif direction == "OUT":
+ parseBulkOut(bulkData)
+ else:
+ assert(0)
+ transtype = None
+ bulkData = []
+
+ m = packethdr_re.match(line)
+ if m:
+ vendor = int(m.group(1), 16)
+ device = int(m.group(2), 16)
+ ep = int(m.group(3), 16)
+ transtype = m.group(4).upper()
+ direction = m.group(5).upper()
+ length = int(m.group(6))
+
+def usage():
+ print "dump-parser.py file.dump"
+
+def main(argv):
+ if len(argv) != 2:
+ usage()
+ return 1
+
+ fd = file(argv[1])
+ parseDumpFile(fd)
+
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
bues.ch cgit interface