blob: c8a497bce847b7a20d20e99994a419764d497092 [file] [log] [blame]
#!/usr/bin/env python3
import argparse
import sys
import csv
import eblif
# =============================================================================
def main():
parser = argparse.ArgumentParser(
description='Creates placement constraints other than IOs'
)
parser.add_argument(
"--input",
'-i',
"-I",
type=argparse.FileType('r'),
default=sys.stdin,
help='The input constraints place file.'
)
parser.add_argument(
"--output",
'-o',
"-O",
type=argparse.FileType('w'),
default=sys.stdout,
help='The output constraints place file.'
)
parser.add_argument(
"--map",
type=argparse.FileType('r'),
required=True,
help="Clock pinmap CSV file"
)
parser.add_argument(
"--blif",
'-b',
type=argparse.FileType('r'),
required=True,
help='BLIF / eBLIF file.'
)
args = parser.parse_args()
# Load clock map
clock_to_gmux = {}
for row in csv.DictReader(args.map):
name = row["name"]
src_loc = (
int(row["src.x"]),
int(row["src.y"]),
int(row["src.z"]),
)
dst_loc = (
int(row["dst.x"]),
int(row["dst.y"]),
int(row["dst.z"]),
)
clock_to_gmux[src_loc] = (dst_loc, name)
# Load EBLIF
eblif_data = eblif.parse_blif(args.blif)
# Process the IO constraints file. Pass the constraints unchanged, store
# them.
io_constraints = {}
for line in args.input:
# Strip, skip comments
line = line.strip()
if line.startswith("#"):
continue
args.output.write(line + "\n")
# Get block and its location
block, x, y, z = line.split()[0:4]
io_constraints[block] = (
int(x),
int(y),
int(z),
)
# Analyze the BLIF netlist. Find clock inputs that go through CLOCK IOB to
# GMUXes.
clock_connections = []
IOB_CELL = ("CLOCK_CELL", "I_PAD", "O_CLK")
BUF_CELL = ("GMUX_IP", "IP", "IZ")
for inp_net in eblif_data["inputs"]["args"]:
# This one is not constrained, skip it
if inp_net not in io_constraints:
continue
# Search for a CLOCK cell connected to that net
for cell in eblif_data["subckt"]:
if cell["type"] == "subckt" and cell["args"][0] == IOB_CELL[0]:
iob_cell = cell
else:
continue
# Get the CLOCK to GMUX net
for i in range(1, len(iob_cell["args"])):
pin, net = iob_cell["args"][i].split("=")
if pin == IOB_CELL[2]:
con_net = net
break
else:
continue
# Search for a GMUX connected to the CLOCK cell
for cell in eblif_data["subckt"]:
if cell["type"] == "subckt" and cell["args"][0] == BUF_CELL[0]:
buf_cell = cell
else:
continue
# Get the output net of the GMUX
for i in range(1, len(buf_cell["args"])):
pin, net = buf_cell["args"][i].split("=")
if pin == BUF_CELL[2]:
clk_net = net
break
else:
continue
# Store data
clock_connections.append(
(inp_net, iob_cell, con_net, buf_cell, clk_net)
)
# Emit constraints for GCLK cells
for inp_net, iob_cell, con_net, buf_cell, clk_net in clock_connections:
src_loc = io_constraints[inp_net]
if src_loc not in clock_to_gmux:
print(
"ERROR: No GMUX location fro input CLOCK pad for net '{}' at {}"
.format(inp_net, src_loc)
)
continue
dst_loc, name = clock_to_gmux[src_loc]
# FIXME: Silently assuming here that VPR will name the GMUX block as
# the GMUX cell in EBLIF. In order to fix that there will be a need
# to read & parse the packed netlist file.
line = "{} {} {} {} # {}\n".format(
buf_cell["cname"][0], *dst_loc, name
)
args.output.write(line)
# =============================================================================
if __name__ == '__main__':
main()