diff ueda/sverp/elaborate.c @ 0:cd92449fdb51

initial import of ueda and ifctf-part-lib from ifctfvax CVS
author Space Falcon <falcon@ivan.Harhan.ORG>
date Mon, 20 Jul 2015 00:24:37 +0000
parents
children 7b4f78fcca08
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ueda/sverp/elaborate.c	Mon Jul 20 00:24:37 2015 +0000
@@ -0,0 +1,392 @@
+/*
+ * Here we elaborate the hierarchy and create our flat netlist.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include "struct.h"
+#include "lexer.h"	/* for MAXDIGITS */
+
+extern char *malloc();
+
+struct output_net *output_net_head;
+struct output_element *output_element_head;
+int total_good_nets, total_singular_nets, total_null_nets;
+int total_output_elements;
+
+static struct output_net **output_net_tail = &output_net_head;
+static struct output_element **output_element_tail = &output_element_head;
+
+static struct output_net **
+alloc_mod_net_array(mod)
+	struct module_def *mod;
+{
+	int total_wires;
+	unsigned alloc_size;
+	register struct output_net **array;
+
+	total_wires = mod->nwires_ports + mod->nwires_internal;
+	alloc_size = sizeof(struct output_net *) * total_wires;
+	array = (struct output_net **) malloc(alloc_size);
+	if (!array) {
+		perror("malloc");
+		exit(1);
+	}
+	return(array);
+}
+
+static struct output_net **
+alloc_connect_net_array(mod)
+	struct module_def *mod;
+{
+	register unsigned alloc_size;
+	register struct output_net **array;
+
+	alloc_size = sizeof(struct output_net *) * mod->nwires_ports;
+	array = (struct output_net **) malloc(alloc_size);
+	if (!array) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(array, alloc_size);
+	return(array);
+}
+
+static struct output_net *
+create_real_net(hier_prefix, base_name, is_bus, bus_pos)
+	char *hier_prefix, *base_name;
+{
+	int len;
+	register char *buf;
+	register struct output_net *net;
+
+	len = sizeof(struct output_net) + strlen(hier_prefix) +
+		strlen(base_name) + 1;
+	if (is_bus)
+		len += MAXDIGITS + 2;
+	buf = malloc(len);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	net = (struct output_net *) buf;
+	bzero(net, sizeof(struct output_net));
+	buf += sizeof(struct output_net);
+	if (is_bus)
+		sprintf(buf, "%s%s[%d]", hier_prefix, base_name, bus_pos);
+	else
+		sprintf(buf, "%s%s", hier_prefix, base_name);
+	net->name = buf;
+	*output_net_tail = net;
+	output_net_tail = &net->next;
+	return(net);
+}
+
+static void
+create_module_nets(mod, hier_prefix, fillp)
+	struct module_def *mod;
+	char *hier_prefix;
+	register struct output_net **fillp;
+{
+	register struct module_net_def *nd;
+	register int i, incr;
+
+	for (nd = mod->nets; nd; nd = nd->next) {
+		if (nd->is_port)
+			continue;
+		if (!nd->is_bus) {
+			*fillp++ = create_real_net(hier_prefix, nd->name, 0);
+			continue;
+		}
+		if (nd->bus_msb < nd->bus_lsb)
+			incr = 1;
+		else
+			incr = -1;
+		for (i = nd->bus_msb; i != nd->bus_lsb + incr; i += incr)
+			*fillp++ = create_real_net(hier_prefix, nd->name, 1, i);
+	}
+}
+
+elaborate_module(mod, inst_name, hier_prefix, in_conn_array)
+	register struct module_def *mod;
+	char *inst_name, *hier_prefix;
+	struct output_net **in_conn_array;
+{
+	register struct output_net **mod_net_array;
+	register struct module_def_subinst *sub;
+
+	if (mod->nwires_internal) {
+		mod_net_array = alloc_mod_net_array(mod);
+		if (mod->nwires_ports)
+			bcopy(in_conn_array, mod_net_array,
+			      sizeof(struct output_net *) * mod->nwires_ports);
+		create_module_nets(mod, hier_prefix,
+				   mod_net_array + mod->nwires_ports);
+	} else
+		mod_net_array = in_conn_array;
+
+	for (sub = mod->subinst; sub; sub = sub->next)
+		elaborate_subinst(mod, inst_name, hier_prefix, mod_net_array,
+				  sub);
+
+	if (mod->nwires_internal)
+		free(mod_net_array);
+}
+
+static void
+report_connect_conflict(new_inst, ce, offset)
+	char *new_inst;
+	struct connect_entry *ce;
+	int offset;
+{
+	register struct module_net_def *port = ce->down_portdef;
+	int bus_pos;
+
+	if (port->is_bus) {
+		offset += ce->down_offset;
+		if (port->bus_msb > port->bus_lsb)
+			bus_pos = port->bus_msb - offset;
+		else
+			bus_pos = port->bus_msb + offset;
+		fprintf(stderr,
+			"elaborating %s: multiple connections to port %s[%d]\n",
+			new_inst, port->name, bus_pos);
+	} else
+		fprintf(stderr,
+			"elaborating %s: multiple connections to port %s\n",
+			new_inst, port->name);
+	exit(1);
+}
+
+static void
+check_connect_conflict(new_inst, ce, conn_array)
+	char *new_inst;
+	register struct connect_entry *ce;
+	register struct output_net **conn_array;
+{
+	register int start, i;
+
+	start = ce->down_portdef->array_index + ce->down_offset;
+	for (i = 0; i < ce->down_width; i++)
+		if (conn_array[start + i])
+			report_connect_conflict(new_inst, ce, i);
+}
+
+static struct output_net *
+create_nc_net(mup, old_inst, ce)
+	struct module_def *mup;
+	char *old_inst;
+	struct connect_entry *ce;
+{
+	register struct output_net *net;
+
+	net = (struct output_net *) malloc(sizeof(struct output_net));
+	if (!net) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(net, sizeof(struct output_net));
+	net->nc_module_name = mup->name;
+	net->nc_module_lineno = ce->src_lineno;
+	net->nc_module_inst = old_inst;
+	return(net);
+}
+
+static struct output_net *
+process_subinst_connect(mup, sub, old_inst, new_inst, mod_net_array, conn_array)
+	struct module_def *mup;
+	struct module_def_subinst *sub;
+	char *old_inst, *new_inst;
+	struct output_net **mod_net_array;
+	register struct output_net **conn_array;
+{
+	struct output_net *nc_head = 0, **nc_tail = &nc_head;
+	register struct connect_entry *ce;
+	int start;
+	register int i;
+	register struct output_net *nc_net;
+
+	for (ce = sub->connections; ce; ce = ce->next) {
+		check_connect_conflict(new_inst, ce, conn_array);
+		if (ce->up_netdef) {
+			bcopy(mod_net_array + ce->up_netdef->array_index +
+				ce->up_offset,
+			      conn_array + ce->down_portdef->array_index +
+				ce->down_offset,
+			      sizeof(struct output_net *) * ce->up_width);
+			continue;
+		}
+		/* it's a no-connect */
+		start = ce->down_portdef->array_index + ce->down_offset;
+		for (i = 0; i < ce->down_width; i++) {
+			nc_net = create_nc_net(mup, old_inst, ce);
+			conn_array[start + i] = nc_net;
+			*nc_tail = nc_net;
+			nc_tail = &nc_net->next;
+		}
+	}
+	return(nc_head);
+}
+
+static void
+report_missing_connect(new_inst, port, offset)
+	char *new_inst;
+	register struct module_net_def *port;
+	int offset;
+{
+	int bus_pos;
+
+	if (port->is_bus) {
+		if (port->bus_msb > port->bus_lsb)
+			bus_pos = port->bus_msb - offset;
+		else
+			bus_pos = port->bus_msb + offset;
+		fprintf(stderr,
+			"elaborating %s: missing connection to port %s[%d]\n",
+			new_inst, port->name, bus_pos);
+	} else
+		fprintf(stderr,
+			"elaborating %s: missing connection to port %s\n",
+			new_inst, port->name);
+	exit(1);
+}
+
+static void
+check_missing_connect(new_inst, mdown, conn_array)
+	char *new_inst;
+	struct module_def *mdown;
+	struct output_net **conn_array;
+{
+	register struct module_net_def *port;
+	register struct output_net **connp = conn_array;
+	register int i;
+
+	for (port = mdown->nets; port; port = port->next) {
+		if (!port->is_port)
+			return;		/* all ports are upfront */
+		if (!port->is_bus) {
+			if (!*connp++)
+				report_missing_connect(new_inst, port, 0);
+			continue;
+		}
+		for (i = 0; i < port->bus_width; i++)
+			if (!*connp++)
+				report_missing_connect(new_inst, port, i);
+	}
+}
+
+static void
+report_bad_nc_net(net)
+	register struct output_net *net;
+{
+	fprintf(stderr,
+"error: NC pseudo-net created at module %s line %d inst %s goes to more than one pin\n",
+		net->nc_module_name, net->nc_module_lineno,
+		net->nc_module_inst);
+	exit(1);
+}
+
+static void
+check_nc_nets(head)
+	struct output_net *head;
+{
+	register struct output_net *net;
+
+	for (net = head; net; net = net->next)
+		if (net->npoints > 1)
+			report_bad_nc_net(net);
+}
+
+elaborate_subinst(mup, inst_name, hier_prefix, mod_net_array, sub)
+	struct module_def *mup;
+	char *inst_name, *hier_prefix;
+	struct output_net **mod_net_array;
+	struct module_def_subinst *sub;
+{
+	char *new_inst, *new_prefix;
+	struct module_def *mdown = sub->submod_def;
+	struct output_net **conn_array, *nc_nets;
+
+	new_inst = malloc(strlen(hier_prefix) + strlen(sub->inst_name) + 1);
+	if (!new_inst) {
+		perror("malloc");
+		exit(1);
+	}
+	sprintf(new_inst, "%s%s", hier_prefix, sub->inst_name);
+	if (mdown->nports) {
+		conn_array = alloc_connect_net_array(mdown);
+		nc_nets = process_subinst_connect(mup, sub, inst_name, new_inst,
+						  mod_net_array, conn_array);
+		check_missing_connect(new_inst, mdown, conn_array);
+	} else {
+		conn_array = 0;
+		nc_nets = 0;
+	}
+
+	if (mdown->is_primitive)
+		elaborate_primitive(mdown, new_inst, conn_array);
+	else {
+		new_prefix = malloc(strlen(hier_prefix) +
+					strlen(sub->inst_name) + 2);
+		if (!new_prefix) {
+			perror("malloc");
+			exit(1);
+		}
+		sprintf(new_prefix, "%s%s.", hier_prefix, sub->inst_name);
+		elaborate_module(mdown, new_inst, new_prefix, conn_array);
+		free(new_prefix);
+		if (conn_array)
+			free(conn_array);
+	}
+
+	if (nc_nets)
+		check_nc_nets(nc_nets);
+}
+
+static void
+incr_net_points_for_output_element(elem)
+	struct output_element *elem;
+{
+	register struct output_net **p, **endp;
+
+	p = elem->connections;
+	endp = p + elem->prim_def->nports;
+	for (; p < endp; p++)
+		(*p)->npoints++;
+}
+
+elaborate_primitive(mod, inst_name, in_conn_array)
+	struct module_def *mod;
+	char *inst_name;
+	struct output_net **in_conn_array;
+{
+	register struct output_element *elem;
+
+	elem = (struct output_element *) malloc(sizeof(struct output_element));
+	if (!elem) {
+		perror("malloc");
+		exit(1);
+	}
+	elem->prim_def = mod;
+	elem->hier_inst_name = inst_name;
+	elem->connections = in_conn_array;
+	elem->next = 0;
+	*output_element_tail = elem;
+	output_element_tail = &elem->next;
+	total_output_elements++;
+	incr_net_points_for_output_element(elem);
+}
+
+tally_output_nets()
+{
+	register struct output_net *net;
+
+	for (net = output_net_head; net; net = net->next) {
+		if (net->npoints > 1)
+			total_good_nets++;
+		else if (net->npoints == 1)
+			total_singular_nets++;
+		else
+			total_null_nets++;
+	}
+}