SOFA/openfpga-physical/python-lib/openfpga_physical/generate_fabric_bitstream.py

162 lines
6.7 KiB
Python

import argparse
import json
import os
import yaml
import logging
import xml.etree.ElementTree as ET
from itertools import chain
from pprint import pprint
logger = logging.getLogger('Bitstream conversion')
#PROJ_NAME = os.environ.get('PROJ_NAME')
def formatter(prog): return argparse.HelpFormatter(prog, max_help_position=60)
def get_module_of_instance(mapping, instance):
for module, instance_list in mapping.items():
if instance in instance_list:
return module
return None
def get_ccff_paths(module, ccff_path_directory):
filename = ccff_path_directory.format(module)
with open(filename, "r") as stream:
try:
bitstream = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
return bitstream
def restructure_bitstream(original_bitstream, original_bitstream_distribution, instance_mapping, ccff_path_directory, output_bitstream_xml, fabric_name):
print(f"-> original_bitstream {original_bitstream}")
print(f"-> instance_mapping {instance_mapping}")
print(f"-> ccff_path_directory {ccff_path_directory}")
with open(instance_mapping, "r") as fp:
instance_map = json.load(fp)
bitstream_tree = ET.parse(original_bitstream)
bitstream = bitstream_tree.getroot()
tree = ET.parse(original_bitstream_distribution)
bitstream_dist = tree.getroot()
with open(ccff_path_directory.format("fpga_top"), "r") as stream:
top_ccff = yaml.safe_load(stream)
validate_bitstream_length(instance_map, bitstream_dist, ccff_path_directory, fabric_name)
# Iterate over each region in fabric key
for each_region, instances in top_ccff.items():
region_id = each_region.split("_")[-1]
bitvalues = bitstream.findall(f'.//region[@id="{region_id}"]/*')
bit_number = 0
# Iterate over each module in fabric region
for instance, head_port in instances:
module = get_module_of_instance(instance_map, instance)
or_bit = bitstream_dist.findall(f'.//*block[@name="{instance}"]')[0]
if module is None:
logger.debug(f"skipping {instance}")
continue # Skip if module is merged already
paths = get_ccff_paths(module, ccff_path_directory)[head_port]
for line in paths:
# replace slash in the line with dot
line_dot = line.replace('/', '.')
line_dot = line_dot[:-1] + "Q"
# print(bit_number, f"fpga_top/fpga_core_inst/{instance}/{line}")
bitvalues[-1*(bit_number+1)].attrib["new_path"] = f"fpga_top.fpga_core_inst.{instance}.{line_dot}"
bitvalues[-1*(bit_number+1)].attrib["id"] = str(bit_number)
bit_number += 1
# print(f"module {module:10} bitno={bit_number:<10} paths={len(paths): 4}")
print(f">>>>> Region {region_id:4} TotalBits {bit_number:5} /" +
f" {len(bitvalues):5} = {(bit_number-len(bitvalues)):3}")
bitstream_tree.write(output_bitstream_xml)
def validate_bitstream_length(instance_map, bitstream_dist, ccff_path_directory, fabric_name):
seen = []
bitmap = {
"cby_0__1_": ["grid_io_left_left_0__1_"],
"cby_8__1_": ["grid_io_right_right_9__1_"],
"cbx_1__0_": ["grid_io_bottom_bottom_1__0_"],
"cbx_1__8_": ["grid_io_top_top_1__9_"],
"cby_0__6_": ["sb_0__5_", "sb_0__6_", "grid_io_left_left_0__1_"],
"cby_8__6_": ["sb_8__5_", "sb_8__6_", "grid_io_right_right_9__1_"],
"cby_0__3_": ["sb_0__2_", "sb_0__3_", "grid_io_left_left_0__1_"],
"cby_8__3_": ["sb_8__2_", "sb_8__3_", "grid_io_right_right_9__1_"],
"cby_2__3_": ["sb_6__2_", "sb_6__3_"],
"cby_2__6_": ["sb_6__5_", "sb_6__6_"],
"grid_ram9k": ["cbx_1__2_", "cbx_1__3_",
"sb_1__2_", "sb_1__3_",
"cbx_2__2_", "cbx_2__3_"],
"grid_dsp": ["cbx_1__5_", "cbx_1__6_",
"sb_1__5_", "sb_1__6_",
"cbx_2__5_", "cbx_2__6_"]
}
if fabric_name == "FPGA25x24_flex4k":
bitmap = {
"cby_0__1_": ["grid_io_left_left_0__1_"],
"cby_8__1_": ["grid_io_right_right_25__1_"],
"cbx_1__0_": ["grid_io_bottom_bottom_1__0_"],
"cbx_1__8_": ["grid_io_top_top_1__26_"],
"cby_0__6_": ["sb_0__12_", "sb_0__13_", "grid_io_left_left_0__1_"],
"cby_8__6_": ["sb_24__12_", "sb_24__13_", "grid_io_right_right_25__1_"],
"cby_0__3_": ["sb_0__2_", "sb_0__3_", "grid_io_left_left_0__1_"],
"cby_8__3_": ["sb_24__2_", "sb_24__3_", "grid_io_right_right_25__1_"],
"cby_2__3_": ["sb_6__2_", "sb_6__3_"],
"cby_2__6_": ["sb_6__12_", "sb_6__13_"],
"grid_ram9k": ["cbx_1__2_", "cbx_1__3_",
"sb_1__2_", "sb_1__3_",
"cbx_2__2_", "cbx_2__3_"],
"grid_dsp": ["cbx_1__12_", "cbx_1__13_",
"sb_1__12_", "sb_1__13_",
"cbx_2__12_", "cbx_2__13_"]
}
print("{:15} {:7} {:8} {:4}".format(
"Modules", "expected", "obtained", "diff"))
for module, instances in instance_map.items():
bit_cnt = 0
for m in bitmap.get(module, []) + [instances[0], ]:
try:
or_bit = bitstream_dist.findall(
f'.//*block[@name="{m}"]')[0]
except IndexError:
print(f"{m} not found")
bit_cnt += int(or_bit.attrib['number_of_bits'])
# CCFF Paths
filename = ccff_path_directory.format(module)
bitstream = yaml.safe_load(open(filename, "r"))
path_cnt = sum([len(i) for i in bitstream.values()])
print(f"{module:15} {bit_cnt:8} {path_cnt:8} {(bit_cnt-path_cnt):4}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(formatter_class=formatter)
# Mandatory arguments
parser.add_argument('--original_bitstream', type=str,
required=True)
parser.add_argument('--instance_mapping', type=str,
required=True)
parser.add_argument('--ccff_path_directory', type=str,
required=True)
parser.add_argument('--original_bitstream_distribution', type=str,
required=True)
parser.add_argument('--output_bitstream_xml', type=str,
required=True)
parser.add_argument('--fabric_name', type=str,
default=os.environ.get('PROJ_NAME'))
args = parser.parse_args()
restructure_bitstream(args.original_bitstream, args.original_bitstream_distribution, args.instance_mapping, args.ccff_path_directory, args.output_bitstream_xml, args.fabric_name)