FreeCalypso > hg > ueda-linux
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); +}