| """ Convert a PCF file into a VPR io.place file. """ | |
| from __future__ import print_function | |
| import argparse | |
| import csv | |
| import json | |
| import sys | |
| import os | |
| import vpr_io_place | |
| from lib.parse_pcf import parse_simple_pcf | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description='Convert a PCF file into a VPR io.place file.' | |
| ) | |
| parser.add_argument( | |
| "--pcf", | |
| '-p', | |
| "-P", | |
| type=argparse.FileType('r'), | |
| required=False, | |
| help='PCF input file' | |
| ) | |
| parser.add_argument( | |
| "--blif", | |
| '-b', | |
| type=argparse.FileType('r'), | |
| required=True, | |
| help='BLIF / eBLIF file' | |
| ) | |
| parser.add_argument( | |
| "--map", | |
| '-m', | |
| "-M", | |
| type=argparse.FileType('r'), | |
| required=True, | |
| help='Pin map CSV file' | |
| ) | |
| parser.add_argument( | |
| "--output", | |
| '-o', | |
| "-O", | |
| type=argparse.FileType('w'), | |
| default=sys.stdout, | |
| help='The output io.place file' | |
| ) | |
| parser.add_argument( | |
| "--iostandard_defs", help='(optional) Output IOSTANDARD def file' | |
| ) | |
| parser.add_argument( | |
| "--iostandard", | |
| default="LVCMOS33", | |
| help='Default IOSTANDARD to use for pins', | |
| ) | |
| parser.add_argument( | |
| "--drive", | |
| type=int, | |
| default=12, | |
| help='Default drive to use for pins', | |
| ) | |
| parser.add_argument( | |
| "--net", | |
| '-n', | |
| type=argparse.FileType('r'), | |
| required=True, | |
| help='top.net file' | |
| ) | |
| args = parser.parse_args() | |
| io_place = vpr_io_place.IoPlace() | |
| io_place.read_io_list_from_eblif(args.blif) | |
| io_place.load_block_names_from_net_file(args.net) | |
| # Map of pad names to VPR locations. | |
| pad_map = {} | |
| for pin_map_entry in csv.DictReader(args.map): | |
| pad_map[pin_map_entry['name']] = ( | |
| ( | |
| int(pin_map_entry['x']), | |
| int(pin_map_entry['y']), | |
| int(pin_map_entry['z']), | |
| ), | |
| pin_map_entry['is_output'], | |
| pin_map_entry['iob'], | |
| pin_map_entry['real_io_assoc'], | |
| ) | |
| iostandard_defs = {} | |
| # Load iostandard constraints. This is a temporary workaround that allows | |
| # to pass them into fasm2bels. As soon as there is support for XDC this | |
| # will not be needed anymore. | |
| # If there is a JSON file with the same name as the PCF file then it is | |
| # loaded and used as iostandard constraint source NOT for the design but | |
| # to be used in fasm2bels. | |
| iostandard_constraints = {} | |
| if args.pcf: | |
| fname = args.pcf.name.replace(".pcf", ".json") | |
| if os.path.isfile(fname): | |
| with open(fname, "r") as fp: | |
| iostandard_constraints = json.load(fp) | |
| net_to_pad = io_place.net_to_pad | |
| if args.pcf: | |
| pcf_constraints = parse_simple_pcf(args.pcf) | |
| net_to_pad |= set( | |
| (constr.net, constr.pad) for constr in pcf_constraints | |
| ) | |
| # Check for conflicting pad constraints | |
| net_to_pad_map = dict() | |
| for (net, pad) in net_to_pad: | |
| if net not in net_to_pad_map: | |
| net_to_pad_map[net] = pad | |
| elif pad != net_to_pad_map[net]: | |
| print( | |
| """ERROR: | |
| Conflicting pad constraints for net {}:\n{}\n{}""".format( | |
| net, pad, net_to_pad_map[net] | |
| ), | |
| file=sys.stderr | |
| ) | |
| sys.exit(1) | |
| # Constrain nets | |
| for net, pad in net_to_pad: | |
| if not io_place.is_net(net): | |
| print( | |
| """ERROR: | |
| Constrained net {} is not in available netlist:\n{}""".format( | |
| net, '\n'.join(io_place.get_nets()) | |
| ), | |
| file=sys.stderr | |
| ) | |
| sys.exit(1) | |
| if pad not in pad_map: | |
| print( | |
| """ERROR: | |
| Constrained pad {} is not in available pad map:\n{}""".format( | |
| pad, '\n'.join(sorted(pad_map.keys())) | |
| ), | |
| file=sys.stderr | |
| ) | |
| sys.exit(1) | |
| loc, is_output, iob, real_io_assoc = pad_map[pad] | |
| io_place.constrain_net( | |
| net_name=net, | |
| loc=loc, | |
| comment="set_property LOC {} [get_ports {{{}}}]".format(pad, net) | |
| ) | |
| if real_io_assoc == 'True': | |
| if pad in iostandard_constraints: | |
| iostandard_defs[iob] = iostandard_constraints[pad] | |
| else: | |
| if is_output: | |
| iostandard_defs[iob] = { | |
| 'DRIVE': args.drive, | |
| 'IOSTANDARD': args.iostandard, | |
| } | |
| else: | |
| iostandard_defs[iob] = { | |
| 'IOSTANDARD': args.iostandard, | |
| } | |
| io_place.output_io_place(args.output) | |
| # Write iostandard definitions | |
| if args.iostandard_defs: | |
| with open(args.iostandard_defs, 'w') as f: | |
| json.dump(iostandard_defs, f, indent=2) | |
| if __name__ == '__main__': | |
| main() |