diff ueda/sverp/vparse.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/vparse.c	Mon Jul 20 00:24:37 2015 +0000
@@ -0,0 +1,512 @@
+/*
+ * Parser for the minimal subset of Verilog we grok
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include "struct.h"
+#include "lexer.h"
+
+extern char *malloc();
+
+extern struct module_def *glob_module_list;
+
+extern char *parser_filename;
+extern FILE *parser_readF;
+extern int parser_lineno;
+extern char parser_read_word[];
+extern int parser_read_number;
+extern int pushback_token;
+
+static struct module_def *curmod;
+static struct module_def_subinst *subinst;
+static struct connect_entry *curconn, **subinst_nextconn;
+
+/* internal (to the parser) structure for passing range info */
+struct range_info {
+	int	range_given;
+	int	range_msb;
+	int	range_lsb;
+};
+
+static int
+capture_range(spec)
+	struct range_info *spec;
+{
+	register int t;
+
+	t = get_token();
+	if (t != '[') {
+		pushback_token = t;
+		bzero(spec, sizeof(struct range_info));
+		return(0);
+	}
+	spec->range_given = 1;
+	t = get_token();
+	if (t != NUMBER)
+		parse_error("expected number after '['");
+	spec->range_msb = parser_read_number;
+	t = get_token();
+	if (t == ']') {
+		spec->range_lsb = spec->range_msb;
+		return(1);
+	}
+	if (t != ':')
+		parse_error("expected ':' or ']' after MSB number");
+	t = get_token();
+	if (t != NUMBER)
+		parse_error("expected number after ':'");
+	spec->range_lsb = parser_read_number;
+	t = get_token();
+	if (t != ']')
+		parse_error("expected ']' after LSB number");
+	return(1);
+}
+
+static void
+create_module()
+{
+	register struct module_def *mod, **modp;
+	char *buf;
+
+	for (modp = &glob_module_list; mod = *modp; modp = &mod->next) {
+		if (!strcmp(mod->name, parser_read_word))
+			parse_error("duplicate module name");
+	}
+	buf = malloc(sizeof(struct module_def) + strlen(parser_read_word) + 1);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	mod = (struct module_def *) buf;
+	bzero(mod, sizeof(struct module_def));
+	buf += sizeof(struct module_def);
+	strcpy(buf, parser_read_word);
+	mod->name = buf;
+	*modp = mod;
+	curmod = mod;
+}
+
+static void
+add_port()
+{
+	register struct module_net_def *n, **np;
+	char *buf;
+
+	for (np = &curmod->nets; n = *np; np = &n->next) {
+		if (!strcmp(n->name, parser_read_word))
+			parse_error("duplicate port name in module line");
+	}
+	buf = malloc(sizeof(struct module_net_def) + strlen(parser_read_word)
+			+ 1);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	n = (struct module_net_def *) buf;
+	bzero(n, sizeof(struct module_net_def));
+	buf += sizeof(struct module_net_def);
+	strcpy(buf, parser_read_word);
+	n->name = buf;
+	n->is_port = 1;
+	*np = n;
+	curmod->nports++;
+}
+
+static void
+process_port_list()
+{
+	register int t;
+
+	for (;;) {
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != WORD)
+			parse_error("expected port name in module line");
+		add_port();
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != ',')
+			parse_error("expected ',' or ')' in module line");
+	}
+}
+
+static void
+netdef_set_businfo(n, range)
+	register struct module_net_def *n;
+	register struct range_info *range;
+{
+	if (!range->range_given) {
+		n->is_bus = 0;
+		n->bus_width = 1;
+		return;
+	}
+	if (range->range_msb == range->range_lsb)
+		parse_error("bus declaration with MSB==LSB is meaningless");
+	n->is_bus = 1;
+	n->bus_msb = range->range_msb;
+	n->bus_lsb = range->range_lsb;
+	if (n->bus_msb > n->bus_lsb)
+		n->bus_width = n->bus_msb - n->bus_lsb + 1;
+	else
+		n->bus_width = n->bus_lsb - n->bus_msb + 1;
+}
+
+static void
+complete_port_def(range)
+	struct range_info *range;
+{
+	register struct module_net_def *n;
+
+	for (n = curmod->nets; n; n = n->next)
+		if (!strcmp(n->name, parser_read_word))
+			break;
+	if (!n) {
+		fprintf(stderr, "%s line %d: no port named %s\n",
+			parser_filename, parser_lineno, parser_read_word);
+		exit(1);
+	}
+	if (n->def_complete) {
+		fprintf(stderr,
+			"%s line %d: inout decl for %s is a redefinition\n",
+			parser_filename, parser_lineno, parser_read_word);
+		exit(1);
+	}
+	netdef_set_businfo(n, range);
+	n->def_complete = 1;
+}
+
+static void
+add_wire(range)
+	struct range_info *range;
+{
+	register struct module_net_def *n, **np;
+	char *buf;
+
+	for (np = &curmod->nets; n = *np; np = &n->next)
+		if (!strcmp(n->name, parser_read_word)) {
+			fprintf(stderr,
+				"%s line %d: wire %s is a redefinition\n",
+				parser_filename, parser_lineno,
+				parser_read_word);
+			exit(1);
+		}
+	buf = malloc(sizeof(struct module_net_def) + strlen(parser_read_word)
+			+ 1);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	n = (struct module_net_def *) buf;
+	bzero(n, sizeof(struct module_net_def));
+	buf += sizeof(struct module_net_def);
+	strcpy(buf, parser_read_word);
+	n->name = buf;
+	*np = n;
+	netdef_set_businfo(n, range);
+	n->def_complete = 1;
+}
+
+static void
+process_netdef_line(is_port)
+{
+	struct range_info range;
+	register int t;
+
+	capture_range(&range);
+	for (;;) {
+		t = get_token();
+		if (t == ';')
+			return;
+		if (t != WORD)
+			parse_error("expected ident on wire def line");
+		if (is_port)
+			complete_port_def(&range);
+		else
+			add_wire(&range);
+		t = get_token();
+		if (t == ';')
+			return;
+		if (t != ',')
+			parse_error("expected ',' or ';' in wire def line");
+	}
+}
+
+static void
+create_subinst(submod_name, inst_name)
+	char *submod_name, *inst_name;
+{
+	register struct module_def_subinst *s, **sp;
+	char *buf;
+
+	for (sp = &curmod->subinst; s = *sp; sp = &s->next)
+		if (!strcmp(s->inst_name, inst_name))
+			parse_error("duplicate subinstance name");
+	buf = malloc(sizeof(struct module_def_subinst) + strlen(submod_name) +
+			strlen(inst_name) + 2);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+	s = (struct module_def_subinst *) buf;
+	bzero(s, sizeof(struct module_def_subinst));
+	buf += sizeof(struct module_def_subinst);
+	strcpy(buf, submod_name);
+	s->submod_name = buf;
+	buf += strlen(submod_name) + 1;
+	strcpy(buf, inst_name);
+	s->inst_name = buf;
+	*sp = s;
+	subinst = s;
+	subinst_nextconn = &s->connections;
+}
+
+static void
+alloc_connect_entry(downport)
+	char *downport;
+{
+	struct connect_entry *s;
+	int len;
+	char *buf;
+
+	if (downport)
+		len = sizeof(struct connect_entry) + strlen(downport) + 1;
+	else
+		len = sizeof(struct connect_entry);
+	s = (struct connect_entry *) malloc(len);
+	if (!s) {
+		perror("malloc");
+		exit(1);
+	}
+	bzero(s, sizeof(struct connect_entry));
+	if (downport) {
+		buf = (char *)(s + 1);
+		strcpy(buf, downport);
+		s->down_portname = buf;
+	}
+	curconn = s;
+	*subinst_nextconn = s;
+	subinst_nextconn = &s->next;
+}
+
+static void
+connect_upper()
+{
+	struct range_info range;
+	register struct module_net_def *n;
+
+	for (n = curmod->nets; n; n = n->next)
+		if (!strcmp(n->name, parser_read_word))
+			break;
+	if (!n) {
+		fprintf(stderr, "%s line %d: no net named %s\n",
+			parser_filename, parser_lineno, parser_read_word);
+		exit(1);
+	}
+	curconn->up_netdef = n;
+	if (!capture_range(&range)) {
+		curconn->up_offset = 0;
+		curconn->up_width = n->bus_width;
+		return;
+	}
+	if (!n->is_bus) {
+		fprintf(stderr,
+		"%s line %d: net %s is not a bus, range spec is meaningless\n",
+			parser_filename, parser_lineno, n->name);
+		exit(1);
+	}
+	if (n->bus_msb > n->bus_lsb) {
+		if (range.range_msb < range.range_lsb) {
+error_reversed:		fprintf(stderr,
+				"%s line %d: reversed range on bus %s\n",
+				parser_filename, parser_lineno, n->name);
+			exit(1);
+		}
+		if (range.range_msb > n->bus_msb) {
+error_outofrange:	fprintf(stderr,
+	"%s line %d: subrange of bus %s to connect exceeds full bus range\n",
+				parser_filename, parser_lineno, n->name);
+			exit(1);
+		}
+		if (range.range_lsb < n->bus_lsb)
+			goto error_outofrange;
+		curconn->up_offset = n->bus_msb - range.range_msb;
+		curconn->up_width = range.range_msb - range.range_lsb + 1;
+	} else {
+		if (range.range_msb > range.range_lsb)
+			goto error_reversed;
+		if (range.range_msb < n->bus_msb)
+			goto error_outofrange;
+		if (range.range_lsb > n->bus_lsb)
+			goto error_outofrange;
+		curconn->up_offset = range.range_msb - n->bus_msb;
+		curconn->up_width = range.range_lsb - range.range_msb + 1;
+	}
+}
+
+static void
+connect_by_name()
+{
+	struct range_info range;
+	register int t;
+
+	for (;;) {
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != '.')
+			parse_error("expected '.' for downward port");
+		t = get_token();
+		if (t != WORD)
+			parse_error("expected downward port name after '.'");
+		alloc_connect_entry(parser_read_word);
+		curconn->src_lineno = parser_lineno;
+		if (capture_range(&range)) {
+			curconn->down_range_given = 1;
+			curconn->down_range_msb = range.range_msb;
+			curconn->down_range_lsb = range.range_lsb;
+		}
+		t = get_token();
+		if (t != '(')
+			parse_error("expected '(' for connect-by-name");
+		t = get_token();
+		if (t != ')') {
+			if (t != WORD)
+				parse_error(
+				"expected in-module net name to connect");
+			connect_upper();
+			t = get_token();
+			if (t != ')')
+				parse_error("expected ')' for connect-by-name");
+		}
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != ',')
+			parse_error("expected ',' or ')' in connection list");
+	}
+}
+
+static void
+connect_by_order()
+{
+	register int t;
+
+	for (;;) {
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != WORD)
+			parse_error("expected in-module net name to connect");
+		alloc_connect_entry(0);
+		curconn->src_lineno = parser_lineno;
+		connect_upper();
+		subinst->connect_by_order++;
+		t = get_token();
+		if (t == ')')
+			return;
+		if (t != ',')
+			parse_error("expected ',' or ')' in connection list");
+	}
+}
+
+static void
+process_subinst()
+{
+	char submod_name[MAXWORD+1];
+	register int t;
+
+	strcpy(submod_name, parser_read_word);
+	t = get_token();
+	if (t != WORD)
+		parse_error("expected instance name after submodule name");
+	create_subinst(submod_name, parser_read_word);
+	t = get_token();
+	if (t != '(')
+		parse_error("expected '(' after <module> <instance>");
+	t = get_token();
+	pushback_token = t;
+	if (t == '.')
+		connect_by_name();
+	else
+		connect_by_order();
+	t = get_token();
+	if (t != ';')
+		parse_error("expected ';' at the end of instantiation");
+}
+
+static void
+preen_module_nets()
+{
+	register struct module_net_def *n;
+	register int idx;
+
+	idx = 0;
+	for (n = curmod->nets; n; n = n->next) {
+		if (!n->def_complete) {
+			fprintf(stderr,
+		"error: definition of port %s in module %s is incomplete\n",
+				n->name, curmod->name);
+			exit(1);
+		}
+		n->array_index = idx;
+		idx += n->bus_width;
+		if (n->is_port)
+			curmod->nwires_ports += n->bus_width;
+		else
+			curmod->nwires_internal += n->bus_width;
+	}
+}
+
+read_verilog_file(filename_arg)
+	char *filename_arg;
+{
+	register int t;
+
+	parser_filename = filename_arg;
+	parser_readF = fopen(parser_filename, "r");
+	if (!parser_readF) {
+		perror(parser_filename);
+		exit(1);
+	}
+	parser_lineno = 1;
+	pushback_token = 0;
+
+	t = get_token();
+	if (t != WORD || strcmp(parser_read_word, "module"))
+		parse_error("first token is expected to be \"module\"");
+	t = get_token();
+	if (t != WORD)
+		parse_error("module name expected after \"module\"");
+	create_module();
+	t = get_token();
+	if (t != '(')
+		parse_error("expected '(' after module <modname>");
+	process_port_list();
+	t = get_token();
+	if (t != ';')
+		parse_error("expected ';' at the end of module line");
+
+	for (;;) {
+		t = get_token();
+		if (t != WORD)
+			parse_error(
+			"expected word token at the beginning of module item");
+		if (!strcmp(parser_read_word, "endmodule"))
+			break;
+		if (!strcmp(parser_read_word, "input") ||
+		    !strcmp(parser_read_word, "output") ||
+		    !strcmp(parser_read_word, "inout"))
+			process_netdef_line(1);
+		else if (!strcmp(parser_read_word, "wire"))
+			process_netdef_line(0);
+		else
+			process_subinst();
+	}
+
+	fclose(parser_readF);
+	preen_module_nets();
+	return(0);
+}