mirror of https://github.com/openXC7/prjxray.git
162 lines
4.9 KiB
Python
162 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2017-2020 The Project X-Ray Authors.
|
|
#
|
|
# Use of this source code is governed by a ISC-style
|
|
# license that can be found in the LICENSE file or at
|
|
# https://opensource.org/licenses/ISC
|
|
#
|
|
# SPDX-License-Identifier: ISC
|
|
class NodeModel():
|
|
""" Node lookup model
|
|
|
|
Terminology:
|
|
Wire - A segment of metal in a tile
|
|
Node - A connected set of wires
|
|
|
|
This class can provide a list of nodes, the wires in a node and the node
|
|
that a wire belongs too.
|
|
|
|
The name of node is always the name of one wire in the node.
|
|
|
|
It is recommended that this class be constructed by calling
|
|
Database.node_model rather than constructing this class directly.
|
|
|
|
"""
|
|
|
|
def __init__(
|
|
self, grid, connections, tile_wires, node_wires, progressbar=None):
|
|
self.grid = grid
|
|
self.connections = connections
|
|
self.tile_wires = tile_wires
|
|
self.specific_node_wires = set(node_wires['specific_node_wires'])
|
|
|
|
node_pattern_wires = node_wires['node_pattern_wires']
|
|
self.node_pattern_wires = {}
|
|
for tile_type in node_pattern_wires:
|
|
assert tile_type not in self.node_pattern_wires
|
|
self.node_pattern_wires[tile_type] = set(
|
|
node_pattern_wires[tile_type])
|
|
|
|
for tile_type in self.tile_wires:
|
|
if tile_type not in self.node_pattern_wires:
|
|
self.node_pattern_wires[tile_type] = set()
|
|
|
|
self.nodes = None
|
|
|
|
self.wire_to_node_map = None
|
|
|
|
if progressbar is None:
|
|
self.progressbar = lambda x: x
|
|
else:
|
|
self.progressbar = progressbar
|
|
|
|
def _build_nodes(self):
|
|
tile_wire_map = {}
|
|
wires = {}
|
|
flat_wires = []
|
|
|
|
for tile in self.progressbar(self.grid.tiles()):
|
|
gridinfo = self.grid.gridinfo_at_tilename(tile)
|
|
tile_type = gridinfo.tile_type
|
|
|
|
for wire in self.tile_wires[tile_type]:
|
|
wire_pkey = len(flat_wires)
|
|
tile_wire_map[(tile, wire)] = wire_pkey
|
|
flat_wires.append((tile, wire))
|
|
wires[wire_pkey] = None
|
|
|
|
for connection in self.progressbar(self.connections.get_connections()):
|
|
a_pkey = tile_wire_map[(
|
|
connection.wire_a.tile, connection.wire_a.wire)]
|
|
b_pkey = tile_wire_map[(
|
|
connection.wire_b.tile, connection.wire_b.wire)]
|
|
|
|
a_node = wires[a_pkey]
|
|
b_node = wires[b_pkey]
|
|
|
|
if a_node is None:
|
|
a_node = set((a_pkey, ))
|
|
|
|
if b_node is None:
|
|
b_node = set((b_pkey, ))
|
|
|
|
if a_node is not b_node:
|
|
a_node |= b_node
|
|
|
|
for wire in a_node:
|
|
wires[wire] = a_node
|
|
|
|
nodes = {}
|
|
for wire_pkey, node in self.progressbar(wires.items()):
|
|
if node is None:
|
|
node = set((wire_pkey, ))
|
|
|
|
assert wire_pkey in node
|
|
|
|
nodes[id(node)] = node
|
|
|
|
def get_node_wire_for_wires(wire_pkeys):
|
|
if len(wire_pkeys) == 1:
|
|
for wire_pkey in wire_pkeys:
|
|
return flat_wires[wire_pkey]
|
|
|
|
for wire_pkey in wire_pkeys:
|
|
tile, wire = flat_wires[wire_pkey]
|
|
|
|
if '{}/{}'.format(tile, wire) in self.specific_node_wires:
|
|
return tile, wire
|
|
|
|
for wire_pkey in wire_pkeys:
|
|
tile, wire = flat_wires[wire_pkey]
|
|
|
|
gridinfo = self.grid.gridinfo_at_tilename(tile)
|
|
|
|
if wire in self.node_pattern_wires[gridinfo.tile_type]:
|
|
return tile, wire
|
|
|
|
return None
|
|
|
|
self.nodes = {}
|
|
for node_wire_pkeys in self.progressbar(nodes.values()):
|
|
node_wire = get_node_wire_for_wires(node_wire_pkeys)
|
|
if node_wire is None:
|
|
continue
|
|
|
|
self.nodes[node_wire] = [
|
|
flat_wires[wire_pkey] for wire_pkey in node_wire_pkeys
|
|
]
|
|
|
|
def get_nodes(self):
|
|
""" Return a set of node names. """
|
|
if self.nodes is None:
|
|
self._build_nodes()
|
|
|
|
return self.nodes.keys()
|
|
|
|
def get_wires_for_node(self, tile, wire):
|
|
""" Get wires in node named for specified tile and wire. """
|
|
if self.nodes is None:
|
|
self._build_nodes()
|
|
|
|
return self.nodes[tile, wire]
|
|
|
|
def _build_wire_to_node_map(self):
|
|
self.wire_to_node_map = {}
|
|
|
|
if self.nodes is None:
|
|
self._build_nodes()
|
|
|
|
for node, wires in self.nodes.items():
|
|
for tile_wire in wires:
|
|
assert tile_wire not in self.wire_to_node_map
|
|
self.wire_to_node_map[tile_wire] = node
|
|
|
|
def get_node_for_wire(self, tile, wire):
|
|
""" Get node for specified tile and wire. """
|
|
if self.wire_to_node_map is None:
|
|
self._build_wire_to_node_map()
|
|
|
|
return self.wire_to_node_map[tile, wire]
|