diff options
Diffstat (limited to 'fpga/usrp3/tools/scripts/xil_bitfile_parser.py')
-rwxr-xr-x | fpga/usrp3/tools/scripts/xil_bitfile_parser.py | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/fpga/usrp3/tools/scripts/xil_bitfile_parser.py b/fpga/usrp3/tools/scripts/xil_bitfile_parser.py new file mode 100755 index 000000000..7201bde17 --- /dev/null +++ b/fpga/usrp3/tools/scripts/xil_bitfile_parser.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +import argparse +import os, sys +import struct +import re + +# Parse command line options +def get_options(): + parser = argparse.ArgumentParser(description='Parser for the Xilinx FPGA Bitfile') + parser.add_argument("bitfile", help="Input bitfile path") + parser.add_argument("--bin_out", help="Output bin file path") + parser.add_argument('--flip', action='store_true', default=False, help='Flip 32-bit endianess') + parser.add_argument('--info', action='store_true', default=False, help='Print bitfile info') + args = parser.parse_args() + if (not os.path.isfile(args.bitfile)): + print('ERROR: Bitfile ' + args.bitfile + ' could not be accessed or is not a file.\n') + parser.print_help() + sys.exit(1) + return args + +short = struct.Struct('>H') +ulong = struct.Struct('>I') +KEYNAMES = {'a':'design_name', 'b':'part_name', 'c':'date', 'd':'time'} + +# Parse bitfile +def parse_bitfile(bitfile_bytes): + header = dict() + ptr = 0 + #Field 1 + if short.unpack(bitfile_bytes[ptr:ptr+2])[0] == 9 and ulong.unpack(bitfile_bytes[ptr+2:ptr+6])[0] == 0x0ff00ff0: + #Headers + ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 2 + ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 1 + #Fields a-d + for keynum in range(0, 4): + key = bitfile_bytes[ptr]; ptr += 1 + val_len = short.unpack(bitfile_bytes[ptr:ptr+2])[0]; ptr += 2 + val = bitfile_bytes[ptr:ptr+val_len]; ptr += val_len + header[KEYNAMES[key]] = str(val).rstrip('\0') + #Field e + ptr += 1 + length = ulong.unpack(bitfile_bytes[ptr:ptr+4])[0]; ptr += 4 + header['bitstream_len'] = length + header['header_len'] = ptr + data = bitfile_bytes[ptr:ptr+length] + return (header, data) + else: + raise Exception('Bitfile header validation failed!') + +# Flip 32-bit endianess +def flip32(data): + sl = struct.Struct('<I') + sb = struct.Struct('>I') + b = buffer(data) + d = bytearray(len(data)) + for offset in xrange(0, len(data), 4): + sb.pack_into(d, offset, sl.unpack_from(b, offset)[0]) + return d + +def main(): + args = get_options(); + with open(args.bitfile, 'rb') as bit_file: + # Parse bytes into a header map and data buffer + (header, data) = parse_bitfile(bit_file.read()) + # Print bitfile info + if args.info: + m = re.search('(.+);UserID=(.+);COMPRESS=(.+);Version=(.+)', header['design_name']) + if m: + print 'Design Name: ' + m.group(1) + print 'User ID: ' + m.group(2) + print 'Compression: ' + m.group(3) + print 'Vivado Version: ' + m.group(4) + else: + print 'Design Name: ' + header['design_name'] + print 'Part Name: ' + header['part_name'] + print 'Datestamp: ' + header['date'] + ' ' + header['time'] + print 'Bitstream Size: ' + str(header['bitstream_len']) + # Write a bin file + if args.bin_out: + open(args.bin_out, 'wb').write(flip32(data) if args.flip else data) + +if __name__ == '__main__': + main()
\ No newline at end of file |