"""
This class is created for OpenFPGA related netlist transformations
"""
import logging
import xml.etree.ElementTree as ET
import spydrnet as sdn
from spydrnet_physical.util import (OpenFPGA_Config_Generator,
OpenFPGA_Tile_Generator)
from spydrnet_physical.util.shell import launch_shell
logger = logging.getLogger('spydrnet_logs')
[docs]class config_chain_simple(OpenFPGA_Config_Generator):
"""
This shows how the configuration chain can be built
"""
def __init__(self, grid, netlist, library, top_module):
super().__init__(grid, netlist, library, top_module)
self.chains = []
self.order = ['grid_io_right', 'grid_io_top', 'grid_io_left',
'grid_io_bottom', 'cbx_1__4_', 'cbx_1__1_', 'cbx_1__0_',
'cby_0__1_', 'cby_1__1_', 'cby_4__1_', 'sb_0__0_',
'sb_0__1_', 'sb_0__4_', 'sb_1__0_', 'sb_1__1_',
'sb_1__4_', 'sb_4__0_', 'sb_4__1_', 'sb_4__4_',
'grid_clb']
def create_chain(self):
chain = []
self.chains.append(chain)
return chain
[docs] def write_fabric_key(self, filename):
# Create XML File
seq = 0
top = ET.Element('fabric_key')
for indx, chain in enumerate(self.chains):
region = ET.SubElement(top, "region", {'id': str(indx)})
for indx, inst in enumerate(chain):
ET.SubElement(region, 'key',
{'id': str(seq+indx), 'alias': inst.name})
seq = seq + indx
ET.ElementTree(top).write(filename)
[docs] def add_configuration_scheme(self):
''' Creates configuration chain '''
logger.info("Running configuration")
chain = self.create_chain()
self.add_top_row(chain)
self.add_middle_rows(chain)
self.add_last_row(chain)
for index, inst in enumerate(chain):
chain[index] = next(self._top_module.get_instances(inst))
self._connect_instances(self._top_module, chain)
self._connect_top_module(chain)
def _connect_top_module(self, chain):
head_cable = next(self._top_module.get_cables(self.head), None)
first_head = next(chain[0].get_port_pins(self.head))
head_cable.wires[0].connect_pin(first_head)
tail_cable = next(self._top_module.get_cables(self.tail), None)
last_tail = next(chain[-1].get_port_pins(self.tail))
tail_cable.wires[0].connect_pin(last_tail)
def add_top_row(self, chain):
x = self.fpga_size[0]
y = self.fpga_size[1]
chain.append(f"grid_io*{x+1}__{y}*")
for x in range(self.fpga_size[0], 0, -1):
chain.append(f"sb*{x}__{y}*")
chain.append(f"cby*{x}__{y}*")
chain.append(f"grid_clb*{x}__{y}*")
chain.append(f"cbx*{x}__{y}*")
chain.append(f"grid_io*{x}__{y+1}*")
chain.append(f"sb*0__{y}*")
chain.append(f"cby*0__{y}*")
chain.append(f"grid_io*_0__{y}*")
def add_middle_rows(self, chain):
for y in range(self.fpga_size[1]-1, 1, -1):
if (y+1) % 2:
for x in range(self.fpga_size[0], 0, -1):
if x == self.fpga_size[0]:
chain.append(f"sb*_{x}__{y}*")
chain.append(f"grid_io*_{x+1}__{y}*")
chain.append(f"cby*_{x}__{y}*")
chain.append(f"grid_clb*{x}__{y}*")
chain.append(f"cbx*{x}__{y}*")
chain.append(f"sb*{x-1}__{y}*")
chain.append(f"cby*{x-1}__{y}*")
chain.append(f"grid_io*_0__{y}*")
else:
for x in range(1, self.fpga_size[0]+1):
if x == 1:
chain.append(f"sb*_0__{y}*")
chain.append(f"grid_io*_0__{y}*")
chain.append(f"cby*_0__{y}*")
chain.append(f"grid_clb*{x}__{y}*")
chain.append(f"cbx*{x}__{y}*")
chain.append(f"sb*{x}__{y}*")
chain.append(f"cby*{x}__{y}*")
chain.append(f"grid_io*_{x+1}__{y}*")
def add_last_row(self, chain):
y = 1
chain.append(f"sb*_0__1*")
chain.append(f"cby*_0__1*")
chain.append(f"grid_io*_0__1*")
chain.append(f"sb*_0__0*")
for x in range(1, self.fpga_size[0]+1):
chain.append(f"grid_io_*{x}__{y-1}*")
chain.append(f"cbx*{x}__{y-1}*")
chain.append(f"grid_clb*{x}__{y}*")
chain.append(f"cbx*{x}__{y}*")
chain.append(f"sb*{x}__{y}*")
chain.append(f"cby*{x}__{y}*")
chain.append(f"sb*{x}__{y-1}*")
chain.append(f"grid_io_*{x+1}__{y}*")
[docs]class config_chain_01(OpenFPGA_Config_Generator):
"""
This example demonstrate how configuration chain can be restructured after
the tile tranformation. This method is better suited while creating
a configuration after the physical tranformation. However mapping the
sequence back to the original sequence could require complex scripting.
# TODO : Need better explanation
"""
def __init__(self, grid, netlist, library, top_module):
super().__init__(grid, netlist, library, top_module)
self.order = ['grid_io_right', 'grid_io_top',
'grid_io_left', 'grid_io_bottom',
'cbx_1__4_', 'cbx_1__1_', 'cbx_1__0_',
'cby_0__1_', 'cby_1__1_', 'cby_4__1_',
'sb_0__0_', 'sb_0__1_', 'sb_0__4_',
'sb_1__0_', 'sb_1__1_', 'sb_1__4_',
'sb_4__0_', 'sb_4__1_', 'sb_4__4_',
'grid_clb']
[docs] def write_fabric_key(self):
pass
[docs] def add_configuration_scheme(self):
''' Creates configuration chain '''
logger.info("Running configuration")
self._create_intra_tiles()
self._create_inter_tiles()
def _create_inter_tiles(self):
inst_list = []
for y in range(self.fpga_size[1], 0, -1):
for x in sorted(range(self.fpga_size[0], 0, -1), reverse=(y+1) % 2):
print(f"*{x}_{y}*")
inst = next(self._top_module.get_instances(f"*{x}__{y}*"))
inst_list.append(inst)
self._connect_instances(self._top_module, inst_list)
head_cable = next(self._top_module.get_cables(self.head))
first_head = next(inst_list[0].get_port_pins(self.head))
head_cable.wires[0].connect_pin(first_head)
tail_cable = next(self._top_module.get_cables(self.tail))
last_tail = next(inst_list[-1].get_port_pins(self.tail))
tail_cable.wires[0].connect_pin(last_tail)
def _create_intra_tiles(self):
for each in ["top_right_tile", "top_tile", "top_left_tile",
"left_tile", "tile", "right_tile",
"bottom_right_tile", "bottom_left_tile"]:
tile = next(self._library.get_definitions(each))
# Remove ccff related cables and port from tile
for cable in list(tile.get_cables("ccff*")):
for pin in list(cable.wires[0].pins):
pin.wire.disconnect_pin(pin)
tile.remove_cable(cable)
for port in list(tile.get_ports("ccff*")):
tile.remove_port(port)
# Create chain
inst_list = sorted([inst for inst in tile.get_instances()],
key=(lambda x: self.order.index(x.reference.name)))
self._connect_instances(tile, inst_list)
# Create ccff_head port
tile.create_port(self._head, direction=sdn.IN, pins=1)
ccff_head_wire = tile.create_cable(self._head, wires=1).wires[0]
ccff_head_wire.connect_pin(
next(inst_list[0].get_port_pins(self.head)))
# Create ccff_tail port
tile.create_port(self._tail, direction=sdn.OUT, pins=1)
ccff_tail_wire = tile.create_cable(self._tail, wires=1).wires[0]
ccff_tail_wire.connect_pin(
next(inst_list[-1].get_port_pins(self.tail)))
class Tile01(OpenFPGA_Tile_Generator):
def create_tiles(self):
'''
Creates tiles
'''
# ############## Main Tiles ##############
self._main_tile()
# ############## Side Tiles ##############
self._left_tile()
self._right_tile()
self._top_tile()
self._bottom_tile()
# ############## Corner Tiles ##############
self._top_left_tile()
self._top_right_tile()
self._bottom_left_tile()
self._bottom_right_tile()
def merge_and_update(self, instance_list, tile_name):
"""
Merges given list of instances and updates width and height parameter
"""
self._top_module.merge_multiple_instance(instance_list,
new_definition_name=tile_name)
tile = next(self._library.get_definitions(tile_name))
tile.OptPins()
width, height = self._get_width_height(instance_list)
self._update_placement(instance_list)
tile.properties["WIDTH"], tile.properties["HEIGHT"] = width, height
def _get_width_height(self, instance_list):
x_min, y_min = float("inf"), float("inf")
x_max, y_max = 0, 0
for instance in instance_list[0][0]:
properties = instance.properties
ref_properties = instance.reference.properties
LOC_X = properties.get("LOC_X", 0)
LOC_Y = properties.get("LOC_Y", 0)
x_min = min(x_min, LOC_X)
y_min = min(y_min, LOC_Y)
x_max = max(x_max, LOC_X+ref_properties["WIDTH"])
y_max = max(y_max, LOC_Y+ref_properties["HEIGHT"])
return ((x_max-x_min), (y_max-y_min))
def _update_placement(self, instance_list):
x_loc, y_loc = float("inf"), float("inf")
# get instance with llx and lly value
for indx, instance in enumerate(instance_list[0][0]):
x = instance.properties.get("LOC_X", 0)
y = instance.properties.get("LOC_Y", 0)
if (x < x_loc):
index_x, x_loc = indx, x
if (y < y_loc):
index_y, y_loc = indx, y
for instances, new_name in instance_list:
new_inst = next(self._top_module.get_instances(new_name))
new_inst.properties["LOC_X"] = instances[index_x].properties.get(
"LOC_X", 0)
new_inst.properties["LOC_Y"] = instances[index_y].properties.get(
"LOC_Y", 0)
logger.debug(f"{new_name} assigned %d %d" %
(new_inst.properties["LOC_X"], new_inst.properties["LOC_Y"]))
def _main_tile(self):
'''Create main Tiles
.. rst-class:: ascii
::
+-----+
| |
+-------+ +---- ---+
| CBY | | SB |
+-------+ +---- ---+
+---------------+ | |
| | +-----+
| | +-----+
| | | |
| CLB | | CBX |
| | +-----+
| |
+---------------+
'''
instance_list = []
for x in range(2, self.fpga_size[0]):
for y in range(2, self.fpga_size[1]):
clb = next(self._top_module.get_instances(
f"grid_clb_{x}__{y}_"))
cbx = next(self._top_module.get_instances(f"cbx_{x}__{y}_"))
cby = next(self._top_module.get_instances(f"cby_{x}__{y}_"))
sb = next(self._top_module.get_instances(f"sb_{x}__{y}_"))
instance_list.append(((clb, cbx, cby, sb),
f"tile_{x}__{y}_"))
self.merge_and_update(instance_list, "tile")
def _left_tile(self):
''' Create Left Tiles
.. rst-class:: ascii
::
+-----+ +-----+
| | | |
| +--+ +-------+ +---+ +--+
| SB | | CBY | | SB |
| +--+ +-------+ +---+ +--+
| | +--------------+ | |
+-----+ | | +-----+
+-----+ | | +-----+
| | | | | |
| CBX | | CLB | | CBX |
+-----+ | | +-----+
| |
+--------------+
'''
instance_list = []
for i in range(2, self.fpga_size[0]):
clb = next(self._top_module.get_instances(f"grid_clb_1__{i}_"))
cby0 = next(self._top_module.get_instances(f"cby_0__{i}_"))
cby1 = next(self._top_module.get_instances(f"cby_1__{i}_"))
cbx1 = next(self._top_module.get_instances(f"cbx_1__{i}_"))
sb0 = next(self._top_module.get_instances(f"sb_0__{i}_"))
sb1 = next(self._top_module.get_instances(f"sb_1__{i}_"))
# grid_io = next(self._top_module.get_instances(
# f"grid_io_left_0__{i}_"))
instance_list.append(((clb, cby0, cby1, cbx1, sb0, sb1),
f"tile_1__{i}_"))
self.merge_and_update(instance_list, "left_tile")
def _right_tile(self):
''' Create Right Tiles
.. rst-class:: ascii
::
+-----+
| |
+-------+ +--+ |
| CBY | | SB |
+-------+ +--+ |
+--------------+ | |
| | +-----+
| | +-----+
| | | |
| CLB | | CBX |
| | +-----+
| |
+--------------+
'''
instance_list = []
for i in range(2, self.fpga_size[0]):
clb = next(self._top_module.get_instances(
f"grid_clb_{self.fpga_size[0]}__{i}_"))
cbx1 = next(self._top_module.get_instances(
f"cbx_{self.fpga_size[0]}__{i}_"))
cby0 = next(self._top_module.get_instances(
f"cby_{self.fpga_size[0]}__{i}_"))
sb0 = next(self._top_module.get_instances(
f"sb_{self.fpga_size[0]}__{i}_"))
# grid_io = next(self._top_module.get_instances(
# f"grid_io_right_{self.fpga_size[0]+1}__{i}_"))
instance_list.append(((clb, cbx1, cby0, sb0),
f"tile_{self.fpga_size[0]}__{i}_"))
self.merge_and_update(instance_list, "right_tile")
def _top_tile(self):
''' Create Top Tiles
.. rst-class:: ascii
::
+-------+ +------------+
| CBY | | SB |
+-------+ +---+ +--+
+--------------+ | |
| | +-----+
| | +-----+
| | | |
| CLB | | CBX |
| | +-----+
| |
+--------------+
'''
instance_list = []
for i in range(2, self.fpga_size[1]):
clb = next(self._top_module.get_instances(
f"grid_clb_{i}__{self.fpga_size[1]}_"))
cbx = next(self._top_module.get_instances(
f"cbx_{i}__{self.fpga_size[1]}_"))
cby = next(self._top_module.get_instances(
f"cby_{i}__{self.fpga_size[1]}_"))
sb = next(self._top_module.get_instances(
f"sb_{i}__{self.fpga_size[1]}_"))
# grid_io = next(self._top_module.get_instances(
# f"grid_io_top_{i}__{self.fpga_size[1]+1}_"))
instance_list.append(((clb, cbx, cby, sb),
f"tile_{i}__{self.fpga_size[1]}_"))
self.merge_and_update(instance_list, "top_tile")
def _bottom_tile(self):
''' Create Bottom Tiles
.. rst-class:: ascii
::
+-----+
| |
+-------+ +---+ +--+
| CBY | | SB |
+-------+ +---+ +--+
+--------------+ | |
| | +-----+
| | +-----+
| | | |
| CLB | | CBX |
| | +-----+
| | +-----+
+--------------+ | |
+-------+ +---+ +--+
| CBY | | SB |
+-------+ +------------+
'''
instance_list = []
for i in range(2, self.fpga_size[1]):
clb = next(self._top_module.get_instances(f"grid_clb_{i}__1_"))
cbx0 = next(self._top_module.get_instances(f"cbx_{i}__0_"))
cbx1 = next(self._top_module.get_instances(f"cbx_{i}__1_"))
cby1 = next(self._top_module.get_instances(f"cby_{i}__1_"))
sb0 = next(self._top_module.get_instances(f"sb_{i}__0_"))
sb1 = next(self._top_module.get_instances(f"sb_{i}__1_"))
# grid_io = next(self._top_module.get_instances(
# f"grid_io_bottom_{i}__0_"))
instance_list.append(((clb, cbx0, cbx1, cby1, sb0, sb1),
f"tile_{i}__1_"))
self.merge_and_update(instance_list, "bottom_tile")
def _top_left_tile(self):
''' Create top left tile
.. rst-class:: ascii
::
+--------+ +-------+ +------------+
| SB | | CBX | | SB |
| +--+ +-------+ +---+ +--+
| | +--------------+ | |
+-----+ | | +-----+
+-----+ | | +-----+
| | | | | |
| CBY | | CLB | | CBY |
+-----+ | | +-----+
| |
+--------------+
'''
instance_list = []
clb = next(self._top_module.get_instances(
f"grid_clb_1__{self.fpga_size[1]}_"))
cbx0 = next(self._top_module.get_instances(
f"cbx_1__{self.fpga_size[1]}_"))
cby0 = next(self._top_module.get_instances(
f"cby_0__{self.fpga_size[1]}_"))
cby1 = next(self._top_module.get_instances(
f"cby_1__{self.fpga_size[1]}_"))
sb0 = next(self._top_module.get_instances(
f"sb_0__{self.fpga_size[1]}_"))
sb1 = next(self._top_module.get_instances(
f"sb_1__{self.fpga_size[1]}_"))
# grid_io_0 = next(self._top_module.get_instances(
# f"grid_io_top_1__{self.fpga_size[1]+1}_"))
# grid_io_1 = next(self._top_module.get_instances(
# f"grid_io_left_0__{self.fpga_size[1]}_"))
instance_list.append(((clb, cbx0, cby0, cby1, sb0, sb1),
f"tile_1__{self.fpga_size[1]}_"))
self.merge_and_update(instance_list, "top_left_tile")
def _top_right_tile(self):
''' Create top right tile
.. rst-class:: ascii
::
+------------+ +-------+ +---------+
| SB | | CBY | | SB |
+---+ +--+ +-------+ +---+ |
| | +--------------+ | |
+-----+ | | +-----+
+-----+ | | +-----+
| | | | | |
| CBX | | CLB | | CBX |
+-----+ | | +-----+
| |
+--------------+
'''
instance_list = []
clb = next(self._top_module.get_instances(
f"grid_clb_{self.fpga_size[0]}__{self.fpga_size[1]}_"))
cbx0 = next(self._top_module.get_instances(
f"cbx_{self.fpga_size[0]}__{self.fpga_size[1]}_"))
cby0 = next(self._top_module.get_instances(
f"cby_{self.fpga_size[0]}__{self.fpga_size[1]}_"))
sb0 = next(self._top_module.get_instances(
f"sb_{self.fpga_size[0]}__{self.fpga_size[1]}_"))
# grid_io_0 = next(self._top_module.get_instances(
# f"grid_io_right_{self.fpga_size[0]+1}__{self.fpga_size[1]}_"))
# grid_io_1 = next(self._top_module.get_instances(
# f"grid_io_top_{self.fpga_size[0]}__{self.fpga_size[1]+1}_"))
instance_list.append(((clb, cbx0, cby0, sb0),
f"tile_{self.fpga_size[0]}__{self.fpga_size[1]}_"))
self.merge_and_update(instance_list, "top_right_tile")
def _bottom_left_tile(self):
''' Create bottom left tile
.. rst-class:: ascii
::
+-----+ +-----+
| | | |
| +--+ +-------+ +---+ +--+
| SB | | CBY | | SB | |
| +--+ +-------+ +---+ +--+
| | +--------------+ | |
+-----+ | | +-----+
+-----+ | | +-----+
| | | | | |
| CBX | | CLB | | CBX |
+-----+ | | +-----+
+-----+ | | +-----+
| | +--------------+ | |
| +--+ +-------+ +---+ +--+
| SB | | CBY | | SB |
+--------+ +-------+ +------------+
'''
instance_list = []
clb = next(self._top_module.get_instances("grid_clb_1__1_"))
cbx0 = next(self._top_module.get_instances("cbx_1__0_"))
cbx1 = next(self._top_module.get_instances("cbx_1__1_"))
cby0 = next(self._top_module.get_instances("cby_0__1_"))
cby1 = next(self._top_module.get_instances("cby_1__1_"))
sb0 = next(self._top_module.get_instances("sb_0__0_"))
sb1 = next(self._top_module.get_instances("sb_0__1_"))
sb2 = next(self._top_module.get_instances("sb_1__0_"))
sb3 = next(self._top_module.get_instances("sb_1__1_"))
# grid_io_0 = next(self._top_module.get_instances("grid_io_left_0__1_"))
# grid_io_1 = next(self._top_module.get_instances("grid_io_bottom_1__0_"))
instance_list.append(((clb, cbx0, cbx1, cby0, cby1, sb0, sb1,
sb2, sb3),
"tile_1__1_"))
self.merge_and_update(instance_list, "bottom_left_tile")
def _bottom_right_tile(self):
''' Create bottom right tile
.. rst-class:: ascii
::
+-----+
| |
+-------+ +---+ |
| CBY | | SB |
+-------+ +---+ |
+--------------+ | |
| | +-----+
| | +-----+
| | | |
| CLB | | CBX |
| | +-----+
| | +-----+
+--------------+ | |
+-------+ +---+ |
| CBY | | SB |
+-------+ +---------+
'''
instance_list = []
clb = next(self._top_module.get_instances(
f"grid_clb_{self.fpga_size[0]}__1_"))
cbx0 = next(self._top_module.get_instances(
f"cbx_{self.fpga_size[0]}__0_"))
cbx1 = next(self._top_module.get_instances(
f"cbx_{self.fpga_size[0]}__1_"))
cby0 = next(self._top_module.get_instances(
f"cby_{self.fpga_size[0]}__1_"))
sb0 = next(self._top_module.get_instances(
f"sb_{self.fpga_size[0]}__0_"))
sb1 = next(self._top_module.get_instances(
f"sb_{self.fpga_size[0]}__1_"))
# grid_io_0 = next(self._top_module.get_instances(
# f"grid_io_bottom_{self.fpga_size[0]}__0_"))
# grid_io_1 = next(self._top_module.get_instances(
# f"grid_io_right_{self.fpga_size[0]+1}__1_"))
instance_list.append(((clb, cbx0, cbx1, cby0, sb0, sb1),
f"tile_{self.fpga_size[0]}__1_"))
self.merge_and_update(instance_list, "bottom_right_tile")