FreeCalypso > hg > ueda-linux
view ueda/sverp/vparse.c @ 139:bf188727e606
donl-rename-parts reader: no tEDAx-style escapes
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 07 Sep 2020 04:25:11 +0000 |
parents | 7b4f78fcca08 |
children |
line wrap: on
line source
/* * Parser for the minimal subset of Verilog we grok */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "struct.h" #include "lexer.h" 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); }