blob: 76604a8378e304609214823486b9ff5ed676b9d1 [file] [log] [blame] [edit]
#!/usr/bin/env python
"""
This script is intended to modify the XML architecture description file
in order to add the tile tags, necessary after the addition of the `tiles`
parsing capabilities of Verilog-to-Routing.
This script needs to be used only if the architecture import scripts do not
take into account the physical tiles tags. In fact, it is used as last step
of the architecture description generation.
"""
import argparse
import sys
import copy
from lxml import etree as ET
def add_tile_tags(arch):
"""
This function moves the top level pb_types attributes
and tags to the tiles high-level tag.
BEFORE:
<complexblocklist>
<pb_type name="BRAM" area="2" height="4" width="1" capacity="1">
<inputs ... />
<outputs ... />
<interconnect ... />
<fc ... />
<pinlocations ... />
<switchblock_locations ... />
</pb_type>
</complexblocklist>
AFTER:
<tiles>
<tile name="BRAM" area="2" height="4" width="1" capacity="1">
<inputs ... />
<outputs ... />
<fc ... />
<pinlocations ... />
<switchblock_locations ... />
<equivalent_sites>
<site pb_type="BRAM"/>
</equivalent_sites>
</tile>
</tiles>
<complexblocklist
<pb_type name="BRAM">
<inputs ... />
<outputs ... />
<interconnect ... />
</pb_type>
</complexblocklist>
"""
TAGS_TO_SWAP = ['fc', 'pinlocations', 'switchblock_locations']
TAGS_TO_COPY = ['input', 'output', 'clock']
ATTR_TO_SWAP = ['area', 'height', 'width', 'capacity']
# A map of attribute names which have to be renamed.
ATTR_MAP = {'num_pb': 'capacity'}
def swap_tags(tile, pb_type):
# Moving tags from top level pb_type to tile
for child in pb_type:
if child.tag in TAGS_TO_SWAP:
pb_type.remove(child)
tile.append(child)
if child.tag in TAGS_TO_COPY:
child_copy = copy.deepcopy(child)
tile.append(child_copy)
if arch.findall('./tiles'):
return False
models = arch.find('./models')
tiles = ET.Element('tiles')
models.addnext(tiles)
top_pb_types = []
for pb_type in arch.iter('pb_type'):
if pb_type.getparent().tag == 'complexblocklist':
top_pb_types.append(pb_type)
for pb_type in top_pb_types:
tile = ET.SubElement(tiles, 'tile')
attrs = pb_type.attrib
for attr in attrs:
if attr in ATTR_MAP:
tile.set(ATTR_MAP[attr], pb_type.get(attr))
else:
tile.set(attr, pb_type.get(attr))
# Remove attributes of top level pb_types only
for attr in ATTR_TO_SWAP:
pb_type.attrib.pop(attr, None)
for attr in ATTR_MAP.keys():
pb_type.attrib.pop(attr, None)
equivalent_sites = ET.Element("equivalent_sites")
site = ET.Element("site")
site.set("pb_type", attrs['name'])
equivalent_sites.append(site)
tile.append(equivalent_sites)
swap_tags(tile, pb_type)
return True
def add_site_directs(arch):
TAGS_TO_COPY = ['input', 'output', 'clock']
def add_directs(equivalent_site, pb_type):
for child in pb_type:
if child.tag in TAGS_TO_COPY:
tile_name = equivalent_site.attrib['pb_type']
port = child.attrib['name']
from_to = "%s.%s" % (tile_name, port)
direct = ET.Element("direct")
direct.set("from", from_to)
direct.set("to", from_to)
equivalent_site.append(direct)
if arch.findall('./tiles/tile/equivalent_sites/site/direct'):
return False
top_pb_types = []
for pb_type in arch.iter('pb_type'):
if pb_type.getparent().tag == 'complexblocklist':
top_pb_types.append(pb_type)
sites = []
for pb_type in arch.iter('site'):
sites.append(pb_type)
for pb_type in top_pb_types:
for site in sites:
if pb_type.attrib['name'] == site.attrib['pb_type']:
add_directs(site, pb_type)
return True
def add_sub_tiles(arch):
"""
This function adds the sub tiles tags to the input architecture.
Each physical tile must contain at least one sub tile.
Note: the example below is only for explanatory reasons, the port/tile names are invented.
BEFORE:
<tiles>
<tile name="BRAM_TILE" area="2" height="4" width="1" capacity="1">
<inputs ... />
<outputs ... />
<fc ... />
<pinlocations ... />
<switchblock_locations ... />
<equivalent_sites>
<site pb_type="BRAM" pin_mapping="direct">
</equivalent_sites>
</tile>
</tiles>
AFTER:
<tiles>
<tile name="BRAM_TILE" area="2" height="4" width="1">
<sub_tile name="BRAM_SUB_TILE_X" capacity="1">
<inputs ... />
<outputs ... />
<fc ... />
<pinlocations ... />
<equivalent_sites>
<site pb_type="BRAM" pin_mapping="direct">
</equivalent_sites>
</sub_tile>
<switchblock_locations ... />
</tile>
</tiles>
"""
TAGS_TO_SWAP = [
'fc', 'pinlocations', 'input', 'output', 'clock', 'equivalent_sites'
]
def swap_tags(sub_tile, tile):
# Moving tags from top level pb_type to tile
for child in tile:
if child.tag in TAGS_TO_SWAP:
tile.remove(child)
sub_tile.append(child)
modified = False
for tile in arch.iter('tile'):
if tile.findall('./sub_tile'):
continue
sub_tile_name = tile.attrib['name']
sub_tile = ET.Element('sub_tile', name='{}'.format(sub_tile_name))
# Transfer capacity to sub tile
if 'capacity' in tile.attrib.keys():
sub_tile.attrib['capacity'] = tile.attrib['capacity']
del tile.attrib['capacity']
# Transfer tags to swap from tile to sub tile
swap_tags(sub_tile, tile)
tile.append(sub_tile)
modified = True
return modified
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--in_xml", required=True, help="xml_file to update")
parser.add_argument("--out_xml", required=True, help="updated xml_file")
args = parser.parse_args()
parser = ET.XMLParser(remove_blank_text=True)
root = ET.parse(args.in_xml, parser)
root_tags = root.findall(".")
assert len(root_tags) == 1
arch = root_tags[0]
if arch.tag != "architecture":
print("Warning! Not an architecture file, exiting...")
sys.exit(0)
modified = False
result = add_tile_tags(arch)
result = add_site_directs(arch)
result = add_sub_tiles(arch)
if result:
modified = True
if modified:
with open(args.out_xml, "wb") as f:
root.write(f, pretty_print=True)
if __name__ == "__main__":
main()