1 /*
2  * Copyright (c) 2007-2013 Stephen Williams (steve@icarus.com)
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 # include "config.h"
21 # include "priv.h"
22 # include <stdlib.h>
23 # include <inttypes.h>
24 # include <assert.h>
25 
vt_type_string(ivl_expr_t net)26 static const char*vt_type_string(ivl_expr_t net)
27 {
28       return data_type_string(ivl_expr_value(net));
29 }
30 
show_array_expression(ivl_expr_t net,unsigned ind)31 static void show_array_expression(ivl_expr_t net, unsigned ind)
32 {
33       ivl_signal_t sig = ivl_expr_signal(net);
34       const char*name = ivl_signal_basename(sig);
35       unsigned width = ivl_signal_width(sig);
36       const char*vt   = vt_type_string(net);
37 
38       fprintf(out, "%*sArray: %s, word_count=%u (%u dimensions), width=%u, type=%s\n",
39 	      ind, "", name, ivl_signal_array_count(sig),
40 	      ivl_signal_dimensions(sig), width, vt);
41 }
42 
show_array_pattern_expression(ivl_expr_t net,unsigned ind)43 static void show_array_pattern_expression(ivl_expr_t net, unsigned ind)
44 {
45       size_t idx;
46       fprintf(out, "%*sArrayPattern (%s): %u expressions\n",
47 	      ind, "", vt_type_string(net), ivl_expr_parms(net));
48       for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) {
49 	    show_expression(ivl_expr_parm(net,idx), ind+4);
50       }
51 }
52 
show_branch_access_expression(ivl_expr_t net,unsigned ind)53 static void show_branch_access_expression(ivl_expr_t net, unsigned ind)
54 {
55       ivl_branch_t bra = ivl_expr_branch(net);
56       ivl_nature_t nature = ivl_expr_nature(net);
57       fprintf(out, "%*s<Access branch %p with nature %s>\n",
58 	      ind, "", bra, ivl_nature_name(nature));
59 
60       if (ivl_expr_value(net) != IVL_VT_REAL) {
61 	    fprintf(out, "%*sERROR: Expecting type IVL_VT_REAL, got %s\n",
62 		    ind, "", vt_type_string(net));
63 	    stub_errors += 1;
64       }
65 
66       ivl_nexus_t ta = ivl_branch_terminal(bra, 0);
67       ivl_nexus_t tb = ivl_branch_terminal(bra, 1);
68 
69       ivl_discipline_t ta_disc = discipline_of_nexus(ta);
70       if (ta_disc == 0) {
71 	    fprintf(out, "%*sERROR: Source terminal of branch has no discipline\n",
72 		    ind, "");
73 	    stub_errors += 1;
74 	    return;
75       }
76 
77       ivl_discipline_t tb_disc = discipline_of_nexus(tb);
78       if (ta_disc == 0) {
79 	    fprintf(out, "%*sERROR: Reference terminal of branch has no discipline\n",
80 		    ind, "");
81 	    stub_errors += 1;
82 	    return;
83       }
84 
85       if (ta_disc != tb_disc) {
86 	    fprintf(out, "%*sERROR: Branch terminal disciplines mismatch: %s != %s\n",
87 		    ind, "", ivl_discipline_name(ta_disc),
88 		    ivl_discipline_name(tb_disc));
89 	    stub_errors += 1;
90       }
91 }
92 
show_binary_expression(ivl_expr_t net,unsigned ind)93 static void show_binary_expression(ivl_expr_t net, unsigned ind)
94 {
95       unsigned width = ivl_expr_width(net);
96       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
97       const char*vt   = vt_type_string(net);
98 
99       ivl_expr_t oper1 = ivl_expr_oper1(net);
100       ivl_expr_t oper2 = ivl_expr_oper2(net);
101 
102       fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "",
103 	      ivl_expr_opcode(net), width, sign, vt);
104       if (oper1) {
105 	    show_expression(oper1, ind+3);
106       } else {
107 	    fprintf(out, "%*sERROR: Missing operand 1\n", ind+3, "");
108 	    stub_errors += 1;
109       }
110       if (oper2) {
111 	    show_expression(oper2, ind+3);
112       } else {
113 	    fprintf(out, "%*sERROR: Missing operand 2\n", ind+3, "");
114 	    stub_errors += 1;
115       }
116 
117       switch (ivl_expr_opcode(net)) {
118 
119 	  case '*':
120 	    if (ivl_expr_value(net) == IVL_VT_REAL) {
121 		  if (ivl_expr_width(net) != 1) {
122 			fprintf(out, "%*sERROR: Result width incorrect. Expecting 1, got %u\n",
123 				ind+3, "", ivl_expr_width(net));
124 			stub_errors += 1;
125 		  }
126 	    } else {
127 		    /* The width of a multiply may be any width. The
128 		       implicit assumption is that the multiply
129 		       returns a width that is the sum of the widths
130 		       of the arguments, that is then truncated to the
131 		       desired width, never padded. The compiler will
132 		       automatically take care of sign extensions of
133 		       arguments, so that the code generator need only
134 		       generate an UNSIGNED multiply, and the result
135 		       will come out right. */
136 		  unsigned max_width = ivl_expr_width(oper1) + ivl_expr_width(oper2);
137 		  if (ivl_expr_width(net) > max_width) {
138 			fprintf(out, "%*sERROR: Result width to width. Expecting <= %u, got %u\n",
139 				ind+3, "", max_width, ivl_expr_width(net));
140 			stub_errors += 1;
141 		  }
142 	    }
143 	    break;
144 
145 	  default:
146 	    break;
147       }
148 }
149 
show_enumtype_expression(ivl_expr_t net,unsigned ind)150 static void show_enumtype_expression(ivl_expr_t net, unsigned ind)
151 {
152       fprintf(out, "%*s<enumtype=%p>\n", ind, "", ivl_expr_enumtype(net));
153 }
154 
show_function_call(ivl_expr_t net,unsigned ind)155 static void show_function_call(ivl_expr_t net, unsigned ind)
156 {
157       ivl_scope_t def = ivl_expr_def(net);
158       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
159       const char*vt = vt_type_string(net);
160       unsigned idx;
161 
162       fprintf(out, "%*s<%s %s function %s with %u arguments (width=%u)>\n",
163 	      ind, "", vt, sign, ivl_scope_name(def), ivl_expr_parms(net),
164 	      ivl_expr_width(net));
165 
166       for (idx = 0 ;  idx < ivl_expr_parms(net) ;  idx += 1)
167 	    show_expression(ivl_expr_parm(net,idx), ind+4);
168 }
169 
show_memory_expression(ivl_expr_t net,unsigned ind)170 static void show_memory_expression(ivl_expr_t net, unsigned ind)
171 {
172       unsigned width = ivl_expr_width(net);
173 
174       fprintf(out, "%*s<memory width=%u>\n", ind, "",
175 	      width);
176 }
177 
show_new_expression(ivl_expr_t net,unsigned ind)178 static void show_new_expression(ivl_expr_t net, unsigned ind)
179 {
180       switch (ivl_expr_value(net)) {
181 	  case IVL_VT_CLASS:
182 	    fprintf(out, "%*snew <class_type>\n", ind, "");
183 	    if (ivl_expr_oper1(net)) {
184 		  fprintf(out, "%*sERROR: class_new expression has a size!\n",
185 			  ind+3, "");
186 		  show_expression(ivl_expr_oper1(net), ind+3);
187 		  stub_errors += 1;
188 	    }
189 	    if (ivl_expr_oper2(net)){
190 		  fprintf(out, "%*sERROR: class_new with array element initializer!\n",
191 			  ind+3, "");
192 		  show_expression(ivl_expr_oper2(net), ind+3);
193 		  stub_errors += 1;
194 	    }
195 	    break;
196 	  case IVL_VT_DARRAY:
197 	    fprintf(out, "%*snew [] <type>\n", ind, "");
198 	    if (ivl_expr_oper1(net)) {
199 		  show_expression(ivl_expr_oper1(net), ind+3);
200 	    } else {
201 		  fprintf(out, "%*sERROR: darray_new missing size expression\n",
202 			  ind+3, "");
203 		  stub_errors += 1;
204 	    }
205 	      /* The IVL_EX_NEW expression may include an element
206 		 initializer. This may be an array pattern or simple
207 		 expression. */
208 	    if (ivl_expr_oper2(net)) {
209 		  show_expression(ivl_expr_oper2(net), ind+3);
210 	    }
211 	    break;
212 	  default:
213 	    fprintf(out, "%*snew ERROR: expression type: %s\n",
214 		    ind+3, "", vt_type_string(net));
215 	    stub_errors += 1;
216 	    break;
217       }
218 }
219 
show_null_expression(ivl_expr_t net,unsigned ind)220 static void show_null_expression(ivl_expr_t net, unsigned ind)
221 {
222       fprintf(out, "%*s<null>\n", ind, "");
223       if (ivl_expr_value(net) != IVL_VT_CLASS) {
224 	    fprintf(out, "%*sERROR: null expression must be IVL_VT_CLASS, got %s.\n",
225 		    ind+3, "", vt_type_string(net));
226 	    stub_errors += 1;
227       }
228 }
229 
show_property_expression(ivl_expr_t net,unsigned ind)230 static void show_property_expression(ivl_expr_t net, unsigned ind)
231 {
232       ivl_signal_t sig = ivl_expr_signal(net);
233       const char* pnam = ivl_expr_name(net);
234       const char*signed_flag = ivl_expr_signed(net)? "signed" : "unsigned";
235       ivl_expr_t index;
236 
237       if (ivl_expr_value(net) == IVL_VT_REAL) {
238 	    fprintf(out, "%*s<property base=%s, prop=%s, real>\n", ind, "",
239 		    ivl_signal_basename(sig), pnam);
240       } else if (ivl_expr_value(net) == IVL_VT_STRING) {
241 	    fprintf(out, "%*s<property base=%s, prop=%s, string>\n", ind, "",
242 		    ivl_signal_basename(sig), pnam);
243       } else {
244 	    fprintf(out, "%*s<property base=%s, prop=%s, width=%u, %s>\n", ind, "",
245 		    ivl_signal_basename(sig), pnam, ivl_expr_width(net), signed_flag);
246       }
247       if ( (index=ivl_expr_oper1(net)) ) {
248 	    show_expression(index, ind+3);
249       }
250       if (ivl_signal_data_type(sig) != IVL_VT_CLASS) {
251 	    fprintf(out, "%*sERROR: Property signal must be IVL_VT_CLASS, got %s.\n",
252 		    ind+3, "", data_type_string(ivl_signal_data_type(sig)));
253       }
254 }
255 
show_select_expression(ivl_expr_t net,unsigned ind)256 static void show_select_expression(ivl_expr_t net, unsigned ind)
257 {
258       unsigned width = ivl_expr_width(net);
259       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
260       const char*vt = vt_type_string(net);
261       ivl_expr_t oper1 = ivl_expr_oper1(net);
262       ivl_expr_t oper2 = ivl_expr_oper2(net);
263 
264       if (ivl_expr_value(oper1) == IVL_VT_STRING) {
265 	      /* If the sub-expression is a STRING, then this is a
266 		 substring and the code generator will handle it
267 		 differently. */
268 	    fprintf(out, "%*s<substring: width=%u bits, %u bytes>\n", ind, "", width, width/8);
269 	    if (width%8 != 0) {
270 		  fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, "");
271 		  stub_errors += 1;
272 	    }
273 	    assert(oper1);
274 	    show_expression(oper1, ind+3);
275 
276 	    if (oper2) {
277 		  show_expression(oper2, ind+3);
278 	    } else {
279 		  fprintf(out, "%*sERROR: oper2 missing! Pad makes no sense for IVL_VT_STRING expressions.\n", ind+3, "");
280 		  stub_errors += 1;
281 	    }
282 
283       } else if (oper2) {
284 	      /* If oper2 is present, then it is the base of a part
285 		 select. The width of the expression defines the range
286 		 of the part select. */
287 	    fprintf(out, "%*s<select: width=%u, %s, type=%s>\n", ind, "",
288 		    width, sign, vt);
289 	    show_expression(oper1, ind+3);
290 	    show_expression(oper2, ind+3);
291 
292       } else {
293 	      /* There is no base expression so this is a pad
294 		 operation. The sub-expression is padded (signed or
295 		 unsigned as appropriate) to the expression width. */
296 	    fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
297 		    width, sign);
298 	    show_expression(oper1, ind+3);
299       }
300 }
301 
show_shallowcopy(ivl_expr_t net,unsigned ind)302 static void show_shallowcopy(ivl_expr_t net, unsigned ind)
303 {
304       ivl_expr_t oper1 = ivl_expr_oper1(net);
305       ivl_expr_t oper2 = ivl_expr_oper2(net);
306       fprintf(out, "%*s<shallow_copy>\n", ind, "");
307       show_expression(oper1, ind+3);
308       show_expression(oper2, ind+3);
309 
310       if (ivl_expr_value(oper1) != ivl_expr_value(oper2)) {
311 	    fprintf(out, "%*sERROR: Shallow copy operand types must match.\n", ind+3,"");
312 	    stub_errors += 1;
313       }
314 
315       if (ivl_expr_value(oper1)!=IVL_VT_CLASS && ivl_expr_value(oper1)!=IVL_VT_DARRAY) {
316 	    fprintf(out, "%*sERROR: Operand 1 type is %s\n", ind+3, "", vt_type_string(oper1));
317 	    stub_errors += 1;
318       }
319 }
320 
show_signal_expression(ivl_expr_t net,unsigned ind)321 static void show_signal_expression(ivl_expr_t net, unsigned ind)
322 {
323       unsigned width = ivl_expr_width(net);
324       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
325       const char*vt = vt_type_string(net);
326       ivl_expr_t word = ivl_expr_oper1(net);
327 
328       ivl_signal_t sig = ivl_expr_signal(net);
329       const char*vt_sig = data_type_string(ivl_signal_data_type(sig));
330       unsigned dimensions = ivl_signal_dimensions(sig);
331       unsigned word_count = ivl_signal_array_count(sig);
332 
333       if (dimensions == 0 && word_count != 1) {
334 	    fprintf(out, "%*sERROR: Word count = %u for non-array object\n",
335 		    ind, "", word_count);
336 	    stub_errors += 1;
337       }
338 
339       fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s (%s)>\n", ind, "",
340 	      ivl_expr_name(net), word_count, width, sign, vt, vt_sig);
341 
342       /* If the expression refers to a signal array, then there must
343          also be a word select expression, and if the signal is not an
344          array, there must NOT be a word expression. */
345       if (dimensions == 0 && word != 0) {
346 	    fprintf(out, "%*sERROR: Unexpected word expression\n", ind+2, "");
347 	    stub_errors += 1;
348       }
349       if (dimensions >= 1 && word == 0) {
350 	    fprintf(out, "%*sERROR: Missing word expression\n", ind+2, "");
351 	    stub_errors += 1;
352       }
353 	/* If this is not an array, then the expression with must
354 	   match the signal width. We have IVL_EX_SELECT expressions
355 	   for casting signal widths. */
356       if (dimensions == 0 && ivl_signal_width(sig) != width) {
357 	    fprintf(out, "%*sERROR: Expression width (%u) doesn't match ivl_signal_width(sig)=%u\n",
358 		    ind+2, "", width, ivl_signal_width(sig));
359 	    stub_errors += 1;
360       }
361 
362       if (word != 0) {
363 	    fprintf(out, "%*sAddress-0 word address:\n", ind+2, "");
364 	    show_expression(word, ind+2);
365       }
366 }
367 
show_ternary_expression(ivl_expr_t net,unsigned ind)368 static void show_ternary_expression(ivl_expr_t net, unsigned ind)
369 {
370       unsigned width = ivl_expr_width(net);
371       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
372       const char*vt = vt_type_string(net);
373 
374       fprintf(out, "%*s<ternary  width=%u, %s type=%s>\n", ind, "",
375 	      width, sign, vt);
376       show_expression(ivl_expr_oper1(net), ind+4);
377       show_expression(ivl_expr_oper2(net), ind+4);
378       show_expression(ivl_expr_oper3(net), ind+4);
379 
380       if (ivl_expr_width(ivl_expr_oper2(net)) != width) {
381 	    fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n",
382 		    ivl_expr_width(ivl_expr_oper2(net)), width);
383 	    stub_errors += 1;
384       }
385 
386       if (ivl_expr_width(ivl_expr_oper3(net)) != width) {
387 	    fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n",
388 		    ivl_expr_width(ivl_expr_oper3(net)), width);
389 	    stub_errors += 1;
390       }
391 }
392 
show_unary_expression(ivl_expr_t net,unsigned ind)393 static void show_unary_expression(ivl_expr_t net, unsigned ind)
394 {
395       unsigned width = ivl_expr_width(net);
396       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
397       const char*vt = vt_type_string(net);
398 
399       char name[8];
400       switch (ivl_expr_opcode(net)) {
401 	  default:
402 	    snprintf(name, sizeof name, "%c", ivl_expr_opcode(net));
403 	    break;
404 
405 	  case 'm':
406 	    snprintf(name, sizeof name, "abs()");
407 	    break;
408       }
409 
410       if (ivl_expr_opcode(net) == '!' && ivl_expr_value(net) == IVL_VT_REAL) {
411 	    fprintf(out, "%*sERROR: Real argument to unary ! !?\n", ind,"");
412 	    stub_errors += 1;
413       }
414 
415       fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
416 	      name, width, sign, vt);
417       show_expression(ivl_expr_oper1(net), ind+4);
418 }
419 
show_expression(ivl_expr_t net,unsigned ind)420 void show_expression(ivl_expr_t net, unsigned ind)
421 {
422       assert(net);
423       unsigned idx;
424       ivl_parameter_t par = ivl_expr_parameter(net);
425       const ivl_expr_type_t code = ivl_expr_type(net);
426       unsigned width = ivl_expr_width(net);
427       const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
428       const char*sized = ivl_expr_sized(net)? "sized" : "unsized";
429       const char*vt = vt_type_string(net);
430 
431       switch (code) {
432 
433 	  case IVL_EX_ARRAY:
434 	    show_array_expression(net, ind);
435 	    break;
436 
437 	  case IVL_EX_ARRAY_PATTERN:
438 	    show_array_pattern_expression(net, ind);
439 	    break;
440 
441 	  case IVL_EX_BACCESS:
442 	    show_branch_access_expression(net, ind);
443 	    break;
444 
445 	  case IVL_EX_BINARY:
446 	    show_binary_expression(net, ind);
447 	    break;
448 
449 	  case IVL_EX_CONCAT:
450 	    fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n",
451 		    ind, "", ivl_expr_repeat(net), width, sign, vt);
452 	    for (idx = 0 ;  idx < ivl_expr_parms(net) ;  idx += 1)
453 		  show_expression(ivl_expr_parm(net, idx), ind+3);
454 
455 	    break;
456 
457 	  case IVL_EX_ENUMTYPE:
458 	    show_enumtype_expression(net, ind);
459 	    break;
460 
461 	  case IVL_EX_MEMORY:
462 	    show_memory_expression(net, ind);
463 	    break;
464 
465 	  case IVL_EX_NEW:
466 	    show_new_expression(net, ind);
467 	    break;
468 
469 	  case IVL_EX_NULL:
470 	    show_null_expression(net, ind);
471 	    break;
472 
473 	  case IVL_EX_PROPERTY:
474 	    show_property_expression(net, ind);
475 	    break;
476 
477 	  case IVL_EX_NUMBER: {
478 		const char*bits = ivl_expr_bits(net);
479 
480 		fprintf(out, "%*s<number=%u'b", ind, "", width);
481 		for (idx = width ;  idx > 0 ;  idx -= 1)
482 		      fprintf(out, "%c", bits[idx-1]);
483 
484 		fprintf(out, ", %s %s %s", sign, sized, vt);
485 		if (par != 0)
486 		      fprintf(out, ", parameter=%s",
487 			      ivl_parameter_basename(par));
488 
489 		fprintf(out, ">\n");
490 		break;
491 	  }
492 
493 	  case IVL_EX_SELECT:
494 	    show_select_expression(net, ind);
495 	    break;
496 
497 	  case IVL_EX_STRING:
498 	    fprintf(out, "%*s<string=\"%s\", width=%u", ind, "",
499 		    ivl_expr_string(net), ivl_expr_width(net));
500 	    if (par != 0)
501 		      fprintf(out, ", parameter=%s",
502 			      ivl_parameter_basename(par));
503 
504 	    fprintf(out, ", type=%s>\n", vt);
505 	    break;
506 
507 	  case IVL_EX_SFUNC:
508 	    fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s file=%s:%u>\n",
509 		    ind, "", ivl_expr_name(net), width, sign, vt,
510 		    ivl_expr_file(net), ivl_expr_lineno(net));
511 	    { unsigned cnt = ivl_expr_parms(net);
512 	      unsigned jdx;
513 	      for (jdx = 0 ;  jdx < cnt ;  jdx += 1)
514 		    show_expression(ivl_expr_parm(net, jdx), ind+3);
515 	    }
516 	    break;
517 
518 	  case IVL_EX_SIGNAL:
519 	    show_signal_expression(net, ind);
520 	    break;
521 
522 	  case IVL_EX_TERNARY:
523 	    show_ternary_expression(net, ind);
524 	    break;
525 
526 	  case IVL_EX_UNARY:
527 	    show_unary_expression(net, ind);
528 	    break;
529 
530 	  case IVL_EX_UFUNC:
531 	    show_function_call(net, ind);
532 	    break;
533 
534 	  case IVL_EX_REALNUM:
535 	      {
536 		    int jdx;
537 		    union foo {
538 			  double rv;
539 			  unsigned char bv[sizeof(double)];
540 		    } tmp;
541 		    tmp.rv = ivl_expr_dvalue(net);
542 		    fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv);
543 		    for (jdx = sizeof(double) ;  jdx > 0 ;  jdx -= 1)
544 			  fprintf(out, "%02x", tmp.bv[jdx-1]);
545 		    fprintf(out, ")");
546 		    if (par != 0)
547 			  fprintf(out, ", parameter=%s",
548 				  ivl_parameter_basename(par));
549 
550 		    fprintf(out, ">\n");
551 	      }
552 	      break;
553 
554 	  case IVL_EX_SHALLOWCOPY:
555 	    show_shallowcopy(net, ind);
556 	    break;
557 
558 	  default:
559 	    fprintf(out, "%*s<expr_type=%d>\n", ind, "", code);
560 	    break;
561       }
562 }
563 
564