blob: 00e824e804d2cb48f8ca18392fcce1c23e388cf6 [file] [log] [blame] [edit]
""" 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()