mirror of https://github.com/openXC7/prjxray.git
171 lines
5.6 KiB
Python
171 lines
5.6 KiB
Python
from collections import namedtuple
|
|
import json
|
|
from prjxray import lib
|
|
""" Database files available for a tile """
|
|
TileDbs = namedtuple('TileDbs', 'segbits ppips mask tile_type')
|
|
|
|
Pip = namedtuple(
|
|
'Pip', 'name net_to net_from can_invert is_directional is_pseudo')
|
|
""" Site - Represents an instance of a site within a tile.
|
|
|
|
name - Name of site within tile, instance specific.
|
|
prefix - Prefix of site naming in Xilinx parlance.
|
|
type - What type of slice this instance presents.
|
|
pins - Instaces of site pins within this site and tile. This is an tuple of
|
|
SitePin tuples, and is specific to this instance of the site within
|
|
the tile.
|
|
|
|
"""
|
|
Site = namedtuple('Site', 'name prefix x y type site_pins')
|
|
""" SitePin - Tuple representing a site pin within a tile.
|
|
|
|
Sites are generic based on type, however sites are instanced
|
|
within a tile 1 or more times. The SitePin contains both site type generic
|
|
information and tile type specific information.
|
|
|
|
name - Site type specific name. This name is expected to be the same for all
|
|
sites of the same type.
|
|
wire - Wire name within the tile. This name is site instance specific.
|
|
|
|
"""
|
|
SitePin = namedtuple('SitePin', 'name wire')
|
|
|
|
WireInfo = namedtuple('WireInfo', 'pips sites')
|
|
|
|
|
|
class Tile(object):
|
|
""" Provides abstration of a tile in the database. """
|
|
|
|
def __init__(self, tilename, tile_dbs):
|
|
self.tilename = tilename
|
|
self.tilename_upper = self.tilename.upper()
|
|
self.tile_dbs = tile_dbs
|
|
|
|
self.wires = None
|
|
self.sites = None
|
|
self.pips = None
|
|
self.pips_by_name = {}
|
|
|
|
def yield_sites(sites):
|
|
for site in sites:
|
|
yield Site(
|
|
name=site['name'],
|
|
prefix=site['prefix'],
|
|
type=site['type'],
|
|
x=site['x_coord'],
|
|
y=site['y_coord'],
|
|
site_pins=tuple(
|
|
SitePin(
|
|
name=name,
|
|
wire=wire,
|
|
) for name, wire in site['site_pins'].items()))
|
|
|
|
def yield_pips(pips):
|
|
for name, pip in pips.items():
|
|
yield Pip(
|
|
name=name,
|
|
net_to=pip['dst_wire'],
|
|
net_from=pip['src_wire'],
|
|
can_invert=bool(int(pip['can_invert'])),
|
|
is_directional=bool(int(pip['is_directional'])),
|
|
is_pseudo=bool(int(pip['is_pseudo'])),
|
|
)
|
|
|
|
with open(self.tile_dbs.tile_type) as f:
|
|
tile_type = json.load(f)
|
|
assert self.tilename_upper == tile_type['tile_type']
|
|
self.wires = tile_type['wires']
|
|
self.sites = tuple(yield_sites(tile_type['sites']))
|
|
self.pips = tuple(yield_pips(tile_type['pips']))
|
|
|
|
self.wire_info = {}
|
|
|
|
def get_wires(self):
|
|
"""Returns a set of wire names present in this tile."""
|
|
return self.wires
|
|
|
|
def get_sites(self):
|
|
""" Returns tuple of Site namedtuple's present in this tile. """
|
|
return self.sites
|
|
|
|
def get_pips(self):
|
|
""" Returns tuple of Pip namedtuple's representing the PIPs in this tile.
|
|
"""
|
|
return self.pips
|
|
|
|
def get_pip_by_name(self, name):
|
|
if len(self.pips_by_name) == 0:
|
|
for pip in self.pips:
|
|
self.pips_by_name[pip.name] = pip
|
|
|
|
return self.pips_by_name[name]
|
|
|
|
def get_wire_info(self, target_wire, allow_pseudo=False):
|
|
if len(self.wire_info) == 0:
|
|
for wire in self.wires:
|
|
pips = list()
|
|
sites = list()
|
|
|
|
for site in self.sites:
|
|
for site_pin in site.site_pins:
|
|
if site_pin.wire == wire:
|
|
sites.append((site.name, site_pin.name))
|
|
|
|
for pip in self.pips:
|
|
pseudo_filter = (not pip.is_pseudo) or allow_pseudo
|
|
if (wire == pip.net_to
|
|
or wire == pip.net_from) and pseudo_filter:
|
|
pips.append(pip.name)
|
|
|
|
assert wire not in self.wire_info
|
|
self.wire_info[wire] = WireInfo(pips=pips, sites=sites)
|
|
|
|
return self.wire_info[target_wire]
|
|
|
|
def get_instance_sites(self, grid_info):
|
|
""" get_sites returns abstract sites for all tiles of type.
|
|
get_instance_sites converts site info from generic to specific
|
|
based on a tile location.
|
|
"""
|
|
origin_x, origin_y = lib.find_origin_coordinate(grid_info.sites.keys())
|
|
|
|
site_names = set()
|
|
|
|
for site in self.sites:
|
|
x = site.x + origin_x
|
|
y = site.y + origin_y
|
|
|
|
site_name = '{}_X{}Y{}'.format(site.prefix, x, y)
|
|
|
|
if site_name not in grid_info.sites:
|
|
type_count = 0
|
|
for site_name_from_grid, site_type in grid_info.sites.items():
|
|
if site.type == site_type:
|
|
type_count += 1
|
|
site_name = site_name_from_grid
|
|
|
|
assert type_count == 1, (site_name, type_count)
|
|
|
|
site_names.add(site_name)
|
|
assert site.type == grid_info.sites[site_name]
|
|
|
|
yield Site(
|
|
name=site_name,
|
|
prefix=site.prefix,
|
|
type=site.type,
|
|
x=x,
|
|
y=y,
|
|
site_pins=site.site_pins,
|
|
)
|
|
|
|
assert site_names == set(grid_info.sites.keys())
|
|
|
|
|
|
def get_other_wire_from_pip(pip, wire):
|
|
if wire == pip.net_to:
|
|
return pip.net_from
|
|
elif wire == pip.net_from:
|
|
return pip.net_to
|
|
else:
|
|
assert False, (pip, wire)
|