Compile time warnings
[iverilog.git] / tgt-vvp / vvp_scope.c
blob8b9e1521da8a67805e35956b5244fb9f9cf36bd5
1 /*
2 * Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com)
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: vvp_scope.c,v 1.160 2007/04/12 04:40:37 steve Exp $"
21 #endif
23 # include "vvp_priv.h"
24 #ifdef HAVE_MALLOC_H
25 # include <malloc.h>
26 #endif
27 # include <stdlib.h>
28 # include <string.h>
29 # include <inttypes.h>
30 # include <assert.h>
32 struct vvp_nexus_data {
33 /* draw_net_input uses this */
34 const char*net_input;
35 unsigned drivers_count;
36 int flags;
37 /* draw_net_in_scope uses these to identify the controlling word. */
38 ivl_signal_t net;
39 unsigned net_word;
41 #define VVP_NEXUS_DATA_STR 0x0001
44 static struct vvp_nexus_data*new_nexus_data()
46 struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
47 return data;
51 * Escape non-symbol characters in ids, and quotes in strings.
54 inline static char hex_digit(unsigned i)
56 i &= 0xf;
57 return i>=10 ? i-10+'A' : i+'0';
60 const char *vvp_mangle_id(const char *id)
62 static char *out = 0x0;
63 static size_t out_len;
65 int nesc = 0;
66 int iout = 0;
67 const char *inp = id;
69 const char nosym[] = "!\"#%&'()*+,-/:;<=>?@[\\]^`{|}~";
71 char *se = strpbrk(inp, nosym);
72 if (!se)
73 return id;
75 do {
76 int n = se - inp;
77 unsigned int nlen = strlen(id) + 4*(++nesc) + 1;
78 if (out_len < nlen) {
79 out = realloc(out, nlen);
80 assert(out);
81 out_len = nlen;
83 if (n) {
84 strncpy(out+iout, inp, n);
85 iout += n;
87 inp += n+1;
88 out[iout++] = '\\';
89 switch (*se) {
90 case '\\':
91 case '/':
92 case '<':
93 case '>':
94 out[iout++] = *se;
95 break;
96 default:
97 out[iout++] = 'x';
98 out[iout++] = hex_digit(*se >> 4);
99 out[iout++] = hex_digit(*se);
100 break;
103 se = strpbrk(inp, nosym);
104 } while (se);
106 strcpy(out+iout, inp);
107 return out;
110 const char *vvp_mangle_name(const char *id)
112 static char *out = 0x0;
113 static size_t out_len;
115 int nesc = 0;
116 int iout = 0;
117 const char *inp = id;
119 const char nosym[] = "\"\\";
121 char *se = strpbrk(inp, nosym);
122 if (!se)
123 return id;
125 do {
126 int n = se - inp;
127 unsigned int nlen = strlen(id) + 2*(++nesc) + 1;
128 if (out_len < nlen) {
129 out = realloc(out, nlen);
130 assert(out);
131 out_len = nlen;
133 if (n) {
134 strncpy(out+iout, inp, n);
135 iout += n;
137 inp += n+1;
138 out[iout++] = '\\';
139 out[iout++] = *se;
141 se = strpbrk(inp, nosym);
142 } while (se);
144 strcpy(out+iout, inp);
145 return out;
148 static void draw_C4_repeated_constant(char bit_char, unsigned width)
150 unsigned idx;
152 fprintf(vvp_out, "C4<");
153 for (idx = 0 ; idx < width ; idx += 1)
154 fprintf(vvp_out, "%c", bit_char);
156 fprintf(vvp_out, ">");
159 static void str_repeat(char*buf, const char*str, unsigned rpt)
161 unsigned idx;
162 size_t len = strlen(str);
163 for (idx = 0 ; idx < rpt ; idx += 1) {
164 strcpy(buf, str);
165 buf += len;
169 /* REMOVE ME: vvp_signal_label should not be used. DEAD CODE
170 * Given a signal, generate a string name that is suitable for use as
171 * a label. The only rule is that the same signal will always have the
172 * same label. The result is stored in static memory, so remember to
173 * copy it out.
175 const char* vvp_signal_label(ivl_signal_t sig)
177 static char buf[32];
178 sprintf(buf, "%p", sig);
179 return buf;
182 ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
184 unsigned idx;
185 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
186 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
187 ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
188 if (sig == 0)
189 continue;
190 if (ivl_signal_local(sig))
191 continue;
192 *word = ivl_nexus_ptr_pin(ptr);
193 return sig;
196 return 0;
199 ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
201 unsigned idx;
202 ivl_signal_type_t out = IVL_SIT_TRI;
204 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
205 ivl_signal_type_t stype;
206 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
207 ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
208 if (sig == 0)
209 continue;
211 stype = ivl_signal_type(sig);
212 if (stype == IVL_SIT_REG)
213 continue;
214 if (stype == IVL_SIT_TRI)
215 continue;
216 if (stype == IVL_SIT_NONE)
217 continue;
218 out = stype;
221 return out;
224 unsigned width_of_nexus(ivl_nexus_t nex)
226 unsigned idx;
228 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
229 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
230 ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
231 if (sig != 0)
232 return ivl_signal_width(sig);
235 return 0;
238 ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex)
240 unsigned idx;
241 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
242 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
243 ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
244 if (sig != 0)
245 return ivl_signal_data_type(sig);
248 /* shouldn't happen! */
249 return IVL_VT_NO_TYPE;
253 ivl_nexus_ptr_t ivl_logic_pin_ptr(ivl_net_logic_t net, unsigned pin)
255 ivl_nexus_t nex = ivl_logic_pin(net, pin);
256 unsigned idx;
258 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
259 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
260 ivl_net_logic_t tmp = ivl_nexus_ptr_log(ptr);
261 if (tmp == 0)
262 continue;
263 if (tmp != net)
264 continue;
265 if (ivl_nexus_ptr_pin(ptr) != pin)
266 continue;
268 return ptr;
270 assert(0);
271 return 0;
274 const char*drive_string(ivl_drive_t drive)
276 switch (drive) {
277 case IVL_DR_HiZ:
278 return "";
279 case IVL_DR_SMALL:
280 return "sm";
281 case IVL_DR_MEDIUM:
282 return "me";
283 case IVL_DR_WEAK:
284 return "we";
285 case IVL_DR_LARGE:
286 return "la";
287 case IVL_DR_PULL:
288 return "pu";
289 case IVL_DR_STRONG:
290 return "";
291 case IVL_DR_SUPPLY:
292 return "su";
295 return "";
300 * The draw_scope function draws the major functional items within a
301 * scope. This includes the scopes themselves, of course. All the
302 * other functions in this file are in support of that task.
307 * NEXUS
308 * ivl builds up the netlist into objects connected together by
309 * ivl_nexus_t objects. The nexus receives all the drivers of the
310 * point in the net and resolves the value. The result is then sent to
311 * all the nets that are connected to the nexus. The nets, then, are
312 * read to get the value of the nexus.
314 * NETS
315 * Nets are interesting and special, because a nexus may be connected
316 * to several of them at once. This can happen, for example, as an
317 * artifact of module port connects, where the inside and the outside
318 * of the module are connected through an in-out port. (In fact, ivl
319 * will simply connect signals that are bound through a port, because
320 * the input/output/inout properties are enforced as compile time.)
322 * This case is handled by choosing one to receive the value of the
323 * nexus. This one then feeds to another net at the nexus, and so
324 * on. The last net is selected as the output of the nexus.
328 * This tests a bufz device against an output receiver, and determines
329 * if the device can be skipped. If this function returns true, then a
330 * gate will be generated for this node. Otherwise, the code generator
331 * will connect its input to its output and skip the gate.
333 static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
335 ivl_nexus_t in_n;
336 unsigned idx;
338 /* These are the drives we expect. */
339 ivl_drive_t dr0 = ivl_nexus_ptr_drive0(nptr);
340 ivl_drive_t dr1 = ivl_nexus_ptr_drive1(nptr);
341 int drive_count = 0;
343 /* If the gate carries a delay, it must remain. */
344 if (ivl_logic_delay(net, 0) != 0)
345 return 0;
347 /* If the input is connected to the output, then do not elide
348 the gate. This is some sort of cycle. */
349 if (ivl_logic_pin(net, 0) == ivl_logic_pin(net, 1))
350 return 0;
352 in_n = ivl_logic_pin(net, 1);
353 for (idx = 0 ; idx < ivl_nexus_ptrs(in_n) ; idx += 1) {
354 ivl_nexus_ptr_t in_np = ivl_nexus_ptr(in_n, idx);
355 if (ivl_nexus_ptr_log(in_np) == net)
356 continue;
358 /* If the driver for the source does not match the
359 expected drive, then we need to keep the bufz. This
360 test also catches the case that the input device is
361 really also an input, as that device will have a
362 drive of HiZ. We need to keep BUFZ devices in that
363 case in order to prevent back-flow of data. */
364 if (ivl_nexus_ptr_drive0(in_np) != dr0)
365 return 0;
366 if (ivl_nexus_ptr_drive1(in_np) != dr1)
367 return 0;
369 drive_count += 1;
372 /* If the BUFZ input has multiple drivers on its input, then
373 we need to keep this device in order to hide the
374 resolution. */
375 if (drive_count != 1)
376 return 0;
378 return 1;
382 * Given a nexus, look for a signal that has module delay
383 * paths. Return that signal. (There should be no more than 1.) If we
384 * don't find any, then return nil.
386 static ivl_signal_t find_modpath(ivl_nexus_t nex)
388 unsigned idx;
389 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
390 ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
391 ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
392 if (sig == 0)
393 continue;
394 if (ivl_signal_npath(sig) == 0)
395 continue;
397 return sig;
400 return 0;
403 static char* draw_C4_to_string(ivl_net_const_t cptr)
405 const char*bits = ivl_const_bits(cptr);
406 unsigned idx;
408 size_t result_len = 5 + ivl_const_width(cptr);
409 char*result = malloc(result_len);
410 char*dp = result;
411 strcpy(dp, "C4<");
412 dp += strlen(dp);
414 for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
415 switch (bits[ivl_const_width(cptr)-idx-1]) {
416 case '0':
417 *dp++ = '0';
418 break;
419 case '1':
420 *dp++ = '1';
421 break;
422 default:
423 *dp++ = bits[idx];
424 break;
426 assert((dp - result) < result_len);
429 strcpy(dp, ">");
430 return result;
433 static char* draw_C8_to_string(ivl_net_const_t cptr,
434 ivl_drive_t dr0, ivl_drive_t dr1)
436 size_t nresult = 5 + 3*ivl_const_width(cptr);
437 char*result = malloc(nresult);
438 const char*bits = ivl_const_bits(cptr);
439 unsigned idx;
441 char dr0c = "01234567"[dr0];
442 char dr1c = "01234567"[dr1];
443 char*dp = result;
445 strcpy(dp, "C8<");
446 dp += strlen(dp);
448 for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
449 switch (bits[ivl_const_width(cptr)-idx-1]) {
450 case '0':
451 *dp++ = dr0c;
452 *dp++ = dr0c;
453 *dp++ = '0';
454 break;
455 case '1':
456 *dp++ = dr1c;
457 *dp++ = dr1c;
458 *dp++ = '1';
459 break;
460 case 'x':
461 case 'X':
462 *dp++ = dr0c;
463 *dp++ = dr1c;
464 *dp++ = 'x';
465 break;
466 case 'z':
467 case 'Z':
468 *dp++ = '0';
469 *dp++ = '0';
470 *dp++ = 'z';
471 break;
472 default:
473 assert(0);
474 break;
476 assert(dp - result < nresult);
479 strcpy(dp, ">");
480 return result;
484 * This function takes a nexus and looks for an input functor. It then
485 * draws to the output a string that represents that functor. What we
486 * are trying to do here is find the input to the net that is attached
487 * to this nexus.
490 static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
492 unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
493 ivl_net_const_t cptr;
494 ivl_net_logic_t lptr;
495 ivl_signal_t sptr;
496 ivl_lpm_t lpm;
498 lptr = ivl_nexus_ptr_log(nptr);
499 if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
500 do {
501 if (! can_elide_bufz(lptr, nptr))
502 break;
504 return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
505 } while(0);
507 /* If this is a pulldown device, then there is a single pin
508 that drives a constant value to the entire width of the
509 vector. The driver normally drives a pull0 value, so a C8<>
510 constant is appropriate, but if the drive is really strong,
511 then we can draw a C4<> constant instead. */
512 if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
513 if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
514 size_t result_len = ivl_logic_width(lptr) + 5;
515 char*result = malloc(result_len);
516 char*dp = result;
517 strcpy(dp, "C4<");
518 dp += strlen(dp);
519 str_repeat(dp, "0", ivl_logic_width(lptr));
520 dp += ivl_logic_width(lptr);
521 *dp++ = '>';
522 *dp = 0;
523 assert((dp-result) <= result_len);
524 return result;
525 } else {
526 char val[4];
527 size_t result_len = 3*ivl_logic_width(lptr) + 5;
528 char*result = malloc(result_len);
529 char*dp = result;
531 val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
532 val[1] = val[0];
533 val[2] = '0';
534 val[3] = 0;
536 strcpy(dp, "C8<");
537 dp += strlen(dp);
538 str_repeat(dp, val, ivl_logic_width(lptr));
539 dp += 3*ivl_logic_width(lptr);
540 *dp++ = '>';
541 *dp = 0;
542 assert((dp-result) <= result_len);
543 return result;
547 if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
548 if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
549 size_t result_len = 5 + ivl_logic_width(lptr);
550 char*result = malloc(result_len);
551 char*dp = result;
552 strcpy(dp, "C4<");
553 dp += strlen(dp);
554 str_repeat(dp, "1", ivl_logic_width(lptr));
555 dp += ivl_logic_width(lptr);
556 *dp++ = '>';
557 *dp = 0;
558 assert((dp-result) <= result_len);
559 return result;
560 } else {
561 char val[4];
562 size_t result_len = 5 + 3*ivl_logic_width(lptr);
563 char*result = malloc(result_len);
564 char*dp = result;
566 val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
567 val[1] = val[0];
568 val[2] = '1';
569 val[3] = 0;
571 strcpy(dp, "C8<");
572 dp += strlen(dp);
573 str_repeat(dp, val, ivl_logic_width(lptr));
574 dp += 3*ivl_logic_width(lptr);
575 *dp++ = '>';
576 *dp = 0;
577 assert((dp-result) <= result_len);
578 return result;
582 if (lptr && (nptr_pin == 0)) {
583 char tmp[128];
584 snprintf(tmp, sizeof tmp, "L_%p", lptr);
585 return strdup(tmp);
588 sptr = ivl_nexus_ptr_sig(nptr);
589 if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
590 char tmp[128];
591 /* Input is a .var. This device may be a non-zero pin
592 because it may be an array of reg vectors. */
593 snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
594 return strdup(tmp);
597 cptr = ivl_nexus_ptr_con(nptr);
598 if (cptr) {
599 /* Constants should have exactly 1 pin, with a literal value. */
600 assert(nptr_pin == 0);
601 char *result = 0;
603 switch (ivl_const_type(cptr)) {
604 case IVL_VT_LOGIC:
605 case IVL_VT_BOOL:
606 if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
607 && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
609 result = draw_C4_to_string(cptr);
611 } else {
612 result = draw_C8_to_string(cptr,
613 ivl_nexus_ptr_drive0(nptr),
614 ivl_nexus_ptr_drive1(nptr));
616 break;
618 case IVL_VT_REAL:
619 { char tmp[256];
620 snprintf(tmp, sizeof(tmp),
621 "Cr<%lg>", ivl_const_real(cptr));
622 result = strdup(tmp);
624 break;
626 default:
627 assert(0);
628 break;
631 return result;
634 lpm = ivl_nexus_ptr_lpm(nptr);
635 if (lpm) switch (ivl_lpm_type(lpm)) {
637 case IVL_LPM_FF:
638 case IVL_LPM_ADD:
639 case IVL_LPM_ARRAY:
640 case IVL_LPM_CONCAT:
641 case IVL_LPM_CMP_EEQ:
642 case IVL_LPM_CMP_EQ:
643 case IVL_LPM_CMP_GE:
644 case IVL_LPM_CMP_GT:
645 case IVL_LPM_CMP_NE:
646 case IVL_LPM_CMP_NEE:
647 case IVL_LPM_RE_AND:
648 case IVL_LPM_RE_OR:
649 case IVL_LPM_RE_XOR:
650 case IVL_LPM_RE_NAND:
651 case IVL_LPM_RE_NOR:
652 case IVL_LPM_RE_XNOR:
653 case IVL_LPM_SFUNC:
654 case IVL_LPM_SHIFTL:
655 case IVL_LPM_SHIFTR:
656 case IVL_LPM_SIGN_EXT:
657 case IVL_LPM_SUB:
658 case IVL_LPM_MULT:
659 case IVL_LPM_MUX:
660 case IVL_LPM_DIVIDE:
661 case IVL_LPM_MOD:
662 case IVL_LPM_UFUNC:
663 case IVL_LPM_PART_VP:
664 case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
665 case IVL_LPM_REPEAT:
666 if (ivl_lpm_q(lpm, 0) == nex) {
667 char tmp[128];
668 snprintf(tmp, sizeof tmp, "L_%p", lpm);
669 return strdup(tmp);
671 break;
673 case IVL_LPM_PART_BI:
674 if (ivl_lpm_q(lpm, 0) == nex) {
675 char tmp[128];
676 snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
677 return strdup(tmp);
678 } else if (ivl_lpm_data(lpm,0) == nex) {
679 char tmp[128];
680 snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
681 return strdup(tmp);
683 break;
686 fprintf(stderr, "internal error: no input to nexus %s\n",
687 ivl_nexus_name(nex));
688 assert(0);
689 return strdup("C<z>");
692 static void draw_modpath(const char*label, const char*driver,
693 ivl_signal_t path_sig)
695 unsigned idx;
696 typedef const char*ccharp;
697 ccharp*src_drivers;
698 ccharp*con_drivers;
700 src_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
701 con_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
702 for (idx = 0 ; idx < ivl_signal_npath(path_sig) ; idx += 1) {
703 ivl_delaypath_t path = ivl_signal_path(path_sig, idx);
704 ivl_nexus_t src = ivl_path_source(path);
705 ivl_nexus_t con = ivl_path_condit(path);
707 src_drivers[idx] = draw_net_input(src);
709 if (con) con_drivers[idx] = draw_net_input(con);
710 else con_drivers[idx] = 0;
713 fprintf(vvp_out, "%s .modpath %s", label, driver);
715 for (idx = 0 ; idx < ivl_signal_npath(path_sig); idx += 1) {
716 ivl_delaypath_t path = ivl_signal_path(path_sig, idx);
717 int ppos = ivl_path_source_posedge(path);
718 int pneg = ivl_path_source_negedge(path);
719 const char*edge = ppos? " +" : pneg ? " -" : "";
720 fprintf(vvp_out, ",\n %s%s", src_drivers[idx], edge);
721 fprintf(vvp_out,
722 " (%"PRIu64",%"PRIu64",%"PRIu64
723 ", %"PRIu64",%"PRIu64",%"PRIu64
724 ", %"PRIu64",%"PRIu64",%"PRIu64
725 ", %"PRIu64",%"PRIu64",%"PRIu64,
726 ivl_path_delay(path, IVL_PE_01),
727 ivl_path_delay(path, IVL_PE_10),
728 ivl_path_delay(path, IVL_PE_0z),
729 ivl_path_delay(path, IVL_PE_z1),
730 ivl_path_delay(path, IVL_PE_1z),
731 ivl_path_delay(path, IVL_PE_z0),
732 ivl_path_delay(path, IVL_PE_0x),
733 ivl_path_delay(path, IVL_PE_x1),
734 ivl_path_delay(path, IVL_PE_1x),
735 ivl_path_delay(path, IVL_PE_x0),
736 ivl_path_delay(path, IVL_PE_xz),
737 ivl_path_delay(path, IVL_PE_zx));
739 if (con_drivers[idx]) {
740 fprintf(vvp_out, " ? %s", con_drivers[idx]);
743 fprintf(vvp_out, ")");
746 fprintf(vvp_out, ";\n");
748 free(src_drivers);
749 free(con_drivers);
753 * This function draws the input to a net into a string. What that
754 * means is that it returns a static string that can be used to
755 * represent a resolved driver to a nexus. If there are multiple
756 * drivers to the nexus, then it writes out the resolver declarations
757 * needed to perform strength resolution.
759 * The string that this returns is malloced, and that means that the
760 * caller must free the string or store it permanently. This function
761 * does *not* check for a previously calculated string. Use the
762 * draw_net_input for the general case.
764 /* Omit LPMPART_BI device pin-data(0) drivers. */
765 # define OMIT_PART_BI_DATA 0x0001
767 static char* draw_net_input_x(ivl_nexus_t nex,
768 ivl_nexus_ptr_t omit_ptr, int omit_flags,
769 struct vvp_nexus_data*nex_data)
771 ivl_signal_type_t res;
772 char result[512];
773 unsigned idx;
774 int level;
775 unsigned ndrivers = 0;
776 static ivl_nexus_ptr_t *drivers = 0x0;
777 static unsigned adrivers = 0;
779 const char*resolv_type;
781 char*nex_private = 0;
783 /* Accumulate nex_data flags. */
784 int nex_flags = 0;
786 res = signal_type_of_nexus(nex);
787 switch (res) {
788 case IVL_SIT_TRI:
789 resolv_type = "tri";
790 break;
791 case IVL_SIT_TRI0:
792 resolv_type = "tri0";
793 nex_flags |= VVP_NEXUS_DATA_STR;
794 break;
795 case IVL_SIT_TRI1:
796 resolv_type = "tri1";
797 nex_flags |= VVP_NEXUS_DATA_STR;
798 break;
799 case IVL_SIT_TRIAND:
800 resolv_type = "triand";
801 break;
802 case IVL_SIT_TRIOR:
803 resolv_type = "trior";
804 break;
805 default:
806 fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
807 assert(0);
808 resolv_type = "tri";
809 break;
813 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
814 ivl_lpm_t lpm_tmp;
815 ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
817 /* If we are supposed to skip LPM_PART_BI data pins,
818 check that this driver is that. */
819 if ((omit_flags&OMIT_PART_BI_DATA)
820 && (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
821 && (nex == ivl_lpm_data(lpm_tmp,0)))
822 continue;
824 if (nptr == omit_ptr)
825 continue;
827 /* Skip input only pins. */
828 if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
829 && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
830 continue;
832 /* Mark the strength-aware flag if the driver can
833 generate values other than the standard "6"
834 strength. */
835 if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
836 nex_flags |= VVP_NEXUS_DATA_STR;
837 if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
838 nex_flags |= VVP_NEXUS_DATA_STR;
840 /* Save this driver. */
841 if (ndrivers >= adrivers) {
842 adrivers += 4;
843 drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
844 assert(drivers);
846 drivers[ndrivers] = nptr;
847 ndrivers += 1;
850 /* If the caller is collecting nexus information, then save
851 the nexus driver count in the nex_data. */
852 if (nex_data) {
853 nex_data->drivers_count = ndrivers;
854 nex_data->flags |= nex_flags;
857 /* If the nexus has no drivers, then send a constant HiZ into
858 the net. */
859 if (ndrivers == 0) {
860 unsigned idx, wid = width_of_nexus(nex);
861 char*tmp = malloc(wid + 5);
862 nex_private = tmp;
863 strcpy(tmp, "C4<");
864 tmp += strlen(tmp);
865 switch (res) {
866 case IVL_SIT_TRI:
867 for (idx = 0 ; idx < wid ; idx += 1)
868 *tmp++ = 'z';
869 break;
870 case IVL_SIT_TRI0:
871 for (idx = 0 ; idx < wid ; idx += 1)
872 *tmp++ = '0';
873 break;
874 case IVL_SIT_TRI1:
875 for (idx = 0 ; idx < wid ; idx += 1)
876 *tmp++ = '1';
877 break;
878 default:
879 assert(0);
881 *tmp++ = '>';
882 *tmp = 0;
883 return nex_private;
887 /* If the nexus has exactly one driver, then simply draw
888 it. Note that this will *not* work if the nexus is not a
889 TRI type nexus. */
890 if (ndrivers == 1 && res == IVL_SIT_TRI) {
891 ivl_signal_t path_sig = find_modpath(nex);
892 if (path_sig) {
893 char*nex_str = draw_net_input_drive(nex, drivers[0]);
894 char modpath_label[64];
895 snprintf(modpath_label, sizeof modpath_label,
896 "V_%p/m", path_sig);
897 draw_modpath(modpath_label, nex_str, path_sig);
898 nex_private = strdup(modpath_label);
899 free(nex_str);
900 } else {
901 nex_private = draw_net_input_drive(nex, drivers[0]);
903 return nex_private;
906 level = 0;
907 while (ndrivers) {
908 unsigned int inst;
909 for (inst = 0; inst < ndrivers; inst += 4) {
910 if (ndrivers > 4)
911 fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
912 nex, level, inst);
913 else
914 fprintf(vvp_out, "RS_%p .resolv %s",
915 nex, resolv_type);
917 for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
918 if (level) {
919 fprintf(vvp_out, ", RS_%p/%d/%d",
920 nex, level - 1, idx*4);
921 } else {
922 char*drive = draw_net_input_drive(nex, drivers[idx]);
923 fprintf(vvp_out, ", %s", drive);
924 free(drive);
927 for ( ; idx < inst+4 ; idx += 1) {
928 fprintf(vvp_out, ", ");
929 draw_C4_repeated_constant('z',width_of_nexus(nex));
932 fprintf(vvp_out, ";\n");
934 if (ndrivers > 4)
935 ndrivers = (ndrivers+3) / 4;
936 else
937 ndrivers = 0;
938 level += 1;
941 sprintf(result, "RS_%p", nex);
942 nex_private = strdup(result);
943 return nex_private;
947 * Get a cached description of the nexus input, or create one if this
948 * nexus has not been cached yet. This is a wrapper for the common
949 * case call to draw_net_input_x.
951 const char*draw_net_input(ivl_nexus_t nex)
953 struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
954 ivl_nexus_get_private(nex);
956 /* If this nexus already has a label, then its input is
957 already figured out. Just return the existing label. */
958 if (nex_data && nex_data->net_input)
959 return nex_data->net_input;
961 if (nex_data == 0) {
962 nex_data = new_nexus_data();
963 ivl_nexus_set_private(nex, nex_data);
966 assert(nex_data->net_input == 0);
967 nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
969 return nex_data->net_input;
972 const char*draw_input_from_net(ivl_nexus_t nex)
974 static char result[32];
975 unsigned word;
977 ivl_signal_t sig = signal_of_nexus(nex, &word);
978 if (sig == 0)
979 return draw_net_input(nex);
981 snprintf(result, sizeof result, "v%p_%u", sig, word);
982 return result;
987 * This function draws a reg/int/variable in the scope. This is a very
988 * simple device to draw as there are no inputs to connect so no need
989 * to scan the nexus. We do have to account for the possibility that
990 * the device is arrayed, though, by making a node for each array element.
992 static void draw_reg_in_scope(ivl_signal_t sig)
994 int msb = ivl_signal_msb(sig);
995 int lsb = ivl_signal_lsb(sig);
997 const char*datatype_flag = ivl_signal_integer(sig) ? "/i" :
998 ivl_signal_signed(sig)? "/s" : "";
1000 switch (ivl_signal_data_type(sig)) {
1001 case IVL_VT_REAL:
1002 datatype_flag = "/real";
1003 break;
1004 default:
1005 break;
1008 /* If the reg objects are collected into an array, then first
1009 write out the .array record to declare the array indices. */
1010 if (ivl_signal_dimensions(sig) > 0) {
1011 unsigned word_count = ivl_signal_array_count(sig);
1012 int last = ivl_signal_array_base(sig)+word_count-1;
1013 int first = ivl_signal_array_base(sig);
1014 fprintf(vvp_out, "v%p .array%s \"%s\", %d %d, %d %d;\n",
1015 sig, datatype_flag,
1016 vvp_mangle_name(ivl_signal_basename(sig)),
1017 last, first, msb, lsb);
1019 } else {
1021 fprintf(vvp_out, "v%p_0 .var%s \"%s\", %d %d;\n",
1022 sig, datatype_flag,
1023 vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb);
1029 * This function draws a net. This is a bit more complicated as we
1030 * have to find an appropriate functor to connect to the input.
1032 static void draw_net_in_scope(ivl_signal_t sig)
1034 int msb = ivl_signal_msb(sig);
1035 int lsb = ivl_signal_lsb(sig);
1037 const char*datatype_flag = ivl_signal_signed(sig)? "/s" : "";
1038 unsigned iword;
1040 /* Skip the local signal. */
1041 if (ivl_signal_local(sig))
1042 return;
1044 switch (ivl_signal_data_type(sig)) {
1045 case IVL_VT_REAL:
1046 datatype_flag = "/real";
1047 break;
1048 default:
1049 break;
1052 for (iword = 0 ; iword < ivl_signal_array_count(sig); iword += 1) {
1054 unsigned word_count = ivl_signal_array_count(sig);
1055 unsigned dimensions = ivl_signal_dimensions(sig);
1056 struct vvp_nexus_data*nex_data;
1058 /* Connect the pin of the signal to something. */
1059 ivl_nexus_t nex = ivl_signal_nex(sig, iword);
1060 const char*driver = draw_net_input(nex);
1062 nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex);
1063 assert(nex_data);
1065 if (nex_data->net == 0) {
1066 int strength_aware_flag = 0;
1067 const char*vec8 = "";
1068 if (nex_data->flags&VVP_NEXUS_DATA_STR)
1069 strength_aware_flag = 1;
1070 if (nex_data->drivers_count > 1)
1071 vec8 = "8";
1072 if (strength_aware_flag)
1073 vec8 = "8";
1075 if (iword == 0 && dimensions > 0) {
1076 int last = ivl_signal_array_base(sig) + word_count-1;
1077 int first = ivl_signal_array_base(sig);
1078 fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
1079 sig, vvp_mangle_name(ivl_signal_basename(sig)),
1080 last, first);
1082 if (dimensions > 0) {
1083 /* If this is a word of an array, then use an
1084 array reference in place of the net name. */
1085 fprintf(vvp_out, "v%p_%u .net%s%s v%p %u, %d %d, %s;"
1086 " %u drivers%s\n",
1087 sig, iword, vec8, datatype_flag, sig,
1088 iword, msb, lsb, driver,
1089 nex_data->drivers_count,
1090 strength_aware_flag?", strength-aware":"");
1091 } else {
1092 /* If this is an isolated word, it uses its
1093 own name. */
1094 assert(word_count == 1);
1095 fprintf(vvp_out, "v%p_%u .net%s%s \"%s\", %d %d, %s;"
1096 " %u drivers%s\n",
1097 sig, iword, vec8, datatype_flag,
1098 vvp_mangle_name(ivl_signal_basename(sig)),
1099 msb, lsb, driver,
1100 nex_data->drivers_count,
1101 strength_aware_flag?", strength-aware":"");
1103 nex_data->net = sig;
1104 nex_data->net_word = iword;
1106 } else if (dimensions > 0) {
1108 /* In this case, we have an alias to an existing
1109 signal array. this typically is an instance of
1110 port collapsing that the elaborator combined to
1111 discover that the entire array can be collapsed,
1112 so the word count for the signal and the alias
1113 *must* match. */
1114 assert(word_count == ivl_signal_array_count(nex_data->net));
1116 if (iword == 0) {
1117 fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
1118 sig, vvp_mangle_name(ivl_signal_basename(sig)),
1119 nex_data->net, ivl_signal_basename(nex_data->net));
1121 /* An alias for the individual words? */
1122 #if 0
1123 fprintf(vvp_out, "v%p_%u .alias%s v%p, %d %d, v%p_%u;\n",
1124 sig, iword, datatype_flag, sig,
1125 msb, lsb, nex_data->net, nex_data->net_word);
1126 #endif
1127 } else {
1128 /* Finally, we may have an alias that is a word
1129 connected to another word. Again, this is a
1130 case of port collapsing. */
1132 /* For the alias, create a different kind of node
1133 that refers to the alias source data instead of
1134 holding our own data. */
1135 fprintf(vvp_out, "v%p_%u .alias%s \"%s\", %d %d, v%p_%u;\n",
1136 sig, iword, datatype_flag,
1137 vvp_mangle_name(ivl_signal_basename(sig)),
1138 msb, lsb, nex_data->net, nex_data->net_word);
1143 static void draw_delay(ivl_net_logic_t lptr)
1145 ivl_expr_t d0 = ivl_logic_delay(lptr, 0);
1146 ivl_expr_t d1 = ivl_logic_delay(lptr, 1);
1147 ivl_expr_t d2 = ivl_logic_delay(lptr, 2);
1149 if (d0 == 0 && d1 == 0 && d2 == 0)
1150 return;
1152 /* FIXME: Assume that the expression is a constant */
1153 assert(number_is_immediate(d0, 64));
1154 assert(number_is_immediate(d1, 64));
1155 assert(number_is_immediate(d2, 64));
1157 if (d0 == d1 && d1 == d2)
1158 fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
1159 else
1160 fprintf(vvp_out, " (%lu,%lu,%lu)",
1161 get_number_immediate(d0),
1162 get_number_immediate(d1),
1163 get_number_immediate(d2));
1166 static void draw_udp_def(ivl_udp_t udp)
1168 unsigned init;
1169 unsigned i;
1171 switch (ivl_udp_init(udp))
1173 case '0':
1174 init = 0;
1175 break;
1176 case '1':
1177 init = 1;
1178 break;
1179 default:
1180 init = 2;
1181 break;
1184 if (ivl_udp_sequ(udp))
1185 fprintf(vvp_out,
1186 "UDP_%s .udp/sequ \"%s\", %d, %d",
1187 vvp_mangle_id(ivl_udp_name(udp)),
1188 vvp_mangle_name(ivl_udp_name(udp)),
1189 ivl_udp_nin(udp),
1190 init );
1191 else
1192 fprintf(vvp_out,
1193 "UDP_%s .udp/comb \"%s\", %d",
1194 vvp_mangle_id(ivl_udp_name(udp)),
1195 vvp_mangle_name(ivl_udp_name(udp)),
1196 ivl_udp_nin(udp));
1198 for (i=0; i<ivl_udp_rows(udp); i++)
1199 fprintf(vvp_out, "\n ,\"%s\"", ivl_udp_row(udp, i) );
1201 fprintf(vvp_out, ";\n");
1204 static void draw_udp_in_scope(ivl_net_logic_t lptr)
1206 unsigned pdx;
1208 ivl_udp_t udp = ivl_logic_udp(lptr);
1210 static ivl_udp_t *udps = 0x0;
1211 static int nudps = 0;
1212 int i;
1214 for (i=0; i<nudps; i++)
1215 if (udps[i] == udp)
1216 break;
1218 if (i >= nudps)
1220 udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
1221 assert(udps);
1222 udps[nudps++] = udp;
1223 draw_udp_def(udp);
1226 fprintf(vvp_out, "L_%p .udp", lptr);
1227 fprintf(vvp_out, " UDP_%s",
1228 vvp_mangle_id(ivl_udp_name(udp)));
1229 draw_delay(lptr);
1231 for (pdx = 1 ; pdx < ivl_logic_pins(lptr) ; pdx += 1) {
1232 ivl_nexus_t nex = ivl_logic_pin(lptr, pdx);
1234 /* Unlike other logic gates, primitives may have unconnected
1235 inputs. The proper behavior is to attach a HiZ to the
1236 port. */
1237 if (nex == 0) {
1238 assert(ivl_logic_width(lptr) == 1);
1239 fprintf(vvp_out, ", C4<z>");
1241 } else {
1242 fprintf(vvp_out, ", %s", draw_net_input(nex));
1246 fprintf(vvp_out, ";\n");
1249 static void draw_logic_in_scope(ivl_net_logic_t lptr)
1251 unsigned pdx;
1252 const char*ltype = "?";
1253 const char*lcasc = 0;
1254 char identity_val = '0';
1256 int need_delay_flag = ivl_logic_delay(lptr,0)? 1 : 0;
1258 unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0));
1260 ivl_drive_t str0, str1;
1262 int level;
1263 int ninp = ivl_logic_pins(lptr) - 1;
1264 typedef const char*const_charp;
1265 const_charp*input_strings = calloc(ninp, sizeof(const_charp));
1267 for (pdx = 0 ; pdx < ninp ; pdx += 1) {
1268 ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
1269 if (nex == 0) {
1270 /* Only UDPs can have unconnected inputs. */
1271 assert(ivl_logic_type(lptr) == IVL_LO_UDP);
1272 input_strings[pdx] = 0;
1273 } else {
1274 input_strings[pdx] = draw_net_input(nex);
1278 switch (ivl_logic_type(lptr)) {
1280 case IVL_LO_UDP:
1281 free(input_strings);
1282 draw_udp_in_scope(lptr);
1283 return;
1285 case IVL_LO_BUFZ: {
1286 /* Draw bufz objects, but only if the gate cannot
1287 be elided. If I can elide it, then the
1288 draw_nex_input will take care of it for me. */
1289 ivl_nexus_ptr_t nptr = ivl_logic_pin_ptr(lptr,0);
1291 ltype = "BUFZ";
1293 if (can_elide_bufz(lptr, nptr))
1294 return;
1296 break;
1299 case IVL_LO_PULLDOWN:
1300 case IVL_LO_PULLUP:
1301 /* Skip pullup and pulldown objects. Things that have
1302 pull objects as inputs will instead generate the
1303 appropriate C<?> symbol. */
1304 free(input_strings);
1305 return;
1307 case IVL_LO_AND:
1308 ltype = "AND";
1309 identity_val = '1';
1310 break;
1312 case IVL_LO_BUF:
1313 ltype = "BUF";
1314 break;
1316 case IVL_LO_BUFIF0:
1317 ltype = "BUFIF0";
1318 break;
1320 case IVL_LO_BUFIF1:
1321 ltype = "BUFIF1";
1322 break;
1324 case IVL_LO_NAND:
1325 ltype = "NAND";
1326 lcasc = "AND";
1327 identity_val = '1';
1328 break;
1330 case IVL_LO_NOR:
1331 ltype = "NOR";
1332 lcasc = "OR";
1333 break;
1335 case IVL_LO_NOT:
1336 ltype = "NOT";
1337 break;
1339 case IVL_LO_OR:
1340 ltype = "OR";
1341 break;
1343 case IVL_LO_XNOR:
1344 ltype = "XNOR";
1345 lcasc = "XOR";
1346 break;
1348 case IVL_LO_XOR:
1349 ltype = "XOR";
1350 break;
1352 case IVL_LO_CMOS:
1353 ltype = "CMOS";
1354 break;
1356 case IVL_LO_PMOS:
1357 ltype = "PMOS";
1358 break;
1360 case IVL_LO_NMOS:
1361 ltype = "NMOS";
1362 break;
1364 case IVL_LO_RCMOS:
1365 ltype = "RCMOS";
1366 break;
1368 case IVL_LO_RPMOS:
1369 ltype = "RPMOS";
1370 break;
1372 case IVL_LO_RNMOS:
1373 ltype = "RNMOS";
1374 break;
1376 case IVL_LO_NOTIF0:
1377 ltype = "NOTIF0";
1378 break;
1380 case IVL_LO_NOTIF1:
1381 ltype = "NOTIF1";
1382 break;
1384 default:
1385 fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %u\n",
1386 ivl_logic_type(lptr));
1387 ltype = "?";
1388 break;
1391 { ivl_nexus_t nex = ivl_logic_pin(lptr, 0);
1392 ivl_nexus_ptr_t nptr = 0;
1393 unsigned idx;
1394 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
1395 nptr = ivl_nexus_ptr(nex,idx);
1396 if (ivl_nexus_ptr_log(nptr) != lptr)
1397 continue;
1398 if (ivl_nexus_ptr_pin(nptr) != 0)
1399 continue;
1400 break;
1402 str0 = ivl_nexus_ptr_drive0(nptr);
1403 str1 = ivl_nexus_ptr_drive1(nptr);
1406 if (!lcasc)
1407 lcasc = ltype;
1409 /* Get all the input label that I will use for parameters to
1410 the functor that I create later. */
1411 ninp = ivl_logic_pins(lptr) - 1;
1412 input_strings = calloc(ninp, sizeof(char*));
1413 for (pdx = 0 ; pdx < ninp ; pdx += 1)
1414 input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));
1416 level = 0;
1417 ninp = ivl_logic_pins(lptr) - 1;
1418 while (ninp) {
1419 int inst;
1420 for (inst = 0; inst < ninp; inst += 4) {
1421 if (ninp > 4)
1422 fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
1423 lptr, level, inst, lcasc, vector_width);
1424 else {
1425 fprintf(vvp_out, "L_%p%s .functor %s %u",
1426 lptr, need_delay_flag? "/d" : "",
1427 ltype, vector_width);
1429 if (str0 != IVL_DR_STRONG || str1 != IVL_DR_STRONG)
1430 fprintf(vvp_out, " [%u %u]", str0, str1);
1433 for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) {
1434 if (level) {
1435 fprintf(vvp_out, ", L_%p/%d/%d",
1436 lptr, level - 1, pdx*4);
1437 } else {
1438 fprintf(vvp_out, ", %s", input_strings[pdx]);
1441 for ( ; pdx < inst+4 ; pdx += 1) {
1442 unsigned wdx;
1443 fprintf(vvp_out, ", C4<");
1444 for (wdx = 0 ; wdx < vector_width ; wdx += 1)
1445 fprintf(vvp_out, "%c", identity_val);
1446 fprintf(vvp_out, ">");
1449 fprintf(vvp_out, ";\n");
1451 if (ninp > 4)
1452 ninp = (ninp+3) / 4;
1453 else
1454 ninp = 0;
1455 level += 1;
1458 /* Free the array of char*. The strings themselves are
1459 persistent, held by the ivl_nexus_t objects. */
1460 free(input_strings);
1462 /* If there are delays, then draw the delay functor to carry
1463 that delay. This is the final output. */
1464 if (need_delay_flag) {
1465 ivl_expr_t rise_exp = ivl_logic_delay(lptr,0);
1466 ivl_expr_t fall_exp = ivl_logic_delay(lptr,1);
1467 ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);
1469 if (number_is_immediate(rise_exp,64)
1470 && number_is_immediate(fall_exp,64)
1471 && number_is_immediate(decay_exp,64)) {
1473 fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
1474 lptr, get_number_immediate(rise_exp),
1475 get_number_immediate(rise_exp),
1476 get_number_immediate(rise_exp), lptr);
1477 } else {
1478 ivl_signal_t sig;
1479 assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
1480 assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
1481 assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);
1483 fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr);
1485 sig = ivl_expr_signal(rise_exp);
1486 assert(ivl_signal_array_count(sig) == 1);
1487 fprintf(vvp_out, ", v%p_0", sig);
1489 sig = ivl_expr_signal(fall_exp);
1490 assert(ivl_signal_array_count(sig) == 1);
1491 fprintf(vvp_out, ", v%p_0", sig);
1493 sig = ivl_expr_signal(decay_exp);
1494 assert(ivl_signal_array_count(sig) == 1);
1495 fprintf(vvp_out, ", v%p_0;\n", sig);
1500 static void draw_event_in_scope(ivl_event_t obj)
1502 unsigned nany = ivl_event_nany(obj);
1503 unsigned nneg = ivl_event_nneg(obj);
1504 unsigned npos = ivl_event_npos(obj);
1506 unsigned cnt = 0;
1508 /* Figure out how many probe functors are needed. */
1509 if (nany > 0)
1510 cnt += (nany+3) / 4;
1512 if (nneg > 0)
1513 cnt += (nneg+3) / 4;
1515 if (npos > 0)
1516 cnt += (npos+3) / 4;
1518 if (cnt == 0) {
1519 /* If none are needed, then this is a named event. The
1520 code needed is easy. */
1521 fprintf(vvp_out, "E_%p .event \"%s\";\n", obj,
1522 vvp_mangle_name(ivl_event_basename(obj)));
1524 } else if (cnt > 1) {
1525 /* There are a bunch of events that need to be event/or
1526 combined. */
1527 unsigned idx;
1528 unsigned ecnt = 0;
1530 for (idx = 0 ; idx < nany ; idx += 4, ecnt += 1) {
1531 unsigned sub, top;
1533 fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt);
1535 top = idx + 4;
1536 if (nany < top)
1537 top = nany;
1538 for (sub = idx ; sub < top ; sub += 1) {
1539 ivl_nexus_t nex = ivl_event_any(obj, sub);
1540 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1542 fprintf(vvp_out, ";\n");
1545 for (idx = 0 ; idx < nneg ; idx += 4, ecnt += 1) {
1546 unsigned sub, top;
1548 fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt);
1550 top = idx + 4;
1551 if (nneg < top)
1552 top = nneg;
1553 for (sub = idx ; sub < top ; sub += 1) {
1554 ivl_nexus_t nex = ivl_event_neg(obj, sub);
1555 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1557 fprintf(vvp_out, ";\n");
1560 for (idx = 0 ; idx < npos ; idx += 4, ecnt += 1) {
1561 unsigned sub, top;
1563 fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt);
1565 top = idx + 4;
1566 if (npos < top)
1567 top = npos;
1568 for (sub = idx ; sub < top ; sub += 1) {
1569 ivl_nexus_t nex = ivl_event_pos(obj, sub);
1570 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1572 fprintf(vvp_out, ";\n");
1575 assert(ecnt == cnt);
1577 fprintf(vvp_out, "E_%p .event/or", obj);
1578 fprintf(vvp_out, " E_%p/0", obj);
1580 for (idx = 1 ; idx < cnt ; idx += 1)
1581 fprintf(vvp_out, ", E_%p/%u", obj, idx);
1583 fprintf(vvp_out, ";\n");
1585 } else {
1586 unsigned num_input_strings = nany + nneg + npos;
1587 unsigned idx;
1588 ivl_nexus_t input_nexa[4];
1589 const char*edge = 0;
1591 assert(num_input_strings <= 4);
1593 if (nany > 0) {
1594 assert((nneg + npos) == 0);
1595 assert(nany <= 4);
1597 edge = "edge";
1599 for (idx = 0 ; idx < nany ; idx += 1) {
1600 ivl_nexus_t nex = ivl_event_any(obj, idx);
1601 input_nexa[idx] = nex;
1604 } else if (nneg > 0) {
1605 assert((nany + npos) == 0);
1606 edge = "negedge";
1608 for (idx = 0 ; idx < nneg ; idx += 1) {
1609 ivl_nexus_t nex = ivl_event_neg(obj, idx);
1610 input_nexa[idx] = nex;
1613 } else {
1614 assert((nany + nneg) == 0);
1615 edge = "posedge";
1617 for (idx = 0 ; idx < npos ; idx += 1) {
1618 ivl_nexus_t nex = ivl_event_pos(obj, idx);
1619 input_nexa[idx] = nex;
1623 fprintf(vvp_out, "E_%p .event %s", obj, edge);
1624 for (idx = 0 ; idx < num_input_strings ; idx += 1)
1625 fprintf(vvp_out, ", %s", draw_input_from_net(input_nexa[idx]));
1627 fprintf(vvp_out, ";\n");
1632 * This function draws any functors needed to calculate the input to
1633 * this nexus, and leaves in the data array strings that can be used
1634 * as functor arguments. The strings are from the draw_net_input
1635 * function, which in turn returns nexus names, so the strings are
1636 * safe to pass around.
1638 static void draw_lpm_data_inputs(ivl_lpm_t net, unsigned base,
1639 unsigned ndata, const char**src_table)
1641 unsigned idx;
1642 for (idx = 0 ; idx < ndata ; idx += 1) {
1643 ivl_nexus_t nex = ivl_lpm_data(net, base+idx);
1644 src_table[idx] = draw_net_input(nex);
1648 static void draw_lpm_add(ivl_lpm_t net)
1650 const char*src_table[2];
1651 unsigned width;
1652 const char*type = "";
1653 ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0));
1654 ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1));
1655 ivl_variable_type_t dto = IVL_VT_LOGIC;
1657 if (dta == IVL_VT_REAL && dtb == IVL_VT_REAL)
1658 dto = IVL_VT_REAL;
1660 width = ivl_lpm_width(net);
1662 switch (ivl_lpm_type(net)) {
1663 case IVL_LPM_ADD:
1664 type = "sum";
1665 break;
1666 case IVL_LPM_SUB:
1667 if (dto == IVL_VT_REAL)
1668 type = "sub.r";
1669 else
1670 type = "sub";
1671 break;
1672 case IVL_LPM_MULT:
1673 type = "mult";
1674 break;
1675 case IVL_LPM_DIVIDE:
1676 if (dto == IVL_VT_REAL)
1677 type = "div.r";
1678 else if (ivl_lpm_signed(net))
1679 type = "div.s";
1680 else
1681 type = "div";
1682 break;
1683 case IVL_LPM_MOD:
1684 type = "mod";
1685 break;
1686 default:
1687 assert(0);
1690 draw_lpm_data_inputs(net, 0, 2, src_table);
1691 fprintf(vvp_out, "L_%p .arith/%s %u, %s, %s;\n",
1692 net, type, width, src_table[0], src_table[1]);
1696 * The read port to an array is generated as a single record that takes
1697 * the address as an input.
1699 static void draw_lpm_array(ivl_lpm_t net)
1701 ivl_nexus_t nex;
1702 ivl_signal_t mem = ivl_lpm_array(net);
1704 fprintf(vvp_out, "L_%p .array/port v%p, ", net, mem);
1706 nex = ivl_lpm_select(net);
1707 fprintf(vvp_out, "%s", draw_net_input(nex));
1709 fprintf(vvp_out, ";\n");
1712 static void draw_lpm_cmp(ivl_lpm_t net)
1714 const char*src_table[2];
1715 unsigned width;
1716 const char*type = "";
1717 const char*signed_string = ivl_lpm_signed(net)? ".s" : "";
1719 width = ivl_lpm_width(net);
1721 switch (ivl_lpm_type(net)) {
1722 case IVL_LPM_CMP_EEQ:
1723 type = "eeq";
1724 signed_string = "";
1725 break;
1726 case IVL_LPM_CMP_EQ:
1727 type = "eq";
1728 signed_string = "";
1729 break;
1730 case IVL_LPM_CMP_GE:
1731 type = "ge";
1732 break;
1733 case IVL_LPM_CMP_GT:
1734 type = "gt";
1735 break;
1736 case IVL_LPM_CMP_NE:
1737 type = "ne";
1738 signed_string = "";
1739 break;
1740 case IVL_LPM_CMP_NEE:
1741 type = "nee";
1742 signed_string = "";
1743 break;
1744 default:
1745 assert(0);
1748 draw_lpm_data_inputs(net, 0, 2, src_table);
1749 fprintf(vvp_out, "L_%p .cmp/%s%s %u, %s, %s;\n",
1750 net, type, signed_string, width,
1751 src_table[0], src_table[1]);
1755 * This function draws the arguments to a .const node using the
1756 * lpm inputs starting at "start" and for "cnt" inputs. This input
1757 * count must be <= 4. It is up to the caller to write the header part
1758 * of the statement, and to organize the data into multiple
1759 * statements.
1761 * Return the width of the final concatenation.
1763 static unsigned lpm_concat_inputs(ivl_lpm_t net, unsigned start,
1764 unsigned cnt, const char*src_table[])
1766 unsigned idx;
1767 unsigned wid = 0;
1769 assert(cnt <= 4);
1771 /* First, draw the [L M N O] part of the statement, the list
1772 of widths for the .concat statement. */
1773 fprintf(vvp_out, "[");
1775 for (idx = 0 ; idx < cnt ; idx += 1) {
1776 ivl_nexus_t nex = ivl_lpm_data(net, start+idx);
1777 unsigned nexus_width = width_of_nexus(nex);
1778 fprintf(vvp_out, " %u", nexus_width);
1779 wid += nexus_width;
1782 for ( ; idx < 4 ; idx += 1)
1783 fprintf(vvp_out, " 0");
1785 fprintf(vvp_out, "]");
1788 for (idx = 0 ; idx < cnt ; idx += 1) {
1789 fprintf(vvp_out, ", %s", src_table[idx]);
1792 fprintf(vvp_out, ";\n");
1793 return wid;
1797 * Implement the general IVL_LPM_CONCAT using .concat nodes. Use as
1798 * many nested nodes as necessary to support the desired number of
1799 * input vectors.
1801 static void draw_lpm_concat(ivl_lpm_t net)
1803 const char*src_table[4];
1804 unsigned icnt = ivl_lpm_selects(net);
1806 if (icnt <= 4) {
1807 /* This is the easiest case. There are 4 or fewer input
1808 vectors, so the entire IVL_LPM_CONCAT can be
1809 implemented with a single .concat node. */
1810 draw_lpm_data_inputs(net, 0, icnt, src_table);
1811 fprintf(vvp_out, "L_%p .concat ", net);
1812 lpm_concat_inputs(net, 0, icnt, src_table);
1814 } else {
1815 /* If there are more than 4 inputs, things get more
1816 complicated. We need to generate a balanced tree of
1817 .concat nodes to blend the inputs down to a single
1818 root node, that becomes the output from the
1819 concatenation. */
1820 unsigned idx, depth;
1821 struct concat_tree {
1822 unsigned base;
1823 unsigned wid;
1824 } *tree;
1826 tree = malloc((icnt + 3)/4 * sizeof(struct concat_tree));
1828 /* First, fill in all the leaves with the initial inputs
1829 to the tree. After this loop, there are (icnt+3)/4
1830 .concat nodes drawn, that together take all the
1831 inputs. */
1832 for (idx = 0 ; idx < icnt ; idx += 4) {
1833 unsigned wid = 0;
1834 unsigned trans = 4;
1835 if ((idx + trans) > icnt)
1836 trans = icnt - idx;
1838 draw_lpm_data_inputs(net, idx, trans, src_table);
1839 fprintf(vvp_out, "LS_%p_0_%u .concat ", net, idx);
1840 wid = lpm_concat_inputs(net, idx, trans, src_table);
1842 tree[idx/4].base = idx;
1843 tree[idx/4].wid = wid;
1846 /* icnt is the input count for the level. It is the
1847 number of .concats of the previous level that have to
1848 be concatenated at the current level. (This is not
1849 the same as the bit width.) */
1850 icnt = (icnt + 3)/4;
1852 /* Tree now has icnt nodes that are depth=0 concat nodes
1853 which take in the leaf inputs. The while loop below
1854 starts and ends with a tree of icnt nodes. Each time
1855 through, there are 1/4 the nodes we started
1856 with. Thus, we eventually get down to <=4 nodes, and
1857 that is when we fall out of the loop. */
1859 depth = 1;
1860 while (icnt > 4) {
1861 for (idx = 0 ; idx < icnt ; idx += 4) {
1862 unsigned tdx;
1863 unsigned wid = 0;
1864 unsigned trans = 4;
1865 if ((idx+trans) > icnt)
1866 trans = icnt - idx;
1868 fprintf(vvp_out, "LS_%p_%u_%u .concat [",
1869 net, depth, idx);
1871 for (tdx = 0 ; tdx < trans ; tdx += 1) {
1872 fprintf(vvp_out, " %u", tree[idx+tdx].wid);
1873 wid += tree[idx+tdx].wid;
1876 for ( ; tdx < 4 ; tdx += 1)
1877 fprintf(vvp_out, " 0");
1879 fprintf(vvp_out, "]");
1881 for (tdx = 0; tdx < trans ; tdx += 1) {
1882 fprintf(vvp_out, ", LS_%p_%u_%u", net,
1883 depth-1, tree[idx+tdx].base);
1886 fprintf(vvp_out, ";\n");
1887 tree[idx/4].base = idx;
1888 tree[idx/4].wid = wid;
1891 depth += 1;
1892 icnt = (icnt + 3)/4;
1895 /* Finally, draw the root node that takes in the final
1896 row of tree nodes and generates a single output. */
1897 fprintf(vvp_out, "L_%p .concat [", net);
1898 for (idx = 0 ; idx < icnt ; idx += 1)
1899 fprintf(vvp_out, " %u", tree[idx].wid);
1900 for ( ; idx < 4 ; idx += 1)
1901 fprintf(vvp_out, " 0");
1902 fprintf(vvp_out, "]");
1904 for (idx = 0 ; idx < icnt ; idx += 1)
1905 fprintf(vvp_out, ", LS_%p_%u_%u",
1906 net, depth-1, tree[idx].base);
1908 fprintf(vvp_out, ";\n");
1909 free(tree);
1914 * primitive FD (q, clk, ce, d);
1915 * output q;
1916 * reg q;
1917 * input clk, ce, d;
1918 * table
1919 * // clk ce d r s q q+
1920 * r 1 0 0 0 : ? : 0;
1921 * r 1 1 0 0 : ? : 1;
1922 * f 1 ? 0 0 : ? : -;
1923 * ? 1 ? 0 0 : ? : -;
1924 * * 0 ? 0 0 : ? : -;
1925 * ? ? ? 1 ? : ? : 0;
1926 * ? ? ? 0 1 : ? : 1;
1927 * endtable
1928 * endprimitive
1930 static void draw_lpm_ff(ivl_lpm_t net)
1932 ivl_expr_t aset_expr = 0;
1933 const char*aset_bits = 0;
1935 ivl_nexus_t nex;
1936 unsigned width;
1938 width = ivl_lpm_width(net);
1940 aset_expr = ivl_lpm_aset_value(net);
1941 if (aset_expr) {
1942 assert(ivl_expr_width(aset_expr) == width);
1943 aset_bits = ivl_expr_bits(aset_expr);
1947 fprintf(vvp_out, "L_%p .dff ", net);
1949 nex = ivl_lpm_data(net,0);
1950 assert(nex);
1951 fprintf(vvp_out, "%s", draw_net_input(nex));
1953 nex = ivl_lpm_clk(net);
1954 assert(nex);
1955 fprintf(vvp_out, ", %s", draw_net_input(nex));
1957 nex = ivl_lpm_enable(net);
1958 if (nex) {
1959 fprintf(vvp_out, ", %s", draw_net_input(nex));
1960 } else {
1961 fprintf(vvp_out, ", C4<1>");
1964 /* Stub asynchronous input for now. */
1965 fprintf(vvp_out, ", C4<z>");
1967 fprintf(vvp_out, ";\n");
1970 static void draw_lpm_shiftl(ivl_lpm_t net)
1972 unsigned width = ivl_lpm_width(net);
1973 const char* signed_flag = ivl_lpm_signed(net)? "s" : "";
1975 if (ivl_lpm_type(net) == IVL_LPM_SHIFTR)
1976 fprintf(vvp_out, "L_%p .shift/r%s %u", net, signed_flag, width);
1977 else
1978 fprintf(vvp_out, "L_%p .shift/l %u", net, width);
1980 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 0)));
1982 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 1)));
1984 fprintf(vvp_out, ";\n");
1987 static void draw_type_string_of_nex(ivl_nexus_t nex)
1989 switch (data_type_of_nexus(nex)) {
1990 case IVL_VT_REAL:
1991 fprintf(vvp_out, "r");
1992 break;
1993 case IVL_VT_LOGIC:
1994 case IVL_VT_BOOL:
1995 fprintf(vvp_out, "v%d", width_of_nexus(nex));
1996 break;
1997 default:
1998 assert(0);
1999 break;
2003 static void draw_lpm_sfunc(ivl_lpm_t net)
2005 unsigned idx;
2006 fprintf(vvp_out, "L_%p .sfunc \"%s\"", net, ivl_lpm_string(net));
2008 /* Print the function type descriptor string. */
2009 fprintf(vvp_out, ", \"");
2011 draw_type_string_of_nex(ivl_lpm_q(net,0));
2013 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1)
2014 draw_type_string_of_nex(ivl_lpm_data(net,idx));
2016 fprintf(vvp_out, "\"");
2018 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2019 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx)));
2022 fprintf(vvp_out, ";\n");
2025 static void draw_lpm_ufunc(ivl_lpm_t net)
2027 unsigned idx;
2028 ivl_scope_t def = ivl_lpm_define(net);
2030 fprintf(vvp_out, "L_%p .ufunc TD_%s, %u", net,
2031 ivl_scope_name(def),
2032 ivl_lpm_width(net));
2034 /* Print all the net signals that connect to the input of the
2035 function. */
2036 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2037 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, idx)));
2041 assert((ivl_lpm_size(net)+1) == ivl_scope_ports(def));
2043 /* Now print all the variables in the function scope that
2044 receive the input values given in the previous list. */
2045 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2046 ivl_signal_t psig = ivl_scope_port(def, idx+1);
2048 if (idx == 0)
2049 fprintf(vvp_out, " (");
2050 else
2051 fprintf(vvp_out, ", ");
2053 assert(ivl_signal_array_count(psig) == 1);
2054 fprintf(vvp_out, "v%p_0", psig);
2057 fprintf(vvp_out, ")");
2059 /* Finally, print the reference to the signal from which the
2060 result is collected. */
2061 { ivl_signal_t psig = ivl_scope_port(def, 0);
2062 assert(ivl_lpm_width(net) == ivl_signal_width(psig));
2063 assert(ivl_signal_array_count(psig) == 1);
2065 fprintf(vvp_out, " v%p_0", psig);
2068 fprintf(vvp_out, ";\n");
2072 * Handle a PART SELECT device. This has a single input and output,
2073 * plus an optional extra input that is a non-constant base.
2075 static void draw_lpm_part(ivl_lpm_t net)
2077 unsigned width, base;
2078 ivl_nexus_t sel;
2080 width = ivl_lpm_width(net);
2081 base = ivl_lpm_base(net);
2082 sel = ivl_lpm_data(net,1);
2084 if (sel == 0) {
2085 fprintf(vvp_out, "L_%p .part %s",
2086 net, draw_net_input(ivl_lpm_data(net, 0)));
2087 fprintf(vvp_out, ", %u, %u;\n", base, width);
2088 } else {
2089 fprintf(vvp_out, "L_%p .part/v %s",
2090 net, draw_net_input(ivl_lpm_data(net,0)));
2091 fprintf(vvp_out, ", %s", draw_net_input(sel));
2092 fprintf(vvp_out, ", %u;\n", width);
2097 * Handle a PART SELECT PV device. Generate a .part/pv node that
2098 * includes the part input, and the geometry of the part.
2100 static void draw_lpm_part_pv(ivl_lpm_t net)
2102 unsigned width = ivl_lpm_width(net);
2103 unsigned base = ivl_lpm_base(net);
2104 unsigned signal_width = width_of_nexus(ivl_lpm_q(net,0));
2106 fprintf(vvp_out, "L_%p .part/pv %s",
2107 net, draw_net_input(ivl_lpm_data(net, 0)));
2109 fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
2113 * Handle the drawing of a bi-directional part select. The two ports
2114 * are simultaneously input and output. A simple minded connect of the
2115 * input to the output causes a functor cycle which will lock into an
2116 * X value, so something special is needed.
2118 * NOTE: The inputs of the tran device at this point need to be from
2119 * all the drivers of the nexus *except* the tran itself. This
2120 * function will draw three labels that can be linked:
2122 * The ivl_lpm_q of a part(bi) may be a smaller vector then the
2123 * ivl_lpm_data, the tran acts like a forward part select in that
2124 * way.
2126 * The device creates these nodes:
2128 * - L_%p/i
2129 * This is the Q port of the tran resolved and padded to the maximum
2130 * width of the tran. The tran itself is not included in the
2131 * resolution of this port.
2133 * - L_%p/V
2134 * This is the Q and D parts resolved together, still without the tran
2135 * driving anything.
2137 * - L_%p/P
2138 * This is the /V node part-selected back to the dimensions of the Q
2139 * side.
2141 static void draw_lpm_part_bi(ivl_lpm_t net)
2143 unsigned width = ivl_lpm_width(net);
2144 unsigned base = ivl_lpm_base(net);
2145 unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
2147 unsigned idx;
2148 ivl_nexus_t nex;
2149 ivl_nexus_ptr_t ptr = 0;
2151 char*p_str;
2152 char*v_str;
2154 /* It seems implausible that the two inputs of a tran will be
2155 connected together. So assert that this is so to simplify
2156 the code to look for the nexus_ptr_t objects. */
2157 assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
2159 nex = ivl_lpm_q(net,0);
2160 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
2161 ptr = ivl_nexus_ptr(nex, idx);
2162 if (ivl_nexus_ptr_lpm(ptr) == net)
2163 break;
2165 assert(ptr != 0);
2166 p_str = draw_net_input_x(nex, ptr, 0, 0);
2168 nex = ivl_lpm_data(net,0);
2169 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
2170 ptr = ivl_nexus_ptr(nex, idx);
2171 if (ivl_nexus_ptr_lpm(ptr) == net)
2172 break;
2174 v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
2176 /* Pad the part-sized input out to a common width...
2177 The /i label is the Q side of the tran, resolved except for
2178 the tran itself and padded (with z) to the larger width. */
2179 fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
2180 net, p_str, base, width, signal_width);
2182 /* Resolve together the two halves of the tran...
2183 The /V label is the ports of the tran (now the same width)
2184 resolved together. Neither input to this resolver includes
2185 the tran itself. */
2186 fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
2187 net, net, v_str);
2189 /* The full-width side is created by the tran device, all we
2190 have left to to is take a part select of that for the
2191 smaller output, and this becomes the part select output of
2192 the BI device. */
2193 fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
2194 net, base, width);
2196 free(p_str);
2197 free(v_str);
2201 * Draw unary reduction devices.
2203 static void draw_lpm_re(ivl_lpm_t net, const char*type)
2205 fprintf(vvp_out, "L_%p .reduce/%s %s;\n",
2206 net, type, draw_net_input(ivl_lpm_data(net,0)));
2209 static void draw_lpm_repeat(ivl_lpm_t net)
2211 fprintf(vvp_out, "L_%p .repeat %u, %u, %s;\n", net,
2212 ivl_lpm_width(net), ivl_lpm_size(net),
2213 draw_net_input(ivl_lpm_data(net,0)));
2216 static void draw_lpm_sign_ext(ivl_lpm_t net)
2218 fprintf(vvp_out, "L_%p .extend/s %u, %s;\n",
2219 net, ivl_lpm_width(net),
2220 draw_net_input(ivl_lpm_data(net,0)));
2223 static void draw_lpm_in_scope(ivl_lpm_t net)
2225 switch (ivl_lpm_type(net)) {
2227 case IVL_LPM_ADD:
2228 case IVL_LPM_SUB:
2229 case IVL_LPM_MULT:
2230 case IVL_LPM_DIVIDE:
2231 case IVL_LPM_MOD:
2232 draw_lpm_add(net);
2233 return;
2235 case IVL_LPM_ARRAY:
2236 draw_lpm_array(net);
2237 return;
2239 case IVL_LPM_PART_BI:
2240 draw_lpm_part_bi(net);
2241 return;
2243 case IVL_LPM_PART_VP:
2244 draw_lpm_part(net);
2245 return;
2247 case IVL_LPM_PART_PV:
2248 draw_lpm_part_pv(net);
2249 return;
2251 case IVL_LPM_CONCAT:
2252 draw_lpm_concat(net);
2253 return;
2255 case IVL_LPM_FF:
2256 draw_lpm_ff(net);
2257 return;
2259 case IVL_LPM_CMP_EEQ:
2260 case IVL_LPM_CMP_EQ:
2261 case IVL_LPM_CMP_GE:
2262 case IVL_LPM_CMP_GT:
2263 case IVL_LPM_CMP_NE:
2264 case IVL_LPM_CMP_NEE:
2265 draw_lpm_cmp(net);
2266 return;
2268 case IVL_LPM_MUX:
2269 draw_lpm_mux(net);
2270 return;
2272 case IVL_LPM_RE_AND:
2273 draw_lpm_re(net, "and");
2274 return;
2275 case IVL_LPM_RE_OR:
2276 draw_lpm_re(net, "or");
2277 return;
2278 case IVL_LPM_RE_XOR:
2279 draw_lpm_re(net, "xor");
2280 return;
2281 case IVL_LPM_RE_NAND:
2282 draw_lpm_re(net, "nand");
2283 return;
2284 case IVL_LPM_RE_NOR:
2285 draw_lpm_re(net, "nor");
2286 return;
2287 case IVL_LPM_RE_XNOR:
2288 draw_lpm_re(net, "xnor");
2289 return;
2291 case IVL_LPM_REPEAT:
2292 draw_lpm_repeat(net);
2293 return;
2295 case IVL_LPM_SHIFTL:
2296 case IVL_LPM_SHIFTR:
2297 draw_lpm_shiftl(net);
2298 return;
2300 case IVL_LPM_SIGN_EXT:
2301 draw_lpm_sign_ext(net);
2302 return;
2304 case IVL_LPM_SFUNC:
2305 draw_lpm_sfunc(net);
2306 return;
2308 case IVL_LPM_UFUNC:
2309 draw_lpm_ufunc(net);
2310 return;
2312 default:
2313 fprintf(stderr, "XXXX LPM not supported: %s.%s\n",
2314 ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net));
2318 int draw_scope(ivl_scope_t net, ivl_scope_t parent)
2320 unsigned idx;
2321 const char *type;
2322 switch (ivl_scope_type(net)) {
2323 case IVL_SCT_MODULE: type = "module"; break;
2324 case IVL_SCT_FUNCTION: type = "function"; break;
2325 case IVL_SCT_TASK: type = "task"; break;
2326 case IVL_SCT_BEGIN: type = "begin"; break;
2327 case IVL_SCT_FORK: type = "fork"; break;
2328 case IVL_SCT_GENERATE: type = "generate"; break;
2329 default: type = "?"; assert(0);
2332 fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\"",
2333 net, type, vvp_mangle_name(ivl_scope_basename(net)),
2334 ivl_scope_tname(net));
2336 if (parent) {
2337 fprintf(vvp_out, ", S_%p;\n", parent);
2338 } else {
2340 fprintf(vvp_out, ";\n");
2343 fprintf(vvp_out, " .timescale %d;\n", ivl_scope_time_units(net));
2345 for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) {
2346 ivl_parameter_t par = ivl_scope_param(net, idx);
2347 ivl_expr_t pex = ivl_parameter_expr(par);
2348 switch (ivl_expr_type(pex)) {
2349 case IVL_EX_STRING:
2350 fprintf(vvp_out, "P_%p .param/str \"%s\", \"%s\";\n",
2351 par, ivl_parameter_basename(par),
2352 ivl_expr_string(pex));
2353 break;
2354 case IVL_EX_NUMBER:
2355 fprintf(vvp_out, "P_%p .param/l \"%s\", %sC4<",
2356 par, ivl_parameter_basename(par),
2357 ivl_expr_signed(pex)? "+":"");
2358 { const char*bits = ivl_expr_bits(pex);
2359 unsigned nbits = ivl_expr_width(pex);
2360 unsigned bb;
2361 for (bb = 0 ; bb < nbits; bb += 1)
2362 fprintf(vvp_out, "%c", bits[nbits-bb-1]);
2364 fprintf(vvp_out, ">;\n");
2365 break;
2366 default:
2367 fprintf(vvp_out, "; parameter type %d unsupported\n",
2368 ivl_expr_type(pex));
2369 break;
2373 /* Scan the scope for logic devices. For each device, draw out
2374 a functor that connects pin 0 to the output, and the
2375 remaining pins to inputs. */
2377 for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1) {
2378 ivl_net_logic_t lptr = ivl_scope_log(net, idx);
2379 draw_logic_in_scope(lptr);
2383 /* Scan the signals (reg and net) and draw the appropriate
2384 statements to make the signal function. */
2386 for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1) {
2387 ivl_signal_t sig = ivl_scope_sig(net, idx);
2389 switch (ivl_signal_type(sig)) {
2390 case IVL_SIT_REG:
2391 draw_reg_in_scope(sig);
2392 break;
2393 default:
2394 draw_net_in_scope(sig);
2395 break;
2399 for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1) {
2400 ivl_event_t event = ivl_scope_event(net, idx);
2401 draw_event_in_scope(event);
2404 for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) {
2405 ivl_lpm_t lpm = ivl_scope_lpm(net, idx);
2406 draw_lpm_in_scope(lpm);
2409 if (ivl_scope_type(net) == IVL_SCT_TASK)
2410 draw_task_definition(net);
2412 if (ivl_scope_type(net) == IVL_SCT_FUNCTION)
2413 draw_func_definition(net);
2415 ivl_scope_children(net, (ivl_scope_f*) draw_scope, net);
2416 return 0;