f4pga: run black
Signed-off-by: Unai Martinez-Corral <umartinezcorral@antmicro.com>
This commit is contained in:
parent
34008841c1
commit
54c4c1ee44
|
@ -47,7 +47,6 @@ def parse_simple_pcf(f):
|
||||||
assert len(args) == 3, args
|
assert len(args) == 3, args
|
||||||
|
|
||||||
if args[0] == "set_io":
|
if args[0] == "set_io":
|
||||||
|
|
||||||
yield PcfIoConstraint(
|
yield PcfIoConstraint(
|
||||||
net=args[1],
|
net=args[1],
|
||||||
pad=args[2],
|
pad=args[2],
|
||||||
|
@ -56,7 +55,6 @@ def parse_simple_pcf(f):
|
||||||
)
|
)
|
||||||
|
|
||||||
if args[0] == "set_clk":
|
if args[0] == "set_clk":
|
||||||
|
|
||||||
yield PcfClkConstraint(
|
yield PcfClkConstraint(
|
||||||
pin=args[1],
|
pin=args[1],
|
||||||
net=args[2],
|
net=args[2],
|
||||||
|
|
|
@ -43,7 +43,6 @@ def parse_options(lines, opts=None):
|
||||||
# join all remaining ones into a single string
|
# join all remaining ones into a single string
|
||||||
opt_string = ""
|
opt_string = ""
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
|
||||||
# Remove comments
|
# Remove comments
|
||||||
pos = line.find("#")
|
pos = line.find("#")
|
||||||
if pos != -1:
|
if pos != -1:
|
||||||
|
@ -60,7 +59,6 @@ def parse_options(lines, opts=None):
|
||||||
|
|
||||||
# Remove all C/C++ style "/* ... */" comments
|
# Remove all C/C++ style "/* ... */" comments
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
# Find beginning of a block comment. Finish if none is found
|
# Find beginning of a block comment. Finish if none is found
|
||||||
p0 = opt_string.find("/*")
|
p0 = opt_string.find("/*")
|
||||||
if p0 == -1:
|
if p0 == -1:
|
||||||
|
@ -82,7 +80,6 @@ def parse_options(lines, opts=None):
|
||||||
# Scan and process options
|
# Scan and process options
|
||||||
parts = iter(shlex.split(opt_string))
|
parts = iter(shlex.split(opt_string))
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
# Get the option
|
# Get the option
|
||||||
try:
|
try:
|
||||||
opt = next(parts)
|
opt = next(parts)
|
||||||
|
@ -210,7 +207,6 @@ def translate_options(opts):
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
# Read lines from stdin, parse options
|
# Read lines from stdin, parse options
|
||||||
lines = sys.stdin.readlines()
|
lines = sys.stdin.readlines()
|
||||||
opts = parse_options(lines)
|
opts = parse_options(lines)
|
||||||
|
|
|
@ -190,7 +190,6 @@ def write_tiles(xml_arch, arch_tile_types, tile_types, equivalent_sites):
|
||||||
|
|
||||||
# Add tiles
|
# Add tiles
|
||||||
for tile_type, sub_tiles in arch_tile_types.items():
|
for tile_type, sub_tiles in arch_tile_types.items():
|
||||||
|
|
||||||
xml = make_top_level_tile(tile_type, sub_tiles, tile_types, equivalent_sites)
|
xml = make_top_level_tile(tile_type, sub_tiles, tile_types, equivalent_sites)
|
||||||
|
|
||||||
xml_tiles.append(xml)
|
xml_tiles.append(xml)
|
||||||
|
@ -208,7 +207,6 @@ def write_pb_types(xml_arch, arch_pb_types, tile_types, nsmap):
|
||||||
|
|
||||||
# Add pb_types
|
# Add pb_types
|
||||||
for pb_type in arch_pb_types:
|
for pb_type in arch_pb_types:
|
||||||
|
|
||||||
xml = make_top_level_pb_type(tile_types[pb_type], nsmap)
|
xml = make_top_level_pb_type(tile_types[pb_type], nsmap)
|
||||||
xml_cplx.append(xml)
|
xml_cplx.append(xml)
|
||||||
|
|
||||||
|
@ -275,7 +273,6 @@ def write_tilegrid(xml_arch, arch_tile_grid, loc_map, layout_name):
|
||||||
|
|
||||||
# Individual tiles
|
# Individual tiles
|
||||||
for flat_loc, tile in arch_tile_grid.items():
|
for flat_loc, tile in arch_tile_grid.items():
|
||||||
|
|
||||||
if tile is None:
|
if tile is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -342,7 +339,6 @@ def write_direct_connections(xml_arch, tile_grid, connections):
|
||||||
# Populate connections
|
# Populate connections
|
||||||
conns = [c for c in connections if is_direct(c)]
|
conns = [c for c in connections if is_direct(c)]
|
||||||
for connection in conns:
|
for connection in conns:
|
||||||
|
|
||||||
src_tile = get_tile(connection.src)
|
src_tile = get_tile(connection.src)
|
||||||
dst_tile = get_tile(connection.dst)
|
dst_tile = get_tile(connection.dst)
|
||||||
|
|
||||||
|
@ -388,7 +384,6 @@ def write_direct_connections(xml_arch, tile_grid, connections):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
@ -417,7 +412,6 @@ def main():
|
||||||
# Flatten the VPR tilegrid
|
# Flatten the VPR tilegrid
|
||||||
flat_tile_grid = dict()
|
flat_tile_grid = dict()
|
||||||
for vpr_loc, tile in vpr_tile_grid.items():
|
for vpr_loc, tile in vpr_tile_grid.items():
|
||||||
|
|
||||||
flat_loc = (vpr_loc.x, vpr_loc.y)
|
flat_loc = (vpr_loc.x, vpr_loc.y)
|
||||||
if flat_loc not in flat_tile_grid:
|
if flat_loc not in flat_tile_grid:
|
||||||
flat_tile_grid[flat_loc] = {}
|
flat_tile_grid[flat_loc] = {}
|
||||||
|
@ -432,9 +426,7 @@ def main():
|
||||||
arch_models = set()
|
arch_models = set()
|
||||||
|
|
||||||
for flat_loc, tiles in flat_tile_grid.items():
|
for flat_loc, tiles in flat_tile_grid.items():
|
||||||
|
|
||||||
if len(tiles):
|
if len(tiles):
|
||||||
|
|
||||||
# Group identical sub-tiles together, maintain their order
|
# Group identical sub-tiles together, maintain their order
|
||||||
sub_tiles = OrderedDict()
|
sub_tiles = OrderedDict()
|
||||||
for z, tile in tiles.items():
|
for z, tile in tiles.items():
|
||||||
|
@ -464,7 +456,6 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Add an empty location
|
# Add an empty location
|
||||||
arch_tile_grid[flat_loc] = None
|
arch_tile_grid[flat_loc] = None
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,6 @@ def build_tile_connections(tile_types, tile_grid, switchbox_types, switchbox_gri
|
||||||
|
|
||||||
# A foreign connection
|
# A foreign connection
|
||||||
elif sbox_pin.type == SwitchboxPinType.FOREIGN:
|
elif sbox_pin.type == SwitchboxPinType.FOREIGN:
|
||||||
|
|
||||||
# Get the hop offset
|
# Get the hop offset
|
||||||
pin_name, hop = get_name_and_hop(sbox_pin.name)
|
pin_name, hop = get_name_and_hop(sbox_pin.name)
|
||||||
assert hop is not None, sbox_pin
|
assert hop is not None, sbox_pin
|
||||||
|
@ -213,7 +212,6 @@ def build_tile_connections(tile_types, tile_grid, switchbox_types, switchbox_gri
|
||||||
# Find the pin in the tile
|
# Find the pin in the tile
|
||||||
for pin in tile.pins:
|
for pin in tile.pins:
|
||||||
if pin.direction == OPPOSITE_DIRECTION[sbox_pin.direction]:
|
if pin.direction == OPPOSITE_DIRECTION[sbox_pin.direction]:
|
||||||
|
|
||||||
# Check if the pin name refers to the full tile pin name
|
# Check if the pin name refers to the full tile pin name
|
||||||
# ie. with the cell name.
|
# ie. with the cell name.
|
||||||
if pin.name == pin_name:
|
if pin.name == pin_name:
|
||||||
|
@ -283,7 +281,6 @@ def build_hop_connections(switchbox_types, switchbox_grid):
|
||||||
# should go into a HOP input.
|
# should go into a HOP input.
|
||||||
dst_pins = [pin for pin in dst_switchbox.inputs.values() if pin.type == SwitchboxPinType.HOP]
|
dst_pins = [pin for pin in dst_switchbox.inputs.values() if pin.type == SwitchboxPinType.HOP]
|
||||||
for dst_pin in dst_pins:
|
for dst_pin in dst_pins:
|
||||||
|
|
||||||
# Parse the name, determine hop offset. Skip non-hop wires.
|
# Parse the name, determine hop offset. Skip non-hop wires.
|
||||||
hop_name, hop_ofs = get_name_and_hop(dst_pin.name)
|
hop_name, hop_ofs = get_name_and_hop(dst_pin.name)
|
||||||
if hop_ofs is None:
|
if hop_ofs is None:
|
||||||
|
@ -346,7 +343,6 @@ def build_hop_connections(switchbox_types, switchbox_grid):
|
||||||
|
|
||||||
|
|
||||||
def find_clock_cell(alias, tile_grid):
|
def find_clock_cell(alias, tile_grid):
|
||||||
|
|
||||||
for loc, tile in tile_grid.items():
|
for loc, tile in tile_grid.items():
|
||||||
if tile is None:
|
if tile is None:
|
||||||
continue
|
continue
|
||||||
|
@ -364,7 +360,6 @@ def find_clock_cell(alias, tile_grid):
|
||||||
|
|
||||||
|
|
||||||
def build_gmux_qmux_connections(tile_types, tile_grid, switchbox_types, switchbox_grid, clock_cells):
|
def build_gmux_qmux_connections(tile_types, tile_grid, switchbox_types, switchbox_grid, clock_cells):
|
||||||
|
|
||||||
# Define names of all global clock wires.
|
# Define names of all global clock wires.
|
||||||
# Each global clock mux as an implicitly defined output equal to its name.
|
# Each global clock mux as an implicitly defined output equal to its name.
|
||||||
clock_wires = list(clock_cells.keys())
|
clock_wires = list(clock_cells.keys())
|
||||||
|
@ -377,9 +372,7 @@ def build_gmux_qmux_connections(tile_types, tile_grid, switchbox_types, switchbo
|
||||||
# Conections between clock cells (muxes)
|
# Conections between clock cells (muxes)
|
||||||
connections = []
|
connections = []
|
||||||
for clock_cell in clock_cells.values():
|
for clock_cell in clock_cells.values():
|
||||||
|
|
||||||
for pin_name, pin_conn in clock_cell.pin_map.items():
|
for pin_name, pin_conn in clock_cell.pin_map.items():
|
||||||
|
|
||||||
# Destination pin name. Treat CAND and QMUX destinations
|
# Destination pin name. Treat CAND and QMUX destinations
|
||||||
# differently as there are going to be no tiles for them.
|
# differently as there are going to be no tiles for them.
|
||||||
if clock_cell.type in ["CAND", "QMUX"]:
|
if clock_cell.type in ["CAND", "QMUX"]:
|
||||||
|
@ -395,14 +388,12 @@ def build_gmux_qmux_connections(tile_types, tile_grid, switchbox_types, switchbo
|
||||||
|
|
||||||
# This pin connects to a global clock wire
|
# This pin connects to a global clock wire
|
||||||
if pin_conn in clock_wires:
|
if pin_conn in clock_wires:
|
||||||
|
|
||||||
# Get the other cell
|
# Get the other cell
|
||||||
other_cell = clock_cells.get(pin_conn, None)
|
other_cell = clock_cells.get(pin_conn, None)
|
||||||
|
|
||||||
# Not found in the clock cells. Probably it is the CLOCK cell
|
# Not found in the clock cells. Probably it is the CLOCK cell
|
||||||
# try finding it by its name / alias
|
# try finding it by its name / alias
|
||||||
if other_cell is None:
|
if other_cell is None:
|
||||||
|
|
||||||
src_loc, src_tile, src_cell = find_clock_cell(pin_conn, tile_grid)
|
src_loc, src_tile, src_cell = find_clock_cell(pin_conn, tile_grid)
|
||||||
|
|
||||||
# Didint find the cell
|
# Didint find the cell
|
||||||
|
|
|
@ -80,7 +80,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# Create all mux nodes
|
# Create all mux nodes
|
||||||
for stage, switch, mux in yield_muxes(self.switchbox):
|
for stage, switch, mux in yield_muxes(self.switchbox):
|
||||||
|
|
||||||
# Create the node
|
# Create the node
|
||||||
key = (stage.id, switch.id, mux.id)
|
key = (stage.id, switch.id, mux.id)
|
||||||
node = self.Node(self.NodeType.MUX, key)
|
node = self.Node(self.NodeType.MUX, key)
|
||||||
|
@ -95,7 +94,6 @@ class SwitchboxConfigBuilder:
|
||||||
# Create all source and sink nodes, populate their connections with mux
|
# Create all source and sink nodes, populate their connections with mux
|
||||||
# nodes.
|
# nodes.
|
||||||
for pin in self.switchbox.pins:
|
for pin in self.switchbox.pins:
|
||||||
|
|
||||||
# Node type
|
# Node type
|
||||||
if pin.direction == PinDirection.INPUT:
|
if pin.direction == PinDirection.INPUT:
|
||||||
node_type = self.NodeType.SOURCE
|
node_type = self.NodeType.SOURCE
|
||||||
|
@ -107,7 +105,6 @@ class SwitchboxConfigBuilder:
|
||||||
# Create one for each stage type
|
# Create one for each stage type
|
||||||
stage_ids = set([loc.stage_id for loc in pin.locs])
|
stage_ids = set([loc.stage_id for loc in pin.locs])
|
||||||
for stage_id in stage_ids:
|
for stage_id in stage_ids:
|
||||||
|
|
||||||
# Create the node
|
# Create the node
|
||||||
key = pin.name
|
key = pin.name
|
||||||
node = self.Node(node_type, key)
|
node = self.Node(node_type, key)
|
||||||
|
@ -127,14 +124,12 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# Populate connections
|
# Populate connections
|
||||||
for pin_loc in pin.locs:
|
for pin_loc in pin.locs:
|
||||||
|
|
||||||
# Get the correct node list
|
# Get the correct node list
|
||||||
stage_type = self.switchbox.stages[pin_loc.stage_id].type
|
stage_type = self.switchbox.stages[pin_loc.stage_id].type
|
||||||
assert stage_type in self.nodes, stage_type
|
assert stage_type in self.nodes, stage_type
|
||||||
nodes = self.nodes[stage_type]
|
nodes = self.nodes[stage_type]
|
||||||
|
|
||||||
if pin.direction == PinDirection.INPUT:
|
if pin.direction == PinDirection.INPUT:
|
||||||
|
|
||||||
# Get the mux node
|
# Get the mux node
|
||||||
key = (pin_loc.stage_id, pin_loc.switch_id, pin_loc.mux_id)
|
key = (pin_loc.stage_id, pin_loc.switch_id, pin_loc.mux_id)
|
||||||
assert key in nodes, key
|
assert key in nodes, key
|
||||||
|
@ -164,7 +159,6 @@ class SwitchboxConfigBuilder:
|
||||||
node.out.add(key)
|
node.out.add(key)
|
||||||
|
|
||||||
elif pin.direction == PinDirection.OUTPUT:
|
elif pin.direction == PinDirection.OUTPUT:
|
||||||
|
|
||||||
# Get the sink node
|
# Get the sink node
|
||||||
key = pin.name
|
key = pin.name
|
||||||
assert key in nodes, key
|
assert key in nodes, key
|
||||||
|
@ -189,7 +183,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# Populate mux to mux connections
|
# Populate mux to mux connections
|
||||||
for conn in self.switchbox.connections:
|
for conn in self.switchbox.connections:
|
||||||
|
|
||||||
# Get the correct node list
|
# Get the correct node list
|
||||||
stage_type = self.switchbox.stages[conn.dst.stage_id].type
|
stage_type = self.switchbox.stages[conn.dst.stage_id].type
|
||||||
assert stage_type in self.nodes, stage_type
|
assert stage_type in self.nodes, stage_type
|
||||||
|
@ -242,7 +235,6 @@ class SwitchboxConfigBuilder:
|
||||||
nodes = self.nodes[stage_type]
|
nodes = self.nodes[stage_type]
|
||||||
|
|
||||||
def walk(node):
|
def walk(node):
|
||||||
|
|
||||||
# Examine all driven nodes
|
# Examine all driven nodes
|
||||||
for sink_key in node.out:
|
for sink_key in node.out:
|
||||||
assert sink_key in nodes, sink_key
|
assert sink_key in nodes, sink_key
|
||||||
|
@ -250,7 +242,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# The sink is free
|
# The sink is free
|
||||||
if sink_node.net is None:
|
if sink_node.net is None:
|
||||||
|
|
||||||
# Assign it to the net
|
# Assign it to the net
|
||||||
sink_node.net = node.net
|
sink_node.net = node.net
|
||||||
if sink_node.type == self.NodeType.MUX:
|
if sink_node.type == self.NodeType.MUX:
|
||||||
|
@ -285,7 +276,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
for stage_type, nodes in self.nodes.items():
|
for stage_type, nodes in self.nodes.items():
|
||||||
for key, node in nodes.items():
|
for key, node in nodes.items():
|
||||||
|
|
||||||
if node.type == self.NodeType.MUX and node.sel is None:
|
if node.type == self.NodeType.MUX and node.sel is None:
|
||||||
result = False
|
result = False
|
||||||
print("WARNING: mux unconfigured", key)
|
print("WARNING: mux unconfigured", key)
|
||||||
|
@ -301,7 +291,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
for stage_type, nodes in self.nodes.items():
|
for stage_type, nodes in self.nodes.items():
|
||||||
for key, node in nodes.items():
|
for key, node in nodes.items():
|
||||||
|
|
||||||
# For muxes with active selection
|
# For muxes with active selection
|
||||||
if node.type == self.NodeType.MUX and node.sel is not None:
|
if node.type == self.NodeType.MUX and node.sel is not None:
|
||||||
stage_id, switch_id, mux_id = key
|
stage_id, switch_id, mux_id = key
|
||||||
|
@ -343,7 +332,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
nets = sorted(list(nets))
|
nets = sorted(list(nets))
|
||||||
for i, net in enumerate(nets):
|
for i, net in enumerate(nets):
|
||||||
|
|
||||||
hue = i / len(nets)
|
hue = i / len(nets)
|
||||||
light = 0.33
|
light = 0.33
|
||||||
saturation = 1.0
|
saturation = 1.0
|
||||||
|
@ -368,14 +356,12 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# Stage types
|
# Stage types
|
||||||
for stage_type, nodes in self.nodes.items():
|
for stage_type, nodes in self.nodes.items():
|
||||||
|
|
||||||
# Stage header
|
# Stage header
|
||||||
dot.append(' subgraph "cluster_{}" {{'.format(stage_type))
|
dot.append(' subgraph "cluster_{}" {{'.format(stage_type))
|
||||||
dot.append(" label=\"Stage '{}'\";".format(stage_type))
|
dot.append(" label=\"Stage '{}'\";".format(stage_type))
|
||||||
|
|
||||||
# Nodes and internal mux edges
|
# Nodes and internal mux edges
|
||||||
for key, node in nodes.items():
|
for key, node in nodes.items():
|
||||||
|
|
||||||
# Source node
|
# Source node
|
||||||
if node.type == self.NodeType.SOURCE:
|
if node.type == self.NodeType.SOURCE:
|
||||||
name = "{}_inp_{}".format(stage_type, key2str(key))
|
name = "{}_inp_{}".format(stage_type, key2str(key))
|
||||||
|
@ -470,7 +456,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
# Mux to mux connections
|
# Mux to mux connections
|
||||||
for key, node in nodes.items():
|
for key, node in nodes.items():
|
||||||
|
|
||||||
# Source node
|
# Source node
|
||||||
if node.type == self.NodeType.SOURCE:
|
if node.type == self.NodeType.SOURCE:
|
||||||
pass
|
pass
|
||||||
|
@ -536,7 +521,6 @@ class SwitchboxConfigBuilder:
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
@ -653,7 +637,6 @@ def main():
|
||||||
|
|
||||||
# Power on all LOGIC cells
|
# Power on all LOGIC cells
|
||||||
for loc, tile in tile_grid.items():
|
for loc, tile in tile_grid.items():
|
||||||
|
|
||||||
# Get the tile type object
|
# Get the tile type object
|
||||||
tile_type = tile_types[tile.type]
|
tile_type = tile_types[tile.type]
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,6 @@ def main():
|
||||||
pad_alias_map = defaultdict(lambda: dict())
|
pad_alias_map = defaultdict(lambda: dict())
|
||||||
|
|
||||||
for pin_map_entry in csv.DictReader(args.map):
|
for pin_map_entry in csv.DictReader(args.map):
|
||||||
|
|
||||||
if pin_map_entry["type"] not in IOB_TYPES:
|
if pin_map_entry["type"] not in IOB_TYPES:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -88,7 +87,6 @@ def main():
|
||||||
used_pads = set()
|
used_pads = set()
|
||||||
|
|
||||||
for pcf_constraint in parse_simple_pcf(args.pcf):
|
for pcf_constraint in parse_simple_pcf(args.pcf):
|
||||||
|
|
||||||
# Skip non-io constraints
|
# Skip non-io constraints
|
||||||
if type(pcf_constraint).__name__ != "PcfIoConstraint":
|
if type(pcf_constraint).__name__ != "PcfIoConstraint":
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -95,7 +95,6 @@ def main():
|
||||||
io_constraints = {}
|
io_constraints = {}
|
||||||
|
|
||||||
for line in args.input:
|
for line in args.input:
|
||||||
|
|
||||||
# Strip, skip comments
|
# Strip, skip comments
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line.startswith("#"):
|
if line.startswith("#"):
|
||||||
|
@ -119,7 +118,6 @@ def main():
|
||||||
BUF_CELL = {"type": "GMUX_IP", "ipin": "IP", "opin": "IZ"}
|
BUF_CELL = {"type": "GMUX_IP", "ipin": "IP", "opin": "IZ"}
|
||||||
|
|
||||||
for inp_net in eblif_data["inputs"]["args"]:
|
for inp_net in eblif_data["inputs"]["args"]:
|
||||||
|
|
||||||
# This one is not constrained, skip it
|
# This one is not constrained, skip it
|
||||||
if inp_net not in io_constraints:
|
if inp_net not in io_constraints:
|
||||||
continue
|
continue
|
||||||
|
@ -159,7 +157,6 @@ def main():
|
||||||
|
|
||||||
# Emit constraints for GCLK cells
|
# Emit constraints for GCLK cells
|
||||||
for inp_net, iob_cell, con_net, buf_cell, clk_net in clock_connections:
|
for inp_net, iob_cell, con_net, buf_cell, clk_net in clock_connections:
|
||||||
|
|
||||||
src_loc = io_constraints[inp_net]
|
src_loc = io_constraints[inp_net]
|
||||||
if src_loc not in clock_to_gmux:
|
if src_loc not in clock_to_gmux:
|
||||||
eprint("ERROR: No GMUX location for input CLOCK pad for net '{}' at {}".format(inp_net, src_loc))
|
eprint("ERROR: No GMUX location for input CLOCK pad for net '{}' at {}".format(inp_net, src_loc))
|
||||||
|
|
|
@ -101,7 +101,6 @@ def parse_library(xml_library):
|
||||||
cells = []
|
cells = []
|
||||||
|
|
||||||
for xml_node in xml_library:
|
for xml_node in xml_library:
|
||||||
|
|
||||||
# Skip those
|
# Skip those
|
||||||
if xml_node.tag in ["PortProperties"]:
|
if xml_node.tag in ["PortProperties"]:
|
||||||
continue
|
continue
|
||||||
|
@ -111,7 +110,6 @@ def parse_library(xml_library):
|
||||||
|
|
||||||
# Load pins
|
# Load pins
|
||||||
for xml_pins in itertools.chain(xml_node.findall("INPUT"), xml_node.findall("OUTPUT")):
|
for xml_pins in itertools.chain(xml_node.findall("INPUT"), xml_node.findall("OUTPUT")):
|
||||||
|
|
||||||
# Pin direction
|
# Pin direction
|
||||||
if xml_pins.tag == "INPUT":
|
if xml_pins.tag == "INPUT":
|
||||||
direction = PinDirection.INPUT
|
direction = PinDirection.INPUT
|
||||||
|
@ -179,7 +177,6 @@ def parse_library(xml_library):
|
||||||
|
|
||||||
|
|
||||||
def load_logic_cells(xml_placement, cellgrid, cells_library):
|
def load_logic_cells(xml_placement, cellgrid, cells_library):
|
||||||
|
|
||||||
# Load "LOGIC" tiles
|
# Load "LOGIC" tiles
|
||||||
xml_logic = xml_placement.find("LOGIC")
|
xml_logic = xml_placement.find("LOGIC")
|
||||||
assert xml_logic is not None
|
assert xml_logic is not None
|
||||||
|
@ -218,10 +215,8 @@ def load_logic_cells(xml_placement, cellgrid, cells_library):
|
||||||
|
|
||||||
|
|
||||||
def load_other_cells(xml_placement, cellgrid, cells_library):
|
def load_other_cells(xml_placement, cellgrid, cells_library):
|
||||||
|
|
||||||
# Loop over XML entries
|
# Loop over XML entries
|
||||||
for xml in xml_placement:
|
for xml in xml_placement:
|
||||||
|
|
||||||
# Got a "Cell" tag
|
# Got a "Cell" tag
|
||||||
if xml.tag == "Cell":
|
if xml.tag == "Cell":
|
||||||
cell_name = xml.get("name")
|
cell_name = xml.get("name")
|
||||||
|
@ -296,7 +291,6 @@ def make_tile_type_name(cells):
|
||||||
|
|
||||||
|
|
||||||
def parse_placement(xml_placement, cells_library):
|
def parse_placement(xml_placement, cells_library):
|
||||||
|
|
||||||
# Load tilegrid quadrants
|
# Load tilegrid quadrants
|
||||||
quadrants = {}
|
quadrants = {}
|
||||||
|
|
||||||
|
@ -342,14 +336,12 @@ def parse_placement(xml_placement, cells_library):
|
||||||
tile_types = {}
|
tile_types = {}
|
||||||
tile_types_at_loc = {}
|
tile_types_at_loc = {}
|
||||||
for loc, cells in cellgrid.items():
|
for loc, cells in cellgrid.items():
|
||||||
|
|
||||||
# Generate type and assign
|
# Generate type and assign
|
||||||
type = make_tile_type_name(cells)
|
type = make_tile_type_name(cells)
|
||||||
tile_types_at_loc[loc] = type
|
tile_types_at_loc[loc] = type
|
||||||
|
|
||||||
# A new type? complete its definition
|
# A new type? complete its definition
|
||||||
if type not in tile_types:
|
if type not in tile_types:
|
||||||
|
|
||||||
cell_types = [c.type for c in cells]
|
cell_types = [c.type for c in cells]
|
||||||
cell_count = {t: len([c for c in cells if c.type == t]) for t in cell_types}
|
cell_count = {t: len([c for c in cells if c.type == t]) for t in cell_types}
|
||||||
|
|
||||||
|
@ -360,11 +352,9 @@ def parse_placement(xml_placement, cells_library):
|
||||||
# Make the final tilegrid
|
# Make the final tilegrid
|
||||||
tilegrid = {}
|
tilegrid = {}
|
||||||
for loc, type in tile_types_at_loc.items():
|
for loc, type in tile_types_at_loc.items():
|
||||||
|
|
||||||
# Group cells by type
|
# Group cells by type
|
||||||
tile_cells_by_type = defaultdict(lambda: [])
|
tile_cells_by_type = defaultdict(lambda: [])
|
||||||
for cell in cellgrid[loc]:
|
for cell in cellgrid[loc]:
|
||||||
|
|
||||||
tile_cells_by_type[cell.type].append(cell)
|
tile_cells_by_type[cell.type].append(cell)
|
||||||
|
|
||||||
# Create a list of cell instances within the tile
|
# Create a list of cell instances within the tile
|
||||||
|
@ -413,10 +403,8 @@ def update_switchbox_pins(switchbox):
|
||||||
for stage_id, stage in switchbox.stages.items():
|
for stage_id, stage in switchbox.stages.items():
|
||||||
for switch_id, switch in stage.switches.items():
|
for switch_id, switch in stage.switches.items():
|
||||||
for mux_id, mux in switch.muxes.items():
|
for mux_id, mux in switch.muxes.items():
|
||||||
|
|
||||||
# Add the mux output pin as top level output if necessary
|
# Add the mux output pin as top level output if necessary
|
||||||
if mux.output.name is not None:
|
if mux.output.name is not None:
|
||||||
|
|
||||||
loc = SwitchboxPinLoc(
|
loc = SwitchboxPinLoc(
|
||||||
stage_id=stage.id,
|
stage_id=stage.id,
|
||||||
switch_id=switch.id,
|
switch_id=switch.id,
|
||||||
|
@ -444,7 +432,6 @@ def update_switchbox_pins(switchbox):
|
||||||
# Add the mux input pins as top level inputs if necessary
|
# Add the mux input pins as top level inputs if necessary
|
||||||
for pin in mux.inputs.values():
|
for pin in mux.inputs.values():
|
||||||
if pin.name is not None:
|
if pin.name is not None:
|
||||||
|
|
||||||
loc = SwitchboxPinLoc(
|
loc = SwitchboxPinLoc(
|
||||||
stage_id=stage.id,
|
stage_id=stage.id,
|
||||||
switch_id=switch.id,
|
switch_id=switch.id,
|
||||||
|
@ -458,7 +445,6 @@ def update_switchbox_pins(switchbox):
|
||||||
# Add top-level input pins to the switchbox.
|
# Add top-level input pins to the switchbox.
|
||||||
keys = sorted(input_locs.keys(), key=lambda k: k[0])
|
keys = sorted(input_locs.keys(), key=lambda k: k[0])
|
||||||
for name, locs in {k: input_locs[k] for k in keys}.items():
|
for name, locs in {k: input_locs[k] for k in keys}.items():
|
||||||
|
|
||||||
# Determine the pin type
|
# Determine the pin type
|
||||||
is_hop = is_regular_hop_wire(name)
|
is_hop = is_regular_hop_wire(name)
|
||||||
_, hop = get_name_and_hop(name)
|
_, hop = get_name_and_hop(name)
|
||||||
|
@ -498,7 +484,6 @@ def parse_switchbox(xml_sbox, xml_common=None):
|
||||||
|
|
||||||
# Load stages
|
# Load stages
|
||||||
for xml_stage in stages:
|
for xml_stage in stages:
|
||||||
|
|
||||||
# Get stage id
|
# Get stage id
|
||||||
stage_id = int(xml_stage.attrib["StageNumber"])
|
stage_id = int(xml_stage.attrib["StageNumber"])
|
||||||
assert stage_id not in switchbox.stages, (stage_id, switchbox.stages.keys())
|
assert stage_id not in switchbox.stages, (stage_id, switchbox.stages.keys())
|
||||||
|
@ -609,7 +594,6 @@ def parse_wire_mapping_table(xml_root, switchbox_grid, switchbox_types):
|
||||||
# Rows
|
# Rows
|
||||||
xml_rows = [e for e in xml_root if e.tag.startswith("Row_")]
|
xml_rows = [e for e in xml_root if e.tag.startswith("Row_")]
|
||||||
for xml_row in xml_rows:
|
for xml_row in xml_rows:
|
||||||
|
|
||||||
# Decode row range
|
# Decode row range
|
||||||
match = RE_LOC.match(xml_row.tag)
|
match = RE_LOC.match(xml_row.tag)
|
||||||
assert match is not None, xml_row.tag
|
assert match is not None, xml_row.tag
|
||||||
|
@ -623,7 +607,6 @@ def parse_wire_mapping_table(xml_root, switchbox_grid, switchbox_types):
|
||||||
# Columns
|
# Columns
|
||||||
xml_cols = [e for e in xml_row if e.tag.startswith("Col_")]
|
xml_cols = [e for e in xml_row if e.tag.startswith("Col_")]
|
||||||
for xml_col in xml_cols:
|
for xml_col in xml_cols:
|
||||||
|
|
||||||
# Decode column range
|
# Decode column range
|
||||||
match = RE_LOC.match(xml_col.tag)
|
match = RE_LOC.match(xml_col.tag)
|
||||||
assert match is not None, xml_col.tag
|
assert match is not None, xml_col.tag
|
||||||
|
@ -651,7 +634,6 @@ def parse_wire_mapping_table(xml_root, switchbox_grid, switchbox_types):
|
||||||
|
|
||||||
for loc, xml_maps in yield_locs_and_maps():
|
for loc, xml_maps in yield_locs_and_maps():
|
||||||
for xml_map in xml_maps:
|
for xml_map in xml_maps:
|
||||||
|
|
||||||
# Decode stage id
|
# Decode stage id
|
||||||
match = RE_STAGE.match(xml_map.tag)
|
match = RE_STAGE.match(xml_map.tag)
|
||||||
assert match is not None, xml_map.tag
|
assert match is not None, xml_map.tag
|
||||||
|
@ -662,7 +644,6 @@ def parse_wire_mapping_table(xml_root, switchbox_grid, switchbox_types):
|
||||||
# Decode wire joints
|
# Decode wire joints
|
||||||
joints = {k: v for k, v in xml_map.attrib.items() if k.startswith("Join.")}
|
joints = {k: v for k, v in xml_map.attrib.items() if k.startswith("Join.")}
|
||||||
for joint_key, joint_map in joints.items():
|
for joint_key, joint_map in joints.items():
|
||||||
|
|
||||||
# Decode the joint key
|
# Decode the joint key
|
||||||
match = RE_JOINT.match(joint_key)
|
match = RE_JOINT.match(joint_key)
|
||||||
assert match is not None, joint_key
|
assert match is not None, joint_key
|
||||||
|
@ -711,7 +692,6 @@ def parse_port_mapping_table(xml_root, switchbox_grid):
|
||||||
# Sections are named "*_Table"
|
# Sections are named "*_Table"
|
||||||
xml_tables = [e for e in xml_root if e.tag.endswith("_Table")]
|
xml_tables = [e for e in xml_root if e.tag.endswith("_Table")]
|
||||||
for xml_table in xml_tables:
|
for xml_table in xml_tables:
|
||||||
|
|
||||||
# Get the origin
|
# Get the origin
|
||||||
origin = xml_table.tag.split("_")[0]
|
origin = xml_table.tag.split("_")[0]
|
||||||
assert origin in ["Left", "Right", "Top", "Bottom"], origin
|
assert origin in ["Left", "Right", "Top", "Bottom"], origin
|
||||||
|
@ -735,7 +715,6 @@ def parse_port_mapping_table(xml_root, switchbox_grid):
|
||||||
|
|
||||||
# Parse the port mapping table(s)
|
# Parse the port mapping table(s)
|
||||||
for port_mapping_xml in xml_table.findall("PortMappingTable"):
|
for port_mapping_xml in xml_table.findall("PortMappingTable"):
|
||||||
|
|
||||||
# Get the direction of the switchbox offset
|
# Get the direction of the switchbox offset
|
||||||
orientation = port_mapping_xml.attrib["Orientation"]
|
orientation = port_mapping_xml.attrib["Orientation"]
|
||||||
if orientation == "Horizontal":
|
if orientation == "Horizontal":
|
||||||
|
@ -762,7 +741,6 @@ def parse_port_mapping_table(xml_root, switchbox_grid):
|
||||||
|
|
||||||
sbox_xmls = [e for e in index_xml if e.tag.startswith("SBox")]
|
sbox_xmls = [e for e in index_xml if e.tag.startswith("SBox")]
|
||||||
for sbox_xml in sbox_xmls:
|
for sbox_xml in sbox_xmls:
|
||||||
|
|
||||||
offset = int(sbox_xml.attrib["Offset"])
|
offset = int(sbox_xml.attrib["Offset"])
|
||||||
mapped_name = sbox_xml.get("MTB_PortName", None)
|
mapped_name = sbox_xml.get("MTB_PortName", None)
|
||||||
|
|
||||||
|
@ -841,7 +819,6 @@ def parse_clock_network(xml_clock_network):
|
||||||
# pin connection from the pinmap. This way the connections between
|
# pin connection from the pinmap. This way the connections between
|
||||||
# switchboxes which drive them can be used for generic routing.
|
# switchboxes which drive them can be used for generic routing.
|
||||||
for cell_name in clock_cells.keys():
|
for cell_name in clock_cells.keys():
|
||||||
|
|
||||||
cell = clock_cells[cell_name]
|
cell = clock_cells[cell_name]
|
||||||
pin_map = cell.pin_map
|
pin_map = cell.pin_map
|
||||||
|
|
||||||
|
@ -879,7 +856,6 @@ def populate_clk_mux_port_maps(port_maps, clock_cells, tile_grid, cells_library)
|
||||||
|
|
||||||
# Add map entries
|
# Add map entries
|
||||||
for mux_pin_name, sbox_pin_name in clock_cell.pin_map.items():
|
for mux_pin_name, sbox_pin_name in clock_cell.pin_map.items():
|
||||||
|
|
||||||
# Get the pin definition to get its driection.
|
# Get the pin definition to get its driection.
|
||||||
cell_pin = [p for p in cell_pins if p.name == mux_pin_name]
|
cell_pin = [p for p in cell_pins if p.name == mux_pin_name]
|
||||||
assert len(cell_pin) == 1, (clock_cell, mux_pin_name)
|
assert len(cell_pin) == 1, (clock_cell, mux_pin_name)
|
||||||
|
@ -905,7 +881,6 @@ def specialize_switchboxes_with_port_maps(switchbox_types, switchbox_grid, port_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for loc, port_map in port_maps.items():
|
for loc, port_map in port_maps.items():
|
||||||
|
|
||||||
# No switchbox at that location
|
# No switchbox at that location
|
||||||
if loc not in switchbox_grid:
|
if loc not in switchbox_grid:
|
||||||
continue
|
continue
|
||||||
|
@ -927,7 +902,6 @@ def specialize_switchboxes_with_port_maps(switchbox_types, switchbox_grid, port_
|
||||||
# Remap pin names
|
# Remap pin names
|
||||||
did_remap = False
|
did_remap = False
|
||||||
for stage, switch, mux in yield_muxes(new_switchbox):
|
for stage, switch, mux in yield_muxes(new_switchbox):
|
||||||
|
|
||||||
# Remap output
|
# Remap output
|
||||||
alt_name = "{}.{}.{}".format(stage.id, switch.id, mux.id)
|
alt_name = "{}.{}.{}".format(stage.id, switch.id, mux.id)
|
||||||
|
|
||||||
|
@ -973,7 +947,6 @@ def specialize_switchboxes_with_wire_maps(switchbox_types, switchbox_grid, port_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for loc, wire_map in wire_maps.items():
|
for loc, wire_map in wire_maps.items():
|
||||||
|
|
||||||
# No switchbox at that location
|
# No switchbox at that location
|
||||||
if loc not in switchbox_grid:
|
if loc not in switchbox_grid:
|
||||||
continue
|
continue
|
||||||
|
@ -995,7 +968,6 @@ def specialize_switchboxes_with_wire_maps(switchbox_types, switchbox_grid, port_
|
||||||
# Remap pin names
|
# Remap pin names
|
||||||
did_remap = False
|
did_remap = False
|
||||||
for pin_loc, (wire_name, map_loc) in wire_map.items():
|
for pin_loc, (wire_name, map_loc) in wire_map.items():
|
||||||
|
|
||||||
# Get port map at the destination location of the wire that is
|
# Get port map at the destination location of the wire that is
|
||||||
# being remapped.
|
# being remapped.
|
||||||
assert map_loc in port_maps, (map_loc, wire_name)
|
assert map_loc in port_maps, (map_loc, wire_name)
|
||||||
|
@ -1051,7 +1023,6 @@ def find_special_cells(tile_grid):
|
||||||
for loc, tile in tile_grid.items():
|
for loc, tile in tile_grid.items():
|
||||||
for cell_type, cell_names in tile.cell_names.items():
|
for cell_type, cell_names in tile.cell_names.items():
|
||||||
for (cell_name,) in cell_names:
|
for (cell_name,) in cell_names:
|
||||||
|
|
||||||
# Skip LOGIC as it is always contained in a single tile
|
# Skip LOGIC as it is always contained in a single tile
|
||||||
if cell_name == "LOGIC":
|
if cell_name == "LOGIC":
|
||||||
continue
|
continue
|
||||||
|
@ -1077,7 +1048,6 @@ def parse_pinmap(xml_root, tile_grid):
|
||||||
|
|
||||||
# Parse "PACKAGE" sections.
|
# Parse "PACKAGE" sections.
|
||||||
for xml_package in xml_root.findall("PACKAGE"):
|
for xml_package in xml_root.findall("PACKAGE"):
|
||||||
|
|
||||||
# Initialize map
|
# Initialize map
|
||||||
pkg_name = xml_package.attrib["name"]
|
pkg_name = xml_package.attrib["name"]
|
||||||
pkg_pin_map = defaultdict(lambda: set())
|
pkg_pin_map = defaultdict(lambda: set())
|
||||||
|
@ -1108,7 +1078,6 @@ def parse_pinmap(xml_root, tile_grid):
|
||||||
|
|
||||||
# Add the pin mapping
|
# Add the pin mapping
|
||||||
for cell_name, cell_loc in zip(cell_names, cell_locs):
|
for cell_name, cell_loc in zip(cell_names, cell_locs):
|
||||||
|
|
||||||
# Find the cell
|
# Find the cell
|
||||||
if cell_loc not in tile_grid:
|
if cell_loc not in tile_grid:
|
||||||
print("WARNING: No tile for package pin '{}' at '{}'".format(pin_name, cell_loc))
|
print("WARNING: No tile for package pin '{}' at '{}'".format(pin_name, cell_loc))
|
||||||
|
@ -1181,7 +1150,6 @@ def import_data(xml_root):
|
||||||
switchbox_grid = {}
|
switchbox_grid = {}
|
||||||
switchbox_types = {}
|
switchbox_types = {}
|
||||||
for xml_node in xml_routing:
|
for xml_node in xml_routing:
|
||||||
|
|
||||||
# Not a switchbox
|
# Not a switchbox
|
||||||
if not xml_node.tag.endswith("_SBOX"):
|
if not xml_node.tag.endswith("_SBOX"):
|
||||||
continue
|
continue
|
||||||
|
@ -1190,7 +1158,6 @@ def import_data(xml_root):
|
||||||
xml_common = xml_node.find("COMMON_STAGES")
|
xml_common = xml_node.find("COMMON_STAGES")
|
||||||
for xml_sbox in xml_node:
|
for xml_sbox in xml_node:
|
||||||
if xml_sbox != xml_common:
|
if xml_sbox != xml_common:
|
||||||
|
|
||||||
# Parse the switchbox definition
|
# Parse the switchbox definition
|
||||||
switchbox = parse_switchbox(xml_sbox, xml_common)
|
switchbox = parse_switchbox(xml_sbox, xml_common)
|
||||||
|
|
||||||
|
@ -1264,7 +1231,6 @@ def import_routing_timing(csv_file):
|
||||||
|
|
||||||
# Read and parse CSV
|
# Read and parse CSV
|
||||||
with open(csv_file, "r") as fp:
|
with open(csv_file, "r") as fp:
|
||||||
|
|
||||||
# Read the first line, it should specify timing units
|
# Read the first line, it should specify timing units
|
||||||
line = fp.readline()
|
line = fp.readline()
|
||||||
line = line.strip().split(",")
|
line = line.strip().split(",")
|
||||||
|
@ -1288,7 +1254,6 @@ def import_routing_timing(csv_file):
|
||||||
# Reformat
|
# Reformat
|
||||||
switchbox_timings = {}
|
switchbox_timings = {}
|
||||||
for timing in data:
|
for timing in data:
|
||||||
|
|
||||||
# Switchbox type
|
# Switchbox type
|
||||||
switchbox_type = timing["SBox_Type"]
|
switchbox_type = timing["SBox_Type"]
|
||||||
if switchbox_type not in switchbox_timings:
|
if switchbox_type not in switchbox_timings:
|
||||||
|
@ -1334,7 +1299,6 @@ def import_routing_timing(csv_file):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,6 @@ def main():
|
||||||
|
|
||||||
# Read the requested configurtion from a JSON file
|
# Read the requested configurtion from a JSON file
|
||||||
if args.json is not None:
|
if args.json is not None:
|
||||||
|
|
||||||
if args.pcf is not None or args.eblif is not None:
|
if args.pcf is not None or args.eblif is not None:
|
||||||
print("Use either '--json' or '--pcf' + '--eblif' options!")
|
print("Use either '--json' or '--pcf' + '--eblif' options!")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
@ -188,7 +187,6 @@ def main():
|
||||||
|
|
||||||
# Generate the config according to the EBLIF netlist and PCF constraints.
|
# Generate the config according to the EBLIF netlist and PCF constraints.
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if args.json is not None or (args.eblif is None or args.pcf is None):
|
if args.json is not None or (args.eblif is None or args.pcf is None):
|
||||||
print("Use either '--json' or '--pcf' + '--eblif' options!")
|
print("Use either '--json' or '--pcf' + '--eblif' options!")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
@ -197,7 +195,6 @@ def main():
|
||||||
pad_alias_map = {}
|
pad_alias_map = {}
|
||||||
|
|
||||||
for pin_map_entry in csv.DictReader(args.map):
|
for pin_map_entry in csv.DictReader(args.map):
|
||||||
|
|
||||||
if pin_map_entry["type"] not in IOB_TYPES:
|
if pin_map_entry["type"] not in IOB_TYPES:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -225,7 +222,6 @@ def main():
|
||||||
eblif_outputs = eblif["outputs"]["args"]
|
eblif_outputs = eblif["outputs"]["args"]
|
||||||
|
|
||||||
for constraint in pcf:
|
for constraint in pcf:
|
||||||
|
|
||||||
pad_name = constraint.pad
|
pad_name = constraint.pad
|
||||||
|
|
||||||
if pad_name not in pad_map and pad_name not in pad_alias_map:
|
if pad_name not in pad_map and pad_name not in pad_alias_map:
|
||||||
|
|
|
@ -516,7 +516,6 @@ class Fasm2Bels(object):
|
||||||
c for c in self.connections if c.src.type == ConnectionType.TILE and c.dst.type == ConnectionType.TILE
|
c for c in self.connections if c.src.type == ConnectionType.TILE and c.dst.type == ConnectionType.TILE
|
||||||
]
|
]
|
||||||
for connection in connections:
|
for connection in connections:
|
||||||
|
|
||||||
# Only to a GMUX at the given location
|
# Only to a GMUX at the given location
|
||||||
dst = connection.dst
|
dst = connection.dst
|
||||||
if dst.loc != loc or "GMUX" not in dst.pin:
|
if dst.loc != loc or "GMUX" not in dst.pin:
|
||||||
|
@ -567,7 +566,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
connections = [c for c in self.connections if c.dst.type == ConnectionType.CLOCK]
|
connections = [c for c in self.connections if c.dst.type == ConnectionType.CLOCK]
|
||||||
for connection in connections:
|
for connection in connections:
|
||||||
|
|
||||||
# Only to a QMUX at the given location
|
# Only to a QMUX at the given location
|
||||||
dst = connection.dst
|
dst = connection.dst
|
||||||
if dst.loc != loc or "QMUX" not in dst.pin:
|
if dst.loc != loc or "QMUX" not in dst.pin:
|
||||||
|
@ -605,7 +603,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# Make map entries
|
# Make map entries
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
|
|
||||||
# Calculate GMUX index for QCLKIN<i> input of the QMUX
|
# Calculate GMUX index for QCLKIN<i> input of the QMUX
|
||||||
idx = (gmux_idx + i) % 5
|
idx = (gmux_idx + i) % 5
|
||||||
|
|
||||||
|
@ -636,7 +633,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
connections = [c for c in self.connections if c.dst.type == ConnectionType.CLOCK]
|
connections = [c for c in self.connections if c.dst.type == ConnectionType.CLOCK]
|
||||||
for connection in connections:
|
for connection in connections:
|
||||||
|
|
||||||
# Only to a CAND at the given location
|
# Only to a CAND at the given location
|
||||||
# Note: Check also the row above. CAND cells are located in two
|
# Note: Check also the row above. CAND cells are located in two
|
||||||
# rows but with fasm features everything gets aligned to even rows
|
# rows but with fasm features everything gets aligned to even rows
|
||||||
|
@ -679,7 +675,6 @@ class Fasm2Bels(object):
|
||||||
gmux_map = dict()
|
gmux_map = dict()
|
||||||
gmux_locs = [loc for loc, tile in self.vpr_tile_grid.items() if "GMUX" in tile.type]
|
gmux_locs = [loc for loc, tile in self.vpr_tile_grid.items() if "GMUX" in tile.type]
|
||||||
for loc in gmux_locs:
|
for loc in gmux_locs:
|
||||||
|
|
||||||
# Group GMUX input pin connections by GMUX cell names
|
# Group GMUX input pin connections by GMUX cell names
|
||||||
gmux_connections = defaultdict(lambda: dict())
|
gmux_connections = defaultdict(lambda: dict())
|
||||||
for cell_pin, conn in self.designconnections[loc].items():
|
for cell_pin, conn in self.designconnections[loc].items():
|
||||||
|
@ -689,7 +684,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# Examine each GMUX config
|
# Examine each GMUX config
|
||||||
for gmux, connections in gmux_connections.items():
|
for gmux, connections in gmux_connections.items():
|
||||||
|
|
||||||
# FIXME: Handle IS0 inversion (if any)
|
# FIXME: Handle IS0 inversion (if any)
|
||||||
|
|
||||||
# The IS0 pin has to be routed
|
# The IS0 pin has to be routed
|
||||||
|
@ -707,7 +701,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# IP selected
|
# IP selected
|
||||||
if sel == 0:
|
if sel == 0:
|
||||||
|
|
||||||
# Create a global clock wire for the CLOCK pad
|
# Create a global clock wire for the CLOCK pad
|
||||||
match = re.match(r"GMUX(?P<idx>[0-9]+)", gmux)
|
match = re.match(r"GMUX(?P<idx>[0-9]+)", gmux)
|
||||||
assert match is not None, gmux
|
assert match is not None, gmux
|
||||||
|
@ -739,7 +732,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# IC selected
|
# IC selected
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Check if the IC pin has an active driver. If not then
|
# Check if the IC pin has an active driver. If not then
|
||||||
# discard the mux.
|
# discard the mux.
|
||||||
if connections.get("IC", (None, None))[1] in [None, "GND", "VCC"]:
|
if connections.get("IC", (None, None))[1] in [None, "GND", "VCC"]:
|
||||||
|
@ -776,7 +768,6 @@ class Fasm2Bels(object):
|
||||||
qmux_map = defaultdict(lambda: dict())
|
qmux_map = defaultdict(lambda: dict())
|
||||||
qmux_locs = [loc for loc, tile in self.vpr_tile_grid.items() if "QMUX" in tile.type]
|
qmux_locs = [loc for loc, tile in self.vpr_tile_grid.items() if "QMUX" in tile.type]
|
||||||
for loc in qmux_locs:
|
for loc in qmux_locs:
|
||||||
|
|
||||||
# Group QMUX input pin connections by QMUX cell names
|
# Group QMUX input pin connections by QMUX cell names
|
||||||
qmux_connections = defaultdict(lambda: dict())
|
qmux_connections = defaultdict(lambda: dict())
|
||||||
for cell_pin, conn in self.designconnections[loc].items():
|
for cell_pin, conn in self.designconnections[loc].items():
|
||||||
|
@ -786,7 +777,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# Examine each QMUX config
|
# Examine each QMUX config
|
||||||
for qmux, connections in qmux_connections.items():
|
for qmux, connections in qmux_connections.items():
|
||||||
|
|
||||||
# FIXME: Handle IS0 and IS1 inversion (if any)
|
# FIXME: Handle IS0 and IS1 inversion (if any)
|
||||||
|
|
||||||
# Both IS0 and IS1 must be routed to something
|
# Both IS0 and IS1 must be routed to something
|
||||||
|
@ -814,7 +804,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# Input from the routing network selected, create a new wire
|
# Input from the routing network selected, create a new wire
|
||||||
if sel == 3:
|
if sel == 3:
|
||||||
|
|
||||||
# Check if the HSCKIN input is connected to an active
|
# Check if the HSCKIN input is connected to an active
|
||||||
# driver. If not then discard the QMUX
|
# driver. If not then discard the QMUX
|
||||||
if connections.get("HSCKIN", (None, None))[1] in [None, "GND", "VCC"]:
|
if connections.get("HSCKIN", (None, None))[1] in [None, "GND", "VCC"]:
|
||||||
|
@ -832,7 +821,6 @@ class Fasm2Bels(object):
|
||||||
|
|
||||||
# Input from a GMUX is selected, assign its wire here
|
# Input from a GMUX is selected, assign its wire here
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# The GMUX is not active. Discard the QMUX
|
# The GMUX is not active. Discard the QMUX
|
||||||
gmux_loc, gmux_cell, gmux_pin = sel_map[sel]
|
gmux_loc, gmux_cell, gmux_pin = sel_map[sel]
|
||||||
if gmux_cell not in gmux_map:
|
if gmux_cell not in gmux_map:
|
||||||
|
@ -867,7 +855,6 @@ class Fasm2Bels(object):
|
||||||
# Process CAND
|
# Process CAND
|
||||||
for loc, all_features in self.colclk_data.items():
|
for loc, all_features in self.colclk_data.items():
|
||||||
for cand, features in all_features.items():
|
for cand, features in all_features.items():
|
||||||
|
|
||||||
hilojoint = False
|
hilojoint = False
|
||||||
enjoint = False
|
enjoint = False
|
||||||
|
|
||||||
|
@ -980,7 +967,6 @@ def parse_pcf(pcf):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,6 @@ def process_cells_library(cells_library):
|
||||||
vpr_cells_library = {}
|
vpr_cells_library = {}
|
||||||
|
|
||||||
for cell_type, cell in cells_library.items():
|
for cell_type, cell in cells_library.items():
|
||||||
|
|
||||||
# If the cell is a QMUX add the missing QCLKIN1 and QCLKIN2
|
# If the cell is a QMUX add the missing QCLKIN1 and QCLKIN2
|
||||||
# input pins.
|
# input pins.
|
||||||
if cell_type == "QMUX":
|
if cell_type == "QMUX":
|
||||||
|
@ -146,7 +145,6 @@ def fixup_cand_loc(vpr_loc, phy_loc):
|
||||||
|
|
||||||
|
|
||||||
def add_synthetic_cell_and_tile_types(tile_types, cells_library):
|
def add_synthetic_cell_and_tile_types(tile_types, cells_library):
|
||||||
|
|
||||||
# Add a synthetic tile types for the VCC and GND const sources.
|
# Add a synthetic tile types for the VCC and GND const sources.
|
||||||
# Models of the VCC and GND cells are already there in the cells_library.
|
# Models of the VCC and GND cells are already there in the cells_library.
|
||||||
for const in ["VCC", "GND"]:
|
for const in ["VCC", "GND"]:
|
||||||
|
@ -238,7 +236,6 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
|
|
||||||
# Generate the VPR tile grid
|
# Generate the VPR tile grid
|
||||||
for phy_loc, tile in tile_grid.items():
|
for phy_loc, tile in tile_grid.items():
|
||||||
|
|
||||||
# Limit the grid range
|
# Limit the grid range
|
||||||
if not is_loc_within_limit(phy_loc, grid_limit):
|
if not is_loc_within_limit(phy_loc, grid_limit):
|
||||||
continue
|
continue
|
||||||
|
@ -249,11 +246,9 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
# new tile type.
|
# new tile type.
|
||||||
tile_type = tile_types[tile.type]
|
tile_type = tile_types[tile.type]
|
||||||
if "QMUX" in tile_type.cells or "CAND" in tile_type.cells:
|
if "QMUX" in tile_type.cells or "CAND" in tile_type.cells:
|
||||||
|
|
||||||
# Store the stripped cells
|
# Store the stripped cells
|
||||||
for cell in tile.cells:
|
for cell in tile.cells:
|
||||||
if cell.type in ["QMUX", "CAND"]:
|
if cell.type in ["QMUX", "CAND"]:
|
||||||
|
|
||||||
# Find it in the physical clock cell list
|
# Find it in the physical clock cell list
|
||||||
if cell.name not in clock_cells:
|
if cell.name not in clock_cells:
|
||||||
print("WARNING: Clock cell '{}' not on the clock cell list!".format(cell.name))
|
print("WARNING: Clock cell '{}' not on the clock cell list!".format(cell.name))
|
||||||
|
@ -298,7 +293,6 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
# The tile contains a BIDIR or CLOCK cell. it is an IO tile
|
# The tile contains a BIDIR or CLOCK cell. it is an IO tile
|
||||||
tile_type = tile_types[tile.type]
|
tile_type = tile_types[tile.type]
|
||||||
if "BIDIR" in tile_type.cells or "CLOCK" in tile_type.cells:
|
if "BIDIR" in tile_type.cells or "CLOCK" in tile_type.cells:
|
||||||
|
|
||||||
# For the BIDIR cell create a synthetic tile
|
# For the BIDIR cell create a synthetic tile
|
||||||
if "BIDIR" in tile_type.cells:
|
if "BIDIR" in tile_type.cells:
|
||||||
assert tile_type.cells["BIDIR"] == 1
|
assert tile_type.cells["BIDIR"] == 1
|
||||||
|
@ -376,12 +370,10 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
|
|
||||||
# The tile contains SDIOMUX cell(s). This is an IO tile.
|
# The tile contains SDIOMUX cell(s). This is an IO tile.
|
||||||
if "SDIOMUX" in tile_type.cells:
|
if "SDIOMUX" in tile_type.cells:
|
||||||
|
|
||||||
# Split the tile into individual SDIOMUX cells. Each one will be
|
# Split the tile into individual SDIOMUX cells. Each one will be
|
||||||
# inside a synthetic tile occupying different grid location.
|
# inside a synthetic tile occupying different grid location.
|
||||||
cells = [c for c in tile.cells if c.type == "SDIOMUX"]
|
cells = [c for c in tile.cells if c.type == "SDIOMUX"]
|
||||||
for i, cell in enumerate(cells):
|
for i, cell in enumerate(cells):
|
||||||
|
|
||||||
# Create a synthetic tile that will hold just the SDIOMUX cell
|
# Create a synthetic tile that will hold just the SDIOMUX cell
|
||||||
new_type = make_tile_type([cell], cells_library, tile_types)
|
new_type = make_tile_type([cell], cells_library, tile_types)
|
||||||
|
|
||||||
|
@ -416,9 +408,7 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
|
|
||||||
# GMUX, split individual GMUX cells into sub-tiles
|
# GMUX, split individual GMUX cells into sub-tiles
|
||||||
elif cell_type == "GMUX":
|
elif cell_type == "GMUX":
|
||||||
|
|
||||||
for i, cell in enumerate(tile.cells):
|
for i, cell in enumerate(tile.cells):
|
||||||
|
|
||||||
# Create a tile type for a single GMUX cell
|
# Create a tile type for a single GMUX cell
|
||||||
new_type = make_tile_type([cell], cells_library, tile_types)
|
new_type = make_tile_type([cell], cells_library, tile_types)
|
||||||
# New location
|
# New location
|
||||||
|
@ -443,7 +433,6 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
# but in fact there is only one ASSP cell for the whole FPGA which is
|
# but in fact there is only one ASSP cell for the whole FPGA which is
|
||||||
# "distributed" along top and left edge of the grid.
|
# "distributed" along top and left edge of the grid.
|
||||||
if "ASSP" in tile_types:
|
if "ASSP" in tile_types:
|
||||||
|
|
||||||
# Verify that the location is empty
|
# Verify that the location is empty
|
||||||
assp_loc = Loc(x=1, y=1, z=0)
|
assp_loc = Loc(x=1, y=1, z=0)
|
||||||
assert is_loc_free(vpr_tile_grid, assp_loc), ("ASSP", assp_loc)
|
assert is_loc_free(vpr_tile_grid, assp_loc), ("ASSP", assp_loc)
|
||||||
|
@ -461,7 +450,6 @@ def process_tilegrid(tile_types, tile_grid, clock_cells, cells_library, grid_siz
|
||||||
# Insert synthetic VCC and GND source tiles.
|
# Insert synthetic VCC and GND source tiles.
|
||||||
# FIXME: This assumes that the locations specified are empty!
|
# FIXME: This assumes that the locations specified are empty!
|
||||||
for const, loc in [("VCC", Loc(x=2, y=1, z=0)), ("GND", Loc(x=3, y=1, z=0))]:
|
for const, loc in [("VCC", Loc(x=2, y=1, z=0)), ("GND", Loc(x=3, y=1, z=0))]:
|
||||||
|
|
||||||
# Verify that the location is empty
|
# Verify that the location is empty
|
||||||
assert is_loc_free(vpr_tile_grid, loc), (const, loc)
|
assert is_loc_free(vpr_tile_grid, loc), (const, loc)
|
||||||
|
|
||||||
|
@ -496,7 +484,6 @@ def process_switchbox_grid(phy_switchbox_grid, loc_map, grid_offset, grid_limit=
|
||||||
bwd_loc_map = loc_map.bwd
|
bwd_loc_map = loc_map.bwd
|
||||||
|
|
||||||
def add_loc_map(phy_loc, vpr_loc):
|
def add_loc_map(phy_loc, vpr_loc):
|
||||||
|
|
||||||
if phy_loc in fwd_loc_map:
|
if phy_loc in fwd_loc_map:
|
||||||
assert fwd_loc_map[phy_loc] == vpr_loc, (phy_loc, vpr_loc)
|
assert fwd_loc_map[phy_loc] == vpr_loc, (phy_loc, vpr_loc)
|
||||||
else:
|
else:
|
||||||
|
@ -510,7 +497,6 @@ def process_switchbox_grid(phy_switchbox_grid, loc_map, grid_offset, grid_limit=
|
||||||
# Remap locations
|
# Remap locations
|
||||||
vpr_switchbox_grid = {}
|
vpr_switchbox_grid = {}
|
||||||
for phy_loc, switchbox_type in phy_switchbox_grid.items():
|
for phy_loc, switchbox_type in phy_switchbox_grid.items():
|
||||||
|
|
||||||
# Limit the grid range
|
# Limit the grid range
|
||||||
if not is_loc_within_limit(phy_loc, grid_limit):
|
if not is_loc_within_limit(phy_loc, grid_limit):
|
||||||
continue
|
continue
|
||||||
|
@ -541,7 +527,6 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# Remap locations, create the VPR connection list
|
# Remap locations, create the VPR connection list
|
||||||
vpr_connections = []
|
vpr_connections = []
|
||||||
for connection in phy_connections:
|
for connection in phy_connections:
|
||||||
|
|
||||||
# Reject connections that reach outsite the grid limit
|
# Reject connections that reach outsite the grid limit
|
||||||
if not is_loc_within_limit(connection.src.loc, grid_limit):
|
if not is_loc_within_limit(connection.src.loc, grid_limit):
|
||||||
continue
|
continue
|
||||||
|
@ -563,7 +548,6 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# If the connection mentions a GMUX cell, remap its Z location so
|
# If the connection mentions a GMUX cell, remap its Z location so
|
||||||
# it points to the correct sub-tile
|
# it points to the correct sub-tile
|
||||||
if "GMUX" in ep.pin and ep.type == ConnectionType.TILE:
|
if "GMUX" in ep.pin and ep.type == ConnectionType.TILE:
|
||||||
|
|
||||||
# Modify the cell name, use always "GMUX0"
|
# Modify the cell name, use always "GMUX0"
|
||||||
cell, pin = ep.pin.split("_", maxsplit=1)
|
cell, pin = ep.pin.split("_", maxsplit=1)
|
||||||
vpr_pin = "GMUX0_{}".format(pin)
|
vpr_pin = "GMUX0_{}".format(pin)
|
||||||
|
@ -581,10 +565,8 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# Remap locations of connections that go to CLOCK pads. A physical
|
# Remap locations of connections that go to CLOCK pads. A physical
|
||||||
# BIDIR+CLOCK tile is split into separate BIDIR and CLOCK tiles.
|
# BIDIR+CLOCK tile is split into separate BIDIR and CLOCK tiles.
|
||||||
for i, connection in enumerate(vpr_connections):
|
for i, connection in enumerate(vpr_connections):
|
||||||
|
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for j, ep in enumerate(eps):
|
for j, ep in enumerate(eps):
|
||||||
|
|
||||||
# This endpoint is not relevant to a CLOCK cell
|
# This endpoint is not relevant to a CLOCK cell
|
||||||
if not ep.pin.startswith("CLOCK"):
|
if not ep.pin.startswith("CLOCK"):
|
||||||
continue
|
continue
|
||||||
|
@ -619,10 +601,8 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, connection in enumerate(vpr_connections):
|
for i, connection in enumerate(vpr_connections):
|
||||||
|
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for j, ep in enumerate(eps):
|
for j, ep in enumerate(eps):
|
||||||
|
|
||||||
# Must have "ASSP" and "FBIO_" in name and refer to a tile.
|
# Must have "ASSP" and "FBIO_" in name and refer to a tile.
|
||||||
if "ASSP" not in ep.pin:
|
if "ASSP" not in ep.pin:
|
||||||
continue
|
continue
|
||||||
|
@ -666,11 +646,9 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
|
|
||||||
# Map connections going to/from them to their locations in the VPR grid
|
# Map connections going to/from them to their locations in the VPR grid
|
||||||
for i, connection in enumerate(vpr_connections):
|
for i, connection in enumerate(vpr_connections):
|
||||||
|
|
||||||
# Process connection endpoints
|
# Process connection endpoints
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for j, ep in enumerate(eps):
|
for j, ep in enumerate(eps):
|
||||||
|
|
||||||
if ep.type != ConnectionType.TILE:
|
if ep.type != ConnectionType.TILE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -707,7 +685,6 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# Process connection endpoints
|
# Process connection endpoints
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for j, ep in enumerate(eps):
|
for j, ep in enumerate(eps):
|
||||||
|
|
||||||
if ep.type != ConnectionType.TILE:
|
if ep.type != ConnectionType.TILE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -744,7 +721,6 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# "QCLKIN1=GMUX_2" etc.
|
# "QCLKIN1=GMUX_2" etc.
|
||||||
new_qmux_connections = []
|
new_qmux_connections = []
|
||||||
for connection in vpr_connections:
|
for connection in vpr_connections:
|
||||||
|
|
||||||
# Get only those that target QCLKIN0 of a QMUX.
|
# Get only those that target QCLKIN0 of a QMUX.
|
||||||
if connection.dst.type != ConnectionType.CLOCK:
|
if connection.dst.type != ConnectionType.CLOCK:
|
||||||
continue
|
continue
|
||||||
|
@ -784,11 +760,9 @@ def process_connections(phy_connections, loc_map, vpr_tile_grid, phy_tile_grid,
|
||||||
# Handle QMUX connections. Instead of making them SWITCHBOX -> TILE convert
|
# Handle QMUX connections. Instead of making them SWITCHBOX -> TILE convert
|
||||||
# to SWITCHBOX -> CLOCK
|
# to SWITCHBOX -> CLOCK
|
||||||
for i, connection in enumerate(vpr_connections):
|
for i, connection in enumerate(vpr_connections):
|
||||||
|
|
||||||
# Process connection endpoints
|
# Process connection endpoints
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for j, ep in enumerate(eps):
|
for j, ep in enumerate(eps):
|
||||||
|
|
||||||
if ep.type != ConnectionType.TILE:
|
if ep.type != ConnectionType.TILE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -839,7 +813,6 @@ def process_package_pinmap(package_pinmap, vpr_tile_grid, grid_limit=None):
|
||||||
|
|
||||||
for pin_name, pins in package_pinmap.items():
|
for pin_name, pins in package_pinmap.items():
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
|
||||||
# The loc is outside the grid limit, skip it.
|
# The loc is outside the grid limit, skip it.
|
||||||
if not is_loc_within_limit(pin.loc, grid_limit):
|
if not is_loc_within_limit(pin.loc, grid_limit):
|
||||||
continue
|
continue
|
||||||
|
@ -993,7 +966,6 @@ def load_sdf_timings(sdf_dir):
|
||||||
for timing, timing_data in instance_data.items():
|
for timing, timing_data in instance_data.items():
|
||||||
paths = timing_data["delay_paths"]
|
paths = timing_data["delay_paths"]
|
||||||
for path_name, path_data in paths.items():
|
for path_name, path_data in paths.items():
|
||||||
|
|
||||||
for k in path_data.keys():
|
for k in path_data.keys():
|
||||||
if path_data[k] is not None:
|
if path_data[k] is not None:
|
||||||
path_data[k] *= scale
|
path_data[k] *= scale
|
||||||
|
@ -1033,7 +1005,6 @@ def load_sdf_timings(sdf_dir):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
@ -1144,7 +1115,6 @@ def main():
|
||||||
print("Processing timing data...")
|
print("Processing timing data...")
|
||||||
|
|
||||||
if switchbox_timing is not None:
|
if switchbox_timing is not None:
|
||||||
|
|
||||||
# The timing data seems to be the same for each switchbox type and is
|
# The timing data seems to be the same for each switchbox type and is
|
||||||
# stored under the SB_LC name.
|
# stored under the SB_LC name.
|
||||||
timing_data = switchbox_timing["SB_LC"]
|
timing_data = switchbox_timing["SB_LC"]
|
||||||
|
@ -1163,7 +1133,6 @@ def main():
|
||||||
copy_switchbox_timing(switchbox, dst_switchbox)
|
copy_switchbox_timing(switchbox, dst_switchbox)
|
||||||
|
|
||||||
if cell_timings is not None:
|
if cell_timings is not None:
|
||||||
|
|
||||||
sw = add_vpr_switches_for_cell("QMUX", cell_timings)
|
sw = add_vpr_switches_for_cell("QMUX", cell_timings)
|
||||||
vpr_switches.update(sw)
|
vpr_switches.update(sw)
|
||||||
|
|
||||||
|
@ -1196,7 +1165,6 @@ def main():
|
||||||
for y in range(ymax + 1):
|
for y in range(ymax + 1):
|
||||||
line = " {:>2}: ".format(y)
|
line = " {:>2}: ".format(y)
|
||||||
for x in range(xmax + 1):
|
for x in range(xmax + 1):
|
||||||
|
|
||||||
tiles = {loc: tile for loc, tile in vpr_tile_grid.items() if loc.x == x and loc.y == y}
|
tiles = {loc: tile for loc, tile in vpr_tile_grid.items() if loc.x == x and loc.y == y}
|
||||||
count = len([t for t in tiles.values() if t is not None])
|
count = len([t for t in tiles.values() if t is not None])
|
||||||
|
|
||||||
|
|
|
@ -97,20 +97,17 @@ def is_local(connection):
|
||||||
|
|
||||||
|
|
||||||
def get_vpr_switch_for_clock_cell(graph, cell, src, dst):
|
def get_vpr_switch_for_clock_cell(graph, cell, src, dst):
|
||||||
|
|
||||||
# Get a switch to model the mux delay properly. First try using
|
# Get a switch to model the mux delay properly. First try using
|
||||||
# the cell name
|
# the cell name
|
||||||
try:
|
try:
|
||||||
switch_name = "{}.{}.{}.{}".format(cell.type, cell.name, src, dst)
|
switch_name = "{}.{}.{}.{}".format(cell.type, cell.name, src, dst)
|
||||||
switch_id = graph.get_switch_id(switch_name)
|
switch_id = graph.get_switch_id(switch_name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
||||||
# Not found, try using the cell type
|
# Not found, try using the cell type
|
||||||
try:
|
try:
|
||||||
switch_name = "{}.{}.{}.{}".format(cell.type, cell.type, src, dst)
|
switch_name = "{}.{}.{}.{}".format(cell.type, cell.type, src, dst)
|
||||||
switch_id = graph.get_switch_id(switch_name)
|
switch_id = graph.get_switch_id(switch_name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
||||||
# Still not found, use the generic one
|
# Still not found, use the generic one
|
||||||
switch_id = graph.get_switch_id("generic")
|
switch_id = graph.get_switch_id("generic")
|
||||||
|
|
||||||
|
@ -256,10 +253,8 @@ class QmuxModel(object):
|
||||||
|
|
||||||
# Collect features
|
# Collect features
|
||||||
for pin, net in pins.items():
|
for pin, net in pins.items():
|
||||||
|
|
||||||
# Get switchbox routing features (already prefixed)
|
# Get switchbox routing features (already prefixed)
|
||||||
for muxsel in self.ctrl_routes[pin][net]:
|
for muxsel in self.ctrl_routes[pin][net]:
|
||||||
|
|
||||||
stage_id, switch_id, mux_id, pin_id = muxsel
|
stage_id, switch_id, mux_id, pin_id = muxsel
|
||||||
stage = self.switchbox_model.switchbox.stages[stage_id]
|
stage = self.switchbox_model.switchbox.stages[stage_id]
|
||||||
|
|
||||||
|
@ -309,7 +304,6 @@ class CandModel(object):
|
||||||
self._build()
|
self._build()
|
||||||
|
|
||||||
def _build(self):
|
def _build(self):
|
||||||
|
|
||||||
# Get segment id
|
# Get segment id
|
||||||
segment_id = self.graph.get_segment_id_from_name("clock")
|
segment_id = self.graph.get_segment_id_from_name("clock")
|
||||||
|
|
||||||
|
@ -430,7 +424,6 @@ def build_tile_pin_to_node_map(graph, nodes_by_id, tile_types, tile_grid):
|
||||||
|
|
||||||
# For each pin of the tile
|
# For each pin of the tile
|
||||||
for pin in tile_types[tile.type].pins:
|
for pin in tile_types[tile.type].pins:
|
||||||
|
|
||||||
node_id = get_node_id_for_tile_pin(graph, loc, tile.type, pin.name)
|
node_id = get_node_id_for_tile_pin(graph, loc, tile.type, pin.name)
|
||||||
if node_id is None:
|
if node_id is None:
|
||||||
print("WARNING: No node for pin '{}' at {}".format(pin.name, loc))
|
print("WARNING: No node for pin '{}' at {}".format(pin.name, loc))
|
||||||
|
@ -452,7 +445,6 @@ def build_tile_connection_map(graph, nodes_by_id, tile_grid, connections):
|
||||||
|
|
||||||
# Adds entry to the map
|
# Adds entry to the map
|
||||||
def add_to_map(conn_loc):
|
def add_to_map(conn_loc):
|
||||||
|
|
||||||
tile = tile_grid.get(conn_loc.loc, None)
|
tile = tile_grid.get(conn_loc.loc, None)
|
||||||
if tile is None:
|
if tile is None:
|
||||||
print("WARNING: No tile for pin '{} at {}".format(conn_loc.pin, conn_loc.loc))
|
print("WARNING: No tile for pin '{} at {}".format(conn_loc.pin, conn_loc.loc))
|
||||||
|
@ -578,7 +570,6 @@ def add_track_chain(graph, direction, u, v0, v1, segment_id, switch_id):
|
||||||
|
|
||||||
# Add track chain
|
# Add track chain
|
||||||
for v in coords:
|
for v in coords:
|
||||||
|
|
||||||
# Add track (node)
|
# Add track (node)
|
||||||
if direction == "X":
|
if direction == "X":
|
||||||
track = tracks.Track(
|
track = tracks.Track(
|
||||||
|
@ -665,7 +656,6 @@ def add_tracks_for_const_network(graph, const, tile_grid):
|
||||||
# For each column add one that spand over the entire grid height
|
# For each column add one that spand over the entire grid height
|
||||||
const_node_map = {}
|
const_node_map = {}
|
||||||
for x in range(xmin, xmax):
|
for x in range(xmin, xmax):
|
||||||
|
|
||||||
# Add the column
|
# Add the column
|
||||||
col_entry_node, _, col_node_map = add_track_chain(graph, "Y", x, ymin + 1, ymax - 1, segment_id, switch_id)
|
col_entry_node, _, col_node_map = add_track_chain(graph, "Y", x, ymin + 1, ymax - 1, segment_id, switch_id)
|
||||||
|
|
||||||
|
@ -725,7 +715,6 @@ def populate_hop_connections(graph, switchbox_models, connections):
|
||||||
bar = progressbar_utils.progressbar
|
bar = progressbar_utils.progressbar
|
||||||
conns = [c for c in connections if is_hop(c)]
|
conns = [c for c in connections if is_hop(c)]
|
||||||
for connection in bar(conns):
|
for connection in bar(conns):
|
||||||
|
|
||||||
# Get switchbox models
|
# Get switchbox models
|
||||||
src_switchbox_model = switchbox_models[connection.src.loc]
|
src_switchbox_model = switchbox_models[connection.src.loc]
|
||||||
dst_switchbox_model = switchbox_models[connection.dst.loc]
|
dst_switchbox_model = switchbox_models[connection.dst.loc]
|
||||||
|
@ -756,7 +745,6 @@ def populate_tile_connections(graph, switchbox_models, connections, connection_l
|
||||||
bar = progressbar_utils.progressbar
|
bar = progressbar_utils.progressbar
|
||||||
conns = [c for c in connections if is_tile(c)]
|
conns = [c for c in connections if is_tile(c)]
|
||||||
for connection in bar(conns):
|
for connection in bar(conns):
|
||||||
|
|
||||||
# Connection to/from the local tile
|
# Connection to/from the local tile
|
||||||
if is_local(connection):
|
if is_local(connection):
|
||||||
loc = connection.src.loc
|
loc = connection.src.loc
|
||||||
|
@ -798,7 +786,6 @@ def populate_tile_connections(graph, switchbox_models, connections, connection_l
|
||||||
|
|
||||||
# Connection to/from a foreign tile
|
# Connection to/from a foreign tile
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Get segment id and switch id
|
# Get segment id and switch id
|
||||||
segment_id = graph.get_segment_id_from_name("special")
|
segment_id = graph.get_segment_id_from_name("special")
|
||||||
switch_id = graph.get_delayless_switch_id()
|
switch_id = graph.get_delayless_switch_id()
|
||||||
|
@ -817,10 +804,8 @@ def populate_tile_connections(graph, switchbox_models, connections, connection_l
|
||||||
# Connect the track
|
# Connect the track
|
||||||
eps = [connection.src, connection.dst]
|
eps = [connection.src, connection.dst]
|
||||||
for i, ep in enumerate(eps):
|
for i, ep in enumerate(eps):
|
||||||
|
|
||||||
# Endpoint at tile
|
# Endpoint at tile
|
||||||
if ep.type == ConnectionType.TILE:
|
if ep.type == ConnectionType.TILE:
|
||||||
|
|
||||||
# To tile
|
# To tile
|
||||||
if ep == connection.dst:
|
if ep == connection.dst:
|
||||||
if ep not in connection_loc_to_node:
|
if ep not in connection_loc_to_node:
|
||||||
|
@ -841,7 +826,6 @@ def populate_tile_connections(graph, switchbox_models, connections, connection_l
|
||||||
|
|
||||||
# Endpoint at switchbox
|
# Endpoint at switchbox
|
||||||
elif ep.type == ConnectionType.SWITCHBOX:
|
elif ep.type == ConnectionType.SWITCHBOX:
|
||||||
|
|
||||||
# No switchbox model at the loc, skip.
|
# No switchbox model at the loc, skip.
|
||||||
if ep.loc not in switchbox_models:
|
if ep.loc not in switchbox_models:
|
||||||
continue
|
continue
|
||||||
|
@ -875,7 +859,6 @@ def populate_direct_connections(graph, connections, connection_loc_to_node):
|
||||||
bar = progressbar_utils.progressbar
|
bar = progressbar_utils.progressbar
|
||||||
conns = [c for c in connections if is_direct(c)]
|
conns = [c for c in connections if is_direct(c)]
|
||||||
for connection in bar(conns):
|
for connection in bar(conns):
|
||||||
|
|
||||||
# Get segment id and switch id
|
# Get segment id and switch id
|
||||||
if connection.src.pin.startswith("CLOCK"):
|
if connection.src.pin.startswith("CLOCK"):
|
||||||
switch_id = graph.get_delayless_switch_id()
|
switch_id = graph.get_delayless_switch_id()
|
||||||
|
@ -913,10 +896,8 @@ def populate_const_connections(graph, switchbox_models, tile_types, tile_grid, t
|
||||||
|
|
||||||
# Connect the global const network to switchbox inputs
|
# Connect the global const network to switchbox inputs
|
||||||
for loc, switchbox_model in bar(switchbox_models.items()):
|
for loc, switchbox_model in bar(switchbox_models.items()):
|
||||||
|
|
||||||
# Look for input connected to a const
|
# Look for input connected to a const
|
||||||
for pin in switchbox_model.switchbox.inputs.values():
|
for pin in switchbox_model.switchbox.inputs.values():
|
||||||
|
|
||||||
# Got a const input
|
# Got a const input
|
||||||
if pin.name in const_node_map:
|
if pin.name in const_node_map:
|
||||||
const_node = const_node_map[pin.name][loc]
|
const_node = const_node_map[pin.name][loc]
|
||||||
|
@ -956,10 +937,8 @@ def populate_cand_connections(graph, switchbox_models, cand_node_map):
|
||||||
|
|
||||||
bar = progressbar_utils.progressbar
|
bar = progressbar_utils.progressbar
|
||||||
for loc, switchbox_model in bar(switchbox_models.items()):
|
for loc, switchbox_model in bar(switchbox_models.items()):
|
||||||
|
|
||||||
# Look for input connected to a CAND
|
# Look for input connected to a CAND
|
||||||
for pin in switchbox_model.switchbox.inputs.values():
|
for pin in switchbox_model.switchbox.inputs.values():
|
||||||
|
|
||||||
# Got a CAND input
|
# Got a CAND input
|
||||||
if pin.name in cand_node_map:
|
if pin.name in cand_node_map:
|
||||||
cand_node = cand_node_map[pin.name][loc]
|
cand_node = cand_node_map[pin.name][loc]
|
||||||
|
@ -994,7 +973,6 @@ def create_quadrant_clock_tracks(graph, connections, connection_loc_to_node):
|
||||||
bar = progressbar_utils.progressbar
|
bar = progressbar_utils.progressbar
|
||||||
conns = [c for c in connections if is_clock(c)]
|
conns = [c for c in connections if is_clock(c)]
|
||||||
for connection in bar(conns):
|
for connection in bar(conns):
|
||||||
|
|
||||||
# Source is a tile
|
# Source is a tile
|
||||||
if connection.src.type == ConnectionType.TILE:
|
if connection.src.type == ConnectionType.TILE:
|
||||||
src_node = connection_loc_to_node.get(connection.src, None)
|
src_node = connection_loc_to_node.get(connection.src, None)
|
||||||
|
@ -1093,7 +1071,6 @@ def create_column_clock_tracks(graph, clock_cells, quadrants):
|
||||||
cand_node_map = {}
|
cand_node_map = {}
|
||||||
|
|
||||||
for cell in clock_cells.values():
|
for cell in clock_cells.values():
|
||||||
|
|
||||||
# A clock column is defined by a CAND cell
|
# A clock column is defined by a CAND cell
|
||||||
if cell.type != "CAND":
|
if cell.type != "CAND":
|
||||||
continue
|
continue
|
||||||
|
@ -1146,7 +1123,6 @@ def yield_edges(edges):
|
||||||
|
|
||||||
# Process edges
|
# Process edges
|
||||||
for edge in edges:
|
for edge in edges:
|
||||||
|
|
||||||
# Reformat metadata
|
# Reformat metadata
|
||||||
if edge.metadata:
|
if edge.metadata:
|
||||||
metadata = [(meta.name, meta.value) for meta in edge.metadata]
|
metadata = [(meta.name, meta.value) for meta in edge.metadata]
|
||||||
|
@ -1172,7 +1148,6 @@ def yield_edges(edges):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ def add_edge(graph, src_node_id, dst_node_id, switch_id, meta_name=None, meta_va
|
||||||
# in the opposite way.
|
# in the opposite way.
|
||||||
switch = graph.switch_map[switch_id]
|
switch = graph.switch_map[switch_id]
|
||||||
if switch.type in [rr.SwitchType.SHORT, rr.SwitchType.PASS_GATE]:
|
if switch.type in [rr.SwitchType.SHORT, rr.SwitchType.PASS_GATE]:
|
||||||
|
|
||||||
graph.add_edge(dst_node_id, src_node_id, switch_id, meta_name, meta_value)
|
graph.add_edge(dst_node_id, src_node_id, switch_id, meta_name, meta_value)
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,7 +154,6 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
chany_to_chany = src_node.type == rr.NodeType.CHANY and dst_node.type == rr.NodeType.CHANY
|
chany_to_chany = src_node.type == rr.NodeType.CHANY and dst_node.type == rr.NodeType.CHANY
|
||||||
chanx_to_chanx = src_node.type == rr.NodeType.CHANX and dst_node.type == rr.NodeType.CHANX
|
chanx_to_chanx = src_node.type == rr.NodeType.CHANX and dst_node.type == rr.NodeType.CHANX
|
||||||
if chany_to_chanx or chanx_to_chany:
|
if chany_to_chanx or chanx_to_chany:
|
||||||
|
|
||||||
# Check loc
|
# Check loc
|
||||||
node_joint_location(src_node, dst_node)
|
node_joint_location(src_node, dst_node)
|
||||||
|
|
||||||
|
@ -164,7 +162,6 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
|
|
||||||
# CHANX to CHANX or CHANY to CHANY
|
# CHANX to CHANX or CHANY to CHANY
|
||||||
elif chany_to_chany or chanx_to_chanx:
|
elif chany_to_chany or chanx_to_chanx:
|
||||||
|
|
||||||
loc = node_joint_location(src_node, dst_node)
|
loc = node_joint_location(src_node, dst_node)
|
||||||
direction = "X" if src_node.type == rr.NodeType.CHANY else "Y"
|
direction = "X" if src_node.type == rr.NodeType.CHANY else "Y"
|
||||||
|
|
||||||
|
@ -178,13 +175,11 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
|
|
||||||
# OPIN to CHANX/CHANY
|
# OPIN to CHANX/CHANY
|
||||||
elif src_node.type == rr.NodeType.OPIN and dst_node.type in [rr.NodeType.CHANX, rr.NodeType.CHANY]:
|
elif src_node.type == rr.NodeType.OPIN and dst_node.type in [rr.NodeType.CHANX, rr.NodeType.CHANY]:
|
||||||
|
|
||||||
# All OPINs go right (towards +X)
|
# All OPINs go right (towards +X)
|
||||||
assert src_node.loc.side == tracks.Direction.RIGHT, src_node
|
assert src_node.loc.side == tracks.Direction.RIGHT, src_node
|
||||||
|
|
||||||
# Connected to CHANX
|
# Connected to CHANX
|
||||||
if dst_node.type == rr.NodeType.CHANX:
|
if dst_node.type == rr.NodeType.CHANX:
|
||||||
|
|
||||||
loc = node_joint_location(src_node, dst_node)
|
loc = node_joint_location(src_node, dst_node)
|
||||||
|
|
||||||
# Padding node
|
# Padding node
|
||||||
|
@ -197,7 +192,6 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
|
|
||||||
# Connected to CHANY
|
# Connected to CHANY
|
||||||
elif dst_node.type == rr.NodeType.CHANY:
|
elif dst_node.type == rr.NodeType.CHANY:
|
||||||
|
|
||||||
# Directly
|
# Directly
|
||||||
add_edge(graph, src_node.id, dst_node.id, switch_id, meta_name, meta_value)
|
add_edge(graph, src_node.id, dst_node.id, switch_id, meta_name, meta_value)
|
||||||
|
|
||||||
|
@ -207,13 +201,11 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
|
|
||||||
# CHANX/CHANY to IPIN
|
# CHANX/CHANY to IPIN
|
||||||
elif dst_node.type == rr.NodeType.IPIN and src_node.type in [rr.NodeType.CHANX, rr.NodeType.CHANY]:
|
elif dst_node.type == rr.NodeType.IPIN and src_node.type in [rr.NodeType.CHANX, rr.NodeType.CHANY]:
|
||||||
|
|
||||||
# All IPINs go top (toward +Y)
|
# All IPINs go top (toward +Y)
|
||||||
assert dst_node.loc.side == tracks.Direction.TOP, dst_node
|
assert dst_node.loc.side == tracks.Direction.TOP, dst_node
|
||||||
|
|
||||||
# Connected to CHANY
|
# Connected to CHANY
|
||||||
if src_node.type == rr.NodeType.CHANY:
|
if src_node.type == rr.NodeType.CHANY:
|
||||||
|
|
||||||
loc = node_joint_location(src_node, dst_node)
|
loc = node_joint_location(src_node, dst_node)
|
||||||
|
|
||||||
# Padding node
|
# Padding node
|
||||||
|
@ -226,7 +218,6 @@ def connect(graph, src_node, dst_node, switch_id=None, segment_id=None, meta_nam
|
||||||
|
|
||||||
# Connected to CHANX
|
# Connected to CHANX
|
||||||
elif src_node.type == rr.NodeType.CHANX:
|
elif src_node.type == rr.NodeType.CHANX:
|
||||||
|
|
||||||
# Directly
|
# Directly
|
||||||
add_edge(graph, src_node.id, dst_node.id, switch_id, meta_name, meta_value)
|
add_edge(graph, src_node.id, dst_node.id, switch_id, meta_name, meta_value)
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,6 @@ class SwitchboxModel(object):
|
||||||
|
|
||||||
# Expand all its inputs
|
# Expand all its inputs
|
||||||
for pin_id, pin in mux.inputs.items():
|
for pin_id, pin in mux.inputs.items():
|
||||||
|
|
||||||
# An input goes to another mux, expand it
|
# An input goes to another mux, expand it
|
||||||
if pin.name is None and pin_id in connections:
|
if pin.name is None and pin_id in connections:
|
||||||
connection = connections[pin_id]
|
connection = connections[pin_id]
|
||||||
|
@ -165,10 +164,8 @@ class SwitchboxModel(object):
|
||||||
|
|
||||||
# This is a switchbox input
|
# This is a switchbox input
|
||||||
elif pin.name is not None:
|
elif pin.name is not None:
|
||||||
|
|
||||||
# We've hit the target
|
# We've hit the target
|
||||||
if pin.name == target_name:
|
if pin.name == target_name:
|
||||||
|
|
||||||
# Append the current mux and its selection
|
# Append the current mux and its selection
|
||||||
final_route = list(route)
|
final_route = list(route)
|
||||||
final_route[-1] = tuple(list(final_route[-1]) + [pin_id])
|
final_route[-1] = tuple(list(final_route[-1]) + [pin_id])
|
||||||
|
@ -268,7 +265,6 @@ class SwitchboxModel(object):
|
||||||
|
|
||||||
# Input nodes + mux edges
|
# Input nodes + mux edges
|
||||||
for pin in mux.inputs.values():
|
for pin in mux.inputs.values():
|
||||||
|
|
||||||
key = (stage.id, switch.id, mux.id, pin.id)
|
key = (stage.id, switch.id, mux.id, pin.id)
|
||||||
assert key not in self.mux_input_to_node
|
assert key not in self.mux_input_to_node
|
||||||
|
|
||||||
|
@ -347,7 +343,6 @@ class SwitchboxModel(object):
|
||||||
|
|
||||||
for pin in self.switchbox.inputs.values():
|
for pin in self.switchbox.inputs.values():
|
||||||
for loc in pin.locs:
|
for loc in pin.locs:
|
||||||
|
|
||||||
stage = self.switchbox.stages[loc.stage_id]
|
stage = self.switchbox.stages[loc.stage_id]
|
||||||
switch = stage.switches[loc.switch_id]
|
switch = stage.switches[loc.switch_id]
|
||||||
mux = switch.muxes[loc.mux_id]
|
mux = switch.muxes[loc.mux_id]
|
||||||
|
@ -365,7 +360,6 @@ class SwitchboxModel(object):
|
||||||
segment_id = self.graph.get_segment_id_from_name("sbox")
|
segment_id = self.graph.get_segment_id_from_name("sbox")
|
||||||
|
|
||||||
for pin in self.switchbox.inputs.values():
|
for pin in self.switchbox.inputs.values():
|
||||||
|
|
||||||
node = add_node(self.graph, self.loc, "Y", segment_id)
|
node = add_node(self.graph, self.loc, "Y", segment_id)
|
||||||
|
|
||||||
assert pin.name not in self.input_to_node, pin.name
|
assert pin.name not in self.input_to_node, pin.name
|
||||||
|
@ -373,7 +367,6 @@ class SwitchboxModel(object):
|
||||||
|
|
||||||
# Create driver nodes, connect everything
|
# Create driver nodes, connect everything
|
||||||
for (pin_name, vpr_switch), locs in driver_map.items():
|
for (pin_name, vpr_switch), locs in driver_map.items():
|
||||||
|
|
||||||
# Create the driver node
|
# Create the driver node
|
||||||
drv_node = add_node(self.graph, self.loc, "X", segment_id)
|
drv_node = add_node(self.graph, self.loc, "X", segment_id)
|
||||||
|
|
||||||
|
@ -394,7 +387,6 @@ class SwitchboxModel(object):
|
||||||
# Now connect the driver node with its loads
|
# Now connect the driver node with its loads
|
||||||
switch_id = self.graph.get_switch_id("short")
|
switch_id = self.graph.get_switch_id("short")
|
||||||
for loc in locs:
|
for loc in locs:
|
||||||
|
|
||||||
key = (loc.stage_id, loc.switch_id, loc.mux_id, loc.pin_id)
|
key = (loc.stage_id, loc.switch_id, loc.mux_id, loc.pin_id)
|
||||||
dst_node = self.mux_input_to_node[key]
|
dst_node = self.mux_input_to_node[key]
|
||||||
|
|
||||||
|
@ -411,7 +403,6 @@ class SwitchboxModel(object):
|
||||||
# to the rr graph. For now if there is any fixed mux, remove the
|
# to the rr graph. For now if there is any fixed mux, remove the
|
||||||
# whole switchbox.
|
# whole switchbox.
|
||||||
if len(self.fixed_muxsels):
|
if len(self.fixed_muxsels):
|
||||||
|
|
||||||
# A list of muxes to avoid
|
# A list of muxes to avoid
|
||||||
self.fixed_muxes = set([f[:3] for f in self.fixed_muxsels])
|
self.fixed_muxes = set([f[:3] for f in self.fixed_muxsels])
|
||||||
|
|
||||||
|
@ -476,7 +467,6 @@ class QmuxSwitchboxModel(SwitchboxModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
for cell in self.qmux_cells.values():
|
for cell in self.qmux_cells.values():
|
||||||
|
|
||||||
# Get IS0 and IS1 connection endpoints
|
# Get IS0 and IS1 connection endpoints
|
||||||
eps = {}
|
eps = {}
|
||||||
for connection in self.connections:
|
for connection in self.connections:
|
||||||
|
@ -489,7 +479,6 @@ class QmuxSwitchboxModel(SwitchboxModel):
|
||||||
# Find all routes for IS0 and IS1 pins that go to GND and VCC
|
# Find all routes for IS0 and IS1 pins that go to GND and VCC
|
||||||
routes = {}
|
routes = {}
|
||||||
for pin in PINS:
|
for pin in PINS:
|
||||||
|
|
||||||
# Find the routes
|
# Find the routes
|
||||||
vcc_routes = self.get_switchbox_routes(self.switchbox, eps[pin].pin, "VCC")
|
vcc_routes = self.get_switchbox_routes(self.switchbox, eps[pin].pin, "VCC")
|
||||||
gnd_routes = self.get_switchbox_routes(self.switchbox, eps[pin].pin, "GND")
|
gnd_routes = self.get_switchbox_routes(self.switchbox, eps[pin].pin, "GND")
|
||||||
|
@ -512,10 +501,8 @@ class QmuxSwitchboxModel(SwitchboxModel):
|
||||||
for cell_name, cell_routes in self.ctrl_routes.items():
|
for cell_name, cell_routes in self.ctrl_routes.items():
|
||||||
for pin, pin_routes in cell_routes.items():
|
for pin, pin_routes in cell_routes.items():
|
||||||
for net, net_routes in pin_routes.items():
|
for net, net_routes in pin_routes.items():
|
||||||
|
|
||||||
routes = []
|
routes = []
|
||||||
for route in net_routes:
|
for route in net_routes:
|
||||||
|
|
||||||
# Assume 3-stage switchbox
|
# Assume 3-stage switchbox
|
||||||
assert len(route) == 3, "FIXME: Assuming 3-stage switchbox!"
|
assert len(route) == 3, "FIXME: Assuming 3-stage switchbox!"
|
||||||
|
|
||||||
|
|
|
@ -193,14 +193,12 @@ def make_top_level_tile(tile_type, sub_tiles, tile_types, equivalent_tiles=None)
|
||||||
# Equivalent sites
|
# Equivalent sites
|
||||||
xml_equiv = ET.SubElement(xml_sub_tile, "equivalent_sites")
|
xml_equiv = ET.SubElement(xml_sub_tile, "equivalent_sites")
|
||||||
for site_type, site_pinmap in equivalent_sub_tiles.items():
|
for site_type, site_pinmap in equivalent_sub_tiles.items():
|
||||||
|
|
||||||
# Site tag
|
# Site tag
|
||||||
pb_name = "PB-{}".format(site_type.upper())
|
pb_name = "PB-{}".format(site_type.upper())
|
||||||
xml_site = ET.SubElement(xml_equiv, "site", {"pb_type": pb_name, "pin_mapping": "custom"})
|
xml_site = ET.SubElement(xml_equiv, "site", {"pb_type": pb_name, "pin_mapping": "custom"})
|
||||||
|
|
||||||
# Same type, map one-to-one
|
# Same type, map one-to-one
|
||||||
if tile_type.upper() == site_type.upper() or site_pinmap is None:
|
if tile_type.upper() == site_type.upper() or site_pinmap is None:
|
||||||
|
|
||||||
all_pins = {**tile_pinlists["clock"], **tile_pinlists["input"], **tile_pinlists["output"]}
|
all_pins = {**tile_pinlists["clock"], **tile_pinlists["input"], **tile_pinlists["output"]}
|
||||||
|
|
||||||
for pin, count in all_pins.items():
|
for pin, count in all_pins.items():
|
||||||
|
@ -211,7 +209,6 @@ def make_top_level_tile(tile_type, sub_tiles, tile_types, equivalent_tiles=None)
|
||||||
|
|
||||||
# Explicit pinmap as a list of tuples (from, to)
|
# Explicit pinmap as a list of tuples (from, to)
|
||||||
elif isinstance(site_pinmap, list):
|
elif isinstance(site_pinmap, list):
|
||||||
|
|
||||||
for tl_pin, pb_pin in site_pinmap:
|
for tl_pin, pb_pin in site_pinmap:
|
||||||
ET.SubElement(
|
ET.SubElement(
|
||||||
xml_site,
|
xml_site,
|
||||||
|
|
|
@ -129,7 +129,6 @@ def compute_switchbox_timing_model(switchbox, timing_data):
|
||||||
|
|
||||||
for pin in switchbox.inputs.values():
|
for pin in switchbox.inputs.values():
|
||||||
for loc in pin.locs:
|
for loc in pin.locs:
|
||||||
|
|
||||||
dst_key = (loc.stage_id, loc.switch_id, loc.mux_id, loc.pin_id)
|
dst_key = (loc.stage_id, loc.switch_id, loc.mux_id, loc.pin_id)
|
||||||
src_key = (loc.stage_id, pin.name)
|
src_key = (loc.stage_id, pin.name)
|
||||||
|
|
||||||
|
@ -138,11 +137,9 @@ def compute_switchbox_timing_model(switchbox, timing_data):
|
||||||
# Compute timing model for each driver
|
# Compute timing model for each driver
|
||||||
driver_timing = {}
|
driver_timing = {}
|
||||||
for driver, sinks in sink_map.items():
|
for driver, sinks in sink_map.items():
|
||||||
|
|
||||||
# Collect timing data for each sink edge
|
# Collect timing data for each sink edge
|
||||||
edge_timings = {}
|
edge_timings = {}
|
||||||
for stage_id, switch_id, mux_id, pin_id in sinks:
|
for stage_id, switch_id, mux_id, pin_id in sinks:
|
||||||
|
|
||||||
# Try getting timing data. If not found then probably we are
|
# Try getting timing data. If not found then probably we are
|
||||||
# computing timing for VCC or GND input.
|
# computing timing for VCC or GND input.
|
||||||
try:
|
try:
|
||||||
|
@ -211,7 +208,6 @@ def compute_switchbox_timing_model(switchbox, timing_data):
|
||||||
|
|
||||||
# Compute error of the delay model
|
# Compute error of the delay model
|
||||||
for sink in sinks:
|
for sink in sinks:
|
||||||
|
|
||||||
# Compute for this sink
|
# Compute for this sink
|
||||||
error = {}
|
error = {}
|
||||||
for n, true_delay in edge_timings[sink].items():
|
for n, true_delay in edge_timings[sink].items():
|
||||||
|
@ -254,7 +250,6 @@ def populate_switchbox_timing(switchbox, driver_timing, sink_map, vpr_switches):
|
||||||
|
|
||||||
# Populate timing data to the switchbox
|
# Populate timing data to the switchbox
|
||||||
for driver, timing in driver_timing.items():
|
for driver, timing in driver_timing.items():
|
||||||
|
|
||||||
# Driver VPR switch
|
# Driver VPR switch
|
||||||
driver_vpr_switch = create_vpr_switch(
|
driver_vpr_switch = create_vpr_switch(
|
||||||
type="mux",
|
type="mux",
|
||||||
|
@ -300,7 +295,6 @@ def copy_switchbox_timing(src_switchbox, dst_switchbox):
|
||||||
|
|
||||||
# Mux timing
|
# Mux timing
|
||||||
for dst_stage, dst_switch, dst_mux in yield_muxes(dst_switchbox):
|
for dst_stage, dst_switch, dst_mux in yield_muxes(dst_switchbox):
|
||||||
|
|
||||||
src_stage = src_switchbox.stages[dst_stage.id]
|
src_stage = src_switchbox.stages[dst_stage.id]
|
||||||
src_switch = src_stage.switches[dst_switch.id]
|
src_switch = src_stage.switches[dst_switch.id]
|
||||||
src_mux = src_switch.muxes[dst_mux.id]
|
src_mux = src_switch.muxes[dst_mux.id]
|
||||||
|
@ -324,7 +318,6 @@ def add_vpr_switches_for_cell(cell_type, cell_timings):
|
||||||
vpr_switches = {}
|
vpr_switches = {}
|
||||||
for celltype, cell_data in timings.items():
|
for celltype, cell_data in timings.items():
|
||||||
for instance, inst_data in cell_data.items():
|
for instance, inst_data in cell_data.items():
|
||||||
|
|
||||||
# Add IOPATHs
|
# Add IOPATHs
|
||||||
for timing, timing_data in inst_data.items():
|
for timing, timing_data in inst_data.items():
|
||||||
if timing_data["type"].lower() != "iopath":
|
if timing_data["type"].lower() != "iopath":
|
||||||
|
|
|
@ -105,7 +105,6 @@ class VModule(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
def group_vector_signals(self, signals, io=False):
|
def group_vector_signals(self, signals, io=False):
|
||||||
|
|
||||||
# IOs beside name, have also direction, convert them to format
|
# IOs beside name, have also direction, convert them to format
|
||||||
# we can process
|
# we can process
|
||||||
if io:
|
if io:
|
||||||
|
@ -225,7 +224,6 @@ class VModule(object):
|
||||||
str: Verilog entry
|
str: Verilog entry
|
||||||
"""
|
"""
|
||||||
if typ == "BIDIR":
|
if typ == "BIDIR":
|
||||||
|
|
||||||
# We do not emit the BIDIR cell for non inout IOs
|
# We do not emit the BIDIR cell for non inout IOs
|
||||||
direction = self.get_io_config(parameters)
|
direction = self.get_io_config(parameters)
|
||||||
if direction is None:
|
if direction is None:
|
||||||
|
@ -337,7 +335,6 @@ class VModule(object):
|
||||||
|
|
||||||
# check every connection pin if it has
|
# check every connection pin if it has
|
||||||
for pin in cellpins:
|
for pin in cellpins:
|
||||||
|
|
||||||
# Cell name and pin name match
|
# Cell name and pin name match
|
||||||
if cell_name in cell_input_names:
|
if cell_name in cell_input_names:
|
||||||
if pin in cell_input_names[cell_name]:
|
if pin in cell_input_names[cell_name]:
|
||||||
|
@ -492,7 +489,6 @@ class VModule(object):
|
||||||
loc,
|
loc,
|
||||||
wire,
|
wire,
|
||||||
) in connections.items():
|
) in connections.items():
|
||||||
|
|
||||||
# That wire is connected to something. Skip processing
|
# That wire is connected to something. Skip processing
|
||||||
# of the cell here
|
# of the cell here
|
||||||
if loc is not None:
|
if loc is not None:
|
||||||
|
@ -561,10 +557,8 @@ class VModule(object):
|
||||||
# Prune BELs that do not drive anythin (have all outputs disconnected)
|
# Prune BELs that do not drive anythin (have all outputs disconnected)
|
||||||
for loc, elements in list(self.elements.items()):
|
for loc, elements in list(self.elements.items()):
|
||||||
for type, element in list(elements.items()):
|
for type, element in list(elements.items()):
|
||||||
|
|
||||||
# Handle IO cells
|
# Handle IO cells
|
||||||
if element.type in ["CLOCK", "BIDIR", "SDIOMUX"]:
|
if element.type in ["CLOCK", "BIDIR", "SDIOMUX"]:
|
||||||
|
|
||||||
if element.type == "CLOCK":
|
if element.type == "CLOCK":
|
||||||
direction = "input"
|
direction = "input"
|
||||||
else:
|
else:
|
||||||
|
@ -576,7 +570,6 @@ class VModule(object):
|
||||||
|
|
||||||
# Handle non-io cells
|
# Handle non-io cells
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Get connected pin names and output pin names
|
# Get connected pin names and output pin names
|
||||||
connected_pins = set(element.ios.keys())
|
connected_pins = set(element.ios.keys())
|
||||||
output_pins = set(
|
output_pins = set(
|
||||||
|
@ -596,7 +589,6 @@ class VModule(object):
|
||||||
del self.elements[loc]
|
del self.elements[loc]
|
||||||
|
|
||||||
def get_io_name(self, loc):
|
def get_io_name(self, loc):
|
||||||
|
|
||||||
# default pin name
|
# default pin name
|
||||||
name = loc2str(loc) + "_inout"
|
name = loc2str(loc) + "_inout"
|
||||||
# check if we have the original name for this io
|
# check if we have the original name for this io
|
||||||
|
@ -650,7 +642,6 @@ class VModule(object):
|
||||||
for eloc, locelements in self.elements.items():
|
for eloc, locelements in self.elements.items():
|
||||||
for element in locelements.values():
|
for element in locelements.values():
|
||||||
if element.type in ["CLOCK", "BIDIR", "SDIOMUX"]:
|
if element.type in ["CLOCK", "BIDIR", "SDIOMUX"]:
|
||||||
|
|
||||||
if element.type == "CLOCK":
|
if element.type == "CLOCK":
|
||||||
direction = "input"
|
direction = "input"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -87,7 +87,6 @@ def switchbox_to_dot(switchbox, stage_types=("STREET", "HIGHWAY")):
|
||||||
|
|
||||||
# Stages
|
# Stages
|
||||||
for stage in switchbox.stages.values():
|
for stage in switchbox.stages.values():
|
||||||
|
|
||||||
if stage.type not in stage_types:
|
if stage.type not in stage_types:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -121,7 +120,6 @@ def switchbox_to_dot(switchbox, stage_types=("STREET", "HIGHWAY")):
|
||||||
|
|
||||||
# Internal connections
|
# Internal connections
|
||||||
for conn in switchbox.connections:
|
for conn in switchbox.connections:
|
||||||
|
|
||||||
if switchbox.stages[conn.src.stage_id].type not in stage_types:
|
if switchbox.stages[conn.src.stage_id].type not in stage_types:
|
||||||
continue
|
continue
|
||||||
if switchbox.stages[conn.dst.stage_id].type not in stage_types:
|
if switchbox.stages[conn.dst.stage_id].type not in stage_types:
|
||||||
|
@ -139,7 +137,6 @@ def switchbox_to_dot(switchbox, stage_types=("STREET", "HIGHWAY")):
|
||||||
src_node = "input_{}".format(fixup_pin_name(pin.name))
|
src_node = "input_{}".format(fixup_pin_name(pin.name))
|
||||||
|
|
||||||
for loc in pin.locs:
|
for loc in pin.locs:
|
||||||
|
|
||||||
if switchbox.stages[loc.stage_id].type not in stage_types:
|
if switchbox.stages[loc.stage_id].type not in stage_types:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -153,7 +150,6 @@ def switchbox_to_dot(switchbox, stage_types=("STREET", "HIGHWAY")):
|
||||||
dst_node = "output_{}".format(fixup_pin_name(pin.name))
|
dst_node = "output_{}".format(fixup_pin_name(pin.name))
|
||||||
|
|
||||||
for loc in pin.locs:
|
for loc in pin.locs:
|
||||||
|
|
||||||
if switchbox.stages[loc.stage_id].type not in stage_types:
|
if switchbox.stages[loc.stage_id].type not in stage_types:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -171,7 +167,6 @@ def switchbox_to_dot(switchbox, stage_types=("STREET", "HIGHWAY")):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ def expand_indices(items):
|
||||||
|
|
||||||
# Process each item
|
# Process each item
|
||||||
for item in items:
|
for item in items:
|
||||||
|
|
||||||
# Match using regex. If there is no match then pass the item through
|
# Match using regex. If there is no match then pass the item through
|
||||||
match = RE_INDICES.fullmatch(item)
|
match = RE_INDICES.fullmatch(item)
|
||||||
if not match:
|
if not match:
|
||||||
|
@ -128,7 +127,6 @@ def process_get_ports(match, pad_to_net, valid_pins=None, valid_nets=None):
|
||||||
|
|
||||||
# A helper mapping func.
|
# A helper mapping func.
|
||||||
def map_pad_to_net(pad):
|
def map_pad_to_net(pad):
|
||||||
|
|
||||||
# Unescape square brackets
|
# Unescape square brackets
|
||||||
pad = pad.replace("\\[", "[")
|
pad = pad.replace("\\[", "[")
|
||||||
pad = pad.replace("\\]", "]")
|
pad = pad.replace("\\]", "]")
|
||||||
|
@ -175,7 +173,6 @@ def process_get_ports(match, pad_to_net, valid_pins=None, valid_nets=None):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,6 @@ def get_parent_pb_and_mode(xml_pbtype):
|
||||||
|
|
||||||
# pb_type parent
|
# pb_type parent
|
||||||
if xml_pbtype.tag == "pb_type":
|
if xml_pbtype.tag == "pb_type":
|
||||||
|
|
||||||
if xml_parent.tag == "pb_type":
|
if xml_parent.tag == "pb_type":
|
||||||
return xml_parent, xml_parent
|
return xml_parent, xml_parent
|
||||||
|
|
||||||
|
@ -83,7 +82,6 @@ def get_parent_pb_and_mode(xml_pbtype):
|
||||||
return xml_parent.getparent(), xml_parent
|
return xml_parent.getparent(), xml_parent
|
||||||
|
|
||||||
elif xml_pbtype.tag == "mode":
|
elif xml_pbtype.tag == "mode":
|
||||||
|
|
||||||
return xml_parent.getparent(), xml_pbtype
|
return xml_parent.getparent(), xml_pbtype
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,7 +150,6 @@ def get_pb_and_port(xml_ic, port_spec):
|
||||||
port = match.group("port")
|
port = match.group("port")
|
||||||
for xml_port in xml_pbtype:
|
for xml_port in xml_pbtype:
|
||||||
if xml_port.tag in ["input", "output", "clock"]:
|
if xml_port.tag in ["input", "output", "clock"]:
|
||||||
|
|
||||||
# Got it
|
# Got it
|
||||||
if xml_port.attrib["name"] == port:
|
if xml_port.attrib["name"] == port:
|
||||||
return xml_pbtype, xml_port
|
return xml_pbtype, xml_port
|
||||||
|
@ -242,7 +239,6 @@ def yield_pins(xml_ic, port_spec, skip_index=True):
|
||||||
# Yield individual pin names
|
# Yield individual pin names
|
||||||
for i in indices:
|
for i in indices:
|
||||||
for j in bits:
|
for j in bits:
|
||||||
|
|
||||||
name = match.group("pbtype")
|
name = match.group("pbtype")
|
||||||
if i is not None:
|
if i is not None:
|
||||||
name += "[{}]".format(i)
|
name += "[{}]".format(i)
|
||||||
|
|
|
@ -38,7 +38,6 @@ class Cell:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, type):
|
def __init__(self, type):
|
||||||
|
|
||||||
# Cell name. This one is for reference only. It won't be writteb back
|
# Cell name. This one is for reference only. It won't be writteb back
|
||||||
# with the .cname attribute. Use the cname field for that.
|
# with the .cname attribute. Use the cname field for that.
|
||||||
self.name = None
|
self.name = None
|
||||||
|
@ -103,7 +102,6 @@ class Eblif:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
|
|
||||||
# Top-level module name
|
# Top-level module name
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
|
@ -168,7 +166,6 @@ class Eblif:
|
||||||
|
|
||||||
# Convert inputs
|
# Convert inputs
|
||||||
for port in self.inputs:
|
for port in self.inputs:
|
||||||
|
|
||||||
cell = Cell("$input")
|
cell = Cell("$input")
|
||||||
cell.name = port
|
cell.name = port
|
||||||
cell.ports["inpad"] = port
|
cell.ports["inpad"] = port
|
||||||
|
@ -177,7 +174,6 @@ class Eblif:
|
||||||
|
|
||||||
# Convert outputs
|
# Convert outputs
|
||||||
for port in self.outputs:
|
for port in self.outputs:
|
||||||
|
|
||||||
cell = Cell("$output")
|
cell = Cell("$output")
|
||||||
cell.name = "out:" + port
|
cell.name = "out:" + port
|
||||||
cell.cname = cell.name
|
cell.cname = cell.name
|
||||||
|
@ -215,7 +211,6 @@ class Eblif:
|
||||||
# Insert a buffer if the port name does not match the net name
|
# Insert a buffer if the port name does not match the net name
|
||||||
net = cell.ports["outpad"]
|
net = cell.ports["outpad"]
|
||||||
if name != net:
|
if name != net:
|
||||||
|
|
||||||
cell = Cell("$lut")
|
cell = Cell("$lut")
|
||||||
cell.name = name
|
cell.name = name
|
||||||
cell.ports["lut_in[0]"] = net
|
cell.ports["lut_in[0]"] = net
|
||||||
|
@ -421,10 +416,8 @@ class Eblif:
|
||||||
|
|
||||||
# Cells
|
# Cells
|
||||||
for cell in self.cells.values():
|
for cell in self.cells.values():
|
||||||
|
|
||||||
# A constant source
|
# A constant source
|
||||||
if cell.type == "$const":
|
if cell.type == "$const":
|
||||||
|
|
||||||
# Skip consts
|
# Skip consts
|
||||||
if not consts:
|
if not consts:
|
||||||
continue
|
continue
|
||||||
|
@ -435,7 +428,6 @@ class Eblif:
|
||||||
|
|
||||||
# A LUT
|
# A LUT
|
||||||
elif cell.type == "$lut":
|
elif cell.type == "$lut":
|
||||||
|
|
||||||
# Identify LUT input pins and their bind indices
|
# Identify LUT input pins and their bind indices
|
||||||
nets = {}
|
nets = {}
|
||||||
for port, net in cell.ports.items():
|
for port, net in cell.ports.items():
|
||||||
|
@ -458,7 +450,6 @@ class Eblif:
|
||||||
|
|
||||||
# A latch
|
# A latch
|
||||||
elif cell.type in ["$fe", "$re", "$ah", "$al", "$as"]:
|
elif cell.type in ["$fe", "$re", "$ah", "$al", "$as"]:
|
||||||
|
|
||||||
line = ".latch {} {} {} {} {}".format(
|
line = ".latch {} {} {} {} {}".format(
|
||||||
str(cell.ports["D"]), str(cell.ports["Q"]), cell.type[1:], str(cell.ports["clock"]), str(cell.init)
|
str(cell.ports["D"]), str(cell.ports["Q"]), cell.type[1:], str(cell.ports["clock"]), str(cell.init)
|
||||||
)
|
)
|
||||||
|
@ -466,13 +457,11 @@ class Eblif:
|
||||||
|
|
||||||
# A generic latch controlled by a single global clock
|
# A generic latch controlled by a single global clock
|
||||||
elif cell.type == "$latch":
|
elif cell.type == "$latch":
|
||||||
|
|
||||||
line = ".latch {} {} {}".format(str(cell.ports["D"]), str(cell.ports["Q"]), str(cell.init))
|
line = ".latch {} {} {}".format(str(cell.ports["D"]), str(cell.ports["Q"]), str(cell.init))
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
|
|
||||||
# A generic subcircuit
|
# A generic subcircuit
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# The subcircuit along with its connections
|
# The subcircuit along with its connections
|
||||||
line = ".subckt {}".format(cell.type)
|
line = ".subckt {}".format(cell.type)
|
||||||
for port, net in cell.ports.items():
|
for port, net in cell.ports.items():
|
||||||
|
|
|
@ -45,7 +45,6 @@ def absorb_buffer_luts(netlist, outputs=False):
|
||||||
|
|
||||||
# A pass-through LUT
|
# A pass-through LUT
|
||||||
if cell.type == "$lut" and cell.init == [0, 1]:
|
if cell.type == "$lut" and cell.init == [0, 1]:
|
||||||
|
|
||||||
# Get input and output nets
|
# Get input and output nets
|
||||||
assert INP_PORT in cell.ports, cell
|
assert INP_PORT in cell.ports, cell
|
||||||
net_inp = cell.ports[INP_PORT]
|
net_inp = cell.ports[INP_PORT]
|
||||||
|
@ -68,7 +67,6 @@ def absorb_buffer_luts(netlist, outputs=False):
|
||||||
# Merge them downstream
|
# Merge them downstream
|
||||||
net_map = {}
|
net_map = {}
|
||||||
for cell in buffers.values():
|
for cell in buffers.values():
|
||||||
|
|
||||||
# Get input and output nets
|
# Get input and output nets
|
||||||
assert INP_PORT in cell.ports, cell
|
assert INP_PORT in cell.ports, cell
|
||||||
net_inp = cell.ports[INP_PORT]
|
net_inp = cell.ports[INP_PORT]
|
||||||
|
@ -83,7 +81,6 @@ def absorb_buffer_luts(netlist, outputs=False):
|
||||||
# This cell drives a top-level output directly. Change input nets and
|
# This cell drives a top-level output directly. Change input nets and
|
||||||
# leave the output one
|
# leave the output one
|
||||||
if net_out in netlist.outputs:
|
if net_out in netlist.outputs:
|
||||||
|
|
||||||
# Replace the output net in all cells with the input one
|
# Replace the output net in all cells with the input one
|
||||||
for c in netlist.cells.values():
|
for c in netlist.cells.values():
|
||||||
for port, net in c.ports.items():
|
for port, net in c.ports.items():
|
||||||
|
@ -99,7 +96,6 @@ def absorb_buffer_luts(netlist, outputs=False):
|
||||||
|
|
||||||
# A regular buffer
|
# A regular buffer
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Replace the output net in all cells with the input one
|
# Replace the output net in all cells with the input one
|
||||||
for c in netlist.cells.values():
|
for c in netlist.cells.values():
|
||||||
for port, net in c.ports.items():
|
for port, net in c.ports.items():
|
||||||
|
|
|
@ -190,7 +190,6 @@ class Block:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, instance, mode=None, parent=None):
|
def __init__(self, name, instance, mode=None, parent=None):
|
||||||
|
|
||||||
# Basic attributes
|
# Basic attributes
|
||||||
self.name = name
|
self.name = name
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
@ -230,7 +229,6 @@ class Block:
|
||||||
xml_ports = elem.find(tag)
|
xml_ports = elem.find(tag)
|
||||||
if xml_ports is not None:
|
if xml_ports is not None:
|
||||||
for xml_port in xml_ports:
|
for xml_port in xml_ports:
|
||||||
|
|
||||||
# Got a port rotation map
|
# Got a port rotation map
|
||||||
if xml_port.tag == "port_rotation_map":
|
if xml_port.tag == "port_rotation_map":
|
||||||
port_name = xml_port.attrib["name"]
|
port_name = xml_port.attrib["name"]
|
||||||
|
@ -257,7 +255,6 @@ class Block:
|
||||||
|
|
||||||
# Recursively parse sub-blocks
|
# Recursively parse sub-blocks
|
||||||
for xml_block in elem.findall("block"):
|
for xml_block in elem.findall("block"):
|
||||||
|
|
||||||
sub_block = Block.from_etree(xml_block)
|
sub_block = Block.from_etree(xml_block)
|
||||||
|
|
||||||
sub_block.parent = block
|
sub_block.parent = block
|
||||||
|
@ -265,11 +262,9 @@ class Block:
|
||||||
|
|
||||||
# Parse attributes and parameters
|
# Parse attributes and parameters
|
||||||
for tag, data in zip(["attributes", "parameters"], [block.attributes, block.parameters]):
|
for tag, data in zip(["attributes", "parameters"], [block.attributes, block.parameters]):
|
||||||
|
|
||||||
# Find the list
|
# Find the list
|
||||||
xml_list = elem.find(tag)
|
xml_list = elem.find(tag)
|
||||||
if xml_list is not None:
|
if xml_list is not None:
|
||||||
|
|
||||||
# Only a leaf block can have attributes / parameters
|
# Only a leaf block can have attributes / parameters
|
||||||
assert block.is_leaf, "Non-leaf block '{}' with {}".format(block.instance, tag)
|
assert block.is_leaf, "Non-leaf block '{}' with {}".format(block.instance, tag)
|
||||||
|
|
||||||
|
@ -303,7 +298,6 @@ class Block:
|
||||||
# Attributes / parameters
|
# Attributes / parameters
|
||||||
if self.is_leaf:
|
if self.is_leaf:
|
||||||
for tag, data in zip(["attributes", "parameters"], [self.attributes, self.parameters]):
|
for tag, data in zip(["attributes", "parameters"], [self.attributes, self.parameters]):
|
||||||
|
|
||||||
xml_list = ET.Element(tag)
|
xml_list = ET.Element(tag)
|
||||||
|
|
||||||
sub_tag = tag[:-1]
|
sub_tag = tag[:-1]
|
||||||
|
@ -323,14 +317,12 @@ class Block:
|
||||||
for key in keys:
|
for key in keys:
|
||||||
port = self.ports[key]
|
port = self.ports[key]
|
||||||
if port.type == port_type:
|
if port.type == port_type:
|
||||||
|
|
||||||
# Encode port
|
# Encode port
|
||||||
xml_port = port.to_etree()
|
xml_port = port.to_etree()
|
||||||
xml_ports.append(xml_port)
|
xml_ports.append(xml_port)
|
||||||
|
|
||||||
# Rotation map
|
# Rotation map
|
||||||
if port.rotation_map:
|
if port.rotation_map:
|
||||||
|
|
||||||
# Encode
|
# Encode
|
||||||
rotation = []
|
rotation = []
|
||||||
for i in range(port.width):
|
for i in range(port.width):
|
||||||
|
@ -387,7 +379,6 @@ class Block:
|
||||||
|
|
||||||
# Walk towards the tree root
|
# Walk towards the tree root
|
||||||
while block is not None:
|
while block is not None:
|
||||||
|
|
||||||
# Type or type with index (instance)
|
# Type or type with index (instance)
|
||||||
if with_indices:
|
if with_indices:
|
||||||
node = block.instance
|
node = block.instance
|
||||||
|
@ -413,7 +404,6 @@ class Block:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block):
|
def walk(block):
|
||||||
|
|
||||||
if not block.is_leaf and not block.is_open:
|
if not block.is_leaf and not block.is_open:
|
||||||
block.name = name
|
block.name = name
|
||||||
|
|
||||||
|
@ -429,14 +419,12 @@ class Block:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block):
|
def walk(block):
|
||||||
|
|
||||||
# Rename nets in port connections. Check whether the block itself
|
# Rename nets in port connections. Check whether the block itself
|
||||||
# should be renamed as well (output pads need to be).
|
# should be renamed as well (output pads need to be).
|
||||||
rename_block = block.name.startswith("out:")
|
rename_block = block.name.startswith("out:")
|
||||||
|
|
||||||
for port in block.ports.values():
|
for port in block.ports.values():
|
||||||
for pin, conn in port.connections.items():
|
for pin, conn in port.connections.items():
|
||||||
|
|
||||||
if isinstance(conn, str):
|
if isinstance(conn, str):
|
||||||
port.connections[pin] = net_map.get(conn, conn)
|
port.connections[pin] = net_map.get(conn, conn)
|
||||||
|
|
||||||
|
@ -445,7 +433,6 @@ class Block:
|
||||||
|
|
||||||
# Rename the leaf block if necessary
|
# Rename the leaf block if necessary
|
||||||
if block.is_leaf and not block.is_open and rename_block:
|
if block.is_leaf and not block.is_open and rename_block:
|
||||||
|
|
||||||
if block.name in net_map:
|
if block.name in net_map:
|
||||||
block.name = net_map[block.name]
|
block.name = net_map[block.name]
|
||||||
elif block.name.startswith("out:"):
|
elif block.name.startswith("out:"):
|
||||||
|
@ -483,7 +470,6 @@ class Block:
|
||||||
|
|
||||||
# Check parent and siblings
|
# Check parent and siblings
|
||||||
if self.parent is not None:
|
if self.parent is not None:
|
||||||
|
|
||||||
# Parent
|
# Parent
|
||||||
if self.parent.type == block_type:
|
if self.parent.type == block_type:
|
||||||
return self.parent
|
return self.parent
|
||||||
|
@ -530,11 +516,9 @@ class Block:
|
||||||
|
|
||||||
# Recursive walk function
|
# Recursive walk function
|
||||||
def walk(block):
|
def walk(block):
|
||||||
|
|
||||||
# Examine block ports
|
# Examine block ports
|
||||||
for port in block.ports.values():
|
for port in block.ports.values():
|
||||||
for pin in range(port.width):
|
for pin in range(port.width):
|
||||||
|
|
||||||
net = block.find_net_for_port(port.name, pin)
|
net = block.find_net_for_port(port.name, pin)
|
||||||
if net:
|
if net:
|
||||||
nets.add(net)
|
nets.add(net)
|
||||||
|
@ -553,7 +537,6 @@ class Block:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block, parts):
|
def walk(block, parts):
|
||||||
|
|
||||||
# Check if instance matches
|
# Check if instance matches
|
||||||
instance = "{}[{}]".format(parts[0].name, parts[0].index)
|
instance = "{}[{}]".format(parts[0].name, parts[0].index)
|
||||||
if block.instance != instance:
|
if block.instance != instance:
|
||||||
|
@ -594,7 +577,6 @@ class Block:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block, count=0):
|
def walk(block, count=0):
|
||||||
|
|
||||||
# This is a non-ope leaf, count it
|
# This is a non-ope leaf, count it
|
||||||
if block.is_leaf and not block.is_open:
|
if block.is_leaf and not block.is_open:
|
||||||
count += 1
|
count += 1
|
||||||
|
|
|
@ -95,7 +95,6 @@ class Graph:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Nodes by id
|
# Nodes by id
|
||||||
self.nodes = {}
|
self.nodes = {}
|
||||||
# Edges (assorted)
|
# Edges (assorted)
|
||||||
|
@ -170,7 +169,6 @@ class Graph:
|
||||||
# Handler for "lut" pb_types. It creates an additional level of
|
# Handler for "lut" pb_types. It creates an additional level of
|
||||||
# hierarchy to match the representation in packed netlist.
|
# hierarchy to match the representation in packed netlist.
|
||||||
def process_lut(xml_pbtype, up_node_map, path):
|
def process_lut(xml_pbtype, up_node_map, path):
|
||||||
|
|
||||||
# The parent is actually a leaf so it does not have any modes
|
# The parent is actually a leaf so it does not have any modes
|
||||||
# However, the mode name must equal to the pb_type name.
|
# However, the mode name must equal to the pb_type name.
|
||||||
curr_path = path + "[{}].lut[0]".format(xml_pbtype.attrib["name"])
|
curr_path = path + "[{}].lut[0]".format(xml_pbtype.attrib["name"])
|
||||||
|
@ -214,14 +212,12 @@ class Graph:
|
||||||
|
|
||||||
# Process each mode
|
# Process each mode
|
||||||
for mode, xml_mode in xml_modes.items():
|
for mode, xml_mode in xml_modes.items():
|
||||||
|
|
||||||
# Append mode name to the current path
|
# Append mode name to the current path
|
||||||
curr_path = path + "[{}]".format(mode)
|
curr_path = path + "[{}]".format(mode)
|
||||||
|
|
||||||
# Enumerate childern, build their paths
|
# Enumerate childern, build their paths
|
||||||
children = []
|
children = []
|
||||||
for xml_child, index in yield_pb_children(xml_mode):
|
for xml_child, index in yield_pb_children(xml_mode):
|
||||||
|
|
||||||
child_path = ".".join([curr_path, "{}[{}]".format(xml_child.attrib["name"], index)])
|
child_path = ".".join([curr_path, "{}[{}]".format(xml_child.attrib["name"], index)])
|
||||||
|
|
||||||
children.append(
|
children.append(
|
||||||
|
@ -294,7 +290,6 @@ class Graph:
|
||||||
|
|
||||||
# Add nodes
|
# Add nodes
|
||||||
for xml_port in xml_pbtype:
|
for xml_port in xml_pbtype:
|
||||||
|
|
||||||
if xml_port.tag in ["input", "output", "clock"]:
|
if xml_port.tag in ["input", "output", "clock"]:
|
||||||
width = int(xml_port.attrib["num_pins"])
|
width = int(xml_port.attrib["num_pins"])
|
||||||
|
|
||||||
|
@ -337,7 +332,6 @@ class Graph:
|
||||||
|
|
||||||
# A helper function
|
# A helper function
|
||||||
def get_node_path(pin):
|
def get_node_path(pin):
|
||||||
|
|
||||||
# Split parts
|
# Split parts
|
||||||
parts = pin.split(".")
|
parts = pin.split(".")
|
||||||
assert len(parts) == 2, pin
|
assert len(parts) == 2, pin
|
||||||
|
@ -365,7 +359,6 @@ class Graph:
|
||||||
|
|
||||||
# Process interconnects
|
# Process interconnects
|
||||||
for xml_conn in xml_ic:
|
for xml_conn in xml_ic:
|
||||||
|
|
||||||
# Direct
|
# Direct
|
||||||
if xml_conn.tag == "direct":
|
if xml_conn.tag == "direct":
|
||||||
inps = list(yield_pins(xml_ic, xml_conn.attrib["input"], False))
|
inps = list(yield_pins(xml_ic, xml_conn.attrib["input"], False))
|
||||||
|
@ -390,7 +383,6 @@ class Graph:
|
||||||
|
|
||||||
# Build edges for each input port
|
# Build edges for each input port
|
||||||
for inp_port in inp_ports:
|
for inp_port in inp_ports:
|
||||||
|
|
||||||
# Get input pins, should be only one
|
# Get input pins, should be only one
|
||||||
inp_pins = list(yield_pins(xml_ic, inp_port, False))
|
inp_pins = list(yield_pins(xml_ic, inp_port, False))
|
||||||
assert len(inp_pins) == 1, xml_conn.attrib
|
assert len(inp_pins) == 1, xml_conn.attrib
|
||||||
|
@ -439,7 +431,6 @@ class Graph:
|
||||||
|
|
||||||
net_colors = {}
|
net_colors = {}
|
||||||
for i, net in enumerate(nets):
|
for i, net in enumerate(nets):
|
||||||
|
|
||||||
h = i / len(nets)
|
h = i / len(nets)
|
||||||
l = 0.50 # noqa: E741
|
l = 0.50 # noqa: E741
|
||||||
s = 1.0
|
s = 1.0
|
||||||
|
@ -455,7 +446,6 @@ class Graph:
|
||||||
|
|
||||||
# Node color
|
# Node color
|
||||||
def node_color(node, highlight=False):
|
def node_color(node, highlight=False):
|
||||||
|
|
||||||
if highlight_nodes:
|
if highlight_nodes:
|
||||||
if highlight:
|
if highlight:
|
||||||
return "#FF2020"
|
return "#FF2020"
|
||||||
|
@ -486,7 +476,6 @@ class Graph:
|
||||||
|
|
||||||
# Edge color
|
# Edge color
|
||||||
def edge_color(edge):
|
def edge_color(edge):
|
||||||
|
|
||||||
if color_by == "net":
|
if color_by == "net":
|
||||||
net = self.edge_net(edge)
|
net = self.edge_net(edge)
|
||||||
if net:
|
if net:
|
||||||
|
@ -508,7 +497,6 @@ class Graph:
|
||||||
# Build nodes
|
# Build nodes
|
||||||
nodes = {}
|
nodes = {}
|
||||||
for node in self.nodes.values():
|
for node in self.nodes.values():
|
||||||
|
|
||||||
if nets_only and node.net is None:
|
if nets_only and node.net is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -555,7 +543,6 @@ class Graph:
|
||||||
|
|
||||||
# Add edges
|
# Add edges
|
||||||
for edge in self.edges:
|
for edge in self.edges:
|
||||||
|
|
||||||
if nets_only:
|
if nets_only:
|
||||||
if not self.edge_net(edge):
|
if not self.edge_net(edge):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -64,7 +64,6 @@ def load_clb_nets_into_pb_graph(clb_block, clb_graph):
|
||||||
|
|
||||||
# Annotate nodes with nets
|
# Annotate nodes with nets
|
||||||
for node in clb_graph.nodes.values():
|
for node in clb_graph.nodes.values():
|
||||||
|
|
||||||
# Disassemble node path parts
|
# Disassemble node path parts
|
||||||
parts = node.path.split(".")
|
parts = node.path.split(".")
|
||||||
parts = [PathNode.from_string(p) for p in parts]
|
parts = [PathNode.from_string(p) for p in parts]
|
||||||
|
@ -125,7 +124,6 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
nodes_up = {}
|
nodes_up = {}
|
||||||
|
|
||||||
for edge in clb_graph.edges:
|
for edge in clb_graph.edges:
|
||||||
|
|
||||||
# Check if the edge is active
|
# Check if the edge is active
|
||||||
if clb_graph.edge_net(edge) is None:
|
if clb_graph.edge_net(edge) is None:
|
||||||
continue
|
continue
|
||||||
|
@ -138,7 +136,6 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
# Create the block hierarchy for nodes that have nets assigned.
|
# Create the block hierarchy for nodes that have nets assigned.
|
||||||
clb_block = None
|
clb_block = None
|
||||||
for node in clb_graph.nodes.values():
|
for node in clb_graph.nodes.values():
|
||||||
|
|
||||||
# No net
|
# No net
|
||||||
if node.net is None:
|
if node.net is None:
|
||||||
continue
|
continue
|
||||||
|
@ -183,7 +180,6 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
|
|
||||||
# Add open blocks.
|
# Add open blocks.
|
||||||
for node in clb_graph.nodes.values():
|
for node in clb_graph.nodes.values():
|
||||||
|
|
||||||
# Consider only nodes without nets
|
# Consider only nodes without nets
|
||||||
if node.net:
|
if node.net:
|
||||||
continue
|
continue
|
||||||
|
@ -218,7 +214,6 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
|
|
||||||
# Add block ports and their connections
|
# Add block ports and their connections
|
||||||
for node in clb_graph.nodes.values():
|
for node in clb_graph.nodes.values():
|
||||||
|
|
||||||
# Disassemble node path parts
|
# Disassemble node path parts
|
||||||
parts = node.path.split(".")
|
parts = node.path.split(".")
|
||||||
parts = [PathNode.from_string(p) for p in parts]
|
parts = [PathNode.from_string(p) for p in parts]
|
||||||
|
@ -237,14 +232,12 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
port_name = parts[-1].name
|
port_name = parts[-1].name
|
||||||
port_type = node.port_type.name.lower()
|
port_type = node.port_type.name.lower()
|
||||||
if port_name not in block.ports:
|
if port_name not in block.ports:
|
||||||
|
|
||||||
# The relevant information will be updated as more nodes gets
|
# The relevant information will be updated as more nodes gets
|
||||||
# discovered.
|
# discovered.
|
||||||
port = packed_netlist.Port(name=port_name, type=port_type)
|
port = packed_netlist.Port(name=port_name, type=port_type)
|
||||||
block.ports[port_name] = port
|
block.ports[port_name] = port
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
port = block.ports[port_name]
|
port = block.ports[port_name]
|
||||||
assert port.type == port_type, (port.type, port_type)
|
assert port.type == port_type, (port.type, port_type)
|
||||||
|
|
||||||
|
@ -265,7 +258,6 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
|
|
||||||
# Got a driver, this is an intermediate port
|
# Got a driver, this is an intermediate port
|
||||||
if driver_node is not None:
|
if driver_node is not None:
|
||||||
|
|
||||||
# Get the driver pb_type and port
|
# Get the driver pb_type and port
|
||||||
driver_path = clb_graph.nodes[driver_node].path.split(".")
|
driver_path = clb_graph.nodes[driver_node].path.split(".")
|
||||||
driver_path = [PathNode.from_string(driver_path[i]) for i in [-2, -1]]
|
driver_path = [PathNode.from_string(driver_path[i]) for i in [-2, -1]]
|
||||||
|
@ -287,10 +279,8 @@ def build_packed_netlist_from_pb_graph(clb_graph):
|
||||||
|
|
||||||
# Assign names to leaf blocks
|
# Assign names to leaf blocks
|
||||||
def leaf_walk(block):
|
def leaf_walk(block):
|
||||||
|
|
||||||
# A leaf
|
# A leaf
|
||||||
if block.is_leaf and not block.is_open:
|
if block.is_leaf and not block.is_open:
|
||||||
|
|
||||||
# Identify all output pins that drive nets
|
# Identify all output pins that drive nets
|
||||||
nets = []
|
nets = []
|
||||||
for port in block.ports.values():
|
for port in block.ports.values():
|
||||||
|
|
|
@ -77,7 +77,6 @@ class Router:
|
||||||
sinks = {}
|
sinks = {}
|
||||||
|
|
||||||
for node in self.graph.nodes.values():
|
for node in self.graph.nodes.values():
|
||||||
|
|
||||||
if node.type not in [NodeType.SOURCE, NodeType.SINK]:
|
if node.type not in [NodeType.SOURCE, NodeType.SINK]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -100,7 +99,6 @@ class Router:
|
||||||
# Make nets
|
# Make nets
|
||||||
nets = set(sinks.keys()) | set(sources.keys())
|
nets = set(sinks.keys()) | set(sources.keys())
|
||||||
for net_name in nets:
|
for net_name in nets:
|
||||||
|
|
||||||
net = Net(net_name)
|
net = Net(net_name)
|
||||||
|
|
||||||
# A net may or may not have a source node(s). If there are no
|
# A net may or may not have a source node(s). If there are no
|
||||||
|
@ -130,7 +128,6 @@ class Router:
|
||||||
top_level_sources = set()
|
top_level_sources = set()
|
||||||
|
|
||||||
def walk_depth_first(node, curr_route=None):
|
def walk_depth_first(node, curr_route=None):
|
||||||
|
|
||||||
# FIXME: Two possible places for optimization:
|
# FIXME: Two possible places for optimization:
|
||||||
# - create an edge lookup list indexed by dst node ids
|
# - create an edge lookup list indexed by dst node ids
|
||||||
# - do not copy the current route list for each recursion level
|
# - do not copy the current route list for each recursion level
|
||||||
|
@ -159,7 +156,6 @@ class Router:
|
||||||
# Check all incoming edges
|
# Check all incoming edges
|
||||||
for edge in self.graph.edges:
|
for edge in self.graph.edges:
|
||||||
if edge.dst_id == node.id:
|
if edge.dst_id == node.id:
|
||||||
|
|
||||||
# Recurse
|
# Recurse
|
||||||
next_node = self.graph.nodes[edge.src_id]
|
next_node = self.graph.nodes[edge.src_id]
|
||||||
route = walk_depth_first(next_node, list(curr_route))
|
route = walk_depth_first(next_node, list(curr_route))
|
||||||
|
@ -181,7 +177,6 @@ class Router:
|
||||||
|
|
||||||
# Route all sinks to any of the net sources
|
# Route all sinks to any of the net sources
|
||||||
for sink in net.sinks:
|
for sink in net.sinks:
|
||||||
|
|
||||||
# Find the route
|
# Find the route
|
||||||
node = self.graph.nodes[sink]
|
node = self.graph.nodes[sink]
|
||||||
|
|
||||||
|
@ -191,7 +186,6 @@ class Router:
|
||||||
# No route found. Check if we have some free top-level ports that
|
# No route found. Check if we have some free top-level ports that
|
||||||
# we can use.
|
# we can use.
|
||||||
if not route and top_level_sources:
|
if not route and top_level_sources:
|
||||||
|
|
||||||
# Use the frist one
|
# Use the frist one
|
||||||
top_node_id = next(iter(top_level_sources))
|
top_node_id = next(iter(top_level_sources))
|
||||||
top_node = self.graph.nodes[top_node_id]
|
top_node = self.graph.nodes[top_node_id]
|
||||||
|
|
|
@ -96,7 +96,6 @@ class Port:
|
||||||
|
|
||||||
# Selected pins
|
# Selected pins
|
||||||
if range_spec is not None:
|
if range_spec is not None:
|
||||||
|
|
||||||
# TODO: Compile the regex upfront
|
# TODO: Compile the regex upfront
|
||||||
match = re.fullmatch(r"((?P<i1>[0-9]+):)?(?P<i0>[0-9]+)", range_spec)
|
match = re.fullmatch(r"((?P<i1>[0-9]+):)?(?P<i0>[0-9]+)", range_spec)
|
||||||
assert match is not None, range_spec
|
assert match is not None, range_spec
|
||||||
|
@ -164,7 +163,6 @@ class Model:
|
||||||
models = {}
|
models = {}
|
||||||
|
|
||||||
def walk(pb_type):
|
def walk(pb_type):
|
||||||
|
|
||||||
# This is a mode, recurse
|
# This is a mode, recurse
|
||||||
if isinstance(pb_type, Mode):
|
if isinstance(pb_type, Mode):
|
||||||
for child in pb_type.pb_types.values():
|
for child in pb_type.pb_types.values():
|
||||||
|
@ -172,7 +170,6 @@ class Model:
|
||||||
|
|
||||||
# This is a pb_type. Make a model if it is a leaf
|
# This is a pb_type. Make a model if it is a leaf
|
||||||
elif isinstance(pb_type, PbType):
|
elif isinstance(pb_type, PbType):
|
||||||
|
|
||||||
# Not a leaf, recurse for modes
|
# Not a leaf, recurse for modes
|
||||||
if not pb_type.is_leaf:
|
if not pb_type.is_leaf:
|
||||||
for mode in pb_type.modes.values():
|
for mode in pb_type.modes.values():
|
||||||
|
@ -282,13 +279,11 @@ class PbType:
|
||||||
# Build ports
|
# Build ports
|
||||||
for xml_port in elem:
|
for xml_port in elem:
|
||||||
if xml_port.tag in ["input", "output", "clock"]:
|
if xml_port.tag in ["input", "output", "clock"]:
|
||||||
|
|
||||||
port = Port.from_etree(xml_port)
|
port = Port.from_etree(xml_port)
|
||||||
pb_type.ports[port.name] = port
|
pb_type.ports[port.name] = port
|
||||||
|
|
||||||
# This is a native LUT leaf pb_type. Add one more level of hierarchy
|
# This is a native LUT leaf pb_type. Add one more level of hierarchy
|
||||||
if is_leaf_pbtype(elem) and cls == "lut":
|
if is_leaf_pbtype(elem) and cls == "lut":
|
||||||
|
|
||||||
# Rename the default mode so that it matches the pb_type name
|
# Rename the default mode so that it matches the pb_type name
|
||||||
mode = pb_type.modes["default"]
|
mode = pb_type.modes["default"]
|
||||||
mode.name = pb_type.name
|
mode.name = pb_type.name
|
||||||
|
@ -344,7 +339,6 @@ class PbType:
|
||||||
# Walk the hierarchy along the path
|
# Walk the hierarchy along the path
|
||||||
pbtype = self
|
pbtype = self
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
# Pop a node from the path
|
# Pop a node from the path
|
||||||
part = path[0]
|
part = path[0]
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
|
@ -368,7 +362,6 @@ class PbType:
|
||||||
|
|
||||||
# Mode not given
|
# Mode not given
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# No more path, return the pb_type
|
# No more path, return the pb_type
|
||||||
if not path:
|
if not path:
|
||||||
return pbtype
|
return pbtype
|
||||||
|
|
|
@ -85,7 +85,6 @@ class RepackingConstraint:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, net, block_type, port_spec):
|
def __init__(self, net, block_type, port_spec):
|
||||||
|
|
||||||
port = PathNode.from_string(port_spec)
|
port = PathNode.from_string(port_spec)
|
||||||
|
|
||||||
self.net = net
|
self.net = net
|
||||||
|
@ -144,7 +143,6 @@ def fixup_route_throu_luts(clb_block, new_net_ids):
|
||||||
|
|
||||||
for port in block.ports.values():
|
for port in block.ports.values():
|
||||||
for pin, conn in port.connections.items():
|
for pin, conn in port.connections.items():
|
||||||
|
|
||||||
if port.type in ["input", "clock"]:
|
if port.type in ["input", "clock"]:
|
||||||
if blk_inp is None:
|
if blk_inp is None:
|
||||||
blk_inp = Port(port, pin)
|
blk_inp = Port(port, pin)
|
||||||
|
@ -221,10 +219,8 @@ def insert_buffers(nets, eblif, clb_block):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block, net, collected_blocks):
|
def walk(block, net, collected_blocks):
|
||||||
|
|
||||||
# This is a leaf block
|
# This is a leaf block
|
||||||
if block.is_leaf:
|
if block.is_leaf:
|
||||||
|
|
||||||
# Check every input port connection, identify driving nets. Store
|
# Check every input port connection, identify driving nets. Store
|
||||||
# the block if at least one input is driven by the given net.
|
# the block if at least one input is driven by the given net.
|
||||||
for port in block.ports.values():
|
for port in block.ports.values():
|
||||||
|
@ -243,7 +239,6 @@ def insert_buffers(nets, eblif, clb_block):
|
||||||
|
|
||||||
# Insert buffers for each new net
|
# Insert buffers for each new net
|
||||||
for net_inp, net_out in nets:
|
for net_inp, net_out in nets:
|
||||||
|
|
||||||
# Insert the buffer cell. Here it is a LUT-1 configured as buffer.
|
# Insert the buffer cell. Here it is a LUT-1 configured as buffer.
|
||||||
cell = Cell("$lut")
|
cell = Cell("$lut")
|
||||||
cell.name = net_out
|
cell.name = net_out
|
||||||
|
@ -259,7 +254,6 @@ def insert_buffers(nets, eblif, clb_block):
|
||||||
|
|
||||||
# Remap block cell connections
|
# Remap block cell connections
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
|
|
||||||
# Find cell for the block
|
# Find cell for the block
|
||||||
cell = eblif.find_cell(block.name)
|
cell = eblif.find_cell(block.name)
|
||||||
assert cell is not None, block
|
assert cell is not None, block
|
||||||
|
@ -321,7 +315,6 @@ def identify_blocks_to_repack(clb_block, repacking_rules):
|
||||||
|
|
||||||
# This is not a leaf block
|
# This is not a leaf block
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Add the implicit LUT hierarchy to the path
|
# Add the implicit LUT hierarchy to the path
|
||||||
if is_lut:
|
if is_lut:
|
||||||
path.append(PathNode.from_string("lut[0]"))
|
path.append(PathNode.from_string("lut[0]"))
|
||||||
|
@ -371,7 +364,6 @@ def fix_block_path(block_path, arch_path, change_mode=True):
|
||||||
|
|
||||||
# Process the path
|
# Process the path
|
||||||
for i in range(length):
|
for i in range(length):
|
||||||
|
|
||||||
# Parse both path nodes
|
# Parse both path nodes
|
||||||
arch_node = PathNode.from_string(arch_path[i])
|
arch_node = PathNode.from_string(arch_path[i])
|
||||||
block_node = PathNode.from_string(block_path[i])
|
block_node = PathNode.from_string(block_path[i])
|
||||||
|
@ -415,7 +407,6 @@ def identify_repack_target_candidates(clb_pbtype, path):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(arch_path, pbtype, pbtype_index, curr_path=None):
|
def walk(arch_path, pbtype, pbtype_index, curr_path=None):
|
||||||
|
|
||||||
# Parse the path node
|
# Parse the path node
|
||||||
if arch_path:
|
if arch_path:
|
||||||
path_node = PathNode.from_string(arch_path[0])
|
path_node = PathNode.from_string(arch_path[0])
|
||||||
|
@ -445,14 +436,12 @@ def identify_repack_target_candidates(clb_pbtype, path):
|
||||||
|
|
||||||
# Recurse
|
# Recurse
|
||||||
for mode_name, mode in pbtype.modes.items():
|
for mode_name, mode in pbtype.modes.items():
|
||||||
|
|
||||||
# Check mode if given
|
# Check mode if given
|
||||||
if path_node.mode is not None and path_node.mode != mode_name:
|
if path_node.mode is not None and path_node.mode != mode_name:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Recurse for children
|
# Recurse for children
|
||||||
for child, i in mode.yield_children():
|
for child, i in mode.yield_children():
|
||||||
|
|
||||||
# Recurse
|
# Recurse
|
||||||
part = "{}[{}][{}]".format(pbtype_name, pbtype_index, mode_name)
|
part = "{}[{}][{}]".format(pbtype_name, pbtype_index, mode_name)
|
||||||
yield from walk(arch_path, child, i, curr_path + [part])
|
yield from walk(arch_path, child, i, curr_path + [part])
|
||||||
|
@ -501,7 +490,6 @@ def annotate_net_endpoints(clb_graph, block, block_path=None, constraints=None,
|
||||||
nodes_by_net = {}
|
nodes_by_net = {}
|
||||||
|
|
||||||
for node in clb_graph.nodes.values():
|
for node in clb_graph.nodes.values():
|
||||||
|
|
||||||
# Consider only SOURCE and SINK nodes
|
# Consider only SOURCE and SINK nodes
|
||||||
if node.type not in [NodeType.SOURCE, NodeType.SINK]:
|
if node.type not in [NodeType.SOURCE, NodeType.SINK]:
|
||||||
continue
|
continue
|
||||||
|
@ -555,7 +543,6 @@ def annotate_net_endpoints(clb_graph, block, block_path=None, constraints=None,
|
||||||
|
|
||||||
# Reassign top-level SOURCE and SINK nodes according to the constraints
|
# Reassign top-level SOURCE and SINK nodes according to the constraints
|
||||||
for constraint in constraints:
|
for constraint in constraints:
|
||||||
|
|
||||||
# Check if the constraint is for this block type
|
# Check if the constraint is for this block type
|
||||||
if constraint.block_type != block_type:
|
if constraint.block_type != block_type:
|
||||||
continue
|
continue
|
||||||
|
@ -586,7 +573,6 @@ def annotate_net_endpoints(clb_graph, block, block_path=None, constraints=None,
|
||||||
# port or vice-versa.
|
# port or vice-versa.
|
||||||
node_types = set([node.type for node in nodes_by_net[constraint.net]])
|
node_types = set([node.type for node in nodes_by_net[constraint.net]])
|
||||||
if port_node.type not in node_types:
|
if port_node.type not in node_types:
|
||||||
|
|
||||||
name_map = {NodeType.SINK: "output", NodeType.SOURCE: "input"}
|
name_map = {NodeType.SINK: "output", NodeType.SOURCE: "input"}
|
||||||
|
|
||||||
logging.warning(
|
logging.warning(
|
||||||
|
@ -626,7 +612,6 @@ def rotate_truth_table(table, rotation_map):
|
||||||
# Rotate
|
# Rotate
|
||||||
new_table = [0 for i in range(2**width)]
|
new_table = [0 for i in range(2**width)]
|
||||||
for daddr in range(2**width):
|
for daddr in range(2**width):
|
||||||
|
|
||||||
# Remap address bits
|
# Remap address bits
|
||||||
saddr = 0
|
saddr = 0
|
||||||
for i in range(width):
|
for i in range(width):
|
||||||
|
@ -711,7 +696,6 @@ def repack_netlist_cell(eblif, cell, block, src_pbtype, model, rule, def_map=Non
|
||||||
# If the cell is a LUT then rotate its truth table. Append the rotated
|
# If the cell is a LUT then rotate its truth table. Append the rotated
|
||||||
# truth table as a parameter to the repacked cell.
|
# truth table as a parameter to the repacked cell.
|
||||||
if cell.type == "$lut":
|
if cell.type == "$lut":
|
||||||
|
|
||||||
# Build the init parameter
|
# Build the init parameter
|
||||||
init = rotate_truth_table(cell.init, lut_rotation)
|
init = rotate_truth_table(cell.init, lut_rotation)
|
||||||
init = "".join(["1" if x else "0" for x in init][::-1])
|
init = "".join(["1" if x else "0" for x in init][::-1])
|
||||||
|
@ -729,7 +713,6 @@ def repack_netlist_cell(eblif, cell, block, src_pbtype, model, rule, def_map=Non
|
||||||
# If the cell is a LUT-based const generator append the LUT parameter as
|
# If the cell is a LUT-based const generator append the LUT parameter as
|
||||||
# well.
|
# well.
|
||||||
if cell.type == "$const":
|
if cell.type == "$const":
|
||||||
|
|
||||||
assert lut_width == 0, (cell, lut_width)
|
assert lut_width == 0, (cell, lut_width)
|
||||||
|
|
||||||
# Assume that the model is a LUT. Take its widest input port and use
|
# Assume that the model is a LUT. Take its widest input port and use
|
||||||
|
@ -745,7 +728,6 @@ def repack_netlist_cell(eblif, cell, block, src_pbtype, model, rule, def_map=Non
|
||||||
|
|
||||||
# Process parameters for "adder_lut4"
|
# Process parameters for "adder_lut4"
|
||||||
if cell.type == "adder_lut4":
|
if cell.type == "adder_lut4":
|
||||||
|
|
||||||
# Remap the Cin mux select to MODE
|
# Remap the Cin mux select to MODE
|
||||||
if "IN2_IS_CIN" in cell.parameters:
|
if "IN2_IS_CIN" in cell.parameters:
|
||||||
repacked_cell.parameters["MODE"] = cell.parameters["IN2_IS_CIN"]
|
repacked_cell.parameters["MODE"] = cell.parameters["IN2_IS_CIN"]
|
||||||
|
@ -779,10 +761,8 @@ def syncrhonize_attributes_and_parameters(eblif, packed_netlist):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def walk(block):
|
def walk(block):
|
||||||
|
|
||||||
# This is a leaf
|
# This is a leaf
|
||||||
if block.is_leaf and not block.is_open:
|
if block.is_leaf and not block.is_open:
|
||||||
|
|
||||||
if any(block.instance.startswith(inst) for inst in ["outpad", "inpad"]):
|
if any(block.instance.startswith(inst) for inst in ["outpad", "inpad"]):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -845,7 +825,6 @@ def expand_port_maps(rules, clb_pbtypes):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
|
|
||||||
# Get src and dst pb_types
|
# Get src and dst pb_types
|
||||||
path = [PathNode.from_string(p) for p in rule.src.split(".")]
|
path = [PathNode.from_string(p) for p in rule.src.split(".")]
|
||||||
path = [PathNode(p.name, mode=p.mode) for p in path]
|
path = [PathNode(p.name, mode=p.mode) for p in path]
|
||||||
|
@ -860,7 +839,6 @@ def expand_port_maps(rules, clb_pbtypes):
|
||||||
# Expand port map
|
# Expand port map
|
||||||
port_map = {}
|
port_map = {}
|
||||||
for src_port, dst_port in rule.port_map.items():
|
for src_port, dst_port in rule.port_map.items():
|
||||||
|
|
||||||
# Get pin lists
|
# Get pin lists
|
||||||
src_pins = list(src_pbtype.yield_port_pins(src_port))
|
src_pins = list(src_pbtype.yield_port_pins(src_port))
|
||||||
dst_pins = list(dst_pbtype.yield_port_pins(dst_port))
|
dst_pins = list(dst_pbtype.yield_port_pins(dst_port))
|
||||||
|
@ -894,7 +872,6 @@ def load_json_constraints(json_root):
|
||||||
|
|
||||||
constraints = []
|
constraints = []
|
||||||
for json_constr in json_constrs:
|
for json_constr in json_constrs:
|
||||||
|
|
||||||
constraint = RepackingConstraint(
|
constraint = RepackingConstraint(
|
||||||
net=json_constr["net"], block_type=json_constr["tile"], port_spec=json_constr["pin"]
|
net=json_constr["net"], block_type=json_constr["tile"], port_spec=json_constr["pin"]
|
||||||
)
|
)
|
||||||
|
@ -918,7 +895,6 @@ def load_pcf_constraints(pcf):
|
||||||
constraints = []
|
constraints = []
|
||||||
for pcf_constr in parse_simple_pcf(pcf):
|
for pcf_constr in parse_simple_pcf(pcf):
|
||||||
if type(pcf_constr).__name__ == "PcfClkConstraint":
|
if type(pcf_constr).__name__ == "PcfClkConstraint":
|
||||||
|
|
||||||
# There are only "clb" and "io" tile types
|
# There are only "clb" and "io" tile types
|
||||||
# We select the same global clock for
|
# We select the same global clock for
|
||||||
# each tile where net is used
|
# each tile where net is used
|
||||||
|
@ -956,7 +932,6 @@ def write_packed_netlist(fname, netlist):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
@ -1151,7 +1126,6 @@ def main():
|
||||||
iter_list = list(blocks_to_repack)
|
iter_list = list(blocks_to_repack)
|
||||||
blocks_to_repack = []
|
blocks_to_repack = []
|
||||||
for block, rule in iter_list:
|
for block, rule in iter_list:
|
||||||
|
|
||||||
# Remap index of the destination block pointed by the path of the
|
# Remap index of the destination block pointed by the path of the
|
||||||
# rule.
|
# rule.
|
||||||
blk_path = block.get_path()
|
blk_path = block.get_path()
|
||||||
|
@ -1197,7 +1171,6 @@ def main():
|
||||||
# Check for conflicts
|
# Check for conflicts
|
||||||
repack_targets = set()
|
repack_targets = set()
|
||||||
for block, rule, (path, pbtype) in blocks_to_repack:
|
for block, rule, (path, pbtype) in blocks_to_repack:
|
||||||
|
|
||||||
if path in repack_targets:
|
if path in repack_targets:
|
||||||
logging.error("Multiple blocks are to be repacked into '{}'".format(path))
|
logging.error("Multiple blocks are to be repacked into '{}'".format(path))
|
||||||
repack_targets.add(path)
|
repack_targets.add(path)
|
||||||
|
@ -1295,7 +1268,6 @@ def main():
|
||||||
# Restore names of leaf blocks
|
# Restore names of leaf blocks
|
||||||
for src_block, rule, (dst_path, dst_pbtype) in blocks_to_repack:
|
for src_block, rule, (dst_path, dst_pbtype) in blocks_to_repack:
|
||||||
if dst_path in leaf_block_names:
|
if dst_path in leaf_block_names:
|
||||||
|
|
||||||
search_path = dst_path.split(".", maxsplit=1)[1]
|
search_path = dst_path.split(".", maxsplit=1)[1]
|
||||||
dst_block = repacked_clb_block.get_block_by_path(search_path)
|
dst_block = repacked_clb_block.get_block_by_path(search_path)
|
||||||
assert dst_block is not None, dst_path
|
assert dst_block is not None, dst_path
|
||||||
|
@ -1339,7 +1311,6 @@ def main():
|
||||||
# would cause top-level port renaming.
|
# would cause top-level port renaming.
|
||||||
logging.info("Cleaning repacked circuit netlist...")
|
logging.info("Cleaning repacked circuit netlist...")
|
||||||
if absorb_buffer_luts:
|
if absorb_buffer_luts:
|
||||||
|
|
||||||
net_map = netlist_cleaning.absorb_buffer_luts(eblif, outputs=True)
|
net_map = netlist_cleaning.absorb_buffer_luts(eblif, outputs=True)
|
||||||
|
|
||||||
# Synchronize packed netlist net names
|
# Synchronize packed netlist net names
|
||||||
|
@ -1384,7 +1355,6 @@ def main():
|
||||||
# Find the header line
|
# Find the header line
|
||||||
for i in range(len(placement)):
|
for i in range(len(placement)):
|
||||||
if placement[i].startswith("Netlist_File:"):
|
if placement[i].startswith("Netlist_File:"):
|
||||||
|
|
||||||
# Replace the header
|
# Replace the header
|
||||||
placement[i] = "Netlist_File: {} Netlist_ID: {}\n".format(
|
placement[i] = "Netlist_File: {} Netlist_ID: {}\n".format(
|
||||||
os.path.basename(net_out_fname), "SHA256:" + net_digest
|
os.path.basename(net_out_fname), "SHA256:" + net_digest
|
||||||
|
|
|
@ -27,7 +27,6 @@ from eblif_netlist import Eblif # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
def test_netlist_roundtrip():
|
def test_netlist_roundtrip():
|
||||||
|
|
||||||
basedir = os.path.dirname(__file__)
|
basedir = os.path.dirname(__file__)
|
||||||
golden_file = os.path.join(basedir, "netlist.golden.eblif")
|
golden_file = os.path.join(basedir, "netlist.golden.eblif")
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ def test_netlist_roundtrip():
|
||||||
eblif = Eblif.from_file(golden_file)
|
eblif = Eblif.from_file(golden_file)
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
|
||||||
# Write the EBLIF back
|
# Write the EBLIF back
|
||||||
output_file = os.path.join(tempdir, "netlist.output.eblif")
|
output_file = os.path.join(tempdir, "netlist.output.eblif")
|
||||||
eblif.to_file(output_file)
|
eblif.to_file(output_file)
|
||||||
|
|
|
@ -57,7 +57,6 @@ def test_lut_padding(monkeypatch, lut_width, lut_inputs):
|
||||||
net_in = os.path.join(basedir, "lut{}_{}.net".format(lut_width, lut_inputs))
|
net_in = os.path.join(basedir, "lut{}_{}.net".format(lut_width, lut_inputs))
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
|
||||||
eblif_out = os.path.join(tempdir, "out.eblif")
|
eblif_out = os.path.join(tempdir, "out.eblif")
|
||||||
net_out = os.path.join(tempdir, "out.net")
|
net_out = os.path.join(tempdir, "out.net")
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ from packed_netlist import PackedNetlist # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
def test_netlist_roundtrip():
|
def test_netlist_roundtrip():
|
||||||
|
|
||||||
basedir = os.path.dirname(__file__)
|
basedir = os.path.dirname(__file__)
|
||||||
golden_file = os.path.join(basedir, "netlist.golden.net")
|
golden_file = os.path.join(basedir, "netlist.golden.net")
|
||||||
|
|
||||||
|
@ -42,7 +41,6 @@ def test_netlist_roundtrip():
|
||||||
xml_tree = ET.parse(golden_file, ET.XMLParser(remove_blank_text=True))
|
xml_tree = ET.parse(golden_file, ET.XMLParser(remove_blank_text=True))
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
|
||||||
# Transform and save the golden file
|
# Transform and save the golden file
|
||||||
sorted_golden_file = os.path.join(tempdir, "netlist.golden.sorted.net")
|
sorted_golden_file = os.path.join(tempdir, "netlist.golden.sorted.net")
|
||||||
with open(sorted_golden_file, "w") as fp:
|
with open(sorted_golden_file, "w") as fp:
|
||||||
|
|
|
@ -41,7 +41,6 @@ def fixup_cell_names(design):
|
||||||
# Process cells
|
# Process cells
|
||||||
cells = mod_data["cells"]
|
cells = mod_data["cells"]
|
||||||
for cell_name in list(cells.keys()):
|
for cell_name in list(cells.keys()):
|
||||||
|
|
||||||
# Fixup name
|
# Fixup name
|
||||||
if "." in cell_name:
|
if "." in cell_name:
|
||||||
new_name = cell_name.replace(".", "_")
|
new_name = cell_name.replace(".", "_")
|
||||||
|
|
|
@ -187,7 +187,6 @@ class IoPlace(object):
|
||||||
# This is an inout net
|
# This is an inout net
|
||||||
if net_name in self.inout_nets:
|
if net_name in self.inout_nets:
|
||||||
for prefix, suffix in zip(["", "out:"], ["_$inp", "_$out"]):
|
for prefix, suffix in zip(["", "out:"], ["_$inp", "_$out"]):
|
||||||
|
|
||||||
match = NETNAME_REGEX.match(net_name)
|
match = NETNAME_REGEX.match(net_name)
|
||||||
name = prefix + match.group(1) + suffix + match.group(2)
|
name = prefix + match.group(1) + suffix + match.group(2)
|
||||||
|
|
||||||
|
@ -225,7 +224,6 @@ class IoPlace(object):
|
||||||
existing = constrained_blocks[name]
|
existing = constrained_blocks[name]
|
||||||
|
|
||||||
if existing.x != constraint.x or existing.y != constraint.y or existing.z != constraint.z:
|
if existing.x != constraint.x or existing.y != constraint.y or existing.z != constraint.z:
|
||||||
|
|
||||||
print("Error: block '{}' has multiple conflicting constraints!".format(name))
|
print("Error: block '{}' has multiple conflicting constraints!".format(name))
|
||||||
print("", constrained_blocks[name])
|
print("", constrained_blocks[name])
|
||||||
print("", constraint)
|
print("", constraint)
|
||||||
|
|
|
@ -73,7 +73,7 @@ def p_main(blif, map, net, pcf=None, output=stdout, iostandard_defs_file=None, i
|
||||||
net_to_pad |= set((constr.net, constr.pad) for constr in parse_simple_pcf(pcf))
|
net_to_pad |= set((constr.net, constr.pad) for constr in parse_simple_pcf(pcf))
|
||||||
# Check for conflicting pad constraints
|
# Check for conflicting pad constraints
|
||||||
net_to_pad_map = dict()
|
net_to_pad_map = dict()
|
||||||
for (net, pad) in net_to_pad:
|
for net, pad in net_to_pad:
|
||||||
if net not in net_to_pad_map:
|
if net not in net_to_pad_map:
|
||||||
net_to_pad_map[net] = pad
|
net_to_pad_map[net] = pad
|
||||||
elif pad != net_to_pad_map[net]:
|
elif pad != net_to_pad_map[net]:
|
||||||
|
|
|
@ -124,7 +124,6 @@ class PlaceConstraints(object):
|
||||||
existing = constrained_blocks[name]
|
existing = constrained_blocks[name]
|
||||||
|
|
||||||
if existing.x != constraint.x or existing.y != constraint.y or existing.z != constraint.z:
|
if existing.x != constraint.x or existing.y != constraint.y or existing.z != constraint.z:
|
||||||
|
|
||||||
print("Error: block '{}' has multiple conflicting constraints!".format(name))
|
print("Error: block '{}' has multiple conflicting constraints!".format(name))
|
||||||
print("", constrained_blocks[name])
|
print("", constrained_blocks[name])
|
||||||
print("", constraint)
|
print("", constraint)
|
||||||
|
@ -307,7 +306,7 @@ def eprint(*args, **kwargs):
|
||||||
def get_cmt(cmt_dict, loc):
|
def get_cmt(cmt_dict, loc):
|
||||||
"""Returns the clock region of an input location."""
|
"""Returns the clock region of an input location."""
|
||||||
for k, v in cmt_dict.items():
|
for k, v in cmt_dict.items():
|
||||||
for (x, y) in v["vpr_loc"]:
|
for x, y in v["vpr_loc"]:
|
||||||
if x == loc[0] and y == loc[1]:
|
if x == loc[0] and y == loc[1]:
|
||||||
return v["clock_region"]
|
return v["clock_region"]
|
||||||
|
|
||||||
|
@ -421,7 +420,6 @@ class VprGrid(object):
|
||||||
|
|
||||||
class ClockPlacer(object):
|
class ClockPlacer(object):
|
||||||
def __init__(self, vpr_grid, io_locs, blif_data, roi, graph_limit, allow_bufg_logic_sources=False):
|
def __init__(self, vpr_grid, io_locs, blif_data, roi, graph_limit, allow_bufg_logic_sources=False):
|
||||||
|
|
||||||
self.roi = roi
|
self.roi = roi
|
||||||
self.cmt_to_bufg_tile = {}
|
self.cmt_to_bufg_tile = {}
|
||||||
self.bufg_from_cmt = {
|
self.bufg_from_cmt = {
|
||||||
|
@ -573,7 +571,6 @@ class ClockPlacer(object):
|
||||||
clock["sink_nets"].append(sink_net)
|
clock["sink_nets"].append(sink_net)
|
||||||
|
|
||||||
if sink_net not in self.input_pins and sink_net not in self.clock_sources:
|
if sink_net not in self.input_pins and sink_net not in self.clock_sources:
|
||||||
|
|
||||||
# Allow IBUFs. At this point we cannot distinguish between
|
# Allow IBUFs. At this point we cannot distinguish between
|
||||||
# IBUFs for clock and logic.
|
# IBUFs for clock and logic.
|
||||||
if bel == "IBUF_VPR":
|
if bel == "IBUF_VPR":
|
||||||
|
@ -608,7 +605,6 @@ class ClockPlacer(object):
|
||||||
# Store the parent CMT in clock_cmts.
|
# Store the parent CMT in clock_cmts.
|
||||||
for block, loc in block_locs.items():
|
for block, loc in block_locs.items():
|
||||||
if block in self.clock_blocks:
|
if block in self.clock_blocks:
|
||||||
|
|
||||||
clock = self.clock_blocks[block]
|
clock = self.clock_blocks[block]
|
||||||
if CLOCKS[clock["subckt"]]["type"] == "BUFGCTRL":
|
if CLOCKS[clock["subckt"]]["type"] == "BUFGCTRL":
|
||||||
pass
|
pass
|
||||||
|
@ -626,7 +622,6 @@ class ClockPlacer(object):
|
||||||
# Any clocks that were previously constrained must be preserved
|
# Any clocks that were previously constrained must be preserved
|
||||||
for block, (loc_x, loc_y, _) in blocks.items():
|
for block, (loc_x, loc_y, _) in blocks.items():
|
||||||
if block in self.clock_blocks:
|
if block in self.clock_blocks:
|
||||||
|
|
||||||
clock = self.clock_blocks[block]
|
clock = self.clock_blocks[block]
|
||||||
if CLOCKS[clock["subckt"]]["type"] == "BUFGCTRL":
|
if CLOCKS[clock["subckt"]]["type"] == "BUFGCTRL":
|
||||||
pass
|
pass
|
||||||
|
@ -677,7 +672,6 @@ class ClockPlacer(object):
|
||||||
ibuf_cmt_sinks = defaultdict(set)
|
ibuf_cmt_sinks = defaultdict(set)
|
||||||
|
|
||||||
for net in self.clock_sources:
|
for net in self.clock_sources:
|
||||||
|
|
||||||
is_net_ibuf = False
|
is_net_ibuf = False
|
||||||
|
|
||||||
if net not in self.input_pins:
|
if net not in self.input_pins:
|
||||||
|
@ -688,7 +682,6 @@ class ClockPlacer(object):
|
||||||
is_net_ibuf = True
|
is_net_ibuf = True
|
||||||
|
|
||||||
for clock_name in self.clock_sources[net]:
|
for clock_name in self.clock_sources[net]:
|
||||||
|
|
||||||
if clock_name in unused_blocks:
|
if clock_name in unused_blocks:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -413,7 +413,6 @@ def create_bit_to_cell_map(design, top_module):
|
||||||
for port, connections in cell["connections"].items():
|
for port, connections in cell["connections"].items():
|
||||||
is_output = port_directions[port] == "output"
|
is_output = port_directions[port] == "output"
|
||||||
for bit_idx, bit in enumerate(connections):
|
for bit_idx, bit in enumerate(connections):
|
||||||
|
|
||||||
list_of_cells = bit_to_cells.get(bit, None)
|
list_of_cells = bit_to_cells.get(bit, None)
|
||||||
if list_of_cells is None:
|
if list_of_cells is None:
|
||||||
list_of_cells = [None]
|
list_of_cells = [None]
|
||||||
|
@ -570,7 +569,6 @@ def fixup_congested_rows(design, top_module, bit_to_cells, bit_to_nets, chain):
|
||||||
# If this is the last CARRY4 in the chain, see if the
|
# If this is the last CARRY4 in the chain, see if the
|
||||||
# remaining part of the chain is idle.
|
# remaining part of the chain is idle.
|
||||||
elif chain_idx == len(chain) - 1 and check_if_rest_of_carry4_is_unused(cellname, cell_idx + 1):
|
elif chain_idx == len(chain) - 1 and check_if_rest_of_carry4_is_unused(cellname, cell_idx + 1):
|
||||||
|
|
||||||
# Because the rest of the CARRY4 is idle, it is safe to
|
# Because the rest of the CARRY4 is idle, it is safe to
|
||||||
# use the next row up to output the top of the carry.
|
# use the next row up to output the top of the carry.
|
||||||
connections["S{}".format(cell_idx + 1)] = ["1'b0"]
|
connections["S{}".format(cell_idx + 1)] = ["1'b0"]
|
||||||
|
|
|
@ -168,7 +168,6 @@ def main(input: str, output: str = None):
|
||||||
net_map = {}
|
net_map = {}
|
||||||
port_map = []
|
port_map = []
|
||||||
for name, port in inouts.items():
|
for name, port in inouts.items():
|
||||||
|
|
||||||
# Remove the inout port from the module
|
# Remove the inout port from the module
|
||||||
del module["ports"][name]
|
del module["ports"][name]
|
||||||
nets -= get_nets(port["bits"])
|
nets -= get_nets(port["bits"])
|
||||||
|
@ -215,10 +214,8 @@ def main(input: str, output: str = None):
|
||||||
|
|
||||||
# Remove remapped nets
|
# Remove remapped nets
|
||||||
for name, net in list(netnames.items()):
|
for name, net in list(netnames.items()):
|
||||||
|
|
||||||
# Remove "bits" used by the net that were re-mapped.
|
# Remove "bits" used by the net that were re-mapped.
|
||||||
if len(set(net["bits"]) & set(net_map.keys())):
|
if len(set(net["bits"]) & set(net_map.keys())):
|
||||||
|
|
||||||
# Remove
|
# Remove
|
||||||
net["bits"] = ["x" if b in net_map else b for b in net["bits"]]
|
net["bits"] = ["x" if b in net_map else b for b in net["bits"]]
|
||||||
|
|
||||||
|
@ -250,7 +247,6 @@ def main(input: str, output: str = None):
|
||||||
|
|
||||||
# Process cell connections
|
# Process cell connections
|
||||||
for port_name, port_nets in list(connections.items()):
|
for port_name, port_nets in list(connections.items()):
|
||||||
|
|
||||||
# Skip if no net of this connection were remapped
|
# Skip if no net of this connection were remapped
|
||||||
if len(set(net_map.keys()) & set(port_nets)) == 0:
|
if len(set(net_map.keys()) & set(port_nets)) == 0:
|
||||||
continue
|
continue
|
||||||
|
@ -259,7 +255,6 @@ def main(input: str, output: str = None):
|
||||||
# versa.
|
# versa.
|
||||||
for dir in ["input", "output"]:
|
for dir in ["input", "output"]:
|
||||||
if port_directions[port_name] == dir and port_name.endswith("$" + dir[:3]):
|
if port_directions[port_name] == dir and port_name.endswith("$" + dir[:3]):
|
||||||
|
|
||||||
for i, n in enumerate(port_nets):
|
for i, n in enumerate(port_nets):
|
||||||
if n in net_map:
|
if n in net_map:
|
||||||
mapped_n = net_map[n][dir[0]]
|
mapped_n = net_map[n][dir[0]]
|
||||||
|
|
|
@ -144,7 +144,6 @@ def p_parse_vpr_args(vpr_options=None, log_suffix=None, isQuickLogic=False):
|
||||||
|
|
||||||
|
|
||||||
def p_parse_vpr_args_xc7(vpr_options=None, log_suffix=None):
|
def p_parse_vpr_args_xc7(vpr_options=None, log_suffix=None):
|
||||||
|
|
||||||
parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter)
|
parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter)
|
||||||
parser.add_argument("--device", "-d", required=False, type=str, help="")
|
parser.add_argument("--device", "-d", required=False, type=str, help="")
|
||||||
parser.add_argument("--eblif", "-e", required=True, type=str, help="")
|
parser.add_argument("--eblif", "-e", required=True, type=str, help="")
|
||||||
|
@ -253,7 +252,6 @@ def p_parse_vpr_args_xc7(vpr_options=None, log_suffix=None):
|
||||||
|
|
||||||
|
|
||||||
def p_parse_vpr_args_quicklogic(vpr_options=None, log_suffix=None):
|
def p_parse_vpr_args_quicklogic(vpr_options=None, log_suffix=None):
|
||||||
|
|
||||||
parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter)
|
parser = ArgumentParser(description=__doc__, formatter_class=RawDescriptionHelpFormatter)
|
||||||
parser.add_argument("--device", "-d", required=True, type=str, help="")
|
parser.add_argument("--device", "-d", required=True, type=str, help="")
|
||||||
parser.add_argument("--family", "-f", required=True, type=str, help="")
|
parser.add_argument("--family", "-f", required=True, type=str, help="")
|
||||||
|
|
Loading…
Reference in New Issue