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