changeset 101:ffab0a4424ad

ueda: unet-bind program moved into sensibly named unet-bind subdir
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 29 Sep 2019 22:42:41 +0000
parents 071b24bca546
children 921018d84161
files .hgignore ueda/Makefile ueda/sverp-bind/Makefile ueda/sverp-bind/enterinst.c ueda/sverp-bind/insthash.c ueda/sverp-bind/main.c ueda/sverp-bind/outcomp.c ueda/sverp-bind/output.c ueda/sverp-bind/readunet.c ueda/sverp-bind/starpoints.c ueda/sverp-bind/struct.h ueda/unet-bind/Makefile ueda/unet-bind/enterinst.c ueda/unet-bind/insthash.c ueda/unet-bind/main.c ueda/unet-bind/outcomp.c ueda/unet-bind/output.c ueda/unet-bind/readunet.c ueda/unet-bind/starpoints.c ueda/unet-bind/struct.h
diffstat 20 files changed, 885 insertions(+), 885 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sun Sep 29 19:13:09 2019 +0000
+++ b/.hgignore	Sun Sep 29 22:42:41 2019 +0000
@@ -7,7 +7,7 @@
 ^ueda/mclutils/mkbom$
 ^ueda/mclutils/shortbom$
 ^ueda/sverp/ueda-sverp$
-^ueda/sverp-bind/unet-bind$
+^ueda/unet-bind/unet-bind$
 ^ueda/unet-utils/unet-destar$
 ^ueda/unet-utils/unet2pads$
 ^ueda/unet-utils/unet2pcb$
--- a/ueda/Makefile	Sun Sep 29 19:13:09 2019 +0000
+++ b/ueda/Makefile	Sun Sep 29 22:42:41 2019 +0000
@@ -1,6 +1,6 @@
-SUBDIR=	libueda libunet libuschem mclutils migration sverp sverp-bind \
+SUBDIR=	libueda libunet libuschem mclutils migration sverp unet-bind \
 	unet-utils uschem-netlist uschem-print uschem-utils utils
-BUILD=	libueda libunet mclutils sverp sverp-bind unet-utils utils
+BUILD=	libueda libunet mclutils sverp unet-bind unet-utils utils
 
 all:	${BUILD}
 
@@ -9,7 +9,7 @@
 
 mclutils:	libueda
 sverp:		libueda
-sverp-bind:	libueda libunet
+unet-bind:	libueda libunet
 unet-utils:	libunet
 uschem-utils:	libueda libuschem
 uschem-print:	libueda libuschem
--- a/ueda/sverp-bind/Makefile	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-CC=	gcc
-CFLAGS=	-O2
-OBJS=	enterinst.o insthash.o main.o outcomp.o output.o readunet.o starpoints.o
-LIBS=	../libunet/libunet.a ../libueda/libueda.a
-PROG=	unet-bind
-BINDIR=	/usr/local/bin
-
-all:	${PROG}
-
-${PROG}:	${OBJS} ${LIBS}
-	${CC} -o $@ ${OBJS} ${LIBS}
-
-${OBJS}:	struct.h
-
-install:
-	install -c -o bin -g bin -m 755 ${PROG} ${BINDIR}
-
-clean:
-	rm -f *.[ao] a.out core errs ${PROG}
--- a/ueda/sverp-bind/enterinst.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "struct.h"
-
-extern char *copystr();
-extern struct instance *enter_instance();
-
-process_hier_attr(oc, hier)
-	register struct outcomp *oc;
-	char *hier;
-{
-	register struct instance *inst;
-
-	if (!strncmp(hier, "flip:", 5)) {
-		if (oc->npins != 2 || oc->grid_pkg) {
-			fprintf(stderr,
-				"error: hier=flip:... makes no sense for %s\n",
-				oc->name);
-			exit(1);
-		}
-		oc->reverse_2pin = 1;
-		hier += 5;
-	}
-	oc->altname = hier;
-	inst = enter_instance(hier);
-	inst->outcomp = oc;
-}
-
-process_slotmap_attr(oc, slotmap_file)
-	struct outcomp *oc;
-	char *slotmap_file;
-{
-	FILE *stream;
-	char linebuf[256];
-	int lineno;
-	register char *cp;
-	char *instname, *slot;
-	register struct instance *inst;
-
-	stream = fopen(slotmap_file, "r");
-	if (!stream) {
-		perror(slotmap_file);
-		exit(1);
-	}
-	for (lineno = 1; fgets(linebuf, sizeof linebuf, stream); lineno++) {
-		cp = index(linebuf, '\n');
-		if (!cp) {
-			fprintf(stderr,
-			"error: %s line %d is too long or unterminated\n",
-				slotmap_file, lineno);
-			exit(1);
-		}
-		*cp = '\0';
-		for (cp = linebuf; isspace(*cp); cp++)
-			;
-		if (*cp == '\0' || *cp == '#')
-			continue;
-		instname = cp;
-		while (*cp && !isspace(*cp))
-			cp++;
-		if (*cp)
-			*cp++ = '\0';
-		while (isspace(*cp))
-			cp++;
-		if (*cp == '\0' || *cp == '#')
-			slot = 0;
-		else {
-			slot = cp;
-			while (*cp && !isspace(*cp))
-				cp++;
-			if (*cp)
-				*cp++ = '\0';
-		}
-		inst = enter_instance(instname);
-		inst->outcomp = oc;
-		if (slot)
-			slot = copystr(slot);
-		inst->slot = slot;
-	}
-	fclose(stream);
-}
--- a/ueda/sverp-bind/insthash.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "struct.h"
-
-#define	HASH_SIZE	1103
-static struct instance *hashtab[HASH_SIZE];
-
-static int
-hash_instname(str)
-	char *str;
-{
-	register u_long accum = 0;
-	register char *cp;
-	register int c, i;
-
-	for (cp = str, i = 1; c = *cp; cp++, i++)
-		accum += c * i;
-	return(accum % HASH_SIZE);
-}
-
-struct instance *
-enter_instance(newname)
-	char *newname;
-{
-	register struct instance *n, **np;
-	int namelen;
-
-	for (np = hashtab + hash_instname(newname); n = *np;
-	     np = &n->nextinhash)
-		if (!strcmp(n->name, newname)) {
-			fprintf(stderr, "error: duplicate instance name %s\n",
-				newname);
-			exit(1);
-		}
-	namelen = strlen(newname);
-	n = (struct instance *) malloc(sizeof(struct instance) + namelen + 1);
-	if (!n) {
-		perror("malloc");
-		exit(1);
-	}
-	bzero(n, sizeof(struct instance));
-	n->name = (char *)(n + 1);
-	strcpy(n->name, newname);
-	*np = n;
-	return n;
-}
-
-struct instance *
-find_instance(soughtname)
-	register char *soughtname;
-{
-	register struct instance *n;
-
-	for (n = hashtab[hash_instname(soughtname)]; n; n = n->nextinhash)
-		if (!strcmp(n->name, soughtname))
-			return(n);
-	return(0);
-}
-
-check_unclaimed_instances()
-{
-	int hb;
-	register struct instance *n;
-	unsigned unclaimed_count = 0;
-
-	for (hb = 0; hb < HASH_SIZE; hb++)
-		for (n = hashtab[hb]; n; n = n->nextinhash)
-			if (!n->claimed) {
-				fprintf(stderr,
-		"error: declared instance %s not claimed by input netlist\n",
-					n->name);
-				unclaimed_count++;
-			}
-	if (unclaimed_count) {
-		fprintf(stderr, "error: unclaimed instances found, aborting\n");
-		exit(1);
-	}
-}
--- a/ueda/sverp-bind/main.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include "struct.h"
-
-extern char *MCLfile;
-
-char *input_filename, *output_filename;
-char *starpoints_file;
-int check_completeness, unbound_instances;
-
-struct wantattr *want_attr_list;
-static struct wantattr **wantattr_tailp = &want_attr_list;
-
-static void
-add_wanted_attr(attr)
-	char *attr;
-{
-	struct wantattr *wa;
-
-	wa = (struct wantattr *) malloc(sizeof(struct wantattr) +
-					strlen(attr) + 1);
-	if (!wa) {
-		perror("malloc");
-		exit(1);
-	}
-	wa->name = (char *)(wa + 1);
-	strcpy(wa->name, attr);
-	wa->next = 0;
-	*wantattr_tailp = wa;
-	wantattr_tailp = &wa->next;
-}
-
-static void
-usage()
-{
-	fprintf(stderr,
-		"usage: unet-bind [options] input.unet [output.unet]\n");
-	exit(1);
-}
-
-static void
-process_options(argc, argv)
-	char **argv;
-{
-	extern char *optarg;
-	register int c;
-
-	while ((c = getopt(argc, argv, "a:cI:M:s:")) != EOF) {
-		switch (c) {
-		case 'a':
-			add_wanted_attr(optarg);
-			continue;
-		case 'c':
-			check_completeness++;
-			continue;
-		case 'I':
-			add_symfile_dir(optarg);
-			continue;
-		case 'M':
-			MCLfile = optarg;
-			continue;
-		case 's':
-			starpoints_file = optarg;
-			continue;
-		default:
-			usage();
-		}
-	}
-}
-
-main(argc, argv)
-	char **argv;
-{
-	extern int optind;
-
-	process_options(argc, argv);
-	if (argc < optind + 1 || argc > optind + 2)
-		usage();
-	input_filename = argv[optind];
-	output_filename = argv[optind+1];
-
-	/* process all inputs from the MCL */
-	read_MCL();
-	set_default_sympath();
-	read_pinouts();
-	init_outcomp_from_MCL();
-	/* do we have any star points? */
-	if (starpoints_file)
-		process_starpoints_file();
-	/* read the netlist from sverp */
-	process_input_unet();
-	if (unbound_instances) {
-		fprintf(stderr,
-		"error: %s input contains unbound instances, aborting\n",
-			input_filename);
-		exit(1);
-	}
-	check_unclaimed_instances();
-	generate_output();
-	exit(0);
-}
--- a/ueda/sverp-bind/outcomp.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "../libueda/mcl.h"
-#include "../libueda/xga.h"
-#include "struct.h"
-
-extern struct component components[];
-extern int ncomponents;
-
-extern char *get_comp_attr();
-extern struct grid_pkg_desc *read_grid_pkg_file();
-
-extern int check_completeness;
-
-struct outcomp *netlist_comps;
-
-static int
-try_numpins(oc)
-	register struct outcomp *oc;
-{
-	char *npins_attr;
-	register int n;
-
-	npins_attr = get_comp_attr(oc->mclcomp, "npins");
-	if (!npins_attr)
-		return(0);
-	n = atoi(npins_attr);
-	if (n <= 0) {
-		fprintf(stderr, "component %s: invalid npins attribute\n",
-			oc->name);
-		exit(1);
-	}
-	oc->npins = n;
-	return(1);
-}
-
-static int
-try_gridpkg(oc)
-	register struct outcomp *oc;
-{
-	char *attr;
-	register struct grid_pkg_desc *desc;
-
-	attr = get_comp_attr(oc->mclcomp, "grid_pkg");
-	if (!attr)
-		return(0);
-	desc = read_grid_pkg_file(attr);
-	oc->grid_pkg = desc;
-	oc->npins = desc->nrows * desc->ncolumns;
-	return(1);
-}
-
-static void
-init_one_outcomp(oc)
-	register struct outcomp *oc;
-{
-	register struct pinconn **conn_array;
-	register char *attr;
-
-	oc->name = oc->mclcomp->name;
-	try_numpins(oc);
-	if (!oc->npins)
-		try_gridpkg(oc);
-	if (!oc->npins) {
-		fprintf(stderr,
-			"error: %s has neither npins nor grid_pkg attribute\n",
-			oc->name);
-		exit(1);
-	}
-	conn_array = (struct pinconn **) malloc(sizeof(struct pinconn *) *
-						oc->npins);
-	if (!conn_array) {
-		perror("malloc");
-		exit(1);
-	}
-	bzero(conn_array, sizeof(struct pinconn *) * oc->npins);
-	oc->conn_array = conn_array;
-	if (attr = get_comp_attr(oc->mclcomp, "hier"))
-		process_hier_attr(oc, attr);
-	else if (attr = get_comp_attr(oc->mclcomp, "slotmap"))
-		process_slotmap_attr(oc, attr);
-	else if (check_completeness)
-		fprintf(stderr, "MCL component %s has no binding\n", oc->name);
-}
-
-init_outcomp_from_MCL()
-{
-	register int i;
-
-	netlist_comps = (struct outcomp *)
-				malloc(sizeof(struct outcomp) * ncomponents);
-	if (!netlist_comps) {
-		perror("malloc");
-		exit(1);
-	}
-	bzero(netlist_comps, sizeof(struct outcomp) * ncomponents);
-	for (i = 0; i < ncomponents; i++) {
-		netlist_comps[i].mclcomp = components + i;
-		init_one_outcomp(netlist_comps + i);
-	}
-}
--- a/ueda/sverp-bind/output.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "../libueda/xga.h"
-#include "../libunet/nethash.h"
-#include "struct.h"
-
-extern char *get_comp_attr();
-
-extern char *MCLfile;
-extern char *input_filename;
-extern char *output_filename;
-
-extern struct net *net_list_head;
-extern int ncomponents;
-extern struct outcomp *netlist_comps;
-extern struct outcomp *starpoint_list_head;
-extern struct wantattr *want_attr_list;
-
-static FILE *outF;
-
-generate_output()
-{
-	if (output_filename) {
-		outF = fopen(output_filename, "w");
-		if (!outF) {
-			perror(output_filename);
-			exit(1);
-		}
-	} else
-		outF = stdout;
-	fprintf(outF, "# This netlist has been generated by unet-bind\n");
-	fprintf(outF, "# from %s and %s\n", MCLfile, input_filename);
-	if (net_list_head)
-		emit_output_nets();
-	if (starpoint_list_head)
-		emit_output_starpoints();
-	if (ncomponents)
-		emit_output_components();
-	if (outF != stdout)
-		fclose(outF);
-}
-
-emit_output_nets()
-{
-	register struct net *n;
-
-	fprintf(outF, "\n# Nets unchanged from %s:\n#\n", input_filename);
-	for (n = net_list_head; n; n = n->nextinlist)
-		fprintf(outF, "NET %s\n", n->name);
-}
-
-emit_output_components()
-{
-	register int n;
-
-	fprintf(outF, "\n# %d components from MCL:\n", ncomponents);
-	for (n = 0; n < ncomponents; n++)
-		emit_component_block(netlist_comps + n, "COMPONENT");
-}
-
-emit_output_starpoints()
-{
-	register struct outcomp *oc;
-
-	fprintf(outF, "\n# Star connection points:\n");
-	for (oc = starpoint_list_head; oc; oc = oc->next)
-		emit_component_block(oc, "STARPOINT");
-}
-
-static void
-emit_output_pin_number(oc, pinidx)
-	register struct outcomp *oc;
-	register int pinidx;
-{
-	register struct grid_pkg_desc *xga = oc->grid_pkg;
-	int r, c;
-
-	if (!xga) {
-		fprintf(outF, "%d", pinidx + 1);
-		return;
-	}
-	r = pinidx / xga->ncolumns;
-	c = pinidx % xga->ncolumns;
-	fprintf(outF, "%c%d", xga->row_letters[r], c + 1);
-}
-
-static void
-emit_output_pin_line(oc, pinidx)
-	register struct outcomp *oc;
-	int pinidx;
-{
-	register struct pinconn *conn;
-
-	fputs("  PIN ", outF);
-	emit_output_pin_number(oc, pinidx);
-	fputs(" = ", outF);
-	conn = oc->conn_array[pinidx];
-	if (!conn) {
-		fprintf(outF, "NC (unet-bind found no connection)\n");
-		return;
-	}
-	if (conn->net)
-		fprintf(outF, "NET %s\n", conn->net->name);
-	else
-		fprintf(outF, "NC (%s)\n", conn->nc_comment);
-}
-
-emit_component_block(oc, comp_type_kw)
-	register struct outcomp *oc;
-	char *comp_type_kw;
-{
-	register int pinidx;
-
-	fprintf(outF, "\n%s %s {\n", comp_type_kw, oc->name);
-	if (oc->altname)
-		fprintf(outF, "  ALTNAME %s\n", oc->altname);
-	if (want_attr_list && oc->mclcomp)
-		emit_component_attributes(oc->mclcomp);
-	for (pinidx = 0; pinidx < oc->npins; pinidx++) {
-		if (oc->grid_pkg && oc->grid_pkg->holes_array[pinidx])
-			continue;
-		emit_output_pin_line(oc, pinidx);
-	}
-	fputs("}\n", outF);
-}
-
-emit_component_attributes(comp)
-	struct component *comp;
-{
-	register struct wantattr *wa;
-	register char *value;
-
-	for (wa = want_attr_list; wa; wa = wa->next) {
-		value = get_comp_attr(comp, wa->name);
-		if (!value)
-			continue;
-		fprintf(outF, "  ATTR %s=%s\n", wa->name, value);
-	}
-}
--- a/ueda/sverp-bind/readunet.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "../libueda/xga.h"
-#include "../libunet/unetrd.h"
-#include "struct.h"
-
-extern char *pinname_to_pinnumber();
-extern struct net *find_net_by_name();
-extern struct instance *find_instance();
-
-extern char *input_filename;
-extern int unbound_instances;
-
-static struct unetrd_state rdstate;
-static struct unetrd_out rdout;
-
-static int
-resolve_pinnum_numeric(oc, pinnumstr)
-	struct outcomp *oc;
-	register char *pinnumstr;
-{
-	register int num;
-
-	if (!string_is_valid_decnum(pinnumstr)) {
-invnum:		fprintf(stderr,
-"%s line %d: component %s has numeric pins and \"%s\" is not a valid pin number\n",
-			input_filename, rdstate.lineno, oc->name, pinnumstr);
-		exit(1);
-	}
-	num = atoi(pinnumstr);
-	if (num < 1)
-		goto invnum;
-	if (num > oc->npins) {
-		fprintf(stderr,
-"%s line %d: attempting connection to pin %d on component %s that only has %d pins\n",
-			input_filename, rdstate.lineno, num, oc->name,
-			oc->npins);
-		exit(1);
-	}
-	return(num - 1);
-}
-
-static int
-resolve_pinnum_grid(oc, pinnumstr)
-	struct outcomp *oc;
-	char *pinnumstr;
-{
-	register struct grid_pkg_desc *xga = oc->grid_pkg;
-	struct xga_parsed_pinnum rowcol;
-	register int idx;
-
-	if (parse_xga_pinnumber(xga, pinnumstr, &rowcol) < 0) {
-		fprintf(stderr,
-	"%s line %d: \"%s\" is not a valid pin number for grid package %s\n",
-			input_filename, rdstate.lineno, pinnumstr, oc->name);
-		exit(1);
-	}
-	idx = rowcol.row_0based * xga->ncolumns + rowcol.col_0based;
-	if (xga->holes_array[idx]) {
-		fprintf(stderr,
-	"%s line %d: pin position %s is a hole in the grid package for %s\n",
-			input_filename, rdstate.lineno, pinnumstr, oc->name);
-		exit(1);
-	}
-	return(idx);
-}
-
-static int
-resolve_pinnum(oc, pinnumstr)
-	register struct outcomp *oc;
-	char *pinnumstr;
-{
-	if (oc->grid_pkg)
-		return resolve_pinnum_grid(oc, pinnumstr);
-	else
-		return resolve_pinnum_numeric(oc, pinnumstr);
-}
-
-static struct pinconn *
-create_pinconn()
-{
-	register struct pinconn *conn;
-	register struct net *net;
-
-	if (rdout.connect_to_net) {
-		net = find_net_by_name(rdout.connect_to_net);
-		conn = (struct pinconn *) malloc(sizeof(struct pinconn));
-		if (!conn) {
-			perror("malloc");
-			exit(1);
-		}
-		conn->net = net;
-		conn->nc_comment = 0;
-	} else {
-		conn = (struct pinconn *) malloc(sizeof(struct pinconn) +
-						 strlen(rdout.nc_comment) + 1);
-		if (!conn) {
-			perror("malloc");
-			exit(1);
-		}
-		conn->net = 0;
-		conn->nc_comment = (char *)(conn + 1);
-		strcpy(conn->nc_comment, rdout.nc_comment);
-	}
-	conn->input_lineno = rdstate.lineno;
-	return conn;
-}
-
-static void
-connect_pin(oc, pinnumstr)
-	register struct outcomp *oc;
-	char *pinnumstr;
-{
-	register int pinidx;
-
-	pinidx = resolve_pinnum(oc, pinnumstr);
-	if (oc->reverse_2pin)
-		pinidx = !pinidx;
-	if (oc->conn_array[pinidx]) {
-		fprintf(stderr,
-	"error: multiple connections to %s pin %s (input lines %d and %d)\n",
-			oc->name, pinnumstr,
-			oc->conn_array[pinidx]->input_lineno, rdstate.lineno);
-		exit(1);
-	}
-	oc->conn_array[pinidx] = create_pinconn();
-}
-
-static void
-process_pinmap(inst)
-	struct instance *inst;
-{
-	register struct outcomp *oc = inst->outcomp;
-	register char *pinnum;
-
-	if (!oc->mclcomp) {
-		fprintf(stderr,
-			"%s line %d: PINMAP is meaningless for starpoints\n",
-			input_filename, rdstate.lineno);
-		exit(1);
-	}
-	pinnum = pinname_to_pinnumber(oc->mclcomp, rdout.objname, inst->slot);
-	if (!pinnum) {
-		fprintf(stderr, "PINMAP error on %s line %d\n",
-			input_filename, rdstate.lineno);
-		exit(1);
-	}
-	connect_pin(oc, pinnum);
-}
-
-static void
-process_component()
-{
-	struct instance *inst;
-
-	inst = find_instance(rdout.objname);
-	if (!inst) {
-		fprintf(stderr, "%s line %d: instance %s not bound in MCL\n",
-			input_filename, rdstate.lineno, rdout.objname);
-		unbound_instances++;
-	} else {
-		if (inst->claimed) {
-			fprintf(stderr,
-			"%s line %d: instance %s appears more than once\n",
-				input_filename, rdstate.lineno, inst->name);
-			exit(1);
-		}
-		inst->claimed = 1;
-	}
-	for (;;) {
-		if (!read_unet_line(&rdstate, &rdout)) {
-			fprintf(stderr, "%s error: EOF in component block\n",
-				input_filename);
-			exit(1);
-		}
-		if (rdout.typecode == UNETOBJ_CLOSINGBRACE)
-			break;
-		switch(rdout.typecode) {
-		case UNETOBJ_PRIMITIVE:
-		case UNETOBJ_ALTNAME:
-		case UNETOBJ_ATTR:
-			continue;
-		case UNETOBJ_PIN:
-			if (inst)
-				connect_pin(inst->outcomp, rdout.objname);
-			continue;
-		case UNETOBJ_PINMAP:
-			if (inst)
-				process_pinmap(inst);
-			continue;
-		default:
-			fprintf(stderr,
-		"%s line %d: object type %s unexpected in component block\n",
-				input_filename, rdstate.lineno, rdout.keyword);
-			exit(1);
-		}
-	}
-}
-
-process_input_unet()
-{
-	open_unet_input_file(input_filename, &rdstate);
-	while (read_unet_line(&rdstate, &rdout)) {
-		switch(rdout.typecode) {
-		case UNETOBJ_CLOSINGBRACE:
-			fprintf(stderr,
-		"%s line %d: unexpected '}' outside of component block\n",
-				input_filename, rdstate.lineno);
-			exit(1);
-		case UNETOBJ_NET:
-			enter_net_object(rdout.objname, 0);
-			continue;
-		case UNETOBJ_COMPONENT:
-			process_component();
-			continue;
-		case UNETOBJ_STARPOINT:
-			fprintf(stderr,
-"error: STARPOINT objects not expected in unet-bind input (%s line %d)\n",
-				input_filename, rdstate.lineno);
-			exit(1);
-		default:
-			fprintf(stderr,
-				"%s line %d: unexpected object type %s\n",
-				input_filename, rdstate.lineno, rdout.keyword);
-			exit(1);
-		}
-	}
-}
--- a/ueda/sverp-bind/starpoints.c	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "struct.h"
-
-extern struct instance *enter_instance();
-
-extern char *starpoints_file;
-
-struct outcomp *starpoint_list_head;
-static struct outcomp **global_tailp = &starpoint_list_head;
-
-process_starpoints_file()
-{
-	FILE *stream;
-	char linebuf[256];
-	int lineno;
-	register char *cp;
-	char *instname, *numstr;
-	int npins;
-	register struct instance *inst;
-	register struct outcomp *oc;
-
-	stream = fopen(starpoints_file, "r");
-	if (!stream) {
-		perror(starpoints_file);
-		exit(1);
-	}
-	for (lineno = 1; fgets(linebuf, sizeof linebuf, stream); lineno++) {
-		cp = index(linebuf, '\n');
-		if (!cp) {
-			fprintf(stderr,
-			"error: %s line %d is too long or unterminated\n",
-				starpoints_file, lineno);
-			exit(1);
-		}
-		*cp = '\0';
-		for (cp = linebuf; isspace(*cp); cp++)
-			;
-		if (*cp == '\0' || *cp == '#')
-			continue;
-		instname = cp;
-		while (*cp && !isspace(*cp))
-			cp++;
-		if (*cp)
-			*cp++ = '\0';
-		while (isspace(*cp))
-			cp++;
-		if (*cp == '\0' || *cp == '#') {
-npins_error:		fprintf(stderr,
-"error in %s line %d: expected number of pins after the instance name\n",
-				starpoints_file, lineno);
-			exit(1);
-		}
-		numstr = cp;
-		while (*cp && !isspace(*cp))
-			cp++;
-		if (*cp)
-			*cp++ = '\0';
-		if (!string_is_valid_decnum(numstr))
-			goto npins_error;
-		npins = atoi(numstr);
-		if (npins < 2) {
-			fprintf(stderr,
-		"error in %s line %d: a starpoint must have 2 or more pins\n",
-				starpoints_file, lineno);
-			exit(1);
-		}
-		inst = enter_instance(instname);
-		oc = (struct outcomp *)
-			malloc(sizeof(struct outcomp) +
-			       sizeof(struct pinconn *) * npins);
-		if (!oc) {
-			perror("malloc");
-			exit(1);
-		}
-		bzero(oc, sizeof(struct outcomp) +
-			  sizeof(struct pinconn *) * npins);
-		oc->name = inst->name;
-		oc->npins = npins;
-		oc->conn_array = (struct pinconn **)(oc + 1);
-		inst->outcomp = oc;
-		*global_tailp = oc;
-		global_tailp = &oc->next;
-	}
-	fclose(stream);
-}
--- a/ueda/sverp-bind/struct.h	Sun Sep 29 19:13:09 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Data structures for the MCL binding step
- */
-
-struct instance {
-	char	*name;
-	struct	instance *nextinhash;
-	struct	outcomp *outcomp;
-	char	*slot;
-	int	claimed;
-};
-
-struct outcomp {
-	char	*name;
-	char	*altname;
-	struct	component *mclcomp;
-	int	npins;
-	int	reverse_2pin;
-	struct	grid_pkg_desc *grid_pkg;
-	struct	pinconn **conn_array;
-	struct	outcomp *next;	/* used only for starpoints */
-};
-
-struct pinconn {
-	struct	net *net;
-	char	*nc_comment;
-	int	input_lineno;
-};
-
-struct wantattr {
-	char	*name;
-	struct	wantattr *next;
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/Makefile	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,19 @@
+CC=	gcc
+CFLAGS=	-O2
+OBJS=	enterinst.o insthash.o main.o outcomp.o output.o readunet.o starpoints.o
+LIBS=	../libunet/libunet.a ../libueda/libueda.a
+PROG=	unet-bind
+BINDIR=	/usr/local/bin
+
+all:	${PROG}
+
+${PROG}:	${OBJS} ${LIBS}
+	${CC} -o $@ ${OBJS} ${LIBS}
+
+${OBJS}:	struct.h
+
+install:
+	install -c -o bin -g bin -m 755 ${PROG} ${BINDIR}
+
+clean:
+	rm -f *.[ao] a.out core errs ${PROG}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/enterinst.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+
+extern char *copystr();
+extern struct instance *enter_instance();
+
+process_hier_attr(oc, hier)
+	register struct outcomp *oc;
+	char *hier;
+{
+	register struct instance *inst;
+
+	if (!strncmp(hier, "flip:", 5)) {
+		if (oc->npins != 2 || oc->grid_pkg) {
+			fprintf(stderr,
+				"error: hier=flip:... makes no sense for %s\n",
+				oc->name);
+			exit(1);
+		}
+		oc->reverse_2pin = 1;
+		hier += 5;
+	}
+	oc->altname = hier;
+	inst = enter_instance(hier);
+	inst->outcomp = oc;
+}
+
+process_slotmap_attr(oc, slotmap_file)
+	struct outcomp *oc;
+	char *slotmap_file;
+{
+	FILE *stream;
+	char linebuf[256];
+	int lineno;
+	register char *cp;
+	char *instname, *slot;
+	register struct instance *inst;
+
+	stream = fopen(slotmap_file, "r");
+	if (!stream) {
+		perror(slotmap_file);
+		exit(1);
+	}
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, stream); lineno++) {
+		cp = index(linebuf, '\n');
+		if (!cp) {
+			fprintf(stderr,
+			"error: %s line %d is too long or unterminated\n",
+				slotmap_file, lineno);
+			exit(1);
+		}
+		*cp = '\0';
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		instname = cp;
+		while (*cp && !isspace(*cp))
+			cp++;
+		if (*cp)
+			*cp++ = '\0';
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#')
+			slot = 0;
+		else {
+			slot = cp;
+			while (*cp && !isspace(*cp))
+				cp++;
+			if (*cp)
+				*cp++ = '\0';
+		}
+		inst = enter_instance(instname);
+		inst->outcomp = oc;
+		if (slot)
+			slot = copystr(slot);
+		inst->slot = slot;
+	}
+	fclose(stream);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/insthash.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+
+#define	HASH_SIZE	1103
+static struct instance *hashtab[HASH_SIZE];
+
+static int
+hash_instname(str)
+	char *str;
+{
+	register u_long accum = 0;
+	register char *cp;
+	register int c, i;
+
+	for (cp = str, i = 1; c = *cp; cp++, i++)
+		accum += c * i;
+	return(accum % HASH_SIZE);
+}
+
+struct instance *
+enter_instance(newname)
+	char *newname;
+{
+	register struct instance *n, **np;
+	int namelen;
+
+	for (np = hashtab + hash_instname(newname); n = *np;
+	     np = &n->nextinhash)
+		if (!strcmp(n->name, newname)) {
+			fprintf(stderr, "error: duplicate instance name %s\n",
+				newname);
+			exit(1);
+		}
+	namelen = strlen(newname);
+	n = (struct instance *) malloc(sizeof(struct instance) + namelen + 1);
+	if (!n) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(n, sizeof(struct instance));
+	n->name = (char *)(n + 1);
+	strcpy(n->name, newname);
+	*np = n;
+	return n;
+}
+
+struct instance *
+find_instance(soughtname)
+	register char *soughtname;
+{
+	register struct instance *n;
+
+	for (n = hashtab[hash_instname(soughtname)]; n; n = n->nextinhash)
+		if (!strcmp(n->name, soughtname))
+			return(n);
+	return(0);
+}
+
+check_unclaimed_instances()
+{
+	int hb;
+	register struct instance *n;
+	unsigned unclaimed_count = 0;
+
+	for (hb = 0; hb < HASH_SIZE; hb++)
+		for (n = hashtab[hb]; n; n = n->nextinhash)
+			if (!n->claimed) {
+				fprintf(stderr,
+		"error: declared instance %s not claimed by input netlist\n",
+					n->name);
+				unclaimed_count++;
+			}
+	if (unclaimed_count) {
+		fprintf(stderr, "error: unclaimed instances found, aborting\n");
+		exit(1);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/main.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "struct.h"
+
+extern char *MCLfile;
+
+char *input_filename, *output_filename;
+char *starpoints_file;
+int check_completeness, unbound_instances;
+
+struct wantattr *want_attr_list;
+static struct wantattr **wantattr_tailp = &want_attr_list;
+
+static void
+add_wanted_attr(attr)
+	char *attr;
+{
+	struct wantattr *wa;
+
+	wa = (struct wantattr *) malloc(sizeof(struct wantattr) +
+					strlen(attr) + 1);
+	if (!wa) {
+		perror("malloc");
+		exit(1);
+	}
+	wa->name = (char *)(wa + 1);
+	strcpy(wa->name, attr);
+	wa->next = 0;
+	*wantattr_tailp = wa;
+	wantattr_tailp = &wa->next;
+}
+
+static void
+usage()
+{
+	fprintf(stderr,
+		"usage: unet-bind [options] input.unet [output.unet]\n");
+	exit(1);
+}
+
+static void
+process_options(argc, argv)
+	char **argv;
+{
+	extern char *optarg;
+	register int c;
+
+	while ((c = getopt(argc, argv, "a:cI:M:s:")) != EOF) {
+		switch (c) {
+		case 'a':
+			add_wanted_attr(optarg);
+			continue;
+		case 'c':
+			check_completeness++;
+			continue;
+		case 'I':
+			add_symfile_dir(optarg);
+			continue;
+		case 'M':
+			MCLfile = optarg;
+			continue;
+		case 's':
+			starpoints_file = optarg;
+			continue;
+		default:
+			usage();
+		}
+	}
+}
+
+main(argc, argv)
+	char **argv;
+{
+	extern int optind;
+
+	process_options(argc, argv);
+	if (argc < optind + 1 || argc > optind + 2)
+		usage();
+	input_filename = argv[optind];
+	output_filename = argv[optind+1];
+
+	/* process all inputs from the MCL */
+	read_MCL();
+	set_default_sympath();
+	read_pinouts();
+	init_outcomp_from_MCL();
+	/* do we have any star points? */
+	if (starpoints_file)
+		process_starpoints_file();
+	/* read the netlist from sverp */
+	process_input_unet();
+	if (unbound_instances) {
+		fprintf(stderr,
+		"error: %s input contains unbound instances, aborting\n",
+			input_filename);
+		exit(1);
+	}
+	check_unclaimed_instances();
+	generate_output();
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/outcomp.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "../libueda/mcl.h"
+#include "../libueda/xga.h"
+#include "struct.h"
+
+extern struct component components[];
+extern int ncomponents;
+
+extern char *get_comp_attr();
+extern struct grid_pkg_desc *read_grid_pkg_file();
+
+extern int check_completeness;
+
+struct outcomp *netlist_comps;
+
+static int
+try_numpins(oc)
+	register struct outcomp *oc;
+{
+	char *npins_attr;
+	register int n;
+
+	npins_attr = get_comp_attr(oc->mclcomp, "npins");
+	if (!npins_attr)
+		return(0);
+	n = atoi(npins_attr);
+	if (n <= 0) {
+		fprintf(stderr, "component %s: invalid npins attribute\n",
+			oc->name);
+		exit(1);
+	}
+	oc->npins = n;
+	return(1);
+}
+
+static int
+try_gridpkg(oc)
+	register struct outcomp *oc;
+{
+	char *attr;
+	register struct grid_pkg_desc *desc;
+
+	attr = get_comp_attr(oc->mclcomp, "grid_pkg");
+	if (!attr)
+		return(0);
+	desc = read_grid_pkg_file(attr);
+	oc->grid_pkg = desc;
+	oc->npins = desc->nrows * desc->ncolumns;
+	return(1);
+}
+
+static void
+init_one_outcomp(oc)
+	register struct outcomp *oc;
+{
+	register struct pinconn **conn_array;
+	register char *attr;
+
+	oc->name = oc->mclcomp->name;
+	try_numpins(oc);
+	if (!oc->npins)
+		try_gridpkg(oc);
+	if (!oc->npins) {
+		fprintf(stderr,
+			"error: %s has neither npins nor grid_pkg attribute\n",
+			oc->name);
+		exit(1);
+	}
+	conn_array = (struct pinconn **) malloc(sizeof(struct pinconn *) *
+						oc->npins);
+	if (!conn_array) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(conn_array, sizeof(struct pinconn *) * oc->npins);
+	oc->conn_array = conn_array;
+	if (attr = get_comp_attr(oc->mclcomp, "hier"))
+		process_hier_attr(oc, attr);
+	else if (attr = get_comp_attr(oc->mclcomp, "slotmap"))
+		process_slotmap_attr(oc, attr);
+	else if (check_completeness)
+		fprintf(stderr, "MCL component %s has no binding\n", oc->name);
+}
+
+init_outcomp_from_MCL()
+{
+	register int i;
+
+	netlist_comps = (struct outcomp *)
+				malloc(sizeof(struct outcomp) * ncomponents);
+	if (!netlist_comps) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(netlist_comps, sizeof(struct outcomp) * ncomponents);
+	for (i = 0; i < ncomponents; i++) {
+		netlist_comps[i].mclcomp = components + i;
+		init_one_outcomp(netlist_comps + i);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/output.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "../libueda/xga.h"
+#include "../libunet/nethash.h"
+#include "struct.h"
+
+extern char *get_comp_attr();
+
+extern char *MCLfile;
+extern char *input_filename;
+extern char *output_filename;
+
+extern struct net *net_list_head;
+extern int ncomponents;
+extern struct outcomp *netlist_comps;
+extern struct outcomp *starpoint_list_head;
+extern struct wantattr *want_attr_list;
+
+static FILE *outF;
+
+generate_output()
+{
+	if (output_filename) {
+		outF = fopen(output_filename, "w");
+		if (!outF) {
+			perror(output_filename);
+			exit(1);
+		}
+	} else
+		outF = stdout;
+	fprintf(outF, "# This netlist has been generated by unet-bind\n");
+	fprintf(outF, "# from %s and %s\n", MCLfile, input_filename);
+	if (net_list_head)
+		emit_output_nets();
+	if (starpoint_list_head)
+		emit_output_starpoints();
+	if (ncomponents)
+		emit_output_components();
+	if (outF != stdout)
+		fclose(outF);
+}
+
+emit_output_nets()
+{
+	register struct net *n;
+
+	fprintf(outF, "\n# Nets unchanged from %s:\n#\n", input_filename);
+	for (n = net_list_head; n; n = n->nextinlist)
+		fprintf(outF, "NET %s\n", n->name);
+}
+
+emit_output_components()
+{
+	register int n;
+
+	fprintf(outF, "\n# %d components from MCL:\n", ncomponents);
+	for (n = 0; n < ncomponents; n++)
+		emit_component_block(netlist_comps + n, "COMPONENT");
+}
+
+emit_output_starpoints()
+{
+	register struct outcomp *oc;
+
+	fprintf(outF, "\n# Star connection points:\n");
+	for (oc = starpoint_list_head; oc; oc = oc->next)
+		emit_component_block(oc, "STARPOINT");
+}
+
+static void
+emit_output_pin_number(oc, pinidx)
+	register struct outcomp *oc;
+	register int pinidx;
+{
+	register struct grid_pkg_desc *xga = oc->grid_pkg;
+	int r, c;
+
+	if (!xga) {
+		fprintf(outF, "%d", pinidx + 1);
+		return;
+	}
+	r = pinidx / xga->ncolumns;
+	c = pinidx % xga->ncolumns;
+	fprintf(outF, "%c%d", xga->row_letters[r], c + 1);
+}
+
+static void
+emit_output_pin_line(oc, pinidx)
+	register struct outcomp *oc;
+	int pinidx;
+{
+	register struct pinconn *conn;
+
+	fputs("  PIN ", outF);
+	emit_output_pin_number(oc, pinidx);
+	fputs(" = ", outF);
+	conn = oc->conn_array[pinidx];
+	if (!conn) {
+		fprintf(outF, "NC (unet-bind found no connection)\n");
+		return;
+	}
+	if (conn->net)
+		fprintf(outF, "NET %s\n", conn->net->name);
+	else
+		fprintf(outF, "NC (%s)\n", conn->nc_comment);
+}
+
+emit_component_block(oc, comp_type_kw)
+	register struct outcomp *oc;
+	char *comp_type_kw;
+{
+	register int pinidx;
+
+	fprintf(outF, "\n%s %s {\n", comp_type_kw, oc->name);
+	if (oc->altname)
+		fprintf(outF, "  ALTNAME %s\n", oc->altname);
+	if (want_attr_list && oc->mclcomp)
+		emit_component_attributes(oc->mclcomp);
+	for (pinidx = 0; pinidx < oc->npins; pinidx++) {
+		if (oc->grid_pkg && oc->grid_pkg->holes_array[pinidx])
+			continue;
+		emit_output_pin_line(oc, pinidx);
+	}
+	fputs("}\n", outF);
+}
+
+emit_component_attributes(comp)
+	struct component *comp;
+{
+	register struct wantattr *wa;
+	register char *value;
+
+	for (wa = want_attr_list; wa; wa = wa->next) {
+		value = get_comp_attr(comp, wa->name);
+		if (!value)
+			continue;
+		fprintf(outF, "  ATTR %s=%s\n", wa->name, value);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/readunet.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,230 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "../libueda/xga.h"
+#include "../libunet/unetrd.h"
+#include "struct.h"
+
+extern char *pinname_to_pinnumber();
+extern struct net *find_net_by_name();
+extern struct instance *find_instance();
+
+extern char *input_filename;
+extern int unbound_instances;
+
+static struct unetrd_state rdstate;
+static struct unetrd_out rdout;
+
+static int
+resolve_pinnum_numeric(oc, pinnumstr)
+	struct outcomp *oc;
+	register char *pinnumstr;
+{
+	register int num;
+
+	if (!string_is_valid_decnum(pinnumstr)) {
+invnum:		fprintf(stderr,
+"%s line %d: component %s has numeric pins and \"%s\" is not a valid pin number\n",
+			input_filename, rdstate.lineno, oc->name, pinnumstr);
+		exit(1);
+	}
+	num = atoi(pinnumstr);
+	if (num < 1)
+		goto invnum;
+	if (num > oc->npins) {
+		fprintf(stderr,
+"%s line %d: attempting connection to pin %d on component %s that only has %d pins\n",
+			input_filename, rdstate.lineno, num, oc->name,
+			oc->npins);
+		exit(1);
+	}
+	return(num - 1);
+}
+
+static int
+resolve_pinnum_grid(oc, pinnumstr)
+	struct outcomp *oc;
+	char *pinnumstr;
+{
+	register struct grid_pkg_desc *xga = oc->grid_pkg;
+	struct xga_parsed_pinnum rowcol;
+	register int idx;
+
+	if (parse_xga_pinnumber(xga, pinnumstr, &rowcol) < 0) {
+		fprintf(stderr,
+	"%s line %d: \"%s\" is not a valid pin number for grid package %s\n",
+			input_filename, rdstate.lineno, pinnumstr, oc->name);
+		exit(1);
+	}
+	idx = rowcol.row_0based * xga->ncolumns + rowcol.col_0based;
+	if (xga->holes_array[idx]) {
+		fprintf(stderr,
+	"%s line %d: pin position %s is a hole in the grid package for %s\n",
+			input_filename, rdstate.lineno, pinnumstr, oc->name);
+		exit(1);
+	}
+	return(idx);
+}
+
+static int
+resolve_pinnum(oc, pinnumstr)
+	register struct outcomp *oc;
+	char *pinnumstr;
+{
+	if (oc->grid_pkg)
+		return resolve_pinnum_grid(oc, pinnumstr);
+	else
+		return resolve_pinnum_numeric(oc, pinnumstr);
+}
+
+static struct pinconn *
+create_pinconn()
+{
+	register struct pinconn *conn;
+	register struct net *net;
+
+	if (rdout.connect_to_net) {
+		net = find_net_by_name(rdout.connect_to_net);
+		conn = (struct pinconn *) malloc(sizeof(struct pinconn));
+		if (!conn) {
+			perror("malloc");
+			exit(1);
+		}
+		conn->net = net;
+		conn->nc_comment = 0;
+	} else {
+		conn = (struct pinconn *) malloc(sizeof(struct pinconn) +
+						 strlen(rdout.nc_comment) + 1);
+		if (!conn) {
+			perror("malloc");
+			exit(1);
+		}
+		conn->net = 0;
+		conn->nc_comment = (char *)(conn + 1);
+		strcpy(conn->nc_comment, rdout.nc_comment);
+	}
+	conn->input_lineno = rdstate.lineno;
+	return conn;
+}
+
+static void
+connect_pin(oc, pinnumstr)
+	register struct outcomp *oc;
+	char *pinnumstr;
+{
+	register int pinidx;
+
+	pinidx = resolve_pinnum(oc, pinnumstr);
+	if (oc->reverse_2pin)
+		pinidx = !pinidx;
+	if (oc->conn_array[pinidx]) {
+		fprintf(stderr,
+	"error: multiple connections to %s pin %s (input lines %d and %d)\n",
+			oc->name, pinnumstr,
+			oc->conn_array[pinidx]->input_lineno, rdstate.lineno);
+		exit(1);
+	}
+	oc->conn_array[pinidx] = create_pinconn();
+}
+
+static void
+process_pinmap(inst)
+	struct instance *inst;
+{
+	register struct outcomp *oc = inst->outcomp;
+	register char *pinnum;
+
+	if (!oc->mclcomp) {
+		fprintf(stderr,
+			"%s line %d: PINMAP is meaningless for starpoints\n",
+			input_filename, rdstate.lineno);
+		exit(1);
+	}
+	pinnum = pinname_to_pinnumber(oc->mclcomp, rdout.objname, inst->slot);
+	if (!pinnum) {
+		fprintf(stderr, "PINMAP error on %s line %d\n",
+			input_filename, rdstate.lineno);
+		exit(1);
+	}
+	connect_pin(oc, pinnum);
+}
+
+static void
+process_component()
+{
+	struct instance *inst;
+
+	inst = find_instance(rdout.objname);
+	if (!inst) {
+		fprintf(stderr, "%s line %d: instance %s not bound in MCL\n",
+			input_filename, rdstate.lineno, rdout.objname);
+		unbound_instances++;
+	} else {
+		if (inst->claimed) {
+			fprintf(stderr,
+			"%s line %d: instance %s appears more than once\n",
+				input_filename, rdstate.lineno, inst->name);
+			exit(1);
+		}
+		inst->claimed = 1;
+	}
+	for (;;) {
+		if (!read_unet_line(&rdstate, &rdout)) {
+			fprintf(stderr, "%s error: EOF in component block\n",
+				input_filename);
+			exit(1);
+		}
+		if (rdout.typecode == UNETOBJ_CLOSINGBRACE)
+			break;
+		switch(rdout.typecode) {
+		case UNETOBJ_PRIMITIVE:
+		case UNETOBJ_ALTNAME:
+		case UNETOBJ_ATTR:
+			continue;
+		case UNETOBJ_PIN:
+			if (inst)
+				connect_pin(inst->outcomp, rdout.objname);
+			continue;
+		case UNETOBJ_PINMAP:
+			if (inst)
+				process_pinmap(inst);
+			continue;
+		default:
+			fprintf(stderr,
+		"%s line %d: object type %s unexpected in component block\n",
+				input_filename, rdstate.lineno, rdout.keyword);
+			exit(1);
+		}
+	}
+}
+
+process_input_unet()
+{
+	open_unet_input_file(input_filename, &rdstate);
+	while (read_unet_line(&rdstate, &rdout)) {
+		switch(rdout.typecode) {
+		case UNETOBJ_CLOSINGBRACE:
+			fprintf(stderr,
+		"%s line %d: unexpected '}' outside of component block\n",
+				input_filename, rdstate.lineno);
+			exit(1);
+		case UNETOBJ_NET:
+			enter_net_object(rdout.objname, 0);
+			continue;
+		case UNETOBJ_COMPONENT:
+			process_component();
+			continue;
+		case UNETOBJ_STARPOINT:
+			fprintf(stderr,
+"error: STARPOINT objects not expected in unet-bind input (%s line %d)\n",
+				input_filename, rdstate.lineno);
+			exit(1);
+		default:
+			fprintf(stderr,
+				"%s line %d: unexpected object type %s\n",
+				input_filename, rdstate.lineno, rdout.keyword);
+			exit(1);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/starpoints.c	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+
+extern struct instance *enter_instance();
+
+extern char *starpoints_file;
+
+struct outcomp *starpoint_list_head;
+static struct outcomp **global_tailp = &starpoint_list_head;
+
+process_starpoints_file()
+{
+	FILE *stream;
+	char linebuf[256];
+	int lineno;
+	register char *cp;
+	char *instname, *numstr;
+	int npins;
+	register struct instance *inst;
+	register struct outcomp *oc;
+
+	stream = fopen(starpoints_file, "r");
+	if (!stream) {
+		perror(starpoints_file);
+		exit(1);
+	}
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, stream); lineno++) {
+		cp = index(linebuf, '\n');
+		if (!cp) {
+			fprintf(stderr,
+			"error: %s line %d is too long or unterminated\n",
+				starpoints_file, lineno);
+			exit(1);
+		}
+		*cp = '\0';
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		instname = cp;
+		while (*cp && !isspace(*cp))
+			cp++;
+		if (*cp)
+			*cp++ = '\0';
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#') {
+npins_error:		fprintf(stderr,
+"error in %s line %d: expected number of pins after the instance name\n",
+				starpoints_file, lineno);
+			exit(1);
+		}
+		numstr = cp;
+		while (*cp && !isspace(*cp))
+			cp++;
+		if (*cp)
+			*cp++ = '\0';
+		if (!string_is_valid_decnum(numstr))
+			goto npins_error;
+		npins = atoi(numstr);
+		if (npins < 2) {
+			fprintf(stderr,
+		"error in %s line %d: a starpoint must have 2 or more pins\n",
+				starpoints_file, lineno);
+			exit(1);
+		}
+		inst = enter_instance(instname);
+		oc = (struct outcomp *)
+			malloc(sizeof(struct outcomp) +
+			       sizeof(struct pinconn *) * npins);
+		if (!oc) {
+			perror("malloc");
+			exit(1);
+		}
+		bzero(oc, sizeof(struct outcomp) +
+			  sizeof(struct pinconn *) * npins);
+		oc->name = inst->name;
+		oc->npins = npins;
+		oc->conn_array = (struct pinconn **)(oc + 1);
+		inst->outcomp = oc;
+		*global_tailp = oc;
+		global_tailp = &oc->next;
+	}
+	fclose(stream);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/unet-bind/struct.h	Sun Sep 29 22:42:41 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * Data structures for the MCL binding step
+ */
+
+struct instance {
+	char	*name;
+	struct	instance *nextinhash;
+	struct	outcomp *outcomp;
+	char	*slot;
+	int	claimed;
+};
+
+struct outcomp {
+	char	*name;
+	char	*altname;
+	struct	component *mclcomp;
+	int	npins;
+	int	reverse_2pin;
+	struct	grid_pkg_desc *grid_pkg;
+	struct	pinconn **conn_array;
+	struct	outcomp *next;	/* used only for starpoints */
+};
+
+struct pinconn {
+	struct	net *net;
+	char	*nc_comment;
+	int	input_lineno;
+};
+
+struct wantattr {
+	char	*name;
+	struct	wantattr *next;
+};