diff options
Diffstat (limited to 'mpm')
-rwxr-xr-x | mpm/python/usrp_mpm/fpga_bit_to_bin.py | 121 |
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) |