| #!/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() |