def main(argv): args = parser.parse_args() def output_block(name, s): if args.verbose: print() print(name, '-' * (75 - (len(name) + 1))) print(s, end="") if s[-1] != '\n': print() print('-' * 75) args.width_bits = mux_lib.clog2(args.width) def normpath(p, to=None): p = os.path.realpath(os.path.abspath(p)) if to is None: return p return os.path.relpath(p, normpath(to)) mypath = normpath(__file__) if not args.outdir: outdir = os.path.join(".", args.name_mux.lower()) else: outdir = args.outdir outdir = normpath(outdir) mydir = normpath(os.path.dirname(mypath), to=outdir) mux_dir = normpath(os.path.join(mydir, '..', 'vpr', 'muxes'), to=outdir) if args.data_width > 1 and not args.split_inputs: assert False, "data_width(%d) > 1 requires using split_inputs" % ( args.data_width) if args.name_inputs: assert_eq(args.name_input, parser.get_default("name_input")) args.name_input = None args.split_inputs = True names = args.name_inputs.split(',') assert len(names) == args.width, "%s input names, but %s needed." % ( names, args.width) args.name_inputs = names elif args.split_inputs: args.name_inputs = [ args.name_input + str(i) for i in range(args.width) ] parser.name_inputs.default = args.name_inputs assert_eq(parser.get_default("name_inputs"), args.name_inputs) if args.name_selects: assert_eq(args.name_select, parser.get_default("name_select")) args.name_select = None args.split_selects = True names = args.name_selects.split(',') assert len(names) == args.width_bits, ( "%s select names, but %s needed." % (names, args.width_bits)) args.name_selects = names elif args.split_selects: args.name_selects = [ args.name_select + str(i) for i in range(args.width_bits) ] parser.name_selects.default = args.name_selects assert_eq(parser.get_default("name_selects"), args.name_selects) os.makedirs(outdir, exist_ok=True) # Generated headers generated_with = """ Generated with %s """ % mypath if args.comment: generated_with = "\n".join([args.comment, generated_with]) # XML Files can't have "--" in them, so instead we use ~~ xml_comment = generated_with.replace("--", "~~") if not args.outfilename: args.outfilename = args.name_mux.lower() model_xml_filename = '%s.model.xml' % args.outfilename pbtype_xml_filename = '%s.pb_type.xml' % args.outfilename sim_filename = '%s.sim.v' % args.outfilename # ------------------------------------------------------------------------ # Work out the port and their names # ------------------------------------------------------------------------ port_names = [] for i in args.order: if i == 'i': if args.split_inputs: port_names.extend( mux_lib.ModulePort(mux_lib.MuxPinType.INPUT, args.name_inputs[j], 1, '[%i]' % j, args.data_width) for j in range(args.width)) else: # verilog range bounds are inclusive and convention is # [<width-1>:0] port_names.append( mux_lib.ModulePort(mux_lib.MuxPinType.INPUT, args.name_input, args.width, '[%i:0]' % (args.width - 1))) elif i == 's': if args.split_selects: port_names.extend( mux_lib.ModulePort(mux_lib.MuxPinType.SELECT, args.name_selects[j], 1, '[%i]' % j) for j in range(args.width_bits)) else: # verilog range bounds are inclusive and convention is # [<width-1>:0] assert args.name_select is not None port_names.append( mux_lib.ModulePort(mux_lib.MuxPinType.SELECT, args.name_select, args.width_bits, '[%i:0]' % (args.width_bits - 1))) elif i == 'o': port_names.append( mux_lib.ModulePort(mux_lib.MuxPinType.OUTPUT, args.name_output, 1, '', args.data_width)) # ------------------------------------------------------------------------ # Generate the sim.v Verilog module # ------------------------------------------------------------------------ sim_pathname = os.path.join(outdir, sim_filename) with open(sim_pathname, "w") as f: module_args = [] for port in port_names: if args.type == 'routing' and port.pin_type == mux_lib.MuxPinType.SELECT: continue module_args.append(port.name) mux_class = {'logic': 'mux', 'routing': 'routing'}[args.type] f.write("/* ") f.write("\n * ".join(generated_with.splitlines())) f.write("\n */\n\n") f.write('`include "%s/%s/%smux%i/%smux%i.sim.v"\n' % ( mux_dir, 'logic', '', args.width, '', args.width, )) f.write("\n") f.write('(* whitebox *) (* CLASS="%s" *)\n' % mux_class) f.write("module %s(%s);\n" % (args.name_mux, ", ".join(module_args))) previous_type = None for port in port_names: if previous_type != port.pin_type: f.write("\n") previous_type = port.pin_type if args.type == 'routing' and port.pin_type == mux_lib.MuxPinType.SELECT: f.write(port.getParameterString()) continue else: f.write(port.getDefinition()) f.write("\n") if args.data_width > 1: f.write('\tgenvar\tii;\n') f.write('\tfor(ii=0; ii<%d; ii++) begin: bitmux\n' % (args.data_width)) f.write('\tMUX%s mux (\n' % args.width) for i in range(0, args.width): j = 0 for port in port_names: if port.pin_type != mux_lib.MuxPinType.INPUT: continue if j + port.width <= i: j += port.width continue break if port.width == 1: if args.data_width > 1: f.write('\t\t.I%i(%s[ii]),\n' % (i, port.name)) else: f.write('\t\t.I%i(%s),\n' % (i, port.name)) else: f.write('\t\t.I%i(%s[%i]),\n' % (i, port.name, i - j)) for i in range(0, args.width_bits): j = 0 for port in port_names: if port.pin_type != mux_lib.MuxPinType.SELECT: continue if j + port.width < i: j += port.width continue break if port.width == 1: f.write('\t\t.S%i(%s),\n' % (i, port.name)) else: f.write('\t\t.S%i(%s[%i]),\n' % (i, port.name, i - j)) for port in port_names: if port.pin_type != mux_lib.MuxPinType.OUTPUT: continue break assert_eq(port.width, 1) if args.data_width > 1: f.write('\t\t.O(%s[ii])\n\t);\n' % port.name) else: f.write('\t\t.O(%s)\n\t);\n' % port.name) if args.data_width > 1: f.write('end\n') f.write('endmodule\n') output_block(sim_filename, open(sim_pathname).read()) if args.type == 'logic': subckt = args.subckt or args.name_mux assert subckt elif args.type == 'routing': assert args.subckt is None subckt = None # ------------------------------------------------------------------------ # Generate the Model XML form. # ------------------------------------------------------------------------ def xml_comment_indent(n, s): return ("\n" + " " * n).join(s.splitlines() + [""]) if args.type == 'logic': models_xml = ET.Element('models') models_xml.append(ET.Comment(xml_comment_indent(4, xml_comment))) model_xml = ET.SubElement(models_xml, 'model', {'name': subckt}) input_ports = ET.SubElement(model_xml, 'input_ports') output_ports = ET.SubElement(model_xml, 'output_ports') for port in port_names: if port.pin_type in (mux_lib.MuxPinType.INPUT, mux_lib.MuxPinType.SELECT): ET.SubElement( input_ports, 'port', { 'name': port.name, 'combinational_sink_ports': ' '.join( port.name for port in port_names if port.pin_type in (mux_lib.MuxPinType.OUTPUT, )), }) elif port.pin_type in (mux_lib.MuxPinType.OUTPUT, ): ET.SubElement(output_ports, 'port', {'name': port.name}) models_str = ET.tostring(models_xml, pretty_print=True).decode('utf-8') else: models_str = "<models><!-- No models for routing elements.--></models>" output_block(model_xml_filename, models_str) with open(os.path.join(outdir, model_xml_filename), "w") as f: f.write(models_str) # ------------------------------------------------------------------------ # Generate the pb_type XML form. # ------------------------------------------------------------------------ pb_type_xml = mux_lib.pb_type_xml( mux_lib.MuxType[args.type.upper()], args.name_mux, port_names, subckt=subckt, num_pb=args.num_pb, comment=xml_comment_indent(4, xml_comment), ) pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8') output_block(pbtype_xml_filename, pb_type_str) with open(os.path.join(outdir, pbtype_xml_filename), "w") as f: f.write(pb_type_str) print("Generated mux {} in {}".format(args.name_mux, outdir))
] for src_wire, index in sorted(srcs): if src_wire in net_dirs['inputs']: src_wire_name = "%s.%s[%s]" % (tile_name, src_wire, index) else: assert src_wire in net_dirs['outputs'] src_wire_name = "BEL_RX-%s%s.OUT" % (src_wire, index) mux_wire_name = "%s%s" % (src_wire, index) add_direct(src_wire_name, "%s.%s" % (mux_name, mux_wire_name)) port_names.append( mux_lib.ModulePort(mux_lib.MuxPinType.INPUT, mux_wire_name, 1, 0), ) pb_type_xml.append( mux_lib.pb_type_xml(mux_lib.MuxType.ROUTING, mux_name, port_names)) add_direct("%s.OUT" % mux_name, dst_wire_name) else: assert (span_wire, pin) not in connections_map[ 'mux'] or not connections_map['mux'][(span_wire, pin)] for clock_wire, pins in sorted(wires_by_type['clock'].items()): ET.SubElement( pb_type_xml, 'clock', { 'name': clock_wire, 'num_pins': str(len(pins)) }, )
def main(argv): call_args = list(argv) args = parser.parse_args() def output_block(name, s): if args.verbose: print() print(name, '-' * (75 - (len(name) + 1))) print(s, end="") if s[-1] != '\n': print() print('-' * 75) args.width_bits = mux_lib.clog2(args.width) def normpath(p, to=None): p = os.path.realpath(os.path.abspath(p)) if to is None: return p return os.path.relpath(p, normpath(to)) mypath = normpath(__file__) if not args.outdir: outdir = os.path.join(".", args.name_mux.lower()) else: outdir = args.outdir outdir = normpath(outdir) mydir = normpath(os.path.dirname(mypath), to=outdir) mypath = normpath(mypath, to=outdir) mux_dir = normpath(os.path.join(mydir, '..', 'vpr', 'muxes'), to=outdir) buf_dir = normpath(os.path.join(mydir, '..', 'vpr', 'buf'), to=outdir) mux_mk = normpath(os.path.join(mydir, '..', 'common', 'make', 'mux.mk'), to=outdir) if args.name_inputs: assert_eq(args.name_input, parser.get_default("name_input")) args.name_input = None args.split_inputs = True names = args.name_inputs.split(',') assert len(names) == args.width, "%s input names, but %s needed." % ( names, args.width) args.name_inputs = names elif args.split_inputs: args.name_inputs = [ args.name_input + str(i) for i in range(args.width) ] parser.name_inputs.default = args.name_inputs assert_eq(parser.get_default("name_inputs"), args.name_inputs) if args.name_selects: assert_eq(args.name_select, parser.get_default("name_select")) args.name_select = None args.split_selects = True names = args.name_selects.split(',') assert len( names) == args.width_bits, "%s select names, but %s needed." % ( names, args.width_bits) args.name_selects = names elif args.split_selects: args.name_selects = [ args.name_select + str(i) for i in range(args.width_bits) ] parser.name_selects.default = args.name_selects assert_eq(parser.get_default("name_selects"), args.name_selects) os.makedirs(outdir, exist_ok=True) # Generated headers generated_with = """ Generated with %s """ % mypath if args.comment: generated_with = "\n".join([args.comment, generated_with]) # XML Files can't have "--" in them, so instead we use ~~ xml_comment = generated_with.replace("--", "~~") # ------------------------------------------------------------------------ # Create a makefile to regenerate files. # ------------------------------------------------------------------------ makefile_file = os.path.join(outdir, "Makefile.mux") if not args.outfilename: args.outfilename = args.name_mux.lower() model_xml_filename = '%s.model.xml' % args.outfilename pbtype_xml_filename = '%s.pb_type.xml' % args.outfilename sim_filename = '%s.sim.v' % args.outfilename output_files = [ model_xml_filename, pbtype_xml_filename, sim_filename, 'Makefile.mux' ] commit_files = ["Makefile.mux"] remove_files = [f for f in output_files if f not in commit_files] new_makefile_contents = io.StringIO() if True: f = new_makefile_contents # Comment goes first so it is the first thing people see. if args.comment: print("MUX_COMMENT = {}".format(args.comment), file=f) # Required values print("MUX_TYPE = {}".format(args.type.lower()), file=f) print("MUX_OUTFILE = {}".format(args.outfilename), file=f) print("MUX_NAME = {}".format(args.name_mux), file=f) print("MUX_WIDTH = {}".format(args.width), file=f) # Optional values if args.split_inputs: print("MUX_SPLIT_INPUTS = 1", file=f) if args.name_inputs != parser.get_default('name_inputs'): print("MUX_INPUTS = {}".format(",".join(args.name_inputs)), file=f) else: if args.name_input != parser.get_default('name_input'): print("MUX_INPUT = {}".format(args.name_input), file=f) if args.split_selects: print("MUX_SPLIT_SELECTS = 1", file=f) if args.name_selects != parser.get_default('name_selects'): print("MUX_SELECTS = {}".format(",".join(args.name_selects)), file=f) else: if args.name_select != parser.get_default('name_select'): print("MUX_SELECT = {}".format(args.name_select), file=f) if args.name_output != parser.get_default('name_output'): print("MUX_OUTPUT = {}".format(args.name_output), file=f) if args.order != parser.get_default('order'): print("MUX_ORDER = {}".format(args.order), file=f) if args.subckt != parser.get_default('subckt'): print("MUX_SUBCKT = {}".format(args.subckt), file=f) new_makefile_contents = new_makefile_contents.getvalue() if not os.path.exists(makefile_file): current_makefile_contents = "" else: current_makefile_contents = open(makefile_file, "r").read() if current_makefile_contents != new_makefile_contents: open(makefile_file, "w").write(new_makefile_contents) output_block("Makefile.mux", open(makefile_file).read()) # ------------------------------------------------------------------------ # Work out the port and their names # ------------------------------------------------------------------------ port_names = [] for i in args.order: if i == 'i': if args.split_inputs: port_names.extend((mux_lib.MuxPinType.INPUT, args.name_inputs[j], 1, '[%i]' % j) for j in range(args.width)) else: # verilog range bounds are inclusive and convention is [<width-1>:0] port_names.append((mux_lib.MuxPinType.INPUT, args.name_input, args.width, '[%i:0]' % (args.width - 1))) elif i == 's': if args.split_selects: port_names.extend((mux_lib.MuxPinType.SELECT, args.name_selects[j], 1, '[%i]' % j) for j in range(args.width_bits)) else: assert args.name_select is not None # verilog array range bounds are inclusive and convention is [<width-1>:0] port_names.append( (mux_lib.MuxPinType.SELECT, args.name_select, args.width_bits, '[%i:0]' % (args.width_bits - 1))) elif i == 'o': port_names.append( (mux_lib.MuxPinType.OUTPUT, args.name_output, 1, '')) # ------------------------------------------------------------------------ # Generate the sim.v Verilog module # ------------------------------------------------------------------------ defs = {'i': 'input wire', 's': 'input wire', 'o': 'output wire'} sim_pathname = os.path.join(outdir, sim_filename) with open(sim_pathname, "w") as f: module_args = [] for type, name, _, _ in port_names: if args.type == 'routing' and type == mux_lib.MuxPinType.SELECT: continue module_args.append(name) mux_prefix = {'logic': '', 'routing': 'r'}[args.type] mux_class = {'logic': 'mux', 'routing': 'routing'}[args.type] f.write("/* ") f.write("\n * ".join(generated_with.splitlines())) f.write("\n */\n\n") f.write('`include "%s/%s/%smux%i/%smux%i.sim.v"\n' % ( mux_dir, 'logic', '', args.width, '', args.width, )) f.write("\n") f.write('(* blackbox *) (* CLASS="%s" *)\n' % mux_class) f.write("module %s(%s);\n" % (args.name_mux, ", ".join(module_args))) previous_type = None for type, name, width, index in port_names: if previous_type != type: f.write("\n") previous_type = type if args.type == 'routing' and type == mux_lib.MuxPinType.SELECT: if width == 1: f.write('\tparameter [0:0] %s = 0;\n' % (name)) else: f.write('\tparameter %s %s = 0;\n' % (index, name)) continue if width == 1: f.write('\t%s %s;\n' % (type.verilog(), name)) else: f.write('\t%s %s %s;\n' % (type.verilog(), index, name)) f.write("\n") f.write('\tMUX%s mux (\n' % args.width) for i in range(0, args.width): j = 0 for type, name, width, index in port_names: if type != mux_lib.MuxPinType.INPUT: continue if j + width <= i: j += width continue break if width == 1: f.write('\t\t.I%i(%s),\n' % (i, name)) else: f.write('\t\t.I%i(%s[%i]),\n' % (i, name, i - j)) for i in range(0, args.width_bits): j = 0 for type, name, width, index in port_names: if type != mux_lib.MuxPinType.SELECT: continue if j + width < i: j += width continue break if width == 1: f.write('\t\t.S%i(%s),\n' % (i, name)) else: f.write('\t\t.S%i(%s[%i]),\n' % (i, name, i - j)) for type, name, width, index in port_names: if type != mux_lib.MuxPinType.OUTPUT: continue break assert_eq(width, 1) f.write('\t\t.O(%s)\n\t);\n' % name) f.write('endmodule\n') output_block(sim_filename, open(sim_pathname).read()) if args.type == 'logic': subckt = args.subckt or args.name_mux assert subckt elif args.type == 'routing': assert args.subckt is None subckt = None # ------------------------------------------------------------------------ # Generate the Model XML form. # ------------------------------------------------------------------------ def xml_comment_indent(n, s): return ("\n" + " " * n).join(s.splitlines() + [""]) if args.type == 'logic': models_xml = ET.Element('models') models_xml.append(ET.Comment(xml_comment_indent(4, xml_comment))) model_xml = ET.SubElement(models_xml, 'model', {'name': subckt}) input_ports = ET.SubElement(model_xml, 'input_ports') output_ports = ET.SubElement(model_xml, 'output_ports') for type, name, width, index in port_names: if type in (mux_lib.MuxPinType.INPUT, mux_lib.MuxPinType.SELECT): ET.SubElement( input_ports, 'port', { 'name': name, 'combinational_sink_ports': ','.join(n for t, n, w, i in port_names if t in (mux_lib.MuxPinType.OUTPUT, )), }) elif type in (mux_lib.MuxPinType.OUTPUT, ): ET.SubElement(output_ports, 'port', {'name': args.name_output}) models_str = ET.tostring(models_xml, pretty_print=True).decode('utf-8') else: models_str = "<models><!-- No models for routing elements.--></models>" output_block(model_xml_filename, models_str) with open(os.path.join(outdir, model_xml_filename), "w") as f: f.write(models_str) # ------------------------------------------------------------------------ # Generate the pb_type XML form. # ------------------------------------------------------------------------ pb_type_xml = mux_lib.pb_type_xml( mux_lib.MuxType[args.type.upper()], args.name_mux, port_names, subckt=subckt, num_pb=args.num_pb, comment=xml_comment_indent(4, xml_comment), ) pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8') output_block(pbtype_xml_filename, pb_type_str) with open(os.path.join(outdir, pbtype_xml_filename), "w") as f: f.write(pb_type_str) print("Generated mux {} in {}".format(args.name_mux, outdir))