diff ueda/sverp/link.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/link.c	Mon Jul 20 00:24:37 2015 +0000
@@ -0,0 +1,198 @@
+/*
+ * ueda-sverp link pass
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include "struct.h"
+
+extern struct module_def *glob_module_list, *top_module_def;
+extern int top_module_candidates;
+
+extern struct module_def *find_module_by_name();
+
+static void
+toplevel_candidate(mod)
+	struct module_def *mod;
+{
+	top_module_candidates++;
+	if (!top_module_def)
+		top_module_def = mod;
+}
+
+static struct module_net_def *
+find_port_by_name(mod, portname)
+	struct module_def *mod;
+	register char *portname;
+{
+	register struct module_net_def *n;
+
+	for (n = mod->nets; n; n = n->next)
+		if (!strcmp(n->name, portname))
+			break;
+	if (n && n->is_port)
+		return(n);
+	else
+		return(0);
+}
+
+static void
+handle_downport_range(mup, ins, conn)
+	struct module_def *mup;
+	struct module_def_subinst *ins;
+	register struct connect_entry *conn;
+{
+	register struct module_net_def *port;
+
+	port = conn->down_portdef;
+	if (!port->is_bus) {
+		fprintf(stderr,
+"module %s line %d: mod %s port %s is not a bus, range spec is meaningless\n",
+			mup->name, conn->src_lineno, ins->submod_name,
+			port->name);
+		exit(1);
+	}
+	if (port->bus_msb > port->bus_lsb) {
+		if (conn->down_range_msb < conn->down_range_lsb) {
+error_reversed:		fprintf(stderr,
+			"module %s line %d: reversed range on bus port %s\n",
+				mup->name, conn->src_lineno, port->name);
+			exit(1);
+		}
+		if (conn->down_range_msb > port->bus_msb) {
+error_outofrange:	fprintf(stderr,
+	"module %s line %d: subrange on bus port %s exceeds full bus range\n",
+				mup->name, conn->src_lineno, port->name);
+			exit(1);
+		}
+		if (conn->down_range_lsb < port->bus_lsb)
+			goto error_outofrange;
+		conn->down_offset = port->bus_msb - conn->down_range_msb;
+		conn->down_width = conn->down_range_msb - conn->down_range_lsb
+					+ 1;
+	} else {
+		if (conn->down_range_msb > conn->down_range_lsb)
+			goto error_reversed;
+		if (conn->down_range_msb < port->bus_msb)
+			goto error_outofrange;
+		if (conn->down_range_lsb > port->bus_lsb)
+			goto error_outofrange;
+		conn->down_offset = conn->down_range_msb - port->bus_msb;
+		conn->down_width = conn->down_range_lsb - conn->down_range_msb
+					+ 1;
+	}
+}
+
+static void
+connect_by_name(mup, ins)
+	struct module_def *mup;
+	register struct module_def_subinst *ins;
+{
+	register struct connect_entry *conn;
+	register struct module_net_def *port;
+
+	for (conn = ins->connections; conn; conn = conn->next) {
+		port = find_port_by_name(ins->submod_def, conn->down_portname);
+		if (!port) {
+			fprintf(stderr,
+	"instance %s in module %s: lower module %s has no port named \"%s\"\n",
+				ins->inst_name, mup->name,
+				ins->submod_name, conn->down_portname);
+			exit(1);
+		}
+		conn->down_portdef = port;
+		if (conn->down_range_given)
+			handle_downport_range(mup, ins, conn);
+		else {
+			conn->down_offset = 0;
+			conn->down_width = port->bus_width;
+		}
+	}
+}
+
+static void
+connect_by_order(mup, ins)
+	struct module_def *mup;
+	register struct module_def_subinst *ins;
+{
+	struct module_def *mdown;
+	register struct module_net_def *port;
+	register struct connect_entry *conn;
+
+	mdown = ins->submod_def;
+	if (ins->connect_by_order != mdown->nports) {
+		fprintf(stderr,
+"instance %s in module %s: connect by order port count mismatch (%d ports, %d connections)\n",
+			ins->inst_name, mup->name, mdown->nports,
+			ins->connect_by_order);
+		exit(1);
+	}
+	for (conn = ins->connections, port = mdown->nets; conn;
+	     conn = conn->next, port = port->next) {
+		conn->down_portdef = port;
+		conn->down_offset = 0;
+		conn->down_width = port->bus_width;
+	}
+}
+
+static void
+check_width_match(mup, ins)
+	struct module_def *mup;
+	struct module_def_subinst *ins;
+{
+	register struct connect_entry *conn;
+
+	for (conn = ins->connections; conn; conn = conn->next)
+		if (conn->up_netdef && conn->up_width != conn->down_width) {
+			fprintf(stderr,
+		"module %s line %d: width mismatch on connection to port %s\n",
+				mup->name, conn->src_lineno,
+				conn->down_portdef->name);
+			exit(1);
+		}
+}
+
+static void
+linkpass_process_inst(mup, ins)
+	struct module_def *mup;
+	register struct module_def_subinst *ins;
+{
+	register struct module_def *mdown;
+
+	mdown = find_module_by_name(ins->submod_name);
+	if (!mdown) {
+		fprintf(stderr,
+		    "instance %s in module %s: lower module \"%s\" not found\n",
+			ins->inst_name, mup->name, ins->submod_name);
+		exit(1);
+	}
+	ins->submod_def = mdown;
+	if (ins->connect_by_order)
+		connect_by_order(mup, ins);
+	else
+		connect_by_name(mup, ins);
+	check_width_match(mup, ins);
+}
+
+static void
+linkpass_process_mod(mod)
+	struct module_def *mod;
+{
+	register struct module_def_subinst *ins;
+
+	for (ins = mod->subinst; ins; ins = ins->next)
+		linkpass_process_inst(mod, ins);
+}
+
+link_pass()
+{
+	register struct module_def *m;
+
+	for (m = glob_module_list; m; m = m->next) {
+		if (m->is_primitive)
+			continue;
+		if (!m->nports)
+			toplevel_candidate(m);
+		linkpass_process_mod(m);
+	}
+}