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. Original-commit: 6046e1a812ba2065d6ae13b4c4afdce8abc99d4f
This commit is contained in:
@@ -1,4 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Parser for Xilinx bitfiles.
|
||||||
|
|
||||||
|
Reads metadata from Xilinx bitfile headers.
|
||||||
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
@@ -7,7 +12,8 @@ import struct
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
# Parse command line options
|
# Parse command line options
|
||||||
def get_options():
|
def get_args():
|
||||||
|
"""Run argparser"""
|
||||||
parser = argparse.ArgumentParser(description='Parser for the Xilinx FPGA Bitfile')
|
parser = argparse.ArgumentParser(description='Parser for the Xilinx FPGA Bitfile')
|
||||||
parser.add_argument("bitfile", help="Input bitfile path")
|
parser.add_argument("bitfile", help="Input bitfile path")
|
||||||
parser.add_argument("--bin_out", help="Output bin file path")
|
parser.add_argument("--bin_out", help="Output bin file path")
|
||||||
@@ -20,60 +26,77 @@ def get_options():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return args
|
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):
|
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()
|
header = dict()
|
||||||
ptr = 0
|
ptr = 0
|
||||||
#Field 1
|
#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
|
#Headers
|
||||||
ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 2
|
ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 2
|
||||||
ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 1
|
ptr += short.unpack(bitfile_bytes[ptr:ptr+2])[0] + 1
|
||||||
#Fields a-d
|
#Fields a-d
|
||||||
for keynum in range(0, 4):
|
for _ in range(0, 4):
|
||||||
key = bitfile_bytes[ptr]; ptr += 1
|
key = chr(bitfile_bytes[ptr])
|
||||||
val_len = short.unpack(bitfile_bytes[ptr:ptr+2])[0]; ptr += 2
|
ptr += 1
|
||||||
val = bitfile_bytes[ptr:ptr+val_len]; ptr += val_len
|
val_len = short.unpack(bitfile_bytes[ptr:ptr+2])[0]
|
||||||
header[KEYNAMES[key]] = str(val).rstrip('\0')
|
ptr += 2
|
||||||
|
val = bitfile_bytes[ptr:ptr+val_len]
|
||||||
|
ptr += val_len
|
||||||
|
header[keynames[key]] = val.decode('ascii').rstrip('\0')
|
||||||
#Field e
|
#Field e
|
||||||
ptr += 1
|
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['bitstream_len'] = length
|
||||||
header['header_len'] = ptr
|
header['header_len'] = ptr
|
||||||
data = bitfile_bytes[ptr:ptr+length]
|
data = bitfile_bytes[ptr:ptr+length]
|
||||||
return (header, data)
|
return (header, data)
|
||||||
else:
|
raise Exception('Bitfile header validation failed!')
|
||||||
raise Exception('Bitfile header validation failed!')
|
|
||||||
|
|
||||||
# Flip 32-bit endianess
|
|
||||||
def flip32(data):
|
def flip32(data):
|
||||||
sl = struct.Struct('<I')
|
"""
|
||||||
sb = struct.Struct('>I')
|
Flip 32-bit endianness
|
||||||
b = memoryview(data)
|
"""
|
||||||
d = bytearray(len(data))
|
le32_struct = struct.Struct('<I')
|
||||||
|
be32_struct = struct.Struct('>I')
|
||||||
|
data_flipped = bytearray(len(data))
|
||||||
for offset in range(0, len(data), 4):
|
for offset in range(0, len(data), 4):
|
||||||
sb.pack_into(d, offset, sl.unpack_from(b, offset)[0])
|
be32_struct.pack_into(
|
||||||
return d
|
data_flipped,
|
||||||
|
offset,
|
||||||
|
le32_struct.unpack_from(memoryview(data), offset)[0])
|
||||||
|
return data_flipped
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = get_options();
|
"""GoGoGo"""
|
||||||
|
args = get_args()
|
||||||
with open(args.bitfile, 'rb') as bit_file:
|
with open(args.bitfile, 'rb') as bit_file:
|
||||||
# Parse bytes into a header map and data buffer
|
# Parse bytes into a header map and data buffer
|
||||||
(header, data) = parse_bitfile(bit_file.read())
|
(header, data) = parse_bitfile(bit_file.read())
|
||||||
# Print bitfile info
|
# Print bitfile info
|
||||||
if args.info:
|
if args.info:
|
||||||
m = re.search('(.+);UserID=(.+);COMPRESS=(.+);Version=(.+)', header['design_name'])
|
keynames = {
|
||||||
if m:
|
'COMPRESS': 'Compression: ',
|
||||||
print('Design Name: ' + m.group(1))
|
'UserID': 'User ID: ',
|
||||||
print('User ID: ' + m.group(2))
|
'Version': 'Vivado Version: '}
|
||||||
print('Compression: ' + m.group(3))
|
name_fields = header['design_name'].split(';')
|
||||||
print('Vivado Version: ' + m.group(4))
|
for field in name_fields:
|
||||||
else:
|
mobj = re.search('(.+)=(.+)', field)
|
||||||
print('Design Name: ' + header['design_name'])
|
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('Part Name: ' + header['part_name'])
|
||||||
print('Datestamp: ' + header['date'] + ' ' + header['time'])
|
print('Datestamp: ' + header['date'] + ' ' + header['time'])
|
||||||
print('Bitstream Size: ' + str(header['bitstream_len']))
|
print('Bitstream Size: ' + str(header['bitstream_len']))
|
||||||
|
|||||||
Reference in New Issue
Block a user