In several cases, we call `python` explicitly. On many modern operating systems (e.g., Ubuntu 22.04), this command no longer exists, and if it does, it's often an alias to python3. Because the python3 executable has been around for so long, simply using that directly (instead of, e.g., autodetecting the OS preferences) is a simple fix that immediately allows building bitfiles, e.g. for the B2xx series, on more recent OSes. Original-commit: 356cd172bb5ae0d043825bd1f4dffbd6646ec3d2
154 lines
4.8 KiB
Python
154 lines
4.8 KiB
Python
#!/usr/bin/python3
|
|
"""
|
|
Generate lvbitx from template and bitfile
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
from xml.etree import ElementTree
|
|
import optparse
|
|
import base64
|
|
import os
|
|
from hashlib import md5
|
|
|
|
def to_native_str(str_or_bstr):
|
|
"""
|
|
Returns a native string, regardless of the input string type (binary or
|
|
UTF-8), and the Python version (2 or 3).
|
|
Note that the native string type is actually not the same in Python 2 and
|
|
3: In the former, it's a binary string, in the latter, it's Unicode.
|
|
>>> to_native_str(b'foo')
|
|
'foo'
|
|
>>> to_native_str(u'foo')
|
|
'foo'
|
|
"""
|
|
if isinstance(str_or_bstr, str):
|
|
return str_or_bstr
|
|
try:
|
|
# This will either fail because we're running Python 2 (which doesn't)
|
|
# have the encoding argument) or because we're not passing in a bytes-
|
|
# like object (e.g., an integer)
|
|
return str(str_or_bstr, encoding='ascii')
|
|
except TypeError:
|
|
return str(str_or_bstr)
|
|
|
|
def get_parser():
|
|
"""Parse args."""
|
|
parser = optparse.OptionParser()
|
|
parser.add_option(
|
|
"--device",
|
|
type="string",
|
|
dest="device_type",
|
|
help="Device Type. (Has to match the LVFPGA target plugin)",
|
|
default=None
|
|
)
|
|
parser.add_option(
|
|
"--input-bin",
|
|
type="string",
|
|
dest="input_bin",
|
|
help="Path to bin file that needs to be merged with the LVBITX before exporting",
|
|
default=None
|
|
)
|
|
parser.add_option(
|
|
"--output-bin",
|
|
type="string",
|
|
dest="output_bin",
|
|
help="Create a binary configuration bitstream",
|
|
default=None
|
|
)
|
|
parser.add_option(
|
|
"--output-lvbitx",
|
|
type="string",
|
|
dest="output_lvbitx_path",
|
|
help="Output path for autogenerated LVBITX file",
|
|
default=None
|
|
)
|
|
parser.add_option(
|
|
"--output-src-path",
|
|
type="string",
|
|
dest="output_src_path",
|
|
help="Output path for autogenerated src file",
|
|
default=None
|
|
)
|
|
return parser
|
|
|
|
def main():
|
|
"""Go, go, go!"""
|
|
parser = get_parser()
|
|
options, args = parser.parse_args()
|
|
# Args
|
|
if len(args) < 1:
|
|
print('ERROR: Please specify the input LVBITX file name')
|
|
parser.print_help()
|
|
exit(1)
|
|
|
|
lvbitx_filename = args[0]
|
|
input_filename = os.path.abspath(lvbitx_filename)
|
|
|
|
if not os.path.isfile(input_filename):
|
|
print("ERROR: LVBITX File `{}' could not be accessed or is not a file."
|
|
.format(input_filename))
|
|
parser.print_help()
|
|
exit(1)
|
|
|
|
if options.input_bin is not None and \
|
|
not os.path.isfile(os.path.abspath(options.input_bin)):
|
|
print("ERROR: FPGA Bin File `{}' could not be accessed or is not a file."
|
|
.format(options.input_bin))
|
|
parser.print_help()
|
|
exit(1)
|
|
|
|
if options.output_lvbitx_path is not None and \
|
|
input_filename == options.output_lvbitx_path:
|
|
print('ERROR: Input and output LVBITX files were the same. '
|
|
'Choose a difference input or output file.')
|
|
parser.print_help()
|
|
exit(1)
|
|
|
|
# Get XML Tree Node
|
|
tree = ElementTree.parse(input_filename)
|
|
root = tree.getroot()
|
|
|
|
# Update device type
|
|
if options.device_type is not None:
|
|
root.find('Project').find('TargetClass').text += '; ' + options.device_type
|
|
|
|
# Merge bitstream into LVBITX
|
|
if options.input_bin is not None:
|
|
with open(os.path.abspath(options.input_bin), 'rb') as bin_file:
|
|
bitstream = bin_file.read()
|
|
bitstream_md5 = md5(bitstream).hexdigest()
|
|
bitstream_b64 = base64.b64encode(bitstream)
|
|
bitstream_b64_lb = b'\n'.join([
|
|
bitstream_b64[i:i+76]
|
|
for i in range(0, len(bitstream_b64), 76)
|
|
]) + b'\n'
|
|
root.find('Bitstream').text = to_native_str(bitstream_b64_lb)
|
|
root.find('BitstreamMD5').text = bitstream_md5
|
|
|
|
# Write BIN file
|
|
bitstream = base64.b64decode(root.find('Bitstream').text)
|
|
if options.output_lvbitx_path is not None \
|
|
and md5(bitstream).hexdigest() != root.find('BitstreamMD5').text:
|
|
print('ERROR: The MD5 sum for the output LVBITX was incorrect. '
|
|
'Make sure that the bitstream in the input LVBITX or BIN file is valid.')
|
|
exit(1)
|
|
|
|
if options.output_bin is not None:
|
|
fpga_bin_file = open(options.output_bin, 'wb')
|
|
fpga_bin_file.write(bitstream)
|
|
fpga_bin_file.close()
|
|
|
|
# Save LVBITX
|
|
if options.output_lvbitx_path is not None:
|
|
with open(options.output_lvbitx_path, 'wb') as lvbitx_file:
|
|
tree.write(
|
|
lvbitx_file,
|
|
encoding="utf-8",
|
|
xml_declaration=True,
|
|
default_namespace=None,
|
|
method="xml"
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|