190 lines
5.7 KiB
Python
Executable File
190 lines
5.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Convert a PCF file into a VPR io.place file.
|
|
"""
|
|
import argparse
|
|
import csv
|
|
import sys
|
|
import re
|
|
from collections import defaultdict
|
|
|
|
import vpr_io_place
|
|
from pinmap_parse import read_pinmapfile_data
|
|
from pinmap_parse import vec_to_scalar
|
|
|
|
from lib.parse_pcf import parse_simple_pcf
|
|
|
|
# =============================================================================
|
|
|
|
BLOCK_INSTANCE_RE = re.compile(r"^(?P<name>\S+)\[(?P<index>[0-9]+)\]$")
|
|
|
|
|
|
# =============================================================================
|
|
def gen_io_def(args):
|
|
'''
|
|
Generate io.place file from pcf file
|
|
'''
|
|
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)
|
|
|
|
# Load all the necessary data from the pinmap_xml
|
|
io_cells, port_map = read_pinmapfile_data(args.pinmap_xml)
|
|
|
|
# Map of pad names to VPR locations.
|
|
pad_map = defaultdict(lambda: dict())
|
|
|
|
with open(args.csv_file, mode='r') as csv_fp:
|
|
reader = csv.DictReader(csv_fp)
|
|
for line in reader:
|
|
port_name_list = vec_to_scalar(line['port_name'])
|
|
pin_name = vec_to_scalar(line['mapped_pin'])
|
|
gpio_type = line['GPIO_type']
|
|
|
|
if len(port_name_list) != len(pin_name):
|
|
print(
|
|
'CSV port name "{}" length does not match with mapped pin name "{}" length'
|
|
.format(line['port_name'], line['mapped_pin']),
|
|
file=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
|
|
for port, pin in zip(port_name_list, pin_name):
|
|
if port in port_map:
|
|
curr_map = port_map[port]
|
|
if gpio_type is None or gpio_type == '':
|
|
pad_map[pin] = (
|
|
int(curr_map.x), int(curr_map.y), int(curr_map.z)
|
|
)
|
|
else:
|
|
gpio_pin = pin + ":" + gpio_type.strip()
|
|
pad_map[gpio_pin] = (
|
|
int(curr_map.x), int(curr_map.y), int(curr_map.z)
|
|
)
|
|
else:
|
|
print(
|
|
'Port name "{}" specified in csv file "{}" is invalid. {} "{}"'
|
|
.format(
|
|
line['port_name'], args.csv_file,
|
|
"Specify from port names in xml file",
|
|
args.pinmap_xml
|
|
),
|
|
file=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
|
|
for pcf_constraint in parse_simple_pcf(args.pcf):
|
|
if (type(pcf_constraint).__name__ == 'PcfIoConstraint'):
|
|
pad_name = pcf_constraint.pad
|
|
if not io_place.is_net(pcf_constraint.net):
|
|
print(
|
|
'PCF constraint "{}" from line {} constraints net {} {}:\n{}'
|
|
.format(
|
|
pcf_constraint.line_str, pcf_constraint.line_num,
|
|
pcf_constraint.net, '\n'.join(io_place.get_nets()),
|
|
"which is not in available netlist"
|
|
),
|
|
file=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
|
|
if pad_name not in pad_map:
|
|
print(
|
|
'PCF constraint "{}" from line {} constraints pad {} {}:\n{}'
|
|
.format(
|
|
pcf_constraint.line_str, pcf_constraint.line_num,
|
|
pad_name, '\n'.join(sorted(pad_map.keys())),
|
|
"which is not in available pad map"
|
|
),
|
|
file=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
|
|
# Get the top-level block instance, strip its index
|
|
inst = io_place.get_top_level_block_instance_for_net(
|
|
pcf_constraint.net
|
|
)
|
|
if inst is None:
|
|
continue
|
|
|
|
match = BLOCK_INSTANCE_RE.match(inst)
|
|
assert match is not None, inst
|
|
|
|
inst = match.group("name")
|
|
|
|
# Constraint the net (block)
|
|
locs = pad_map[pad_name]
|
|
io_place.constrain_net(
|
|
net_name=pcf_constraint.net,
|
|
loc=locs,
|
|
comment=pcf_constraint.line_str
|
|
)
|
|
|
|
if io_place.constraints:
|
|
io_place.output_io_place(args.output)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
def main():
|
|
'''
|
|
Convert a PCF file into a VPR io.place file
|
|
'''
|
|
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=True,
|
|
help='PCF input file'
|
|
)
|
|
parser.add_argument(
|
|
"--blif",
|
|
"-b",
|
|
type=argparse.FileType('r'),
|
|
required=True,
|
|
help='BLIF / eBLIF file'
|
|
)
|
|
parser.add_argument(
|
|
"--output",
|
|
"-o",
|
|
"-O",
|
|
type=argparse.FileType('w'),
|
|
default=sys.stdout,
|
|
help='The output io.place file'
|
|
)
|
|
parser.add_argument(
|
|
"--net",
|
|
"-n",
|
|
type=argparse.FileType('r'),
|
|
required=True,
|
|
help='top.net file'
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--pinmap_xml",
|
|
type=str,
|
|
required=True,
|
|
help="Input pin-mapping xml file"
|
|
)
|
|
parser.add_argument(
|
|
"--csv_file",
|
|
type=str,
|
|
required=True,
|
|
help="Input user-defined pinmap CSV file"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
gen_io_def(args)
|
|
|
|
|
|
# =============================================================================
|
|
|
|
if __name__ == '__main__':
|
|
main()
|