OpenFPGA/openfpga_flow/scripts/create_ioplace.py

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()