| #!/usr/bin/env python3 | |
| ''' | |
| Take bitstream .bit files and decode them to FASM. | |
| ''' | |
| import contextlib | |
| import os | |
| import fasm | |
| import fasm.output | |
| from db import Database | |
| import fasm_disassembler | |
| import bitstream | |
| import subprocess | |
| import tempfile | |
| def bit_to_bits(bitread, | |
| part_yaml, | |
| arch, | |
| bit_file, | |
| bits_file, | |
| frame_range=None): | |
| """ Calls bitread to create bits (ASCII) from bit file (binary) """ | |
| if frame_range: | |
| frame_range_arg = '-F {}'.format(frame_range) | |
| else: | |
| frame_range_arg = '' | |
| subprocess.check_output( | |
| '{} --part_file {} --architecture {} {} -o {} -z -y {}'.format( | |
| bitread, part_yaml, arch, frame_range_arg, bits_file, bit_file), | |
| shell=True) | |
| def bits_to_fasm(db_root, part, bits_file, verbose, canonical): | |
| db = Database(db_root, part) | |
| grid = db.grid() | |
| disassembler = fasm_disassembler.FasmDisassembler(db) | |
| with open(bits_file) as f: | |
| bitdata = bitstream.load_bitdata(f) | |
| model = fasm.output.merge_and_sort( | |
| disassembler.find_features_in_bitstream(bitdata, verbose=verbose), | |
| zero_function=disassembler.is_zero_feature, | |
| sort_key=grid.tile_key, | |
| ) | |
| print(fasm.fasm_tuple_to_string(model, canonical=canonical), end='') | |
| def main(): | |
| import argparse | |
| parser = argparse.ArgumentParser( | |
| description='Convert UltraScale/UltraScalePlus bit file to FASM.') | |
| database_dir = os.getenv("URAY_DATABASE_DIR") | |
| database = os.getenv("URAY_DATABASE") | |
| db_root_kwargs = {} | |
| if database_dir is None or database is None: | |
| db_root_kwargs['required'] = True | |
| else: | |
| db_root_kwargs['required'] = False | |
| db_root_kwargs['default'] = os.path.join(database_dir, database) | |
| default_part = os.getenv("URAY_PART") | |
| part_kwargs = {} | |
| if default_part is None: | |
| part_kwargs['required'] = True | |
| else: | |
| part_kwargs['required'] = False | |
| part_kwargs['default'] = default_part | |
| if os.getenv("URAY_TOOLS_DIR") is None: | |
| default_bitread = 'bitread' | |
| else: | |
| default_bitread = os.path.join(os.getenv("URAY_TOOLS_DIR"), 'bitread') | |
| parser.add_argument('--db-root', help="Database root.", **db_root_kwargs) | |
| parser.add_argument( | |
| '--bits-file', | |
| help="Output filename for bitread output, default is deleted tempfile.", | |
| default=None) | |
| parser.add_argument( | |
| '--part', help="Name of part being targetted.", **part_kwargs) | |
| parser.add_argument( | |
| '--bitread', | |
| help="Name of part being targetted.", | |
| default=default_bitread) | |
| parser.add_argument( | |
| '--architecture', | |
| help= | |
| "Name of the device architecture family (e.g. UltraScale, Series7, etc.)", | |
| default="UltraScale") | |
| parser.add_argument( | |
| '--frame_range', help="Frame range to use with bitread.") | |
| parser.add_argument('bit_file', help='') | |
| parser.add_argument( | |
| '--verbose', | |
| help='Print lines for unknown tiles and bits', | |
| action='store_true') | |
| parser.add_argument( | |
| '--canonical', help='Output canonical bitstream.', action='store_true') | |
| args = parser.parse_args() | |
| with contextlib.ExitStack() as stack: | |
| if args.bits_file: | |
| bits_file = stack.enter_context(open(args.bits_file, 'wb')) | |
| else: | |
| bits_file = stack.enter_context(tempfile.NamedTemporaryFile()) | |
| bit_to_bits( | |
| bitread=args.bitread, | |
| part_yaml=os.path.join(args.db_root, args.part, "part.yaml"), | |
| arch=args.architecture, | |
| bit_file=args.bit_file, | |
| bits_file=bits_file.name, | |
| frame_range=args.frame_range, | |
| ) | |
| bits_to_fasm(args.db_root, args.part, bits_file.name, args.verbose, | |
| args.canonical) | |
| if __name__ == '__main__': | |
| main() |