Correct elaboration of network constants.
[iverilog.git] / tgt-vvp / vvp_scope.c
blob026c70816f39a55e9e176a7ebcfb318e2185138c
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 char bitchar = bits[ivl_const_width(cptr)-idx-1];
416 *dp++ = bitchar;
417 assert((dp - result) < result_len);
420 strcpy(dp, ">");
421 return result;
424 static char* draw_C8_to_string(ivl_net_const_t cptr,
425 ivl_drive_t dr0, ivl_drive_t dr1)
427 size_t nresult = 5 + 3*ivl_const_width(cptr);
428 char*result = malloc(nresult);
429 const char*bits = ivl_const_bits(cptr);
430 unsigned idx;
432 char dr0c = "01234567"[dr0];
433 char dr1c = "01234567"[dr1];
434 char*dp = result;
436 strcpy(dp, "C8<");
437 dp += strlen(dp);
439 for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
440 switch (bits[ivl_const_width(cptr)-idx-1]) {
441 case '0':
442 *dp++ = dr0c;
443 *dp++ = dr0c;
444 *dp++ = '0';
445 break;
446 case '1':
447 *dp++ = dr1c;
448 *dp++ = dr1c;
449 *dp++ = '1';
450 break;
451 case 'x':
452 case 'X':
453 *dp++ = dr0c;
454 *dp++ = dr1c;
455 *dp++ = 'x';
456 break;
457 case 'z':
458 case 'Z':
459 *dp++ = '0';
460 *dp++ = '0';
461 *dp++ = 'z';
462 break;
463 default:
464 assert(0);
465 break;
467 assert(dp - result < nresult);
470 strcpy(dp, ">");
471 return result;
475 * This function takes a nexus and looks for an input functor. It then
476 * draws to the output a string that represents that functor. What we
477 * are trying to do here is find the input to the net that is attached
478 * to this nexus.
481 static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
483 unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
484 ivl_net_const_t cptr;
485 ivl_net_logic_t lptr;
486 ivl_signal_t sptr;
487 ivl_lpm_t lpm;
489 lptr = ivl_nexus_ptr_log(nptr);
490 if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
491 do {
492 if (! can_elide_bufz(lptr, nptr))
493 break;
495 return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
496 } while(0);
498 /* If this is a pulldown device, then there is a single pin
499 that drives a constant value to the entire width of the
500 vector. The driver normally drives a pull0 value, so a C8<>
501 constant is appropriate, but if the drive is really strong,
502 then we can draw a C4<> constant instead. */
503 if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
504 if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
505 size_t result_len = ivl_logic_width(lptr) + 5;
506 char*result = malloc(result_len);
507 char*dp = result;
508 strcpy(dp, "C4<");
509 dp += strlen(dp);
510 str_repeat(dp, "0", ivl_logic_width(lptr));
511 dp += ivl_logic_width(lptr);
512 *dp++ = '>';
513 *dp = 0;
514 assert((dp-result) <= result_len);
515 return result;
516 } else {
517 char val[4];
518 size_t result_len = 3*ivl_logic_width(lptr) + 5;
519 char*result = malloc(result_len);
520 char*dp = result;
522 val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
523 val[1] = val[0];
524 val[2] = '0';
525 val[3] = 0;
527 strcpy(dp, "C8<");
528 dp += strlen(dp);
529 str_repeat(dp, val, ivl_logic_width(lptr));
530 dp += 3*ivl_logic_width(lptr);
531 *dp++ = '>';
532 *dp = 0;
533 assert((dp-result) <= result_len);
534 return result;
538 if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
539 if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
540 size_t result_len = 5 + ivl_logic_width(lptr);
541 char*result = malloc(result_len);
542 char*dp = result;
543 strcpy(dp, "C4<");
544 dp += strlen(dp);
545 str_repeat(dp, "1", ivl_logic_width(lptr));
546 dp += ivl_logic_width(lptr);
547 *dp++ = '>';
548 *dp = 0;
549 assert((dp-result) <= result_len);
550 return result;
551 } else {
552 char val[4];
553 size_t result_len = 5 + 3*ivl_logic_width(lptr);
554 char*result = malloc(result_len);
555 char*dp = result;
557 val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
558 val[1] = val[0];
559 val[2] = '1';
560 val[3] = 0;
562 strcpy(dp, "C8<");
563 dp += strlen(dp);
564 str_repeat(dp, val, ivl_logic_width(lptr));
565 dp += 3*ivl_logic_width(lptr);
566 *dp++ = '>';
567 *dp = 0;
568 assert((dp-result) <= result_len);
569 return result;
573 if (lptr && (nptr_pin == 0)) {
574 char tmp[128];
575 snprintf(tmp, sizeof tmp, "L_%p", lptr);
576 return strdup(tmp);
579 sptr = ivl_nexus_ptr_sig(nptr);
580 if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
581 char tmp[128];
582 /* Input is a .var. This device may be a non-zero pin
583 because it may be an array of reg vectors. */
584 snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
585 return strdup(tmp);
588 cptr = ivl_nexus_ptr_con(nptr);
589 if (cptr) {
590 /* Constants should have exactly 1 pin, with a literal value. */
591 assert(nptr_pin == 0);
592 char *result = 0;
594 switch (ivl_const_type(cptr)) {
595 case IVL_VT_LOGIC:
596 case IVL_VT_BOOL:
597 if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
598 && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
600 result = draw_C4_to_string(cptr);
602 } else {
603 result = draw_C8_to_string(cptr,
604 ivl_nexus_ptr_drive0(nptr),
605 ivl_nexus_ptr_drive1(nptr));
607 break;
609 case IVL_VT_REAL:
610 { char tmp[256];
611 snprintf(tmp, sizeof(tmp),
612 "Cr<%lg>", ivl_const_real(cptr));
613 result = strdup(tmp);
615 break;
617 default:
618 assert(0);
619 break;
622 return result;
625 lpm = ivl_nexus_ptr_lpm(nptr);
626 if (lpm) switch (ivl_lpm_type(lpm)) {
628 case IVL_LPM_FF:
629 case IVL_LPM_ADD:
630 case IVL_LPM_ARRAY:
631 case IVL_LPM_CONCAT:
632 case IVL_LPM_CMP_EEQ:
633 case IVL_LPM_CMP_EQ:
634 case IVL_LPM_CMP_GE:
635 case IVL_LPM_CMP_GT:
636 case IVL_LPM_CMP_NE:
637 case IVL_LPM_CMP_NEE:
638 case IVL_LPM_RE_AND:
639 case IVL_LPM_RE_OR:
640 case IVL_LPM_RE_XOR:
641 case IVL_LPM_RE_NAND:
642 case IVL_LPM_RE_NOR:
643 case IVL_LPM_RE_XNOR:
644 case IVL_LPM_SFUNC:
645 case IVL_LPM_SHIFTL:
646 case IVL_LPM_SHIFTR:
647 case IVL_LPM_SIGN_EXT:
648 case IVL_LPM_SUB:
649 case IVL_LPM_MULT:
650 case IVL_LPM_MUX:
651 case IVL_LPM_DIVIDE:
652 case IVL_LPM_MOD:
653 case IVL_LPM_UFUNC:
654 case IVL_LPM_PART_VP:
655 case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
656 case IVL_LPM_REPEAT:
657 if (ivl_lpm_q(lpm, 0) == nex) {
658 char tmp[128];
659 snprintf(tmp, sizeof tmp, "L_%p", lpm);
660 return strdup(tmp);
662 break;
664 case IVL_LPM_PART_BI:
665 if (ivl_lpm_q(lpm, 0) == nex) {
666 char tmp[128];
667 snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
668 return strdup(tmp);
669 } else if (ivl_lpm_data(lpm,0) == nex) {
670 char tmp[128];
671 snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
672 return strdup(tmp);
674 break;
677 fprintf(stderr, "internal error: no input to nexus %s\n",
678 ivl_nexus_name(nex));
679 assert(0);
680 return strdup("C<z>");
683 static void draw_modpath(const char*label, const char*driver,
684 ivl_signal_t path_sig)
686 unsigned idx;
687 typedef const char*ccharp;
688 ccharp*src_drivers;
689 ccharp*con_drivers;
691 src_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
692 con_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
693 for (idx = 0 ; idx < ivl_signal_npath(path_sig) ; idx += 1) {
694 ivl_delaypath_t path = ivl_signal_path(path_sig, idx);
695 ivl_nexus_t src = ivl_path_source(path);
696 ivl_nexus_t con = ivl_path_condit(path);
698 src_drivers[idx] = draw_net_input(src);
700 if (con) con_drivers[idx] = draw_net_input(con);
701 else con_drivers[idx] = 0;
704 fprintf(vvp_out, "%s .modpath %s", label, driver);
706 for (idx = 0 ; idx < ivl_signal_npath(path_sig); idx += 1) {
707 ivl_delaypath_t path = ivl_signal_path(path_sig, idx);
708 int ppos = ivl_path_source_posedge(path);
709 int pneg = ivl_path_source_negedge(path);
710 const char*edge = ppos? " +" : pneg ? " -" : "";
711 fprintf(vvp_out, ",\n %s%s", src_drivers[idx], edge);
712 fprintf(vvp_out,
713 " (%"PRIu64",%"PRIu64",%"PRIu64
714 ", %"PRIu64",%"PRIu64",%"PRIu64
715 ", %"PRIu64",%"PRIu64",%"PRIu64
716 ", %"PRIu64",%"PRIu64",%"PRIu64,
717 ivl_path_delay(path, IVL_PE_01),
718 ivl_path_delay(path, IVL_PE_10),
719 ivl_path_delay(path, IVL_PE_0z),
720 ivl_path_delay(path, IVL_PE_z1),
721 ivl_path_delay(path, IVL_PE_1z),
722 ivl_path_delay(path, IVL_PE_z0),
723 ivl_path_delay(path, IVL_PE_0x),
724 ivl_path_delay(path, IVL_PE_x1),
725 ivl_path_delay(path, IVL_PE_1x),
726 ivl_path_delay(path, IVL_PE_x0),
727 ivl_path_delay(path, IVL_PE_xz),
728 ivl_path_delay(path, IVL_PE_zx));
730 if (con_drivers[idx]) {
731 fprintf(vvp_out, " ? %s", con_drivers[idx]);
734 fprintf(vvp_out, ")");
737 fprintf(vvp_out, ";\n");
739 free(src_drivers);
740 free(con_drivers);
743 static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
745 if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
746 return 1;
747 if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
748 return 1;
750 ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
751 if (log != 0) {
752 /* These logic gates are able to generate unusual
753 strength values and so their outputs are considered
754 strength aware. */
755 if (ivl_logic_type(log) == IVL_LO_BUFIF0)
756 return 1;
757 if (ivl_logic_type(log) == IVL_LO_BUFIF1)
758 return 1;
759 if (ivl_logic_type(log) == IVL_LO_PMOS)
760 return 1;
761 if (ivl_logic_type(log) == IVL_LO_NMOS)
762 return 1;
765 return 0;
769 * This function draws the input to a net into a string. What that
770 * means is that it returns a static string that can be used to
771 * represent a resolved driver to a nexus. If there are multiple
772 * drivers to the nexus, then it writes out the resolver declarations
773 * needed to perform strength resolution.
775 * The string that this returns is malloced, and that means that the
776 * caller must free the string or store it permanently. This function
777 * does *not* check for a previously calculated string. Use the
778 * draw_net_input for the general case.
780 /* Omit LPMPART_BI device pin-data(0) drivers. */
781 # define OMIT_PART_BI_DATA 0x0001
783 static char* draw_net_input_x(ivl_nexus_t nex,
784 ivl_nexus_ptr_t omit_ptr, int omit_flags,
785 struct vvp_nexus_data*nex_data)
787 ivl_signal_type_t res;
788 char result[512];
789 unsigned idx;
790 int level;
791 unsigned ndrivers = 0;
792 static ivl_nexus_ptr_t *drivers = 0x0;
793 static unsigned adrivers = 0;
795 const char*resolv_type;
797 char*nex_private = 0;
799 /* Accumulate nex_data flags. */
800 int nex_flags = 0;
802 res = signal_type_of_nexus(nex);
803 switch (res) {
804 case IVL_SIT_TRI:
805 resolv_type = "tri";
806 break;
807 case IVL_SIT_TRI0:
808 resolv_type = "tri0";
809 nex_flags |= VVP_NEXUS_DATA_STR;
810 break;
811 case IVL_SIT_TRI1:
812 resolv_type = "tri1";
813 nex_flags |= VVP_NEXUS_DATA_STR;
814 break;
815 case IVL_SIT_TRIAND:
816 resolv_type = "triand";
817 break;
818 case IVL_SIT_TRIOR:
819 resolv_type = "trior";
820 break;
821 default:
822 fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
823 assert(0);
824 resolv_type = "tri";
825 break;
829 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
830 ivl_lpm_t lpm_tmp;
831 ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
833 /* If we are supposed to skip LPM_PART_BI data pins,
834 check that this driver is that. */
835 if ((omit_flags&OMIT_PART_BI_DATA)
836 && (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
837 && (nex == ivl_lpm_data(lpm_tmp,0)))
838 continue;
840 if (nptr == omit_ptr)
841 continue;
843 /* Skip input only pins. */
844 if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
845 && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
846 continue;
848 /* Mark the strength-aware flag if the driver can
849 generate values other than the standard "6"
850 strength. */
851 if (nexus_drive_is_strength_aware(nptr))
852 nex_flags |= VVP_NEXUS_DATA_STR;
854 /* Save this driver. */
855 if (ndrivers >= adrivers) {
856 adrivers += 4;
857 drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
858 assert(drivers);
860 drivers[ndrivers] = nptr;
861 ndrivers += 1;
864 /* If the caller is collecting nexus information, then save
865 the nexus driver count in the nex_data. */
866 if (nex_data) {
867 nex_data->drivers_count = ndrivers;
868 nex_data->flags |= nex_flags;
871 /* If the nexus has no drivers, then send a constant HiZ into
872 the net. */
873 if (ndrivers == 0) {
874 unsigned idx, wid = width_of_nexus(nex);
875 char*tmp = malloc(wid + 5);
876 nex_private = tmp;
877 strcpy(tmp, "C4<");
878 tmp += strlen(tmp);
879 switch (res) {
880 case IVL_SIT_TRI:
881 for (idx = 0 ; idx < wid ; idx += 1)
882 *tmp++ = 'z';
883 break;
884 case IVL_SIT_TRI0:
885 for (idx = 0 ; idx < wid ; idx += 1)
886 *tmp++ = '0';
887 break;
888 case IVL_SIT_TRI1:
889 for (idx = 0 ; idx < wid ; idx += 1)
890 *tmp++ = '1';
891 break;
892 default:
893 assert(0);
895 *tmp++ = '>';
896 *tmp = 0;
897 return nex_private;
901 /* If the nexus has exactly one driver, then simply draw
902 it. Note that this will *not* work if the nexus is not a
903 TRI type nexus. */
904 if (ndrivers == 1 && res == IVL_SIT_TRI) {
905 ivl_signal_t path_sig = find_modpath(nex);
906 if (path_sig) {
907 char*nex_str = draw_net_input_drive(nex, drivers[0]);
908 char modpath_label[64];
909 snprintf(modpath_label, sizeof modpath_label,
910 "V_%p/m", path_sig);
911 draw_modpath(modpath_label, nex_str, path_sig);
912 nex_private = strdup(modpath_label);
913 free(nex_str);
914 } else {
915 nex_private = draw_net_input_drive(nex, drivers[0]);
917 return nex_private;
920 level = 0;
921 while (ndrivers) {
922 unsigned int inst;
923 for (inst = 0; inst < ndrivers; inst += 4) {
924 if (ndrivers > 4)
925 fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
926 nex, level, inst);
927 else
928 fprintf(vvp_out, "RS_%p .resolv %s",
929 nex, resolv_type);
931 for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
932 if (level) {
933 fprintf(vvp_out, ", RS_%p/%d/%d",
934 nex, level - 1, idx*4);
935 } else {
936 char*drive = draw_net_input_drive(nex, drivers[idx]);
937 fprintf(vvp_out, ", %s", drive);
938 free(drive);
941 for ( ; idx < inst+4 ; idx += 1) {
942 fprintf(vvp_out, ", ");
943 draw_C4_repeated_constant('z',width_of_nexus(nex));
946 fprintf(vvp_out, ";\n");
948 if (ndrivers > 4)
949 ndrivers = (ndrivers+3) / 4;
950 else
951 ndrivers = 0;
952 level += 1;
955 sprintf(result, "RS_%p", nex);
956 nex_private = strdup(result);
957 return nex_private;
961 * Get a cached description of the nexus input, or create one if this
962 * nexus has not been cached yet. This is a wrapper for the common
963 * case call to draw_net_input_x.
965 const char*draw_net_input(ivl_nexus_t nex)
967 struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
968 ivl_nexus_get_private(nex);
970 /* If this nexus already has a label, then its input is
971 already figured out. Just return the existing label. */
972 if (nex_data && nex_data->net_input)
973 return nex_data->net_input;
975 if (nex_data == 0) {
976 nex_data = new_nexus_data();
977 ivl_nexus_set_private(nex, nex_data);
980 assert(nex_data->net_input == 0);
981 nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
983 return nex_data->net_input;
986 const char*draw_input_from_net(ivl_nexus_t nex)
988 static char result[32];
989 unsigned word;
991 ivl_signal_t sig = signal_of_nexus(nex, &word);
992 if (sig == 0)
993 return draw_net_input(nex);
995 snprintf(result, sizeof result, "v%p_%u", sig, word);
996 return result;
1001 * This function draws a reg/int/variable in the scope. This is a very
1002 * simple device to draw as there are no inputs to connect so no need
1003 * to scan the nexus. We do have to account for the possibility that
1004 * the device is arrayed, though, by making a node for each array element.
1006 static void draw_reg_in_scope(ivl_signal_t sig)
1008 int msb = ivl_signal_msb(sig);
1009 int lsb = ivl_signal_lsb(sig);
1011 const char*datatype_flag = ivl_signal_integer(sig) ? "/i" :
1012 ivl_signal_signed(sig)? "/s" : "";
1014 switch (ivl_signal_data_type(sig)) {
1015 case IVL_VT_REAL:
1016 datatype_flag = "/real";
1017 break;
1018 default:
1019 break;
1022 /* If the reg objects are collected into an array, then first
1023 write out the .array record to declare the array indices. */
1024 if (ivl_signal_dimensions(sig) > 0) {
1025 unsigned word_count = ivl_signal_array_count(sig);
1026 int last = ivl_signal_array_base(sig)+word_count-1;
1027 int first = ivl_signal_array_base(sig);
1028 fprintf(vvp_out, "v%p .array%s \"%s\", %d %d, %d %d;\n",
1029 sig, datatype_flag,
1030 vvp_mangle_name(ivl_signal_basename(sig)),
1031 last, first, msb, lsb);
1033 } else {
1035 fprintf(vvp_out, "v%p_0 .var%s \"%s\", %d %d;\n",
1036 sig, datatype_flag,
1037 vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb);
1043 * This function draws a net. This is a bit more complicated as we
1044 * have to find an appropriate functor to connect to the input.
1046 static void draw_net_in_scope(ivl_signal_t sig)
1048 int msb = ivl_signal_msb(sig);
1049 int lsb = ivl_signal_lsb(sig);
1051 const char*datatype_flag = ivl_signal_signed(sig)? "/s" : "";
1052 unsigned iword;
1054 /* Skip the local signal. */
1055 if (ivl_signal_local(sig))
1056 return;
1058 switch (ivl_signal_data_type(sig)) {
1059 case IVL_VT_REAL:
1060 datatype_flag = "/real";
1061 break;
1062 default:
1063 break;
1066 for (iword = 0 ; iword < ivl_signal_array_count(sig); iword += 1) {
1068 unsigned word_count = ivl_signal_array_count(sig);
1069 unsigned dimensions = ivl_signal_dimensions(sig);
1070 struct vvp_nexus_data*nex_data;
1072 /* Connect the pin of the signal to something. */
1073 ivl_nexus_t nex = ivl_signal_nex(sig, iword);
1074 const char*driver = draw_net_input(nex);
1076 nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex);
1077 assert(nex_data);
1079 if (nex_data->net == 0) {
1080 int strength_aware_flag = 0;
1081 const char*vec8 = "";
1082 if (nex_data->flags&VVP_NEXUS_DATA_STR)
1083 strength_aware_flag = 1;
1084 if (nex_data->drivers_count > 1)
1085 vec8 = "8";
1086 if (strength_aware_flag)
1087 vec8 = "8";
1089 if (iword == 0 && dimensions > 0) {
1090 int last = ivl_signal_array_base(sig) + word_count-1;
1091 int first = ivl_signal_array_base(sig);
1092 fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n",
1093 sig, vvp_mangle_name(ivl_signal_basename(sig)),
1094 last, first);
1096 if (dimensions > 0) {
1097 /* If this is a word of an array, then use an
1098 array reference in place of the net name. */
1099 fprintf(vvp_out, "v%p_%u .net%s%s v%p %u, %d %d, %s;"
1100 " %u drivers%s\n",
1101 sig, iword, vec8, datatype_flag, sig,
1102 iword, msb, lsb, driver,
1103 nex_data->drivers_count,
1104 strength_aware_flag?", strength-aware":"");
1105 } else {
1106 /* If this is an isolated word, it uses its
1107 own name. */
1108 assert(word_count == 1);
1109 fprintf(vvp_out, "v%p_%u .net%s%s \"%s\", %d %d, %s;"
1110 " %u drivers%s\n",
1111 sig, iword, vec8, datatype_flag,
1112 vvp_mangle_name(ivl_signal_basename(sig)),
1113 msb, lsb, driver,
1114 nex_data->drivers_count,
1115 strength_aware_flag?", strength-aware":"");
1117 nex_data->net = sig;
1118 nex_data->net_word = iword;
1120 } else if (dimensions > 0) {
1122 /* In this case, we have an alias to an existing
1123 signal array. this typically is an instance of
1124 port collapsing that the elaborator combined to
1125 discover that the entire array can be collapsed,
1126 so the word count for the signal and the alias
1127 *must* match. */
1128 assert(word_count == ivl_signal_array_count(nex_data->net));
1130 if (iword == 0) {
1131 fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n",
1132 sig, vvp_mangle_name(ivl_signal_basename(sig)),
1133 nex_data->net, ivl_signal_basename(nex_data->net));
1135 /* An alias for the individual words? */
1136 #if 0
1137 fprintf(vvp_out, "v%p_%u .alias%s v%p, %d %d, v%p_%u;\n",
1138 sig, iword, datatype_flag, sig,
1139 msb, lsb, nex_data->net, nex_data->net_word);
1140 #endif
1141 } else {
1142 /* Finally, we may have an alias that is a word
1143 connected to another word. Again, this is a
1144 case of port collapsing. */
1146 /* For the alias, create a different kind of node
1147 that refers to the alias source data instead of
1148 holding our own data. */
1149 fprintf(vvp_out, "v%p_%u .alias%s \"%s\", %d %d, v%p_%u;\n",
1150 sig, iword, datatype_flag,
1151 vvp_mangle_name(ivl_signal_basename(sig)),
1152 msb, lsb, nex_data->net, nex_data->net_word);
1157 static void draw_delay(ivl_net_logic_t lptr)
1159 ivl_expr_t d0 = ivl_logic_delay(lptr, 0);
1160 ivl_expr_t d1 = ivl_logic_delay(lptr, 1);
1161 ivl_expr_t d2 = ivl_logic_delay(lptr, 2);
1163 if (d0 == 0 && d1 == 0 && d2 == 0)
1164 return;
1166 /* FIXME: Assume that the expression is a constant */
1167 assert(number_is_immediate(d0, 64));
1168 assert(number_is_immediate(d1, 64));
1169 assert(number_is_immediate(d2, 64));
1171 if (d0 == d1 && d1 == d2)
1172 fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
1173 else
1174 fprintf(vvp_out, " (%lu,%lu,%lu)",
1175 get_number_immediate(d0),
1176 get_number_immediate(d1),
1177 get_number_immediate(d2));
1180 static void draw_udp_def(ivl_udp_t udp)
1182 unsigned init;
1183 unsigned i;
1185 switch (ivl_udp_init(udp))
1187 case '0':
1188 init = 0;
1189 break;
1190 case '1':
1191 init = 1;
1192 break;
1193 default:
1194 init = 2;
1195 break;
1198 if (ivl_udp_sequ(udp))
1199 fprintf(vvp_out,
1200 "UDP_%s .udp/sequ \"%s\", %d, %d",
1201 vvp_mangle_id(ivl_udp_name(udp)),
1202 vvp_mangle_name(ivl_udp_name(udp)),
1203 ivl_udp_nin(udp),
1204 init );
1205 else
1206 fprintf(vvp_out,
1207 "UDP_%s .udp/comb \"%s\", %d",
1208 vvp_mangle_id(ivl_udp_name(udp)),
1209 vvp_mangle_name(ivl_udp_name(udp)),
1210 ivl_udp_nin(udp));
1212 for (i=0; i<ivl_udp_rows(udp); i++)
1213 fprintf(vvp_out, "\n ,\"%s\"", ivl_udp_row(udp, i) );
1215 fprintf(vvp_out, ";\n");
1218 static void draw_udp_in_scope(ivl_net_logic_t lptr)
1220 unsigned pdx;
1222 ivl_udp_t udp = ivl_logic_udp(lptr);
1224 static ivl_udp_t *udps = 0x0;
1225 static int nudps = 0;
1226 int i;
1228 for (i=0; i<nudps; i++)
1229 if (udps[i] == udp)
1230 break;
1232 if (i >= nudps)
1234 udps = realloc(udps, (nudps+1)*sizeof(ivl_udp_t));
1235 assert(udps);
1236 udps[nudps++] = udp;
1237 draw_udp_def(udp);
1240 fprintf(vvp_out, "L_%p .udp", lptr);
1241 fprintf(vvp_out, " UDP_%s",
1242 vvp_mangle_id(ivl_udp_name(udp)));
1243 draw_delay(lptr);
1245 for (pdx = 1 ; pdx < ivl_logic_pins(lptr) ; pdx += 1) {
1246 ivl_nexus_t nex = ivl_logic_pin(lptr, pdx);
1248 /* Unlike other logic gates, primitives may have unconnected
1249 inputs. The proper behavior is to attach a HiZ to the
1250 port. */
1251 if (nex == 0) {
1252 assert(ivl_logic_width(lptr) == 1);
1253 fprintf(vvp_out, ", C4<z>");
1255 } else {
1256 fprintf(vvp_out, ", %s", draw_net_input(nex));
1260 fprintf(vvp_out, ";\n");
1263 static void draw_logic_in_scope(ivl_net_logic_t lptr)
1265 unsigned pdx;
1266 const char*ltype = "?";
1267 const char*lcasc = 0;
1268 char identity_val = '0';
1270 int need_delay_flag = ivl_logic_delay(lptr,0)? 1 : 0;
1272 unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0));
1274 ivl_drive_t str0, str1;
1276 int level;
1277 int ninp = ivl_logic_pins(lptr) - 1;
1278 typedef const char*const_charp;
1279 const_charp*input_strings = calloc(ninp, sizeof(const_charp));
1281 for (pdx = 0 ; pdx < ninp ; pdx += 1) {
1282 ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
1283 if (nex == 0) {
1284 /* Only UDPs can have unconnected inputs. */
1285 assert(ivl_logic_type(lptr) == IVL_LO_UDP);
1286 input_strings[pdx] = 0;
1287 } else {
1288 input_strings[pdx] = draw_net_input(nex);
1292 switch (ivl_logic_type(lptr)) {
1294 case IVL_LO_UDP:
1295 free(input_strings);
1296 draw_udp_in_scope(lptr);
1297 return;
1299 case IVL_LO_BUFZ: {
1300 /* Draw bufz objects, but only if the gate cannot
1301 be elided. If I can elide it, then the
1302 draw_nex_input will take care of it for me. */
1303 ivl_nexus_ptr_t nptr = ivl_logic_pin_ptr(lptr,0);
1305 ltype = "BUFZ";
1307 if (can_elide_bufz(lptr, nptr))
1308 return;
1310 break;
1313 case IVL_LO_PULLDOWN:
1314 case IVL_LO_PULLUP:
1315 /* Skip pullup and pulldown objects. Things that have
1316 pull objects as inputs will instead generate the
1317 appropriate C<?> symbol. */
1318 free(input_strings);
1319 return;
1321 case IVL_LO_AND:
1322 ltype = "AND";
1323 identity_val = '1';
1324 break;
1326 case IVL_LO_BUF:
1327 ltype = "BUF";
1328 break;
1330 case IVL_LO_BUFIF0:
1331 ltype = "BUFIF0";
1332 break;
1334 case IVL_LO_BUFIF1:
1335 ltype = "BUFIF1";
1336 break;
1338 case IVL_LO_NAND:
1339 ltype = "NAND";
1340 lcasc = "AND";
1341 identity_val = '1';
1342 break;
1344 case IVL_LO_NOR:
1345 ltype = "NOR";
1346 lcasc = "OR";
1347 break;
1349 case IVL_LO_NOT:
1350 ltype = "NOT";
1351 break;
1353 case IVL_LO_OR:
1354 ltype = "OR";
1355 break;
1357 case IVL_LO_XNOR:
1358 ltype = "XNOR";
1359 lcasc = "XOR";
1360 break;
1362 case IVL_LO_XOR:
1363 ltype = "XOR";
1364 break;
1366 case IVL_LO_CMOS:
1367 ltype = "CMOS";
1368 break;
1370 case IVL_LO_PMOS:
1371 ltype = "PMOS";
1372 break;
1374 case IVL_LO_NMOS:
1375 ltype = "NMOS";
1376 break;
1378 case IVL_LO_RCMOS:
1379 ltype = "RCMOS";
1380 break;
1382 case IVL_LO_RPMOS:
1383 ltype = "RPMOS";
1384 break;
1386 case IVL_LO_RNMOS:
1387 ltype = "RNMOS";
1388 break;
1390 case IVL_LO_NOTIF0:
1391 ltype = "NOTIF0";
1392 break;
1394 case IVL_LO_NOTIF1:
1395 ltype = "NOTIF1";
1396 break;
1398 default:
1399 fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %u\n",
1400 ivl_logic_type(lptr));
1401 ltype = "?";
1402 break;
1405 { ivl_nexus_t nex = ivl_logic_pin(lptr, 0);
1406 ivl_nexus_ptr_t nptr = 0;
1407 unsigned idx;
1408 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
1409 nptr = ivl_nexus_ptr(nex,idx);
1410 if (ivl_nexus_ptr_log(nptr) != lptr)
1411 continue;
1412 if (ivl_nexus_ptr_pin(nptr) != 0)
1413 continue;
1414 break;
1416 str0 = ivl_nexus_ptr_drive0(nptr);
1417 str1 = ivl_nexus_ptr_drive1(nptr);
1420 if (!lcasc)
1421 lcasc = ltype;
1423 /* Get all the input label that I will use for parameters to
1424 the functor that I create later. */
1425 ninp = ivl_logic_pins(lptr) - 1;
1426 input_strings = calloc(ninp, sizeof(char*));
1427 for (pdx = 0 ; pdx < ninp ; pdx += 1)
1428 input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));
1430 level = 0;
1431 ninp = ivl_logic_pins(lptr) - 1;
1432 while (ninp) {
1433 int inst;
1434 for (inst = 0; inst < ninp; inst += 4) {
1435 if (ninp > 4)
1436 fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
1437 lptr, level, inst, lcasc, vector_width);
1438 else {
1439 fprintf(vvp_out, "L_%p%s .functor %s %u",
1440 lptr, need_delay_flag? "/d" : "",
1441 ltype, vector_width);
1443 if (str0 != IVL_DR_STRONG || str1 != IVL_DR_STRONG)
1444 fprintf(vvp_out, " [%u %u]", str0, str1);
1447 for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) {
1448 if (level) {
1449 fprintf(vvp_out, ", L_%p/%d/%d",
1450 lptr, level - 1, pdx*4);
1451 } else {
1452 fprintf(vvp_out, ", %s", input_strings[pdx]);
1455 for ( ; pdx < inst+4 ; pdx += 1) {
1456 unsigned wdx;
1457 fprintf(vvp_out, ", C4<");
1458 for (wdx = 0 ; wdx < vector_width ; wdx += 1)
1459 fprintf(vvp_out, "%c", identity_val);
1460 fprintf(vvp_out, ">");
1463 fprintf(vvp_out, ";\n");
1465 if (ninp > 4)
1466 ninp = (ninp+3) / 4;
1467 else
1468 ninp = 0;
1469 level += 1;
1472 /* Free the array of char*. The strings themselves are
1473 persistent, held by the ivl_nexus_t objects. */
1474 free(input_strings);
1476 /* If there are delays, then draw the delay functor to carry
1477 that delay. This is the final output. */
1478 if (need_delay_flag) {
1479 ivl_expr_t rise_exp = ivl_logic_delay(lptr,0);
1480 ivl_expr_t fall_exp = ivl_logic_delay(lptr,1);
1481 ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);
1483 if (number_is_immediate(rise_exp,64)
1484 && number_is_immediate(fall_exp,64)
1485 && number_is_immediate(decay_exp,64)) {
1487 fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
1488 lptr, get_number_immediate(rise_exp),
1489 get_number_immediate(rise_exp),
1490 get_number_immediate(rise_exp), lptr);
1491 } else {
1492 ivl_signal_t sig;
1493 assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
1494 assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
1495 assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);
1497 fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr);
1499 sig = ivl_expr_signal(rise_exp);
1500 assert(ivl_signal_array_count(sig) == 1);
1501 fprintf(vvp_out, ", v%p_0", sig);
1503 sig = ivl_expr_signal(fall_exp);
1504 assert(ivl_signal_array_count(sig) == 1);
1505 fprintf(vvp_out, ", v%p_0", sig);
1507 sig = ivl_expr_signal(decay_exp);
1508 assert(ivl_signal_array_count(sig) == 1);
1509 fprintf(vvp_out, ", v%p_0;\n", sig);
1514 static void draw_event_in_scope(ivl_event_t obj)
1516 unsigned nany = ivl_event_nany(obj);
1517 unsigned nneg = ivl_event_nneg(obj);
1518 unsigned npos = ivl_event_npos(obj);
1520 unsigned cnt = 0;
1522 /* Figure out how many probe functors are needed. */
1523 if (nany > 0)
1524 cnt += (nany+3) / 4;
1526 if (nneg > 0)
1527 cnt += (nneg+3) / 4;
1529 if (npos > 0)
1530 cnt += (npos+3) / 4;
1532 if (cnt == 0) {
1533 /* If none are needed, then this is a named event. The
1534 code needed is easy. */
1535 fprintf(vvp_out, "E_%p .event \"%s\";\n", obj,
1536 vvp_mangle_name(ivl_event_basename(obj)));
1538 } else if (cnt > 1) {
1539 /* There are a bunch of events that need to be event/or
1540 combined. */
1541 unsigned idx;
1542 unsigned ecnt = 0;
1544 for (idx = 0 ; idx < nany ; idx += 4, ecnt += 1) {
1545 unsigned sub, top;
1547 fprintf(vvp_out, "E_%p/%u .event edge", obj, ecnt);
1549 top = idx + 4;
1550 if (nany < top)
1551 top = nany;
1552 for (sub = idx ; sub < top ; sub += 1) {
1553 ivl_nexus_t nex = ivl_event_any(obj, sub);
1554 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1556 fprintf(vvp_out, ";\n");
1559 for (idx = 0 ; idx < nneg ; idx += 4, ecnt += 1) {
1560 unsigned sub, top;
1562 fprintf(vvp_out, "E_%p/%u .event negedge", obj, ecnt);
1564 top = idx + 4;
1565 if (nneg < top)
1566 top = nneg;
1567 for (sub = idx ; sub < top ; sub += 1) {
1568 ivl_nexus_t nex = ivl_event_neg(obj, sub);
1569 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1571 fprintf(vvp_out, ";\n");
1574 for (idx = 0 ; idx < npos ; idx += 4, ecnt += 1) {
1575 unsigned sub, top;
1577 fprintf(vvp_out, "E_%p/%u .event posedge", obj, ecnt);
1579 top = idx + 4;
1580 if (npos < top)
1581 top = npos;
1582 for (sub = idx ; sub < top ; sub += 1) {
1583 ivl_nexus_t nex = ivl_event_pos(obj, sub);
1584 fprintf(vvp_out, ", %s", draw_input_from_net(nex));
1586 fprintf(vvp_out, ";\n");
1589 assert(ecnt == cnt);
1591 fprintf(vvp_out, "E_%p .event/or", obj);
1592 fprintf(vvp_out, " E_%p/0", obj);
1594 for (idx = 1 ; idx < cnt ; idx += 1)
1595 fprintf(vvp_out, ", E_%p/%u", obj, idx);
1597 fprintf(vvp_out, ";\n");
1599 } else {
1600 unsigned num_input_strings = nany + nneg + npos;
1601 unsigned idx;
1602 ivl_nexus_t input_nexa[4];
1603 const char*edge = 0;
1605 assert(num_input_strings <= 4);
1607 if (nany > 0) {
1608 assert((nneg + npos) == 0);
1609 assert(nany <= 4);
1611 edge = "edge";
1613 for (idx = 0 ; idx < nany ; idx += 1) {
1614 ivl_nexus_t nex = ivl_event_any(obj, idx);
1615 input_nexa[idx] = nex;
1618 } else if (nneg > 0) {
1619 assert((nany + npos) == 0);
1620 edge = "negedge";
1622 for (idx = 0 ; idx < nneg ; idx += 1) {
1623 ivl_nexus_t nex = ivl_event_neg(obj, idx);
1624 input_nexa[idx] = nex;
1627 } else {
1628 assert((nany + nneg) == 0);
1629 edge = "posedge";
1631 for (idx = 0 ; idx < npos ; idx += 1) {
1632 ivl_nexus_t nex = ivl_event_pos(obj, idx);
1633 input_nexa[idx] = nex;
1637 fprintf(vvp_out, "E_%p .event %s", obj, edge);
1638 for (idx = 0 ; idx < num_input_strings ; idx += 1)
1639 fprintf(vvp_out, ", %s", draw_input_from_net(input_nexa[idx]));
1641 fprintf(vvp_out, ";\n");
1646 * This function draws any functors needed to calculate the input to
1647 * this nexus, and leaves in the data array strings that can be used
1648 * as functor arguments. The strings are from the draw_net_input
1649 * function, which in turn returns nexus names, so the strings are
1650 * safe to pass around.
1652 static void draw_lpm_data_inputs(ivl_lpm_t net, unsigned base,
1653 unsigned ndata, const char**src_table)
1655 unsigned idx;
1656 for (idx = 0 ; idx < ndata ; idx += 1) {
1657 ivl_nexus_t nex = ivl_lpm_data(net, base+idx);
1658 src_table[idx] = draw_net_input(nex);
1662 static void draw_lpm_add(ivl_lpm_t net)
1664 const char*src_table[2];
1665 unsigned width;
1666 const char*type = "";
1667 ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0));
1668 ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1));
1669 ivl_variable_type_t dto = IVL_VT_LOGIC;
1671 if (dta == IVL_VT_REAL && dtb == IVL_VT_REAL)
1672 dto = IVL_VT_REAL;
1674 width = ivl_lpm_width(net);
1676 switch (ivl_lpm_type(net)) {
1677 case IVL_LPM_ADD:
1678 type = "sum";
1679 break;
1680 case IVL_LPM_SUB:
1681 if (dto == IVL_VT_REAL)
1682 type = "sub.r";
1683 else
1684 type = "sub";
1685 break;
1686 case IVL_LPM_MULT:
1687 type = "mult";
1688 break;
1689 case IVL_LPM_DIVIDE:
1690 if (dto == IVL_VT_REAL)
1691 type = "div.r";
1692 else if (ivl_lpm_signed(net))
1693 type = "div.s";
1694 else
1695 type = "div";
1696 break;
1697 case IVL_LPM_MOD:
1698 type = "mod";
1699 break;
1700 default:
1701 assert(0);
1704 draw_lpm_data_inputs(net, 0, 2, src_table);
1705 fprintf(vvp_out, "L_%p .arith/%s %u, %s, %s;\n",
1706 net, type, width, src_table[0], src_table[1]);
1710 * The read port to an array is generated as a single record that takes
1711 * the address as an input.
1713 static void draw_lpm_array(ivl_lpm_t net)
1715 ivl_nexus_t nex;
1716 ivl_signal_t mem = ivl_lpm_array(net);
1718 fprintf(vvp_out, "L_%p .array/port v%p, ", net, mem);
1720 nex = ivl_lpm_select(net);
1721 fprintf(vvp_out, "%s", draw_net_input(nex));
1723 fprintf(vvp_out, ";\n");
1726 static void draw_lpm_cmp(ivl_lpm_t net)
1728 const char*src_table[2];
1729 unsigned width;
1730 const char*type = "";
1731 const char*signed_string = ivl_lpm_signed(net)? ".s" : "";
1733 width = ivl_lpm_width(net);
1735 switch (ivl_lpm_type(net)) {
1736 case IVL_LPM_CMP_EEQ:
1737 type = "eeq";
1738 signed_string = "";
1739 break;
1740 case IVL_LPM_CMP_EQ:
1741 type = "eq";
1742 signed_string = "";
1743 break;
1744 case IVL_LPM_CMP_GE:
1745 type = "ge";
1746 break;
1747 case IVL_LPM_CMP_GT:
1748 type = "gt";
1749 break;
1750 case IVL_LPM_CMP_NE:
1751 type = "ne";
1752 signed_string = "";
1753 break;
1754 case IVL_LPM_CMP_NEE:
1755 type = "nee";
1756 signed_string = "";
1757 break;
1758 default:
1759 assert(0);
1762 draw_lpm_data_inputs(net, 0, 2, src_table);
1763 fprintf(vvp_out, "L_%p .cmp/%s%s %u, %s, %s;\n",
1764 net, type, signed_string, width,
1765 src_table[0], src_table[1]);
1769 * This function draws the arguments to a .const node using the
1770 * lpm inputs starting at "start" and for "cnt" inputs. This input
1771 * count must be <= 4. It is up to the caller to write the header part
1772 * of the statement, and to organize the data into multiple
1773 * statements.
1775 * Return the width of the final concatenation.
1777 static unsigned lpm_concat_inputs(ivl_lpm_t net, unsigned start,
1778 unsigned cnt, const char*src_table[])
1780 unsigned idx;
1781 unsigned wid = 0;
1783 assert(cnt <= 4);
1785 /* First, draw the [L M N O] part of the statement, the list
1786 of widths for the .concat statement. */
1787 fprintf(vvp_out, "[");
1789 for (idx = 0 ; idx < cnt ; idx += 1) {
1790 ivl_nexus_t nex = ivl_lpm_data(net, start+idx);
1791 unsigned nexus_width = width_of_nexus(nex);
1792 fprintf(vvp_out, " %u", nexus_width);
1793 wid += nexus_width;
1796 for ( ; idx < 4 ; idx += 1)
1797 fprintf(vvp_out, " 0");
1799 fprintf(vvp_out, "]");
1802 for (idx = 0 ; idx < cnt ; idx += 1) {
1803 fprintf(vvp_out, ", %s", src_table[idx]);
1806 fprintf(vvp_out, ";\n");
1807 return wid;
1811 * Implement the general IVL_LPM_CONCAT using .concat nodes. Use as
1812 * many nested nodes as necessary to support the desired number of
1813 * input vectors.
1815 static void draw_lpm_concat(ivl_lpm_t net)
1817 const char*src_table[4];
1818 unsigned icnt = ivl_lpm_selects(net);
1820 if (icnt <= 4) {
1821 /* This is the easiest case. There are 4 or fewer input
1822 vectors, so the entire IVL_LPM_CONCAT can be
1823 implemented with a single .concat node. */
1824 draw_lpm_data_inputs(net, 0, icnt, src_table);
1825 fprintf(vvp_out, "L_%p .concat ", net);
1826 lpm_concat_inputs(net, 0, icnt, src_table);
1828 } else {
1829 /* If there are more than 4 inputs, things get more
1830 complicated. We need to generate a balanced tree of
1831 .concat nodes to blend the inputs down to a single
1832 root node, that becomes the output from the
1833 concatenation. */
1834 unsigned idx, depth;
1835 struct concat_tree {
1836 unsigned base;
1837 unsigned wid;
1838 } *tree;
1840 tree = malloc((icnt + 3)/4 * sizeof(struct concat_tree));
1842 /* First, fill in all the leaves with the initial inputs
1843 to the tree. After this loop, there are (icnt+3)/4
1844 .concat nodes drawn, that together take all the
1845 inputs. */
1846 for (idx = 0 ; idx < icnt ; idx += 4) {
1847 unsigned wid = 0;
1848 unsigned trans = 4;
1849 if ((idx + trans) > icnt)
1850 trans = icnt - idx;
1852 draw_lpm_data_inputs(net, idx, trans, src_table);
1853 fprintf(vvp_out, "LS_%p_0_%u .concat ", net, idx);
1854 wid = lpm_concat_inputs(net, idx, trans, src_table);
1856 tree[idx/4].base = idx;
1857 tree[idx/4].wid = wid;
1860 /* icnt is the input count for the level. It is the
1861 number of .concats of the previous level that have to
1862 be concatenated at the current level. (This is not
1863 the same as the bit width.) */
1864 icnt = (icnt + 3)/4;
1866 /* Tree now has icnt nodes that are depth=0 concat nodes
1867 which take in the leaf inputs. The while loop below
1868 starts and ends with a tree of icnt nodes. Each time
1869 through, there are 1/4 the nodes we started
1870 with. Thus, we eventually get down to <=4 nodes, and
1871 that is when we fall out of the loop. */
1873 depth = 1;
1874 while (icnt > 4) {
1875 for (idx = 0 ; idx < icnt ; idx += 4) {
1876 unsigned tdx;
1877 unsigned wid = 0;
1878 unsigned trans = 4;
1879 if ((idx+trans) > icnt)
1880 trans = icnt - idx;
1882 fprintf(vvp_out, "LS_%p_%u_%u .concat [",
1883 net, depth, idx);
1885 for (tdx = 0 ; tdx < trans ; tdx += 1) {
1886 fprintf(vvp_out, " %u", tree[idx+tdx].wid);
1887 wid += tree[idx+tdx].wid;
1890 for ( ; tdx < 4 ; tdx += 1)
1891 fprintf(vvp_out, " 0");
1893 fprintf(vvp_out, "]");
1895 for (tdx = 0; tdx < trans ; tdx += 1) {
1896 fprintf(vvp_out, ", LS_%p_%u_%u", net,
1897 depth-1, tree[idx+tdx].base);
1900 fprintf(vvp_out, ";\n");
1901 tree[idx/4].base = idx;
1902 tree[idx/4].wid = wid;
1905 depth += 1;
1906 icnt = (icnt + 3)/4;
1909 /* Finally, draw the root node that takes in the final
1910 row of tree nodes and generates a single output. */
1911 fprintf(vvp_out, "L_%p .concat [", net);
1912 for (idx = 0 ; idx < icnt ; idx += 1)
1913 fprintf(vvp_out, " %u", tree[idx].wid);
1914 for ( ; idx < 4 ; idx += 1)
1915 fprintf(vvp_out, " 0");
1916 fprintf(vvp_out, "]");
1918 for (idx = 0 ; idx < icnt ; idx += 1)
1919 fprintf(vvp_out, ", LS_%p_%u_%u",
1920 net, depth-1, tree[idx].base);
1922 fprintf(vvp_out, ";\n");
1923 free(tree);
1928 * primitive FD (q, clk, ce, d);
1929 * output q;
1930 * reg q;
1931 * input clk, ce, d;
1932 * table
1933 * // clk ce d r s q q+
1934 * r 1 0 0 0 : ? : 0;
1935 * r 1 1 0 0 : ? : 1;
1936 * f 1 ? 0 0 : ? : -;
1937 * ? 1 ? 0 0 : ? : -;
1938 * * 0 ? 0 0 : ? : -;
1939 * ? ? ? 1 ? : ? : 0;
1940 * ? ? ? 0 1 : ? : 1;
1941 * endtable
1942 * endprimitive
1944 static void draw_lpm_ff(ivl_lpm_t net)
1946 ivl_expr_t aset_expr = 0;
1947 const char*aset_bits = 0;
1949 ivl_nexus_t nex;
1950 unsigned width;
1952 width = ivl_lpm_width(net);
1954 aset_expr = ivl_lpm_aset_value(net);
1955 if (aset_expr) {
1956 assert(ivl_expr_width(aset_expr) == width);
1957 aset_bits = ivl_expr_bits(aset_expr);
1961 fprintf(vvp_out, "L_%p .dff ", net);
1963 nex = ivl_lpm_data(net,0);
1964 assert(nex);
1965 fprintf(vvp_out, "%s", draw_net_input(nex));
1967 nex = ivl_lpm_clk(net);
1968 assert(nex);
1969 fprintf(vvp_out, ", %s", draw_net_input(nex));
1971 nex = ivl_lpm_enable(net);
1972 if (nex) {
1973 fprintf(vvp_out, ", %s", draw_net_input(nex));
1974 } else {
1975 fprintf(vvp_out, ", C4<1>");
1978 /* Stub asynchronous input for now. */
1979 fprintf(vvp_out, ", C4<z>");
1981 fprintf(vvp_out, ";\n");
1984 static void draw_lpm_shiftl(ivl_lpm_t net)
1986 unsigned width = ivl_lpm_width(net);
1987 const char* signed_flag = ivl_lpm_signed(net)? "s" : "";
1989 if (ivl_lpm_type(net) == IVL_LPM_SHIFTR)
1990 fprintf(vvp_out, "L_%p .shift/r%s %u", net, signed_flag, width);
1991 else
1992 fprintf(vvp_out, "L_%p .shift/l %u", net, width);
1994 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 0)));
1996 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 1)));
1998 fprintf(vvp_out, ";\n");
2001 static void draw_type_string_of_nex(ivl_nexus_t nex)
2003 switch (data_type_of_nexus(nex)) {
2004 case IVL_VT_REAL:
2005 fprintf(vvp_out, "r");
2006 break;
2007 case IVL_VT_LOGIC:
2008 case IVL_VT_BOOL:
2009 fprintf(vvp_out, "v%d", width_of_nexus(nex));
2010 break;
2011 default:
2012 assert(0);
2013 break;
2017 static void draw_lpm_sfunc(ivl_lpm_t net)
2019 unsigned idx;
2020 fprintf(vvp_out, "L_%p .sfunc \"%s\"", net, ivl_lpm_string(net));
2022 /* Print the function type descriptor string. */
2023 fprintf(vvp_out, ", \"");
2025 draw_type_string_of_nex(ivl_lpm_q(net,0));
2027 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1)
2028 draw_type_string_of_nex(ivl_lpm_data(net,idx));
2030 fprintf(vvp_out, "\"");
2032 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2033 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx)));
2036 fprintf(vvp_out, ";\n");
2039 static void draw_lpm_ufunc(ivl_lpm_t net)
2041 unsigned idx;
2042 ivl_scope_t def = ivl_lpm_define(net);
2044 fprintf(vvp_out, "L_%p .ufunc TD_%s, %u", net,
2045 ivl_scope_name(def),
2046 ivl_lpm_width(net));
2048 /* Print all the net signals that connect to the input of the
2049 function. */
2050 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2051 fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, idx)));
2055 assert((ivl_lpm_size(net)+1) == ivl_scope_ports(def));
2057 /* Now print all the variables in the function scope that
2058 receive the input values given in the previous list. */
2059 for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
2060 ivl_signal_t psig = ivl_scope_port(def, idx+1);
2062 if (idx == 0)
2063 fprintf(vvp_out, " (");
2064 else
2065 fprintf(vvp_out, ", ");
2067 assert(ivl_signal_array_count(psig) == 1);
2068 fprintf(vvp_out, "v%p_0", psig);
2071 fprintf(vvp_out, ")");
2073 /* Finally, print the reference to the signal from which the
2074 result is collected. */
2075 { ivl_signal_t psig = ivl_scope_port(def, 0);
2076 assert(ivl_lpm_width(net) == ivl_signal_width(psig));
2077 assert(ivl_signal_array_count(psig) == 1);
2079 fprintf(vvp_out, " v%p_0", psig);
2082 fprintf(vvp_out, ";\n");
2086 * Handle a PART SELECT device. This has a single input and output,
2087 * plus an optional extra input that is a non-constant base.
2089 static void draw_lpm_part(ivl_lpm_t net)
2091 unsigned width, base;
2092 ivl_nexus_t sel;
2094 width = ivl_lpm_width(net);
2095 base = ivl_lpm_base(net);
2096 sel = ivl_lpm_data(net,1);
2098 if (sel == 0) {
2099 fprintf(vvp_out, "L_%p .part %s",
2100 net, draw_net_input(ivl_lpm_data(net, 0)));
2101 fprintf(vvp_out, ", %u, %u;\n", base, width);
2102 } else {
2103 fprintf(vvp_out, "L_%p .part/v %s",
2104 net, draw_net_input(ivl_lpm_data(net,0)));
2105 fprintf(vvp_out, ", %s", draw_net_input(sel));
2106 fprintf(vvp_out, ", %u;\n", width);
2111 * Handle a PART SELECT PV device. Generate a .part/pv node that
2112 * includes the part input, and the geometry of the part.
2114 static void draw_lpm_part_pv(ivl_lpm_t net)
2116 unsigned width = ivl_lpm_width(net);
2117 unsigned base = ivl_lpm_base(net);
2118 unsigned signal_width = width_of_nexus(ivl_lpm_q(net,0));
2120 fprintf(vvp_out, "L_%p .part/pv %s",
2121 net, draw_net_input(ivl_lpm_data(net, 0)));
2123 fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
2127 * Handle the drawing of a bi-directional part select. The two ports
2128 * are simultaneously input and output. A simple minded connect of the
2129 * input to the output causes a functor cycle which will lock into an
2130 * X value, so something special is needed.
2132 * NOTE: The inputs of the tran device at this point need to be from
2133 * all the drivers of the nexus *except* the tran itself. This
2134 * function will draw three labels that can be linked:
2136 * The ivl_lpm_q of a part(bi) may be a smaller vector then the
2137 * ivl_lpm_data, the tran acts like a forward part select in that
2138 * way.
2140 * The device creates these nodes:
2142 * - L_%p/i
2143 * This is the Q port of the tran resolved and padded to the maximum
2144 * width of the tran. The tran itself is not included in the
2145 * resolution of this port.
2147 * - L_%p/V
2148 * This is the Q and D parts resolved together, still without the tran
2149 * driving anything.
2151 * - L_%p/P
2152 * This is the /V node part-selected back to the dimensions of the Q
2153 * side.
2155 static void draw_lpm_part_bi(ivl_lpm_t net)
2157 unsigned width = ivl_lpm_width(net);
2158 unsigned base = ivl_lpm_base(net);
2159 unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
2161 unsigned idx;
2162 ivl_nexus_t nex;
2163 ivl_nexus_ptr_t ptr = 0;
2165 char*p_str;
2166 char*v_str;
2168 /* It seems implausible that the two inputs of a tran will be
2169 connected together. So assert that this is so to simplify
2170 the code to look for the nexus_ptr_t objects. */
2171 assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
2173 nex = ivl_lpm_q(net,0);
2174 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
2175 ptr = ivl_nexus_ptr(nex, idx);
2176 if (ivl_nexus_ptr_lpm(ptr) == net)
2177 break;
2179 assert(ptr != 0);
2180 p_str = draw_net_input_x(nex, ptr, 0, 0);
2182 nex = ivl_lpm_data(net,0);
2183 for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
2184 ptr = ivl_nexus_ptr(nex, idx);
2185 if (ivl_nexus_ptr_lpm(ptr) == net)
2186 break;
2188 v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
2190 /* Pad the part-sized input out to a common width...
2191 The /i label is the Q side of the tran, resolved except for
2192 the tran itself and padded (with z) to the larger width. */
2193 fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
2194 net, p_str, base, width, signal_width);
2196 /* Resolve together the two halves of the tran...
2197 The /V label is the ports of the tran (now the same width)
2198 resolved together. Neither input to this resolver includes
2199 the tran itself. */
2200 fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
2201 net, net, v_str);
2203 /* The full-width side is created by the tran device, all we
2204 have left to to is take a part select of that for the
2205 smaller output, and this becomes the part select output of
2206 the BI device. */
2207 fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
2208 net, base, width);
2210 free(p_str);
2211 free(v_str);
2215 * Draw unary reduction devices.
2217 static void draw_lpm_re(ivl_lpm_t net, const char*type)
2219 fprintf(vvp_out, "L_%p .reduce/%s %s;\n",
2220 net, type, draw_net_input(ivl_lpm_data(net,0)));
2223 static void draw_lpm_repeat(ivl_lpm_t net)
2225 fprintf(vvp_out, "L_%p .repeat %u, %u, %s;\n", net,
2226 ivl_lpm_width(net), ivl_lpm_size(net),
2227 draw_net_input(ivl_lpm_data(net,0)));
2230 static void draw_lpm_sign_ext(ivl_lpm_t net)
2232 fprintf(vvp_out, "L_%p .extend/s %u, %s;\n",
2233 net, ivl_lpm_width(net),
2234 draw_net_input(ivl_lpm_data(net,0)));
2237 static void draw_lpm_in_scope(ivl_lpm_t net)
2239 switch (ivl_lpm_type(net)) {
2241 case IVL_LPM_ADD:
2242 case IVL_LPM_SUB:
2243 case IVL_LPM_MULT:
2244 case IVL_LPM_DIVIDE:
2245 case IVL_LPM_MOD:
2246 draw_lpm_add(net);
2247 return;
2249 case IVL_LPM_ARRAY:
2250 draw_lpm_array(net);
2251 return;
2253 case IVL_LPM_PART_BI:
2254 draw_lpm_part_bi(net);
2255 return;
2257 case IVL_LPM_PART_VP:
2258 draw_lpm_part(net);
2259 return;
2261 case IVL_LPM_PART_PV:
2262 draw_lpm_part_pv(net);
2263 return;
2265 case IVL_LPM_CONCAT:
2266 draw_lpm_concat(net);
2267 return;
2269 case IVL_LPM_FF:
2270 draw_lpm_ff(net);
2271 return;
2273 case IVL_LPM_CMP_EEQ:
2274 case IVL_LPM_CMP_EQ:
2275 case IVL_LPM_CMP_GE:
2276 case IVL_LPM_CMP_GT:
2277 case IVL_LPM_CMP_NE:
2278 case IVL_LPM_CMP_NEE:
2279 draw_lpm_cmp(net);
2280 return;
2282 case IVL_LPM_MUX:
2283 draw_lpm_mux(net);
2284 return;
2286 case IVL_LPM_RE_AND:
2287 draw_lpm_re(net, "and");
2288 return;
2289 case IVL_LPM_RE_OR:
2290 draw_lpm_re(net, "or");
2291 return;
2292 case IVL_LPM_RE_XOR:
2293 draw_lpm_re(net, "xor");
2294 return;
2295 case IVL_LPM_RE_NAND:
2296 draw_lpm_re(net, "nand");
2297 return;
2298 case IVL_LPM_RE_NOR:
2299 draw_lpm_re(net, "nor");
2300 return;
2301 case IVL_LPM_RE_XNOR:
2302 draw_lpm_re(net, "xnor");
2303 return;
2305 case IVL_LPM_REPEAT:
2306 draw_lpm_repeat(net);
2307 return;
2309 case IVL_LPM_SHIFTL:
2310 case IVL_LPM_SHIFTR:
2311 draw_lpm_shiftl(net);
2312 return;
2314 case IVL_LPM_SIGN_EXT:
2315 draw_lpm_sign_ext(net);
2316 return;
2318 case IVL_LPM_SFUNC:
2319 draw_lpm_sfunc(net);
2320 return;
2322 case IVL_LPM_UFUNC:
2323 draw_lpm_ufunc(net);
2324 return;
2326 default:
2327 fprintf(stderr, "XXXX LPM not supported: %s.%s\n",
2328 ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net));
2332 int draw_scope(ivl_scope_t net, ivl_scope_t parent)
2334 unsigned idx;
2335 const char *type;
2336 switch (ivl_scope_type(net)) {
2337 case IVL_SCT_MODULE: type = "module"; break;
2338 case IVL_SCT_FUNCTION: type = "function"; break;
2339 case IVL_SCT_TASK: type = "task"; break;
2340 case IVL_SCT_BEGIN: type = "begin"; break;
2341 case IVL_SCT_FORK: type = "fork"; break;
2342 case IVL_SCT_GENERATE: type = "generate"; break;
2343 default: type = "?"; assert(0);
2346 fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\"",
2347 net, type, vvp_mangle_name(ivl_scope_basename(net)),
2348 ivl_scope_tname(net));
2350 if (parent) {
2351 fprintf(vvp_out, ", S_%p;\n", parent);
2352 } else {
2354 fprintf(vvp_out, ";\n");
2357 fprintf(vvp_out, " .timescale %d %d;\n", ivl_scope_time_units(net),
2358 ivl_scope_time_precision(net));
2360 for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) {
2361 ivl_parameter_t par = ivl_scope_param(net, idx);
2362 ivl_expr_t pex = ivl_parameter_expr(par);
2363 switch (ivl_expr_type(pex)) {
2364 case IVL_EX_STRING:
2365 fprintf(vvp_out, "P_%p .param/str \"%s\", \"%s\";\n",
2366 par, ivl_parameter_basename(par),
2367 ivl_expr_string(pex));
2368 break;
2369 case IVL_EX_NUMBER:
2370 fprintf(vvp_out, "P_%p .param/l \"%s\", %sC4<",
2371 par, ivl_parameter_basename(par),
2372 ivl_expr_signed(pex)? "+":"");
2373 { const char*bits = ivl_expr_bits(pex);
2374 unsigned nbits = ivl_expr_width(pex);
2375 unsigned bb;
2376 for (bb = 0 ; bb < nbits; bb += 1)
2377 fprintf(vvp_out, "%c", bits[nbits-bb-1]);
2379 fprintf(vvp_out, ">;\n");
2380 break;
2381 default:
2382 fprintf(vvp_out, "; parameter type %d unsupported\n",
2383 ivl_expr_type(pex));
2384 break;
2388 /* Scan the scope for logic devices. For each device, draw out
2389 a functor that connects pin 0 to the output, and the
2390 remaining pins to inputs. */
2392 for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1) {
2393 ivl_net_logic_t lptr = ivl_scope_log(net, idx);
2394 draw_logic_in_scope(lptr);
2398 /* Scan the signals (reg and net) and draw the appropriate
2399 statements to make the signal function. */
2401 for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1) {
2402 ivl_signal_t sig = ivl_scope_sig(net, idx);
2404 switch (ivl_signal_type(sig)) {
2405 case IVL_SIT_REG:
2406 draw_reg_in_scope(sig);
2407 break;
2408 default:
2409 draw_net_in_scope(sig);
2410 break;
2414 for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1) {
2415 ivl_event_t event = ivl_scope_event(net, idx);
2416 draw_event_in_scope(event);
2419 for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) {
2420 ivl_lpm_t lpm = ivl_scope_lpm(net, idx);
2421 draw_lpm_in_scope(lpm);
2424 if (ivl_scope_type(net) == IVL_SCT_TASK)
2425 draw_task_definition(net);
2427 if (ivl_scope_type(net) == IVL_SCT_FUNCTION)
2428 draw_func_definition(net);
2430 ivl_scope_children(net, (ivl_scope_f*) draw_scope, net);
2431 return 0;