Files
prjxray/utils/bit2fasm.py
T
Carlos Venegas Arrabé 19d29f9c84 bit2fasm: close the temporary bits file before bitread writes it
The temporary bits file was created with NamedTemporaryFile() and kept
open while the bitread subprocess wrote to it by name. On Windows that
is a sharing violation (the open handle blocks the child's write), so
bit2fasm always failed there. Create the file with delete=False, close
it immediately, and unlink it via the ExitStack instead.

No behaviour change on POSIX beyond the file being closed while
bitread runs.
2026-07-31 22:47:03 +02:00

133 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
'''
Take bitstream .bit files and decode them to FASM.
'''
import contextlib
import os
import fasm
import fasm.output
from prjxray import fasm_disassembler
from prjxray import bitstream
from prjxray.db import Database
from prjxray.util import OpenSafeFile
import subprocess
import tempfile
def bit_to_bits(bitread, part_yaml, 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 {} {} -o {} -z -y {}'.format(
bitread, part_yaml, 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 OpenSafeFile(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 7-series bit file to FASM.')
database_dir = os.getenv("XRAY_DATABASE_DIR")
database = os.getenv("XRAY_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("XRAY_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("XRAY_TOOLS_DIR") is None:
default_bitread = 'bitread'
else:
default_bitread = os.path.join(os.getenv("XRAY_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="bitread tool to to use",
default=default_bitread)
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:
# On Windows an open NamedTemporaryFile cannot be re-opened by
# the bitread subprocess (sharing violation): create it closed
# and clean it up ourselves.
bits_file = tempfile.NamedTemporaryFile(delete=False)
bits_file.close()
stack.callback(os.unlink, bits_file.name)
bit_to_bits(
bitread=args.bitread,
part_yaml=os.path.join(args.db_root, args.part, "part.yaml"),
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()