aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/fpga_bit_to_bin.py
diff options
context:
space:
mode:
authorBrent Stapleton <brent.stapleton@ettus.com>2017-10-09 17:35:47 -0700
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:04:02 -0800
commitd7df61852426490fd051bc2f23d5e360d19e6417 (patch)
tree327a9e68c663df104fe47d3025c763f1d0939ceb /mpm/python/usrp_mpm/fpga_bit_to_bin.py
parent96f012a14a75ddd559be2c22b87dc03025d3ea1e (diff)
downloaduhd-d7df61852426490fd051bc2f23d5e360d19e6417.tar.gz
uhd-d7df61852426490fd051bc2f23d5e360d19e6417.tar.bz2
uhd-d7df61852426490fd051bc2f23d5e360d19e6417.zip
bit to bin: initial commit of converter script
Diffstat (limited to 'mpm/python/usrp_mpm/fpga_bit_to_bin.py')
-rwxr-xr-xmpm/python/usrp_mpm/fpga_bit_to_bin.py121
1 files changed, 121 insertions, 0 deletions
diff --git a/mpm/python/usrp_mpm/fpga_bit_to_bin.py b/mpm/python/usrp_mpm/fpga_bit_to_bin.py
new file mode 100755
index 000000000..bf0c6e03f
--- /dev/null
+++ b/mpm/python/usrp_mpm/fpga_bit_to_bin.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+#
+# Copyright 2017 Ettus Research (National Instruments Corp.)
+#
+# SPDX-License-Identifier: GPL-3.0
+#
+"""
+Convert FPGA Bit files to bin files suitable for flashing
+"""
+import argparse
+import struct
+
+def parse_args():
+ """Parse arguments when running this as a script"""
+ parser_help = 'Convert FPGA bit files to raw bin format suitable for flashing'
+ parser = argparse.ArgumentParser(description=parser_help)
+ parser.add_argument('-f', '--flip', dest='flip', action='store_true', default=False,
+ help='Flip 32-bit endianess (needed for Zynq)')
+ parser.add_argument('-l', '--blen', type=int, default=-1,
+ help="Size of block (in words) to read at one time")
+ parser.add_argument("bitfile", help="Input bit file name")
+ parser.add_argument("binfile", help="Output bin file name")
+ return parser.parse_args()
+
+
+def bin_to_file(bitfile, binfilename, flip, blocksize):
+ """Reads a raw bitstream, byte-swaps (if desired), and writes to a binfile"""
+ with open(binfilename, 'wb') as binfile:
+ while True:
+ # Calculate how many bytes to read the requested blocksize
+ # -1 feels a little cleaner than -1*(large number), but isn't necessary
+ readlen = -1 if (blocksize <= 0) else blocksize * struct.calcsize('I')
+ byteblock = bitfile.read(readlen)
+ if flip:
+ # Check how many ints we actually read
+ actual_blocksize = int(len(byteblock) / struct.calcsize('I'))
+ # Create the format string accordingly
+ fmt_string = str(actual_blocksize)+"I"
+ # Byte swap with an unpack and a pack with opposite endianness
+ int_arr = struct.unpack(">"+fmt_string, byteblock)
+ binstream = struct.pack("<"+fmt_string, *int_arr)
+ else:
+ # Don't need to do anything special
+ binstream = byteblock
+ binfile.write(binstream)
+ # Check if we're done. Either we
+ # a) read the entire file in one go, or
+ # b) read a partial block in the last read
+ if (blocksize == -1) or (len(byteblock) < readlen):
+ break
+
+
+def fpga_bit_to_bin(bitfilename, binfilename, flip=False, blocklen=-1):
+ """Process the FPGA bit file at bitfilename, and write a bin file to binfilename"""
+ # Read the header
+ # The header consists of several fields, with keys and lengths to divide the file.
+ with open(bitfilename, 'rb') as bitfile:
+ # Field 0:
+ # 2 byte length
+ # Some header
+ length = struct.unpack('>H', bitfile.read(2))[0]
+ if length != 9:
+ raise RuntimeError("Missing <0009> header (0x%i), not a bit file" % length)
+ bitfile.read(length) # Xilinx header
+ # Field 1:
+ # 2 byte length
+ # The letter 'a'
+ length = struct.unpack('>H', bitfile.read(2))[0] # Should be 1
+ key = bitfile.read(length)
+ if key != b'a':
+ raise RuntimeError("Missing <a> header, not a bit file")
+ # 2 byte length
+ # File name (with trailing 0x00)
+ length = struct.unpack('>H', bitfile.read(2))[0]
+ bitfile.read(length) # read the design name
+ # Field 2:
+ # 1 byte key ('b')
+ # 2 byte length
+ # Part name (with trailing 0x00)
+ # If bitstream is a partial bitstream, get some information from filename and header
+ key = bitfile.read(1)
+ if key != b'b':
+ raise RuntimeError("Missing <b> header, not a bit file")
+ length = struct.unpack('>H', bitfile.read(2))[0]
+ part_name = bitfile.read(length)
+ if b"PARTIAL=TRUE" in part_name:
+ # TODO: Handle this when we need partial bitstreams
+ raise NotImplementedError("Partial bitstream processing not implemented")
+ # Field 3:
+ # 1 byte key ('c')
+ # 2 byte length
+ # Date YYYY/MM/DD (with trailing 0x00)
+ key = bitfile.read(1)
+ if key != b'c':
+ raise RuntimeError("Missing <c> Date key")
+ length = struct.unpack('>H', bitfile.read(2))[0]
+ bitfile.read(length) # read the date
+ # Field 4:
+ # 1 byte key ('d')
+ # 2 byte length
+ # Time HH:MM:SS (with trailing 0x00)
+ key = bitfile.read(1)
+ if key != b'd':
+ raise RuntimeError("Missing <d> Time key")
+ length = struct.unpack('>H', bitfile.read(2))[0]
+ bitfile.read(length) # read the time
+ # Field 5:
+ # 1 byte key ('e')
+ # 4 byte length
+ # Raw bitstream
+ key = bitfile.read(1)
+ if key != b'e':
+ raise RuntimeError("Missing <e> bitstream key.")
+ length = struct.unpack('>I', bitfile.read(4))[0] # The raw bitstream's length
+ # Now read the raw bitstream and write to file
+ bin_to_file(bitfile, binfilename, flip, blocklen)
+
+
+if __name__ == "__main__":
+ args = parse_args()
+ fpga_bit_to_bin(args.bitfile, args.binfile, args.flip, args.blen)