aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2021-08-23 18:05:21 +0200
committerWade Fife <wade.fife@ettus.com>2021-08-24 09:45:36 -0500
commit6046e1a812ba2065d6ae13b4c4afdce8abc99d4f (patch)
tree94f4caa0ac5bab60e9e0eea05ef141a580baba50 /fpga/usrp3
parent3111b4a230ce7534912600fe045114fed5c8ed6d (diff)
downloaduhd-6046e1a812ba2065d6ae13b4c4afdce8abc99d4f.tar.gz
uhd-6046e1a812ba2065d6ae13b4c4afdce8abc99d4f.tar.bz2
uhd-6046e1a812ba2065d6ae13b4c4afdce8abc99d4f.zip
fpga: Fix Xilinx bitfile parser for Python 3
The script was previously only Python 2 compatible. Python 2 support is now removed, so we don't maintain backwards compatibility with Python 2. This also fixes all linter warnings.
Diffstat (limited to 'fpga/usrp3')
-rwxr-xr-xfpga/usrp3/tools/scripts/xil_bitfile_parser.py85
1 files changed, 54 insertions, 31 deletions
diff --git a/fpga/usrp3/tools/scripts/xil_bitfile_parser.py b/fpga/usrp3/tools/scripts/xil_bitfile_parser.py
index cace9b4df..19c6b696a 100755
--- a/fpga/usrp3/tools/scripts/xil_bitfile_parser.py
+++ b/fpga/usrp3/tools/scripts/xil_bitfile_parser.py
@@ -1,4 +1,9 @@
#!/usr/bin/env python3
+"""
+Parser for Xilinx bitfiles.
+
+Reads metadata from Xilinx bitfile headers.
+"""
import argparse
import os
@@ -7,7 +12,8 @@ import struct
import re
# Parse command line options
-def get_options():
+def get_args():
+ """Run argparser"""
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")
@@ -20,60 +26,77 @@ def get_options():
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):
+ """
+ Parse bitfile
+ """
+ short = struct.Struct('>H')
+ ulong = struct.Struct('>I')
+ keynames = {'a': 'design_name', 'b': 'part_name', 'c': 'date', 'd': 'time'}
+
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:
+ 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')
+ for _ in range(0, 4):
+ key = chr(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]] = val.decode('ascii').rstrip('\0')
#Field e
ptr += 1
- length = ulong.unpack(bitfile_bytes[ptr:ptr+4])[0]; ptr += 4
+ 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!')
+ raise Exception('Bitfile header validation failed!')
-# Flip 32-bit endianess
def flip32(data):
- sl = struct.Struct('<I')
- sb = struct.Struct('>I')
- b = memoryview(data)
- d = bytearray(len(data))
+ """
+ Flip 32-bit endianness
+ """
+ le32_struct = struct.Struct('<I')
+ be32_struct = struct.Struct('>I')
+ data_flipped = bytearray(len(data))
for offset in range(0, len(data), 4):
- sb.pack_into(d, offset, sl.unpack_from(b, offset)[0])
- return d
+ be32_struct.pack_into(
+ data_flipped,
+ offset,
+ le32_struct.unpack_from(memoryview(data), offset)[0])
+ return data_flipped
def main():
- args = get_options();
+ """GoGoGo"""
+ args = get_args()
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'])
+ keynames = {
+ 'COMPRESS': 'Compression: ',
+ 'UserID': 'User ID: ',
+ 'Version': 'Vivado Version: '}
+ name_fields = header['design_name'].split(';')
+ for field in name_fields:
+ mobj = re.search('(.+)=(.+)', field)
+ if mobj:
+ if mobj.group(1) in keynames:
+ print(keynames[mobj.group(1)] + mobj.group(2))
+ else:
+ print(mobj.group(1) + ': ' + mobj.group(2))
+ else:
+ print('Design Name: ' + field)
print('Part Name: ' + header['part_name'])
print('Datestamp: ' + header['date'] + ' ' + header['time'])
print('Bitstream Size: ' + str(header['bitstream_len']))