mirror of https://github.com/openXC7/prjxray.git
Add methods to library.
Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
825d2dd9f0
commit
8ad5e64f85
|
|
@ -17,7 +17,6 @@ import progressbar
|
|||
import multiprocessing
|
||||
import os
|
||||
import functools
|
||||
import re
|
||||
|
||||
|
||||
def check_and_strip_prefix(name, prefix):
|
||||
|
|
@ -45,67 +44,6 @@ def flatten_site_pins(tile, site, site_pins, site_pin_node_to_wires):
|
|||
return dict(inner())
|
||||
|
||||
|
||||
# All site names appear to follow the pattern <type>_X<abs coord>Y<abs coord>.
|
||||
# Generally speaking, only the tile relatively coordinates are required to
|
||||
# assemble arch defs, so we re-origin the coordinates to be relative to the tile
|
||||
# (e.g. start at X0Y0) and discard the prefix from the name.
|
||||
SITE_COORDINATE_PATTERN = re.compile('^(.+)_X([0-9]+)Y([0-9]+)$')
|
||||
|
||||
|
||||
def find_origin_coordinate(sites):
|
||||
""" Find the coordinates of each site within the tile, and then subtract the
|
||||
smallest coordinate to re-origin them all to be relative to the tile.
|
||||
"""
|
||||
|
||||
if len(sites) == 0:
|
||||
return 0, 0
|
||||
|
||||
def inner_():
|
||||
for site in sites:
|
||||
coordinate = SITE_COORDINATE_PATTERN.match(site['site'])
|
||||
assert coordinate is not None, site
|
||||
|
||||
x_coord = int(coordinate.group(2))
|
||||
y_coord = int(coordinate.group(3))
|
||||
yield x_coord, y_coord
|
||||
|
||||
x_coords, y_coords = zip(*inner_())
|
||||
min_x_coord = min(x_coords)
|
||||
min_y_coord = min(y_coords)
|
||||
|
||||
return min_x_coord, min_y_coord
|
||||
|
||||
|
||||
def get_sites(tile, site_pin_node_to_wires):
|
||||
min_x_coord, min_y_coord = find_origin_coordinate(tile['sites'])
|
||||
|
||||
for site in tile['sites']:
|
||||
orig_site_name = site['site']
|
||||
coordinate = SITE_COORDINATE_PATTERN.match(orig_site_name)
|
||||
|
||||
x_coord = int(coordinate.group(2))
|
||||
y_coord = int(coordinate.group(3))
|
||||
|
||||
yield (
|
||||
{
|
||||
'name':
|
||||
'X{}Y{}'.format(x_coord - min_x_coord, y_coord - min_y_coord),
|
||||
'prefix':
|
||||
coordinate.group(1),
|
||||
'x_coord':
|
||||
x_coord - min_x_coord,
|
||||
'y_coord':
|
||||
y_coord - min_y_coord,
|
||||
'type':
|
||||
site['type'],
|
||||
'site_pins':
|
||||
dict(
|
||||
flatten_site_pins(
|
||||
tile['tile'], site['site'], site['site_pins'],
|
||||
site_pin_node_to_wires)),
|
||||
})
|
||||
|
||||
|
||||
def compare_sites_and_update(tile, sites, new_sites):
|
||||
for site_a, site_b in zip(sites, new_sites):
|
||||
assert site_a['type'] == site_b['type']
|
||||
|
|
@ -219,6 +157,37 @@ def check_wires(wires, sites, pips):
|
|||
assert pip['dst_wire'] in wires, repr((pip['dst_wire'], wires))
|
||||
|
||||
|
||||
def get_sites(tile, site_pin_node_to_wires):
|
||||
min_x_coord, min_y_coord = prjxray.lib.find_origin_coordinate(
|
||||
site['site'] for site in tile['sites'])
|
||||
|
||||
for site in tile['sites']:
|
||||
orig_site_name = site['site']
|
||||
coordinate = prjxray.lib.get_site_coordinate_from_name(orig_site_name)
|
||||
|
||||
x_coord = coordinate.x_coord
|
||||
y_coord = coordinate.y_coord
|
||||
|
||||
yield (
|
||||
{
|
||||
'name':
|
||||
'X{}Y{}'.format(x_coord - min_x_coord, y_coord - min_y_coord),
|
||||
'prefix':
|
||||
coordinate.prefix,
|
||||
'x_coord':
|
||||
x_coord - min_x_coord,
|
||||
'y_coord':
|
||||
y_coord - min_y_coord,
|
||||
'type':
|
||||
site['type'],
|
||||
'site_pins':
|
||||
dict(
|
||||
flatten_site_pins(
|
||||
tile['tile'], site['site'], site['site_pins'],
|
||||
site_pin_node_to_wires)),
|
||||
})
|
||||
|
||||
|
||||
def read_json5(fname, nodes):
|
||||
node_lookup = prjxray.lib.NodeLookup()
|
||||
node_lookup.load_from_nodes(nodes)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import os.path
|
|||
import json
|
||||
from prjxray import grid
|
||||
from prjxray import tile
|
||||
from prjxray import site_type
|
||||
from prjxray import connections
|
||||
|
||||
|
||||
|
|
@ -36,6 +37,7 @@ class Database(object):
|
|||
self.tile_types = None
|
||||
|
||||
self.tile_types = {}
|
||||
self.site_types = {}
|
||||
for f in os.listdir(self.db_root):
|
||||
if f.endswith('.json') and f.startswith('tile_type_'):
|
||||
tile_type = f[len('tile_type_'):-len('.json')].lower()
|
||||
|
|
@ -62,6 +64,11 @@ class Database(object):
|
|||
tile_type=tile_type_file,
|
||||
)
|
||||
|
||||
if f.endswith('.json') and f.startswith('site_type_'):
|
||||
site_type_name = f[len('site_type_'):-len('.json')]
|
||||
|
||||
self.site_types[site_type_name] = os.path.join(self.db_root, f)
|
||||
|
||||
def get_tile_types(self):
|
||||
""" Return list of tile types """
|
||||
return self.tile_types.keys()
|
||||
|
|
@ -102,3 +109,12 @@ class Database(object):
|
|||
for tile_type, db in self.tile_types.items())
|
||||
return connections.Connections(
|
||||
self.tilegrid, self.tileconn, tile_wires)
|
||||
|
||||
def get_site_types(self):
|
||||
return self.site_types.keys()
|
||||
|
||||
def get_site_type(self, site_type_name):
|
||||
with open(self.site_types[site_type_name]) as f:
|
||||
site_type_data = json.load(f)
|
||||
|
||||
return site_type.SiteType(site_type_data)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class Grid(object):
|
|||
for tile in self.tilegrid['tiles']:
|
||||
tileinfo = self.tilegrid['tiles'][tile]
|
||||
grid_loc = GridLoc(tileinfo['grid_x'], tileinfo['grid_y'])
|
||||
assert grid_loc not in self.loc
|
||||
self.loc[grid_loc] = tile
|
||||
self.tileinfo[tile] = GridInfo(
|
||||
segment=tileinfo['segment'] if 'segment' in tileinfo else None,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import csv
|
|||
import pickle
|
||||
import pyjson5 as json5
|
||||
import progressbar
|
||||
import re
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
def read_root_csv(root_dir):
|
||||
|
|
@ -148,3 +150,55 @@ def compare_prototype_site(proto_a, proto_b):
|
|||
|
||||
"""
|
||||
assert proto_a == proto_b, repr((proto_a, proto_b))
|
||||
|
||||
|
||||
# All site names appear to follow the pattern <type>_X<abs coord>Y<abs coord>.
|
||||
# Generally speaking, only the tile relatively coordinates are required to
|
||||
# assemble arch defs, so we re-origin the coordinates to be relative to the tile
|
||||
# (e.g. start at X0Y0) and discard the prefix from the name.
|
||||
SITE_COORDINATE_PATTERN = re.compile('^(.+)_X([0-9]+)Y([0-9]+)$')
|
||||
|
||||
SiteCoordinate = namedtuple('SiteCoordinate', 'prefix x_coord y_coord')
|
||||
|
||||
|
||||
def get_site_coordinate_from_name(name):
|
||||
"""
|
||||
>>> get_site_coordinate_from_name('SLICE_X1Y0')
|
||||
SiteCoordinate(prefix='SLICE', x_coord=1, y_coord=0)
|
||||
|
||||
>>> get_site_coordinate_from_name('SLICE_X0Y0')
|
||||
SiteCoordinate(prefix='SLICE', x_coord=0, y_coord=0)
|
||||
|
||||
>>> get_site_coordinate_from_name('INT_L_X500Y999')
|
||||
SiteCoordinate(prefix='INT_L', x_coord=500, y_coord=999)
|
||||
|
||||
"""
|
||||
coordinate = SITE_COORDINATE_PATTERN.match(name)
|
||||
assert coordinate is not None, name
|
||||
|
||||
return SiteCoordinate(
|
||||
prefix=coordinate.group(1),
|
||||
x_coord=int(coordinate.group(2)),
|
||||
y_coord=int(coordinate.group(3)),
|
||||
)
|
||||
|
||||
|
||||
def find_origin_coordinate(site_names):
|
||||
""" Find the coordinates of each site within the tile, and then subtract the
|
||||
smallest coordinate to re-origin them all to be relative to the tile.
|
||||
"""
|
||||
|
||||
if len(site_names) == 0:
|
||||
return 0, 0
|
||||
|
||||
def inner_():
|
||||
for site in site_names:
|
||||
coordinate = get_site_coordinate_from_name(site)
|
||||
|
||||
yield coordinate.x_coord, coordinate.y_coord
|
||||
|
||||
x_coords, y_coords = zip(*inner_())
|
||||
min_x_coord = min(x_coords)
|
||||
min_y_coord = min(y_coords)
|
||||
|
||||
return min_x_coord, min_y_coord
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
""" Description of a site type """
|
||||
|
||||
from collections import namedtuple
|
||||
import enum
|
||||
|
||||
|
||||
class SitePinDirection(enum.Enum):
|
||||
IN = "IN"
|
||||
OUT = "OUT"
|
||||
|
||||
|
||||
SiteTypePin = namedtuple('SiteTypePin', 'name direction')
|
||||
|
||||
|
||||
class SiteType(object):
|
||||
def __init__(self, site_type):
|
||||
self.type = site_type['type']
|
||||
self.site_pins = {}
|
||||
for site_pin, site_pin_info in site_type['site_pins'].items():
|
||||
self.site_pins[site_pin] = SiteTypePin(
|
||||
name=site_pin,
|
||||
direction=SitePinDirection(site_pin_info['direction']),
|
||||
)
|
||||
|
||||
def get_site_pins(self):
|
||||
return self.site_pins.keys()
|
||||
|
||||
def get_site_pin(self, site_pin):
|
||||
return self.site_pins[site_pin]
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
from collections import namedtuple
|
||||
import json
|
||||
from prjxray import lib
|
||||
""" Database files available for a tile """
|
||||
TileDbs = namedtuple('TileDbs', 'segbits mask tile_type')
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ pins - Instaces of site pins within this site and tile. This is an tuple of
|
|||
the tile.
|
||||
|
||||
"""
|
||||
Site = namedtuple('Site', 'name x y type site_pins')
|
||||
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
|
||||
|
|
@ -28,7 +29,7 @@ direction - Direction of this site pin. This direction is expected to be the
|
|||
wire - Wire name within the tile. This name is site instance specific.
|
||||
|
||||
"""
|
||||
SitePin = namedtuple('SitePin', 'name wire direction')
|
||||
SitePin = namedtuple('SitePin', 'name wire')
|
||||
|
||||
|
||||
class Tile(object):
|
||||
|
|
@ -46,15 +47,19 @@ class Tile(object):
|
|||
def yield_sites(sites):
|
||||
for site in sites:
|
||||
yield Site(
|
||||
name=None,
|
||||
name=site['name'],
|
||||
prefix=site['prefix'],
|
||||
type=site['type'],
|
||||
x=None,
|
||||
y=None,
|
||||
site_pins=site['site_pins'],
|
||||
)
|
||||
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 pip in pips:
|
||||
for pip in pips.values():
|
||||
yield Pip(
|
||||
net_to=pip['dst_wire'],
|
||||
net_from=pip['src_wire'],
|
||||
|
|
@ -82,3 +87,41 @@ class Tile(object):
|
|||
""" Returns tuple of Pip namedtuple's representing the PIPs in this tile.
|
||||
"""
|
||||
return self.pips
|
||||
|
||||
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())
|
||||
|
|
|
|||
|
|
@ -11,14 +11,46 @@ def quick_test(db_root):
|
|||
tile_types_in_grid = set(
|
||||
g.gridinfo_at_loc(loc).tile_type for loc in g.tile_locations())
|
||||
tile_types_in_db = set(db.get_tile_types())
|
||||
site_types = set(db.get_site_types())
|
||||
assert len(tile_types_in_grid - tile_types_in_db) == 0
|
||||
|
||||
# Verify that all tile types can be loaded.
|
||||
for tile_type in db.get_tile_types():
|
||||
tile = db.get_tile_type(tile_type)
|
||||
tile.get_wires()
|
||||
tile.get_sites()
|
||||
tile.get_pips()
|
||||
wires = tile.get_wires()
|
||||
for site in tile.get_sites():
|
||||
assert site.type in site_types
|
||||
site_type = db.get_site_type(site.type)
|
||||
site_pins = site_type.get_site_pins()
|
||||
for site_pin in site.site_pins:
|
||||
if site_pin.wire is not None:
|
||||
assert site_pin.wire in wires, (site_pin.wire, )
|
||||
|
||||
assert site_pin.name in site_pins
|
||||
|
||||
for pip in tile.get_pips():
|
||||
assert pip.net_to in wires
|
||||
assert pip.net_from in wires
|
||||
|
||||
for loc in g.tile_locations():
|
||||
gridinfo = g.gridinfo_at_loc(loc)
|
||||
assert gridinfo.tile_type in db.get_tile_types()
|
||||
for site_name, site_type in gridinfo.sites.items():
|
||||
assert site_type in site_types
|
||||
|
||||
tile = db.get_tile_type(gridinfo.tile_type)
|
||||
|
||||
# FIXME: The way sites are named in Tile.get_instance_sites is broken
|
||||
# for thes tile types, skip them until the underlying data is fixed.
|
||||
BROKEN_TILE_TYPES = [
|
||||
'BRAM_L', 'BRAM_R', 'HCLK_IOI3', 'CMT_TOP_L_UPPER_B',
|
||||
'CMT_TOP_R_UPPER_B'
|
||||
]
|
||||
if gridinfo.tile_type in BROKEN_TILE_TYPES:
|
||||
continue
|
||||
|
||||
instance_sites = list(tile.get_instance_sites(gridinfo))
|
||||
assert len(instance_sites) == len(tile.get_sites())
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
Loading…
Reference in New Issue