My omnium-gatherom of scripts and source code.
1/* Functions to generate C or Verilog code from HCL */
2/* This file maintains a parse tree representation of expressions */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8#include <ctype.h>
9
10#include "node.h"
11#include "outgen.h"
12
13#define MAXBUF 1024
14
15void yyerror(const char *str);
16void yyserror(const char *str, char *other);
17
18/* For error reporting */
19static char* show_expr(node_ptr expr);
20
21/* The symbol table */
22#define SYM_LIM 100
23static node_ptr sym_tab[2][SYM_LIM];
24static int sym_count = 0;
25
26/* Optional simulator name */
27char simname[MAXBUF] = "";
28
29#ifdef UCLID
30int annotate = 0;
31/* Keep list of argument names encountered in node definition */
32char *arg_names[SYM_LIM];
33int arg_cnt = 0;
34#endif
35
36
37extern FILE *outfile;
38
39/*
40 * usage - print helpful diagnostic information
41 */
42static void usage(char *name)
43{
44#ifdef VLOG
45 fprintf(stderr, "Usage: %s [-h] < HCL_file > verilog_file\n", name);
46#else
47#ifdef UCLID
48 fprintf(stderr, "Usage: %s [-ah] < HCL_file > uclid_file\n", name);
49 fprintf(stderr, " -a Add define/use annotations\n");
50#else /* !UCLID */
51 fprintf(stderr, "Usage: %s [-h][-n NAM] < HCL_file > C_file\n", name);
52#endif /* UCLID */
53#endif /* VLOG */
54 fprintf(stderr, " -h Print this message\n");
55 fprintf(stderr, " -n NAM Specify processor name\n");
56 exit(0);
57}
58
59
60/* Initialization */
61void init_node(int argc, char **argv)
62{
63 int c;
64 int max_column = 75;
65 int first_indent = 4;
66 int other_indents = 2;
67
68 /* Parse the command line arguments */
69 while ((c = getopt(argc, argv, "hna")) != -1) {
70 switch(c) {
71 case 'h':
72 usage(argv[0]);
73 break;
74 case 'n': /* Optional simulator name */
75 strcpy(simname, argv[optind]);
76 break;
77#ifdef UCLID
78 case 'a':
79 annotate = 1;
80 break;
81#endif
82 default:
83 printf("Invalid option '%c'\n", c);
84 usage(argv[0]);
85 break;
86 }
87 }
88
89#if !defined(VLOG) && !defined(UCLID)
90 /* Define and initialize the simulator name */
91 if (!strcmp(simname, ""))
92 printf("char simname[] = \"Y86-64 Processor\";\n");
93 else
94 printf("char simname[] = \"Y86-64 Processor: %s\";\n", simname);
95#endif
96 outgen_init(outfile, max_column, first_indent, other_indents);
97}
98
99static void add_symbol(node_ptr name, node_ptr val)
100{
101 if (sym_count >= SYM_LIM) {
102 yyerror("Symbol table limit exceeded");
103 return;
104 }
105 sym_tab[0][sym_count] = name;
106 sym_tab[1][sym_count] = val;
107 sym_count++;
108}
109
110
111static char *node_names[] =
112 {"quote", "var", "num", "and", "or", "not", "comp", "ele", "case"};
113
114static void show_node(node_ptr node)
115{
116 printf("Node type: %s, Boolean ? %c, String value: %s\n",
117 node_names[node->type], node->isbool ? 'Y':'N', node->sval);
118}
119
120
121void finish_node(int check_ref)
122{
123 if (check_ref) {
124 int i;
125 for (i = 0; i < sym_count; i++)
126 if (!sym_tab[0][i]->ref) {
127 fprintf(stderr, "Warning, argument '%s' not referenced\n",
128 sym_tab[0][i]->sval);
129 }
130 }
131}
132
133static node_ptr find_symbol(char *name)
134{
135 int i;
136 for (i = 0; i < sym_count; i++) {
137 if (strcmp(name, sym_tab[0][i]->sval) == 0) {
138 node_ptr result = sym_tab[1][i];
139 sym_tab[0][i]->ref++;
140 return result;
141 }
142 }
143 yyserror("Symbol %s not found", name);
144 return NULL;
145}
146
147#ifdef UCLID
148/* See if string should be considered argument.
149 Currently, omit strings that are all upper case */
150static int is_arg(char *name)
151{
152 int upper = 1;
153 int c;
154 while ((c=*name++) != '\0')
155 upper = upper && isupper(c);
156 return !upper;
157}
158
159/* See if string is part of current argument list */
160static void check_for_arg(char *name)
161{
162 int i;
163 if (!is_arg(name))
164 return;
165 for (i = 0; i < arg_cnt; i++)
166 if (strcmp(arg_names[i], name) == 0)
167 return;
168 arg_names[arg_cnt++] = name;
169}
170#endif
171
172static node_ptr new_node(node_type_t t, int isbool,
173 char *s, node_ptr a1, node_ptr a2)
174{
175 node_ptr result = malloc(sizeof(node_rec));
176 result->type = t;
177 result->isbool = isbool;
178 result->sval = s;
179 result->arg1 = a1;
180 result->arg2 = a2;
181 result->ref = 0;
182 result->next = NULL;
183 return result;
184}
185
186/* Concatenate two lists */
187node_ptr concat(node_ptr n1, node_ptr n2)
188{
189 node_ptr tail = n1;
190 if (!n1)
191 return n2;
192 while (tail->next)
193 tail = tail->next;
194 tail->next = n2;
195 return n1;
196}
197
198static void free_node(node_ptr n)
199{
200 free(n->sval);
201 free(n);
202}
203
204node_ptr make_quote(char *qstring)
205{
206
207 /* Quoted string still has quotes around it */
208 int len = strlen(qstring)-2;
209 char *sname = malloc(len+1);
210 strncpy(sname, qstring+1, len);
211 sname[len] = '\0';
212 return new_node(N_QUOTE, 0, sname, NULL, NULL);
213}
214
215node_ptr make_var(char *name)
216{
217 char *sname = malloc(strlen(name)+1);
218 strcpy(sname, name);
219 /* Initially assume var is not Boolean */
220 return new_node(N_VAR, 0, sname, NULL, NULL);
221}
222
223node_ptr make_num(char *name)
224{
225 char *sname = malloc(strlen(name)+1);
226 strcpy(sname, name);
227 return new_node(N_NUM, 0, sname, NULL, NULL);
228}
229
230void set_bool(node_ptr varnode)
231{
232 if (!varnode)
233 yyerror("Null node encountered");
234 varnode->isbool = 1;
235}
236
237/* Make sure argument is OK */
238static int check_arg(node_ptr arg, int wantbool)
239{
240 if (!arg) {
241 yyerror("Null node encountered");
242 return 0;
243 }
244 if (arg->type == N_VAR) {
245 node_ptr qval = find_symbol(arg->sval);
246 if (!qval) {
247 yyserror("Variable '%s' not found", arg->sval);
248 return 0;
249 }
250 if (wantbool != qval->isbool) {
251 if (wantbool)
252 yyserror("Variable '%s' not Boolean", arg->sval);
253 else
254 yyserror("Variable '%s' not integer", arg->sval);
255 return 0;
256 }
257 return 1;
258 }
259 if (arg->type == N_NUM) {
260 if (wantbool && strcmp(arg->sval,"0") != 0 &&
261 strcmp(arg->sval,"1") != 0) {
262 yyserror("Value '%s' not Boolean", arg->sval);
263 return 0;
264 }
265 return 1;
266 }
267 if (wantbool && !arg->isbool)
268 yyserror("Non Boolean argument '%s'", show_expr(arg));
269 if (!wantbool && arg->isbool)
270 yyserror("Non integer argument '%s'", show_expr(arg));
271 return (wantbool == arg->isbool);
272}
273
274node_ptr make_not(node_ptr arg)
275{
276 check_arg(arg, 1);
277 return new_node(N_NOT, 1, "!", arg, NULL);
278}
279
280node_ptr make_and(node_ptr arg1, node_ptr arg2)
281{
282 check_arg(arg1, 1);
283 check_arg(arg2, 1);
284 return new_node(N_AND, 1, "&", arg1, arg2);
285}
286
287node_ptr make_or(node_ptr arg1, node_ptr arg2)
288{
289 check_arg(arg1, 1);
290 check_arg(arg2, 1);
291 return new_node(N_OR, 1, "|", arg1, arg2);
292}
293
294node_ptr make_comp(node_ptr op, node_ptr arg1, node_ptr arg2)
295{
296 check_arg(arg1, 0);
297 check_arg(arg2, 0);
298 return new_node(N_COMP, 1, op->sval, arg1, arg2);
299}
300
301node_ptr make_ele(node_ptr arg1, node_ptr arg2)
302{
303 node_ptr ele;
304 check_arg(arg1, 0);
305 for (ele = arg1; ele; ele = ele->next)
306 check_arg(ele, 0);
307 return new_node(N_ELE, 1, "in", arg1, arg2);
308}
309
310node_ptr make_case(node_ptr arg1, node_ptr arg2)
311{
312 check_arg(arg1, 1);
313 check_arg(arg2, 0);
314 return new_node(N_CASE, 0, ":", arg1, arg2);
315}
316
317void insert_code(node_ptr qstring)
318{
319 if (!qstring)
320 yyerror("Null node");
321 else {
322#if !defined(VLOG) && !defined(UCLID)
323 fputs(qstring->sval, outfile);
324 fputs("\n", outfile);
325#endif
326 }
327}
328
329void add_arg(node_ptr var, node_ptr qstring, int isbool)
330{
331 if (!var || !qstring) {
332 yyerror("Null node");
333 return;
334 }
335 add_symbol(var, qstring);
336 if (isbool) {
337 set_bool(var);
338 set_bool(qstring);
339 }
340}
341
342static char expr_buf[1024];
343static int errlen = 0;
344#define MAXERRLEN 80
345
346/* Recursively display expression for error reporting */
347static void show_expr_helper(node_ptr expr)
348{
349 switch(expr->type) {
350 int len;
351 node_ptr ele;
352 case N_QUOTE:
353 len = strlen(expr->sval) + 2;
354 if (len + errlen < MAXERRLEN) {
355 sprintf(expr_buf+errlen, "'%s'", expr->sval);
356 errlen += len;
357 }
358 break;
359 case N_VAR:
360 len = strlen(expr->sval);
361 if (len + errlen < MAXERRLEN) {
362 sprintf(expr_buf+errlen, "%s", expr->sval);
363 errlen += len;
364 }
365 break;
366 case N_NUM:
367 len = strlen(expr->sval);
368 if (len + errlen < MAXERRLEN) {
369 sprintf(expr_buf+errlen, "%s", expr->sval);
370 errlen += len;
371 }
372 break;
373 case N_AND:
374 if (errlen < MAXERRLEN) {
375 sprintf(expr_buf+errlen, "(");
376 errlen+=1;
377 show_expr_helper(expr->arg1);
378 sprintf(expr_buf+errlen, " & ");
379 errlen+=3;
380 }
381 if (errlen < MAXERRLEN) {
382 show_expr_helper(expr->arg2);
383 sprintf(expr_buf+errlen, ")");
384 errlen+=1;
385 }
386 break;
387 case N_OR:
388 if (errlen < MAXERRLEN) {
389 sprintf(expr_buf+errlen, "(");
390 errlen+=1;
391 show_expr_helper(expr->arg1);
392 sprintf(expr_buf+errlen, " | ");
393 errlen+=3;
394 }
395 if (errlen < MAXERRLEN) {
396 show_expr_helper(expr->arg2);
397 sprintf(expr_buf+errlen, ")");
398 errlen+=1;
399 }
400 break;
401 case N_NOT:
402 if (errlen < MAXERRLEN) {
403 sprintf(expr_buf+errlen, "!");
404 errlen+=1;
405 show_expr_helper(expr->arg1);
406 }
407 break;
408 case N_COMP:
409 if (errlen < MAXERRLEN) {
410 sprintf(expr_buf+errlen, "(");
411 errlen+=1;
412 show_expr_helper(expr->arg1);
413 sprintf(expr_buf+errlen, " %s ", expr->sval);
414 errlen+=4;
415 }
416 if (errlen < MAXERRLEN) {
417 show_expr_helper(expr->arg2);
418 sprintf(expr_buf+errlen, ")");
419 errlen+=1;
420 }
421 break;
422 case N_ELE:
423 if (errlen < MAXERRLEN) {
424 sprintf(expr_buf+errlen, "(");
425 errlen+=1;
426 show_expr_helper(expr->arg1);
427 sprintf(expr_buf+errlen, " in {");
428 errlen+=5;
429 }
430 for (ele = expr->arg2; ele; ele=ele->next) {
431 if (errlen < MAXERRLEN) {
432 show_expr_helper(ele);
433 if (ele->next) {
434 sprintf(expr_buf+errlen, ", ");
435 errlen+=2;
436 }
437 }
438 }
439 if (errlen < MAXERRLEN) {
440 sprintf(expr_buf+errlen, "})");
441 errlen+=2;
442 }
443 break;
444 case N_CASE:
445 if (errlen < MAXERRLEN) {
446 sprintf(expr_buf+errlen, "[ ");
447 errlen+=2;
448 }
449 for (ele = expr; errlen < MAXERRLEN && ele; ele=ele->next) {
450 show_expr_helper(ele->arg1);
451 sprintf(expr_buf+errlen, " : ");
452 errlen += 3;
453 show_expr_helper(ele->arg2);
454 }
455 if (errlen < MAXERRLEN) {
456 sprintf(expr_buf+errlen, " ]");
457 errlen+=2;
458 }
459 break;
460 default:
461 if (errlen < MAXERRLEN) {
462 sprintf(expr_buf+errlen, "??");
463 errlen+=2;
464 }
465 break;
466 }
467}
468
469static char *show_expr(node_ptr expr)
470{
471 errlen = 0;
472 show_expr_helper(expr);
473 if (errlen >= MAXERRLEN)
474 sprintf(expr_buf+errlen, "...");
475 return expr_buf;
476}
477
478/* Recursively generate code for function */
479static void gen_expr(node_ptr expr)
480{
481 node_ptr ele;
482 switch(expr->type) {
483 case N_QUOTE:
484 yyserror("Unexpected quoted string", expr->sval);
485 break;
486 case N_VAR:
487 {
488 node_ptr qstring = find_symbol(expr->sval);
489 if (qstring)
490#if defined(VLOG) || defined(UCLID)
491 outgen_print("%s", expr->sval);
492#else
493 outgen_print("(%s)", qstring->sval);
494#endif
495 else
496 yyserror("Invalid variable '%s'", expr->sval);
497#ifdef UCLID
498 check_for_arg(expr->sval);
499#endif
500
501 }
502 break;
503 case N_NUM:
504#ifdef UCLID
505 {
506 long long int val = atoll(expr->sval);
507 if (val < -1)
508 outgen_print("pred^%d(CZERO)", -val);
509 else if (val == -1)
510 outgen_print("pred(CZERO)");
511 else if (val == 0)
512 outgen_print("CZERO");
513 else if (val == 1)
514 outgen_print("succ(CZERO)");
515 else
516 outgen_print("succ^%d(CZERO)", val);
517 }
518#else /* !UCLID */
519 fputs(expr->sval, outfile);
520#endif /* UCLID */
521 break;
522 case N_AND:
523 outgen_print("(");
524 outgen_upindent();
525 gen_expr(expr->arg1);
526 outgen_print(" & ");
527 gen_expr(expr->arg2);
528 outgen_print(")");
529 outgen_downindent();
530 break;
531 case N_OR:
532 outgen_print("(");
533 outgen_upindent();
534 gen_expr(expr->arg1);
535 outgen_print(" | ");
536 gen_expr(expr->arg2);
537 outgen_print(")");
538 outgen_downindent();
539 break;
540 case N_NOT:
541#if defined(VLOG) || defined(UCLID)
542 outgen_print("~");
543#else
544 outgen_print("!");
545#endif
546 gen_expr(expr->arg1);
547 break;
548 case N_COMP:
549 outgen_print("(");
550 outgen_upindent();
551 gen_expr(expr->arg1);
552#ifdef UCLID
553 {
554 char *cval = expr->sval;
555 if (strcmp(cval, "==") == 0)
556 cval = "=";
557 outgen_print(" %s ", cval);
558 }
559#else /* !UCLID */
560 outgen_print(" %s ", expr->sval);
561#endif /* UCLID */
562 gen_expr(expr->arg2);
563 outgen_print(")");
564 outgen_downindent();
565 break;
566 case N_ELE:
567 outgen_print("(");
568 outgen_upindent();
569 for (ele = expr->arg2; ele; ele=ele->next) {
570 gen_expr(expr->arg1);
571#ifdef UCLID
572 outgen_print(" = ");
573#else
574 outgen_print(" == ");
575#endif
576 gen_expr(ele);
577 if (ele->next)
578#if defined(VLOG) || defined(UCLID)
579 outgen_print(" | ");
580#else
581 outgen_print(" || ");
582#endif
583 }
584 outgen_print(")");
585 outgen_downindent();
586 break;
587 case N_CASE:
588#ifdef UCLID
589 outgen_print("case");
590 outgen_terminate();
591 {
592 /* Use this to keep track of last case when no default is given */
593 node_ptr last_arg2 = NULL;
594 for (ele = expr; ele; ele=ele->next) {
595 outgen_print(" ");
596 if (ele->arg1->type == N_NUM && atoll(ele->arg1->sval) == 1) {
597 outgen_print("default");
598 last_arg2 = NULL;
599 }
600 else {
601 gen_expr(ele->arg1);
602 last_arg2 = ele->arg2;
603 }
604 outgen_print(" : ");
605 gen_expr(ele->arg2);
606 outgen_print(";");
607 outgen_terminate();
608 }
609 if (last_arg2) {
610 /* Use final case as default */
611 outgen_print(" default : ");
612 gen_expr(last_arg2);
613 outgen_print(";");
614 outgen_terminate();
615 }
616 }
617 outgen_print(" esac");
618#else /* !UCLID */
619 outgen_print("(");
620 outgen_upindent();
621 int done = 0;
622 for (ele = expr; ele && !done; ele=ele->next) {
623 if (ele->arg1->type == N_NUM && atoll(ele->arg1->sval) == 1) {
624 gen_expr(ele->arg2);
625 done = 1;
626 } else {
627 gen_expr(ele->arg1);
628 outgen_print(" ? ");
629 gen_expr(ele->arg2);
630 outgen_print(" : ");
631 }
632 }
633 if (!done)
634 outgen_print("0");
635 outgen_print(")");
636 outgen_downindent();
637#endif
638 break;
639 default:
640 yyerror("Unknown node type");
641 break;
642 }
643}
644
645
646/* Generate code defining function for var */
647void gen_funct(node_ptr var, node_ptr expr, int isbool)
648{
649 if (!var || !expr) {
650 yyerror("Null node");
651 return;
652 }
653 check_arg(expr, isbool);
654#ifdef VLOG
655 outgen_print("assign %s = ", var->sval);
656 outgen_terminate();
657 outgen_print(" ");
658 gen_expr(expr);
659 outgen_print(";");
660 outgen_terminate();
661 outgen_terminate();
662#else /* !VLOG */
663#ifdef UCLID
664 if (annotate) {
665 /* Print annotation information*/
666 outgen_print("(* $define %s *)", var->sval);
667 outgen_terminate();
668 }
669 outgen_print("%s := ", var->sval);
670 outgen_terminate();
671 outgen_print(" ");
672 if (isbool && expr->type == N_NUM) {
673 outgen_print("%d", atoll(var->sval));
674 } else
675 gen_expr(expr);
676 outgen_print(";");
677 outgen_terminate();
678 if (annotate) {
679 int i;
680 outgen_print("(* $args");
681 for (i = 0; i < arg_cnt; i++)
682 outgen_print("%c%s", i == 0 ? ' ' : ':', arg_names[i]);
683 outgen_print(" *)");
684 outgen_terminate();
685 arg_cnt = 0;
686 }
687 outgen_terminate();
688#else /* !UCLID */
689 /* Print function header */
690 outgen_print("long long gen_%s()", var->sval);
691 outgen_terminate();
692 outgen_print("{");
693 outgen_terminate();
694 outgen_print(" return ");
695 gen_expr(expr);
696 outgen_print(";");
697 outgen_terminate();
698 outgen_print("}");
699 outgen_terminate();
700 outgen_terminate();
701#endif /* UCLID */
702#endif /* VLOG */
703}