comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:cd92449fdb51
1 /*
2 * Parser for the minimal subset of Verilog we grok
3 */
4
5 #include <stdio.h>
6 #include <strings.h>
7 #include "struct.h"
8 #include "lexer.h"
9
10 extern char *malloc();
11
12 extern struct module_def *glob_module_list;
13
14 extern char *parser_filename;
15 extern FILE *parser_readF;
16 extern int parser_lineno;
17 extern char parser_read_word[];
18 extern int parser_read_number;
19 extern int pushback_token;
20
21 static struct module_def *curmod;
22 static struct module_def_subinst *subinst;
23 static struct connect_entry *curconn, **subinst_nextconn;
24
25 /* internal (to the parser) structure for passing range info */
26 struct range_info {
27 int range_given;
28 int range_msb;
29 int range_lsb;
30 };
31
32 static int
33 capture_range(spec)
34 struct range_info *spec;
35 {
36 register int t;
37
38 t = get_token();
39 if (t != '[') {
40 pushback_token = t;
41 bzero(spec, sizeof(struct range_info));
42 return(0);
43 }
44 spec->range_given = 1;
45 t = get_token();
46 if (t != NUMBER)
47 parse_error("expected number after '['");
48 spec->range_msb = parser_read_number;
49 t = get_token();
50 if (t == ']') {
51 spec->range_lsb = spec->range_msb;
52 return(1);
53 }
54 if (t != ':')
55 parse_error("expected ':' or ']' after MSB number");
56 t = get_token();
57 if (t != NUMBER)
58 parse_error("expected number after ':'");
59 spec->range_lsb = parser_read_number;
60 t = get_token();
61 if (t != ']')
62 parse_error("expected ']' after LSB number");
63 return(1);
64 }
65
66 static void
67 create_module()
68 {
69 register struct module_def *mod, **modp;
70 char *buf;
71
72 for (modp = &glob_module_list; mod = *modp; modp = &mod->next) {
73 if (!strcmp(mod->name, parser_read_word))
74 parse_error("duplicate module name");
75 }
76 buf = malloc(sizeof(struct module_def) + strlen(parser_read_word) + 1);
77 if (!buf) {
78 perror("malloc");
79 exit(1);
80 }
81 mod = (struct module_def *) buf;
82 bzero(mod, sizeof(struct module_def));
83 buf += sizeof(struct module_def);
84 strcpy(buf, parser_read_word);
85 mod->name = buf;
86 *modp = mod;
87 curmod = mod;
88 }
89
90 static void
91 add_port()
92 {
93 register struct module_net_def *n, **np;
94 char *buf;
95
96 for (np = &curmod->nets; n = *np; np = &n->next) {
97 if (!strcmp(n->name, parser_read_word))
98 parse_error("duplicate port name in module line");
99 }
100 buf = malloc(sizeof(struct module_net_def) + strlen(parser_read_word)
101 + 1);
102 if (!buf) {
103 perror("malloc");
104 exit(1);
105 }
106 n = (struct module_net_def *) buf;
107 bzero(n, sizeof(struct module_net_def));
108 buf += sizeof(struct module_net_def);
109 strcpy(buf, parser_read_word);
110 n->name = buf;
111 n->is_port = 1;
112 *np = n;
113 curmod->nports++;
114 }
115
116 static void
117 process_port_list()
118 {
119 register int t;
120
121 for (;;) {
122 t = get_token();
123 if (t == ')')
124 return;
125 if (t != WORD)
126 parse_error("expected port name in module line");
127 add_port();
128 t = get_token();
129 if (t == ')')
130 return;
131 if (t != ',')
132 parse_error("expected ',' or ')' in module line");
133 }
134 }
135
136 static void
137 netdef_set_businfo(n, range)
138 register struct module_net_def *n;
139 register struct range_info *range;
140 {
141 if (!range->range_given) {
142 n->is_bus = 0;
143 n->bus_width = 1;
144 return;
145 }
146 if (range->range_msb == range->range_lsb)
147 parse_error("bus declaration with MSB==LSB is meaningless");
148 n->is_bus = 1;
149 n->bus_msb = range->range_msb;
150 n->bus_lsb = range->range_lsb;
151 if (n->bus_msb > n->bus_lsb)
152 n->bus_width = n->bus_msb - n->bus_lsb + 1;
153 else
154 n->bus_width = n->bus_lsb - n->bus_msb + 1;
155 }
156
157 static void
158 complete_port_def(range)
159 struct range_info *range;
160 {
161 register struct module_net_def *n;
162
163 for (n = curmod->nets; n; n = n->next)
164 if (!strcmp(n->name, parser_read_word))
165 break;
166 if (!n) {
167 fprintf(stderr, "%s line %d: no port named %s\n",
168 parser_filename, parser_lineno, parser_read_word);
169 exit(1);
170 }
171 if (n->def_complete) {
172 fprintf(stderr,
173 "%s line %d: inout decl for %s is a redefinition\n",
174 parser_filename, parser_lineno, parser_read_word);
175 exit(1);
176 }
177 netdef_set_businfo(n, range);
178 n->def_complete = 1;
179 }
180
181 static void
182 add_wire(range)
183 struct range_info *range;
184 {
185 register struct module_net_def *n, **np;
186 char *buf;
187
188 for (np = &curmod->nets; n = *np; np = &n->next)
189 if (!strcmp(n->name, parser_read_word)) {
190 fprintf(stderr,
191 "%s line %d: wire %s is a redefinition\n",
192 parser_filename, parser_lineno,
193 parser_read_word);
194 exit(1);
195 }
196 buf = malloc(sizeof(struct module_net_def) + strlen(parser_read_word)
197 + 1);
198 if (!buf) {
199 perror("malloc");
200 exit(1);
201 }
202 n = (struct module_net_def *) buf;
203 bzero(n, sizeof(struct module_net_def));
204 buf += sizeof(struct module_net_def);
205 strcpy(buf, parser_read_word);
206 n->name = buf;
207 *np = n;
208 netdef_set_businfo(n, range);
209 n->def_complete = 1;
210 }
211
212 static void
213 process_netdef_line(is_port)
214 {
215 struct range_info range;
216 register int t;
217
218 capture_range(&range);
219 for (;;) {
220 t = get_token();
221 if (t == ';')
222 return;
223 if (t != WORD)
224 parse_error("expected ident on wire def line");
225 if (is_port)
226 complete_port_def(&range);
227 else
228 add_wire(&range);
229 t = get_token();
230 if (t == ';')
231 return;
232 if (t != ',')
233 parse_error("expected ',' or ';' in wire def line");
234 }
235 }
236
237 static void
238 create_subinst(submod_name, inst_name)
239 char *submod_name, *inst_name;
240 {
241 register struct module_def_subinst *s, **sp;
242 char *buf;
243
244 for (sp = &curmod->subinst; s = *sp; sp = &s->next)
245 if (!strcmp(s->inst_name, inst_name))
246 parse_error("duplicate subinstance name");
247 buf = malloc(sizeof(struct module_def_subinst) + strlen(submod_name) +
248 strlen(inst_name) + 2);
249 if (!buf) {
250 perror("malloc");
251 exit(1);
252 }
253 s = (struct module_def_subinst *) buf;
254 bzero(s, sizeof(struct module_def_subinst));
255 buf += sizeof(struct module_def_subinst);
256 strcpy(buf, submod_name);
257 s->submod_name = buf;
258 buf += strlen(submod_name) + 1;
259 strcpy(buf, inst_name);
260 s->inst_name = buf;
261 *sp = s;
262 subinst = s;
263 subinst_nextconn = &s->connections;
264 }
265
266 static void
267 alloc_connect_entry(downport)
268 char *downport;
269 {
270 struct connect_entry *s;
271 int len;
272 char *buf;
273
274 if (downport)
275 len = sizeof(struct connect_entry) + strlen(downport) + 1;
276 else
277 len = sizeof(struct connect_entry);
278 s = (struct connect_entry *) malloc(len);
279 if (!s) {
280 perror("malloc");
281 exit(1);
282 }
283 bzero(s, sizeof(struct connect_entry));
284 if (downport) {
285 buf = (char *)(s + 1);
286 strcpy(buf, downport);
287 s->down_portname = buf;
288 }
289 curconn = s;
290 *subinst_nextconn = s;
291 subinst_nextconn = &s->next;
292 }
293
294 static void
295 connect_upper()
296 {
297 struct range_info range;
298 register struct module_net_def *n;
299
300 for (n = curmod->nets; n; n = n->next)
301 if (!strcmp(n->name, parser_read_word))
302 break;
303 if (!n) {
304 fprintf(stderr, "%s line %d: no net named %s\n",
305 parser_filename, parser_lineno, parser_read_word);
306 exit(1);
307 }
308 curconn->up_netdef = n;
309 if (!capture_range(&range)) {
310 curconn->up_offset = 0;
311 curconn->up_width = n->bus_width;
312 return;
313 }
314 if (!n->is_bus) {
315 fprintf(stderr,
316 "%s line %d: net %s is not a bus, range spec is meaningless\n",
317 parser_filename, parser_lineno, n->name);
318 exit(1);
319 }
320 if (n->bus_msb > n->bus_lsb) {
321 if (range.range_msb < range.range_lsb) {
322 error_reversed: fprintf(stderr,
323 "%s line %d: reversed range on bus %s\n",
324 parser_filename, parser_lineno, n->name);
325 exit(1);
326 }
327 if (range.range_msb > n->bus_msb) {
328 error_outofrange: fprintf(stderr,
329 "%s line %d: subrange of bus %s to connect exceeds full bus range\n",
330 parser_filename, parser_lineno, n->name);
331 exit(1);
332 }
333 if (range.range_lsb < n->bus_lsb)
334 goto error_outofrange;
335 curconn->up_offset = n->bus_msb - range.range_msb;
336 curconn->up_width = range.range_msb - range.range_lsb + 1;
337 } else {
338 if (range.range_msb > range.range_lsb)
339 goto error_reversed;
340 if (range.range_msb < n->bus_msb)
341 goto error_outofrange;
342 if (range.range_lsb > n->bus_lsb)
343 goto error_outofrange;
344 curconn->up_offset = range.range_msb - n->bus_msb;
345 curconn->up_width = range.range_lsb - range.range_msb + 1;
346 }
347 }
348
349 static void
350 connect_by_name()
351 {
352 struct range_info range;
353 register int t;
354
355 for (;;) {
356 t = get_token();
357 if (t == ')')
358 return;
359 if (t != '.')
360 parse_error("expected '.' for downward port");
361 t = get_token();
362 if (t != WORD)
363 parse_error("expected downward port name after '.'");
364 alloc_connect_entry(parser_read_word);
365 curconn->src_lineno = parser_lineno;
366 if (capture_range(&range)) {
367 curconn->down_range_given = 1;
368 curconn->down_range_msb = range.range_msb;
369 curconn->down_range_lsb = range.range_lsb;
370 }
371 t = get_token();
372 if (t != '(')
373 parse_error("expected '(' for connect-by-name");
374 t = get_token();
375 if (t != ')') {
376 if (t != WORD)
377 parse_error(
378 "expected in-module net name to connect");
379 connect_upper();
380 t = get_token();
381 if (t != ')')
382 parse_error("expected ')' for connect-by-name");
383 }
384 t = get_token();
385 if (t == ')')
386 return;
387 if (t != ',')
388 parse_error("expected ',' or ')' in connection list");
389 }
390 }
391
392 static void
393 connect_by_order()
394 {
395 register int t;
396
397 for (;;) {
398 t = get_token();
399 if (t == ')')
400 return;
401 if (t != WORD)
402 parse_error("expected in-module net name to connect");
403 alloc_connect_entry(0);
404 curconn->src_lineno = parser_lineno;
405 connect_upper();
406 subinst->connect_by_order++;
407 t = get_token();
408 if (t == ')')
409 return;
410 if (t != ',')
411 parse_error("expected ',' or ')' in connection list");
412 }
413 }
414
415 static void
416 process_subinst()
417 {
418 char submod_name[MAXWORD+1];
419 register int t;
420
421 strcpy(submod_name, parser_read_word);
422 t = get_token();
423 if (t != WORD)
424 parse_error("expected instance name after submodule name");
425 create_subinst(submod_name, parser_read_word);
426 t = get_token();
427 if (t != '(')
428 parse_error("expected '(' after <module> <instance>");
429 t = get_token();
430 pushback_token = t;
431 if (t == '.')
432 connect_by_name();
433 else
434 connect_by_order();
435 t = get_token();
436 if (t != ';')
437 parse_error("expected ';' at the end of instantiation");
438 }
439
440 static void
441 preen_module_nets()
442 {
443 register struct module_net_def *n;
444 register int idx;
445
446 idx = 0;
447 for (n = curmod->nets; n; n = n->next) {
448 if (!n->def_complete) {
449 fprintf(stderr,
450 "error: definition of port %s in module %s is incomplete\n",
451 n->name, curmod->name);
452 exit(1);
453 }
454 n->array_index = idx;
455 idx += n->bus_width;
456 if (n->is_port)
457 curmod->nwires_ports += n->bus_width;
458 else
459 curmod->nwires_internal += n->bus_width;
460 }
461 }
462
463 read_verilog_file(filename_arg)
464 char *filename_arg;
465 {
466 register int t;
467
468 parser_filename = filename_arg;
469 parser_readF = fopen(parser_filename, "r");
470 if (!parser_readF) {
471 perror(parser_filename);
472 exit(1);
473 }
474 parser_lineno = 1;
475 pushback_token = 0;
476
477 t = get_token();
478 if (t != WORD || strcmp(parser_read_word, "module"))
479 parse_error("first token is expected to be \"module\"");
480 t = get_token();
481 if (t != WORD)
482 parse_error("module name expected after \"module\"");
483 create_module();
484 t = get_token();
485 if (t != '(')
486 parse_error("expected '(' after module <modname>");
487 process_port_list();
488 t = get_token();
489 if (t != ';')
490 parse_error("expected ';' at the end of module line");
491
492 for (;;) {
493 t = get_token();
494 if (t != WORD)
495 parse_error(
496 "expected word token at the beginning of module item");
497 if (!strcmp(parser_read_word, "endmodule"))
498 break;
499 if (!strcmp(parser_read_word, "input") ||
500 !strcmp(parser_read_word, "output") ||
501 !strcmp(parser_read_word, "inout"))
502 process_netdef_line(1);
503 else if (!strcmp(parser_read_word, "wire"))
504 process_netdef_line(0);
505 else
506 process_subinst();
507 }
508
509 fclose(parser_readF);
510 preen_module_nets();
511 return(0);
512 }