mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-15 21:01:26 +00:00
121 lines
5 KiB
Python
Executable file
121 lines
5 KiB
Python
Executable file
#!/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)
|