#!/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\S+)\[(?P[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()