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